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
89 * Turn on debugging output (currently only the factory uses this)
96 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
99 enableGarbageCollector : true,
102 * True to automatically purge event listeners after uncaching an element (defaults to false).
103 * Note: this only happens if enableGarbageCollector is true.
106 enableListenerCollection:false,
109 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110 * the IE insecure content warning (defaults to javascript:false).
113 SSL_SECURE_URL : "javascript:false",
116 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
120 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
122 emptyFn : function(){},
125 * Copies all the properties of config to obj if they don't already exist.
126 * @param {Object} obj The receiver of the properties
127 * @param {Object} config The source of the properties
128 * @return {Object} returns obj
130 applyIf : function(o, c){
133 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
140 * Applies event listeners to elements by selectors when the document is ready.
141 * The event name is specified with an @ suffix.
144 // add a listener for click on all anchors in element with id foo
145 '#foo a@click' : function(e, t){
149 // add the same listener to multiple selectors (separated by comma BEFORE the @)
150 '#foo a, #bar span.some-class@mouseover' : function(){
155 * @param {Object} obj The list of behaviors to apply
157 addBehaviors : function(o){
159 Roo.onReady(function(){
164 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
166 var parts = b.split('@');
167 if(parts[1]){ // for Object prototype breakers
170 cache[s] = Roo.select(s);
172 cache[s].on(parts[1], o[b]);
179 * Generates unique ids. If the element already has an id, it is unchanged
180 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182 * @return {String} The generated Id.
184 id : function(el, prefix){
185 prefix = prefix || "roo-gen";
187 var id = prefix + (++idSeed);
188 return el ? (el.id ? el.id : (el.id = id)) : id;
193 * Extends one class with another class and optionally overrides members with the passed literal. This class
194 * also adds the function "override()" to the class that can be used to override
195 * members on an instance.
196 * @param {Object} subclass The class inheriting the functionality
197 * @param {Object} superclass The class being extended
198 * @param {Object} overrides (optional) A literal with members
203 var io = function(o){
208 return function(sb, sp, overrides){
209 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
212 sb = function(){sp.apply(this, arguments);};
214 var F = function(){}, sbp, spp = sp.prototype;
216 sbp = sb.prototype = new F();
220 if(spp.constructor == Object.prototype.constructor){
225 sb.override = function(o){
229 Roo.override(sb, overrides);
235 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
237 Roo.override(MyClass, {
238 newMethod1: function(){
241 newMethod2: function(foo){
246 * @param {Object} origclass The class to override
247 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
248 * containing one or more methods.
251 override : function(origclass, overrides){
253 var p = origclass.prototype;
254 for(var method in overrides){
255 p[method] = overrides[method];
260 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
266 * @param {String} namespace1
267 * @param {String} namespace2
268 * @param {String} etc
271 namespace : function(){
272 var a=arguments, o=null, i, j, d, rt;
273 for (i=0; i<a.length; ++i) {
277 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278 for (j=1; j<d.length; ++j) {
279 o[d[j]]=o[d[j]] || {};
285 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
290 * @param {String} classname
291 * @param {String} namespace (optional)
295 factory : function(c, ns)
297 // no xtype, no ns or c.xns - or forced off by c.xns
298 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
301 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302 if (c.constructor == ns[c.xtype]) {// already created...
306 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307 var ret = new ns[c.xtype](c);
311 c.xns = false; // prevent recursion..
315 * Logs to console if it can.
317 * @param {String|Object} string
322 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
329 * 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.
333 urlEncode : function(o){
339 var ov = o[key], k = Roo.encodeURIComponent(key);
340 var type = typeof ov;
341 if(type == 'undefined'){
343 }else if(type != "function" && type != "object"){
344 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345 }else if(ov instanceof Array){
347 for(var i = 0, len = ov.length; i < len; i++) {
348 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
359 * Safe version of encodeURIComponent
360 * @param {String} data
364 encodeURIComponent : function (data)
367 return encodeURIComponent(data);
368 } catch(e) {} // should be an uri encode error.
370 if (data == '' || data == null){
373 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374 function nibble_to_hex(nibble){
375 var chars = '0123456789ABCDEF';
376 return chars.charAt(nibble);
378 data = data.toString();
380 for(var i=0; i<data.length; i++){
381 var c = data.charCodeAt(i);
382 var bs = new Array();
385 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388 bs[3] = 0x80 | (c & 0x3F);
389 }else if (c > 0x800){
391 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393 bs[2] = 0x80 | (c & 0x3F);
396 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397 bs[1] = 0x80 | (c & 0x3F);
402 for(var j=0; j<bs.length; j++){
404 var hex = nibble_to_hex((b & 0xF0) >>> 4)
405 + nibble_to_hex(b &0x0F);
414 * 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]}.
415 * @param {String} string
416 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417 * @return {Object} A literal with members
419 urlDecode : function(string, overwrite){
420 if(!string || !string.length){
424 var pairs = string.split('&');
425 var pair, name, value;
426 for(var i = 0, len = pairs.length; i < len; i++){
427 pair = pairs[i].split('=');
428 name = decodeURIComponent(pair[0]);
429 value = decodeURIComponent(pair[1]);
430 if(overwrite !== true){
431 if(typeof obj[name] == "undefined"){
433 }else if(typeof obj[name] == "string"){
434 obj[name] = [obj[name]];
435 obj[name].push(value);
437 obj[name].push(value);
447 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448 * passed array is not really an array, your function is called once with it.
449 * The supplied function is called with (Object item, Number index, Array allItems).
450 * @param {Array/NodeList/Mixed} array
451 * @param {Function} fn
452 * @param {Object} scope
454 each : function(array, fn, scope){
455 if(typeof array.length == "undefined" || typeof array == "string"){
458 for(var i = 0, len = array.length; i < len; i++){
459 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
464 combine : function(){
465 var as = arguments, l = as.length, r = [];
466 for(var i = 0; i < l; i++){
468 if(a instanceof Array){
470 }else if(a.length !== undefined && !a.substr){
471 r = r.concat(Array.prototype.slice.call(a, 0));
480 * Escapes the passed string for use in a regular expression
481 * @param {String} str
484 escapeRe : function(s) {
485 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
489 callback : function(cb, scope, args, delay){
490 if(typeof cb == "function"){
492 cb.defer(delay, scope, args || []);
494 cb.apply(scope, args || []);
500 * Return the dom node for the passed string (id), dom node, or Roo.Element
501 * @param {String/HTMLElement/Roo.Element} el
502 * @return HTMLElement
504 getDom : function(el){
508 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
512 * Shorthand for {@link Roo.ComponentMgr#get}
514 * @return Roo.Component
516 getCmp : function(id){
517 return Roo.ComponentMgr.get(id);
520 num : function(v, defaultValue){
521 if(typeof v != 'number'){
527 destroy : function(){
528 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
532 as.removeAllListeners();
536 if(typeof as.purgeListeners == 'function'){
539 if(typeof as.destroy == 'function'){
546 // inpired by a similar function in mootools library
548 * Returns the type of object that is passed in. If the object passed in is null or undefined it
549 * return false otherwise it returns one of the following values:<ul>
550 * <li><b>string</b>: If the object passed is a string</li>
551 * <li><b>number</b>: If the object passed is a number</li>
552 * <li><b>boolean</b>: If the object passed is a boolean value</li>
553 * <li><b>function</b>: If the object passed is a function reference</li>
554 * <li><b>object</b>: If the object passed is an object</li>
555 * <li><b>array</b>: If the object passed is an array</li>
556 * <li><b>regexp</b>: If the object passed is a regular expression</li>
557 * <li><b>element</b>: If the object passed is a DOM Element</li>
558 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561 * @param {Mixed} object
565 if(o === undefined || o === null){
572 if(t == 'object' && o.nodeName) {
574 case 1: return 'element';
575 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
578 if(t == 'object' || t == 'function') {
579 switch(o.constructor) {
580 case Array: return 'array';
581 case RegExp: return 'regexp';
583 if(typeof o.length == 'number' && typeof o.item == 'function') {
591 * Returns true if the passed value is null, undefined or an empty string (optional).
592 * @param {Mixed} value The value to test
593 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
596 isEmpty : function(v, allowBlank){
597 return v === null || v === undefined || (!allowBlank ? v === '' : false);
611 isBorderBox : isBorderBox,
613 isWindows : isWindows,
620 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
621 * you may want to set this to true.
624 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
629 * Selects a single element as a Roo Element
630 * This is about as close as you can get to jQuery's $('do crazy stuff')
631 * @param {String} selector The selector/xpath query
632 * @param {Node} root (optional) The start of the query (defaults to document).
633 * @return {Roo.Element}
635 selectNode : function(selector, root)
637 var node = Roo.DomQuery.selectNode(selector,root);
638 return node ? Roo.get(node) : new Roo.Element(false);
646 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
647 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
650 * Ext JS Library 1.1.1
651 * Copyright(c) 2006-2007, Ext JS, LLC.
653 * Originally Released Under LGPL - original licence link has changed is not relivant.
656 * <script type="text/javascript">
660 // wrappedn so fnCleanup is not in global scope...
662 function fnCleanUp() {
663 var p = Function.prototype;
664 delete p.createSequence;
666 delete p.createDelegate;
667 delete p.createCallback;
668 delete p.createInterceptor;
670 window.detachEvent("onunload", fnCleanUp);
672 window.attachEvent("onunload", fnCleanUp);
679 * These functions are available on every Function object (any JavaScript function).
681 Roo.apply(Function.prototype, {
683 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
684 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
685 * Will create a function that is bound to those 2 args.
686 * @return {Function} The new function
688 createCallback : function(/*args...*/){
689 // make args available, in function below
690 var args = arguments;
693 return method.apply(window, args);
698 * Creates a delegate (callback) that sets the scope to obj.
699 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
700 * Will create a function that is automatically scoped to this.
701 * @param {Object} obj (optional) The object for which the scope is set
702 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
703 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
704 * if a number the args are inserted at the specified position
705 * @return {Function} The new function
707 createDelegate : function(obj, args, appendArgs){
710 var callArgs = args || arguments;
711 if(appendArgs === true){
712 callArgs = Array.prototype.slice.call(arguments, 0);
713 callArgs = callArgs.concat(args);
714 }else if(typeof appendArgs == "number"){
715 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
716 var applyArgs = [appendArgs, 0].concat(args); // create method call params
717 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
719 return method.apply(obj || window, callArgs);
724 * Calls this function after the number of millseconds specified.
725 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
726 * @param {Object} obj (optional) The object for which the scope is set
727 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
728 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
729 * if a number the args are inserted at the specified position
730 * @return {Number} The timeout id that can be used with clearTimeout
732 defer : function(millis, obj, args, appendArgs){
733 var fn = this.createDelegate(obj, args, appendArgs);
735 return setTimeout(fn, millis);
741 * Create a combined function call sequence of the original function + the passed function.
742 * The resulting function returns the results of the original function.
743 * The passed fcn is called with the parameters of the original function
744 * @param {Function} fcn The function to sequence
745 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
746 * @return {Function} The new function
748 createSequence : function(fcn, scope){
749 if(typeof fcn != "function"){
754 var retval = method.apply(this || window, arguments);
755 fcn.apply(scope || this || window, arguments);
761 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
762 * The resulting function returns the results of the original function.
763 * The passed fcn is called with the parameters of the original function.
765 * @param {Function} fcn The function to call before the original
766 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
767 * @return {Function} The new function
769 createInterceptor : function(fcn, scope){
770 if(typeof fcn != "function"){
777 if(fcn.apply(scope || this || window, arguments) === false){
780 return method.apply(this || window, arguments);
786 * Ext JS Library 1.1.1
787 * Copyright(c) 2006-2007, Ext JS, LLC.
789 * Originally Released Under LGPL - original licence link has changed is not relivant.
792 * <script type="text/javascript">
795 Roo.applyIf(String, {
800 * Escapes the passed string for ' and \
801 * @param {String} string The string to escape
802 * @return {String} The escaped string
805 escape : function(string) {
806 return string.replace(/('|\\)/g, "\\$1");
810 * Pads the left side of a string with a specified character. This is especially useful
811 * for normalizing number and date strings. Example usage:
813 var s = String.leftPad('123', 5, '0');
814 // s now contains the string: '00123'
816 * @param {String} string The original string
817 * @param {Number} size The total length of the output string
818 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
819 * @return {String} The padded string
822 leftPad : function (val, size, ch) {
823 var result = new String(val);
824 if(ch === null || ch === undefined || ch === '') {
827 while (result.length < size) {
828 result = ch + result;
834 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
835 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
837 var cls = 'my-class', text = 'Some text';
838 var s = String.format('<div class="{0}">{1}</div>', cls, text);
839 // s now contains the string: '<div class="my-class">Some text</div>'
841 * @param {String} string The tokenized string to be formatted
842 * @param {String} value1 The value to replace token {0}
843 * @param {String} value2 Etc...
844 * @return {String} The formatted string
847 format : function(format){
848 var args = Array.prototype.slice.call(arguments, 1);
849 return format.replace(/\{(\d+)\}/g, function(m, i){
850 return Roo.util.Format.htmlEncode(args[i]);
856 * Utility function that allows you to easily switch a string between two alternating values. The passed value
857 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
858 * they are already different, the first value passed in is returned. Note that this method returns the new value
859 * but does not change the current string.
861 // alternate sort directions
862 sort = sort.toggle('ASC', 'DESC');
864 // instead of conditional logic:
865 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
867 * @param {String} value The value to compare to the current string
868 * @param {String} other The new value to use if the string already equals the first value passed in
869 * @return {String} The new value
872 String.prototype.toggle = function(value, other){
873 return this == value ? other : value;
876 * Ext JS Library 1.1.1
877 * Copyright(c) 2006-2007, Ext JS, LLC.
879 * Originally Released Under LGPL - original licence link has changed is not relivant.
882 * <script type="text/javascript">
888 Roo.applyIf(Number.prototype, {
890 * Checks whether or not the current number is within a desired range. If the number is already within the
891 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
892 * exceeded. Note that this method returns the constrained value but does not change the current number.
893 * @param {Number} min The minimum number in the range
894 * @param {Number} max The maximum number in the range
895 * @return {Number} The constrained value if outside the range, otherwise the current value
897 constrain : function(min, max){
898 return Math.min(Math.max(this, min), max);
902 * Ext JS Library 1.1.1
903 * Copyright(c) 2006-2007, Ext JS, LLC.
905 * Originally Released Under LGPL - original licence link has changed is not relivant.
908 * <script type="text/javascript">
913 Roo.applyIf(Array.prototype, {
915 * Checks whether or not the specified object exists in the array.
916 * @param {Object} o The object to check for
917 * @return {Number} The index of o in the array (or -1 if it is not found)
919 indexOf : function(o){
920 for (var i = 0, len = this.length; i < len; i++){
921 if(this[i] == o) return i;
927 * Removes the specified object from the array. If the object is not found nothing happens.
928 * @param {Object} o The object to remove
930 remove : function(o){
931 var index = this.indexOf(o);
933 this.splice(index, 1);
937 * Map (JS 1.6 compatibility)
938 * @param {Function} function to call
942 var len = this.length >>> 0;
943 if (typeof fun != "function")
944 throw new TypeError();
946 var res = new Array(len);
947 var thisp = arguments[1];
948 for (var i = 0; i < len; i++)
951 res[i] = fun.call(thisp, this[i], i, this);
962 * Ext JS Library 1.1.1
963 * Copyright(c) 2006-2007, Ext JS, LLC.
965 * Originally Released Under LGPL - original licence link has changed is not relivant.
968 * <script type="text/javascript">
974 * The date parsing and format syntax is a subset of
975 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
976 * supported will provide results equivalent to their PHP versions.
978 * Following is the list of all currently supported formats:
981 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
983 Format Output Description
984 ------ ---------- --------------------------------------------------------------
985 d 10 Day of the month, 2 digits with leading zeros
986 D Wed A textual representation of a day, three letters
987 j 10 Day of the month without leading zeros
988 l Wednesday A full textual representation of the day of the week
989 S th English ordinal day of month suffix, 2 chars (use with j)
990 w 3 Numeric representation of the day of the week
991 z 9 The julian date, or day of the year (0-365)
992 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
993 F January A full textual representation of the month
994 m 01 Numeric representation of a month, with leading zeros
995 M Jan Month name abbreviation, three letters
996 n 1 Numeric representation of a month, without leading zeros
997 t 31 Number of days in the given month
998 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
999 Y 2007 A full numeric representation of a year, 4 digits
1000 y 07 A two digit representation of a year
1001 a pm Lowercase Ante meridiem and Post meridiem
1002 A PM Uppercase Ante meridiem and Post meridiem
1003 g 3 12-hour format of an hour without leading zeros
1004 G 15 24-hour format of an hour without leading zeros
1005 h 03 12-hour format of an hour with leading zeros
1006 H 15 24-hour format of an hour with leading zeros
1007 i 05 Minutes with leading zeros
1008 s 01 Seconds, with leading zeros
1009 O -0600 Difference to Greenwich time (GMT) in hours
1010 T CST Timezone setting of the machine running the code
1011 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1014 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1016 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1017 document.write(dt.format('Y-m-d')); //2007-01-10
1018 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1019 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
1022 * Here are some standard date/time patterns that you might find helpful. They
1023 * are not part of the source of Date.js, but to use them you can simply copy this
1024 * block of code into any script that is included after Date.js and they will also become
1025 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1028 ISO8601Long:"Y-m-d H:i:s",
1029 ISO8601Short:"Y-m-d",
1031 LongDate: "l, F d, Y",
1032 FullDateTime: "l, F d, Y g:i:s A",
1035 LongTime: "g:i:s A",
1036 SortableDateTime: "Y-m-d\\TH:i:s",
1037 UniversalSortableDateTime: "Y-m-d H:i:sO",
1044 var dt = new Date();
1045 document.write(dt.format(Date.patterns.ShortDate));
1050 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1051 * They generate precompiled functions from date formats instead of parsing and
1052 * processing the pattern every time you format a date. These functions are available
1053 * on every Date object (any javascript function).
1055 * The original article and download are here:
1056 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1063 Returns the number of milliseconds between this date and date
1064 @param {Date} date (optional) Defaults to now
1065 @return {Number} The diff in milliseconds
1066 @member Date getElapsed
1068 Date.prototype.getElapsed = function(date) {
1069 return Math.abs((date || new Date()).getTime()-this.getTime());
1071 // was in date file..
1075 Date.parseFunctions = {count:0};
1077 Date.parseRegexes = [];
1079 Date.formatFunctions = {count:0};
1082 Date.prototype.dateFormat = function(format) {
1083 if (Date.formatFunctions[format] == null) {
1084 Date.createNewFormat(format);
1086 var func = Date.formatFunctions[format];
1087 return this[func]();
1092 * Formats a date given the supplied format string
1093 * @param {String} format The format string
1094 * @return {String} The formatted date
1097 Date.prototype.format = Date.prototype.dateFormat;
1100 Date.createNewFormat = function(format) {
1101 var funcName = "format" + Date.formatFunctions.count++;
1102 Date.formatFunctions[format] = funcName;
1103 var code = "Date.prototype." + funcName + " = function(){return ";
1104 var special = false;
1106 for (var i = 0; i < format.length; ++i) {
1107 ch = format.charAt(i);
1108 if (!special && ch == "\\") {
1113 code += "'" + String.escape(ch) + "' + ";
1116 code += Date.getFormatCode(ch);
1119 /** eval:var:zzzzzzzzzzzzz */
1120 eval(code.substring(0, code.length - 3) + ";}");
1124 Date.getFormatCode = function(character) {
1125 switch (character) {
1127 return "String.leftPad(this.getDate(), 2, '0') + ";
1129 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1131 return "this.getDate() + ";
1133 return "Date.dayNames[this.getDay()] + ";
1135 return "this.getSuffix() + ";
1137 return "this.getDay() + ";
1139 return "this.getDayOfYear() + ";
1141 return "this.getWeekOfYear() + ";
1143 return "Date.monthNames[this.getMonth()] + ";
1145 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1147 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1149 return "(this.getMonth() + 1) + ";
1151 return "this.getDaysInMonth() + ";
1153 return "(this.isLeapYear() ? 1 : 0) + ";
1155 return "this.getFullYear() + ";
1157 return "('' + this.getFullYear()).substring(2, 4) + ";
1159 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1161 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1163 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1165 return "this.getHours() + ";
1167 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1169 return "String.leftPad(this.getHours(), 2, '0') + ";
1171 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1173 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1175 return "this.getGMTOffset() + ";
1177 return "this.getTimezone() + ";
1179 return "(this.getTimezoneOffset() * -60) + ";
1181 return "'" + String.escape(character) + "' + ";
1186 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1187 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1188 * the date format that is not specified will default to the current date value for that part. Time parts can also
1189 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1190 * string or the parse operation will fail.
1193 //dt = Fri May 25 2007 (current date)
1194 var dt = new Date();
1196 //dt = Thu May 25 2006 (today's month/day in 2006)
1197 dt = Date.parseDate("2006", "Y");
1199 //dt = Sun Jan 15 2006 (all date parts specified)
1200 dt = Date.parseDate("2006-1-15", "Y-m-d");
1202 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1203 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1205 * @param {String} input The unparsed date as a string
1206 * @param {String} format The format the date is in
1207 * @return {Date} The parsed date
1210 Date.parseDate = function(input, format) {
1211 if (Date.parseFunctions[format] == null) {
1212 Date.createParser(format);
1214 var func = Date.parseFunctions[format];
1215 return Date[func](input);
1220 Date.createParser = function(format) {
1221 var funcName = "parse" + Date.parseFunctions.count++;
1222 var regexNum = Date.parseRegexes.length;
1223 var currentGroup = 1;
1224 Date.parseFunctions[format] = funcName;
1226 var code = "Date." + funcName + " = function(input){\n"
1227 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1228 + "var d = new Date();\n"
1229 + "y = d.getFullYear();\n"
1230 + "m = d.getMonth();\n"
1231 + "d = d.getDate();\n"
1232 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1233 + "if (results && results.length > 0) {";
1236 var special = false;
1238 for (var i = 0; i < format.length; ++i) {
1239 ch = format.charAt(i);
1240 if (!special && ch == "\\") {
1245 regex += String.escape(ch);
1248 var obj = Date.formatCodeToRegex(ch, currentGroup);
1249 currentGroup += obj.g;
1251 if (obj.g && obj.c) {
1257 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1258 + "{v = new Date(y, m, d, h, i, s);}\n"
1259 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1260 + "{v = new Date(y, m, d, h, i);}\n"
1261 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1262 + "{v = new Date(y, m, d, h);}\n"
1263 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1264 + "{v = new Date(y, m, d);}\n"
1265 + "else if (y >= 0 && m >= 0)\n"
1266 + "{v = new Date(y, m);}\n"
1267 + "else if (y >= 0)\n"
1268 + "{v = new Date(y);}\n"
1269 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1270 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1271 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1274 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1275 /** eval:var:zzzzzzzzzzzzz */
1280 Date.formatCodeToRegex = function(character, currentGroup) {
1281 switch (character) {
1285 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1288 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1289 s:"(\\d{1,2})"}; // day of month without leading zeroes
1292 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1293 s:"(\\d{2})"}; // day of month with leading zeroes
1297 s:"(?:" + Date.dayNames.join("|") + ")"};
1301 s:"(?:st|nd|rd|th)"};
1316 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1317 s:"(" + Date.monthNames.join("|") + ")"};
1320 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1321 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1324 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1325 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1328 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1329 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1340 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1344 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1345 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1349 c:"if (results[" + currentGroup + "] == 'am') {\n"
1350 + "if (h == 12) { h = 0; }\n"
1351 + "} else { if (h < 12) { h += 12; }}",
1355 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1356 + "if (h == 12) { h = 0; }\n"
1357 + "} else { if (h < 12) { h += 12; }}",
1362 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1363 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1367 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1371 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1375 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1380 "o = results[", currentGroup, "];\n",
1381 "var sn = o.substring(0,1);\n", // get + / - sign
1382 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1383 "var mn = o.substring(3,5) % 60;\n", // get minutes
1384 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1385 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1391 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1394 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1395 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1396 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1400 s:String.escape(character)};
1405 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1406 * @return {String} The abbreviated timezone name (e.g. 'CST')
1408 Date.prototype.getTimezone = function() {
1409 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1413 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1414 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1416 Date.prototype.getGMTOffset = function() {
1417 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1418 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1419 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1423 * Get the numeric day number of the year, adjusted for leap year.
1424 * @return {Number} 0 through 364 (365 in leap years)
1426 Date.prototype.getDayOfYear = function() {
1428 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1429 for (var i = 0; i < this.getMonth(); ++i) {
1430 num += Date.daysInMonth[i];
1432 return num + this.getDate() - 1;
1436 * Get the string representation of the numeric week number of the year
1437 * (equivalent to the format specifier 'W').
1438 * @return {String} '00' through '52'
1440 Date.prototype.getWeekOfYear = function() {
1441 // Skip to Thursday of this week
1442 var now = this.getDayOfYear() + (4 - this.getDay());
1443 // Find the first Thursday of the year
1444 var jan1 = new Date(this.getFullYear(), 0, 1);
1445 var then = (7 - jan1.getDay() + 4);
1446 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1450 * Whether or not the current date is in a leap year.
1451 * @return {Boolean} True if the current date is in a leap year, else false
1453 Date.prototype.isLeapYear = function() {
1454 var year = this.getFullYear();
1455 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1459 * Get the first day of the current month, adjusted for leap year. The returned value
1460 * is the numeric day index within the week (0-6) which can be used in conjunction with
1461 * the {@link #monthNames} array to retrieve the textual day name.
1464 var dt = new Date('1/10/2007');
1465 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1467 * @return {Number} The day number (0-6)
1469 Date.prototype.getFirstDayOfMonth = function() {
1470 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1471 return (day < 0) ? (day + 7) : day;
1475 * Get the last day of the current month, adjusted for leap year. The returned value
1476 * is the numeric day index within the week (0-6) which can be used in conjunction with
1477 * the {@link #monthNames} array to retrieve the textual day name.
1480 var dt = new Date('1/10/2007');
1481 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1483 * @return {Number} The day number (0-6)
1485 Date.prototype.getLastDayOfMonth = function() {
1486 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1487 return (day < 0) ? (day + 7) : day;
1492 * Get the first date of this date's month
1495 Date.prototype.getFirstDateOfMonth = function() {
1496 return new Date(this.getFullYear(), this.getMonth(), 1);
1500 * Get the last date of this date's month
1503 Date.prototype.getLastDateOfMonth = function() {
1504 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1507 * Get the number of days in the current month, adjusted for leap year.
1508 * @return {Number} The number of days in the month
1510 Date.prototype.getDaysInMonth = function() {
1511 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1512 return Date.daysInMonth[this.getMonth()];
1516 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1517 * @return {String} 'st, 'nd', 'rd' or 'th'
1519 Date.prototype.getSuffix = function() {
1520 switch (this.getDate()) {
1537 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1540 * An array of textual month names.
1541 * Override these values for international dates, for example...
1542 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1561 * An array of textual day names.
1562 * Override these values for international dates, for example...
1563 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1579 Date.monthNumbers = {
1594 * Creates and returns a new Date instance with the exact same date value as the called instance.
1595 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1596 * variable will also be changed. When the intention is to create a new variable that will not
1597 * modify the original instance, you should create a clone.
1599 * Example of correctly cloning a date:
1602 var orig = new Date('10/1/2006');
1605 document.write(orig); //returns 'Thu Oct 05 2006'!
1608 var orig = new Date('10/1/2006');
1609 var copy = orig.clone();
1611 document.write(orig); //returns 'Thu Oct 01 2006'
1613 * @return {Date} The new Date instance
1615 Date.prototype.clone = function() {
1616 return new Date(this.getTime());
1620 * Clears any time information from this date
1621 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1622 @return {Date} this or the clone
1624 Date.prototype.clearTime = function(clone){
1626 return this.clone().clearTime();
1631 this.setMilliseconds(0);
1636 // safari setMonth is broken
1638 Date.brokenSetMonth = Date.prototype.setMonth;
1639 Date.prototype.setMonth = function(num){
1641 var n = Math.ceil(-num);
1642 var back_year = Math.ceil(n/12);
1643 var month = (n % 12) ? 12 - n % 12 : 0 ;
1644 this.setFullYear(this.getFullYear() - back_year);
1645 return Date.brokenSetMonth.call(this, month);
1647 return Date.brokenSetMonth.apply(this, arguments);
1652 /** Date interval constant
1656 /** Date interval constant
1660 /** Date interval constant
1664 /** Date interval constant
1668 /** Date interval constant
1672 /** Date interval constant
1676 /** Date interval constant
1682 * Provides a convenient method of performing basic date arithmetic. This method
1683 * does not modify the Date instance being called - it creates and returns
1684 * a new Date instance containing the resulting date value.
1689 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1690 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1692 //Negative values will subtract correctly:
1693 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1694 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1696 //You can even chain several calls together in one line!
1697 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1698 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1701 * @param {String} interval A valid date interval enum value
1702 * @param {Number} value The amount to add to the current date
1703 * @return {Date} The new Date instance
1705 Date.prototype.add = function(interval, value){
1706 var d = this.clone();
1707 if (!interval || value === 0) return d;
1708 switch(interval.toLowerCase()){
1710 d.setMilliseconds(this.getMilliseconds() + value);
1713 d.setSeconds(this.getSeconds() + value);
1716 d.setMinutes(this.getMinutes() + value);
1719 d.setHours(this.getHours() + value);
1722 d.setDate(this.getDate() + value);
1725 var day = this.getDate();
1727 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1730 d.setMonth(this.getMonth() + value);
1733 d.setFullYear(this.getFullYear() + value);
1739 * Ext JS Library 1.1.1
1740 * Copyright(c) 2006-2007, Ext JS, LLC.
1742 * Originally Released Under LGPL - original licence link has changed is not relivant.
1745 * <script type="text/javascript">
1749 getViewWidth : function(full) {
1750 return full ? this.getDocumentWidth() : this.getViewportWidth();
1753 getViewHeight : function(full) {
1754 return full ? this.getDocumentHeight() : this.getViewportHeight();
1757 getDocumentHeight: function() {
1758 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1759 return Math.max(scrollHeight, this.getViewportHeight());
1762 getDocumentWidth: function() {
1763 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1764 return Math.max(scrollWidth, this.getViewportWidth());
1767 getViewportHeight: function() {
1768 var height = self.innerHeight;
1769 var mode = document.compatMode;
1771 if ((mode || Roo.isIE) && !Roo.isOpera) {
1772 height = (mode == "CSS1Compat") ?
1773 document.documentElement.clientHeight :
1774 document.body.clientHeight;
1780 getViewportWidth: function() {
1781 var width = self.innerWidth;
1782 var mode = document.compatMode;
1784 if (mode || Roo.isIE) {
1785 width = (mode == "CSS1Compat") ?
1786 document.documentElement.clientWidth :
1787 document.body.clientWidth;
1792 isAncestor : function(p, c) {
1799 if (p.contains && !Roo.isSafari) {
1800 return p.contains(c);
1801 } else if (p.compareDocumentPosition) {
1802 return !!(p.compareDocumentPosition(c) & 16);
1804 var parent = c.parentNode;
1809 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1812 parent = parent.parentNode;
1818 getRegion : function(el) {
1819 return Roo.lib.Region.getRegion(el);
1822 getY : function(el) {
1823 return this.getXY(el)[1];
1826 getX : function(el) {
1827 return this.getXY(el)[0];
1830 getXY : function(el) {
1831 var p, pe, b, scroll, bd = document.body;
1832 el = Roo.getDom(el);
1833 var fly = Roo.lib.AnimBase.fly;
1834 if (el.getBoundingClientRect) {
1835 b = el.getBoundingClientRect();
1836 scroll = fly(document).getScroll();
1837 return [b.left + scroll.left, b.top + scroll.top];
1843 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1850 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1857 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1858 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1865 if (p != el && pe.getStyle('overflow') != 'visible') {
1873 if (Roo.isSafari && hasAbsolute) {
1878 if (Roo.isGecko && !hasAbsolute) {
1880 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1881 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1885 while (p && p != bd) {
1886 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1898 setXY : function(el, xy) {
1899 el = Roo.fly(el, '_setXY');
1901 var pts = el.translatePoints(xy);
1902 if (xy[0] !== false) {
1903 el.dom.style.left = pts.left + "px";
1905 if (xy[1] !== false) {
1906 el.dom.style.top = pts.top + "px";
1910 setX : function(el, x) {
1911 this.setXY(el, [x, false]);
1914 setY : function(el, y) {
1915 this.setXY(el, [false, y]);
1919 * Portions of this file are based on pieces of Yahoo User Interface Library
1920 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1921 * YUI licensed under the BSD License:
1922 * http://developer.yahoo.net/yui/license.txt
1923 * <script type="text/javascript">
1927 Roo.lib.Event = function() {
1928 var loadComplete = false;
1930 var unloadListeners = [];
1932 var onAvailStack = [];
1934 var lastError = null;
1947 startInterval: function() {
1948 if (!this._interval) {
1950 var callback = function() {
1951 self._tryPreloadAttach();
1953 this._interval = setInterval(callback, this.POLL_INTERVAL);
1958 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1959 onAvailStack.push({ id: p_id,
1962 override: p_override,
1963 checkReady: false });
1965 retryCount = this.POLL_RETRYS;
1966 this.startInterval();
1970 addListener: function(el, eventName, fn) {
1971 el = Roo.getDom(el);
1976 if ("unload" == eventName) {
1977 unloadListeners[unloadListeners.length] =
1978 [el, eventName, fn];
1982 var wrappedFn = function(e) {
1983 return fn(Roo.lib.Event.getEvent(e));
1986 var li = [el, eventName, fn, wrappedFn];
1988 var index = listeners.length;
1989 listeners[index] = li;
1991 this.doAdd(el, eventName, wrappedFn, false);
1997 removeListener: function(el, eventName, fn) {
2000 el = Roo.getDom(el);
2003 return this.purgeElement(el, false, eventName);
2007 if ("unload" == eventName) {
2009 for (i = 0,len = unloadListeners.length; i < len; i++) {
2010 var li = unloadListeners[i];
2013 li[1] == eventName &&
2015 unloadListeners.splice(i, 1);
2023 var cacheItem = null;
2026 var index = arguments[3];
2028 if ("undefined" == typeof index) {
2029 index = this._getCacheIndex(el, eventName, fn);
2033 cacheItem = listeners[index];
2036 if (!el || !cacheItem) {
2040 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2042 delete listeners[index][this.WFN];
2043 delete listeners[index][this.FN];
2044 listeners.splice(index, 1);
2051 getTarget: function(ev, resolveTextNode) {
2052 ev = ev.browserEvent || ev;
2053 var t = ev.target || ev.srcElement;
2054 return this.resolveTextNode(t);
2058 resolveTextNode: function(node) {
2059 if (Roo.isSafari && node && 3 == node.nodeType) {
2060 return node.parentNode;
2067 getPageX: function(ev) {
2068 ev = ev.browserEvent || ev;
2070 if (!x && 0 !== x) {
2071 x = ev.clientX || 0;
2074 x += this.getScroll()[1];
2082 getPageY: function(ev) {
2083 ev = ev.browserEvent || ev;
2085 if (!y && 0 !== y) {
2086 y = ev.clientY || 0;
2089 y += this.getScroll()[0];
2098 getXY: function(ev) {
2099 ev = ev.browserEvent || ev;
2100 return [this.getPageX(ev), this.getPageY(ev)];
2104 getRelatedTarget: function(ev) {
2105 ev = ev.browserEvent || ev;
2106 var t = ev.relatedTarget;
2108 if (ev.type == "mouseout") {
2110 } else if (ev.type == "mouseover") {
2115 return this.resolveTextNode(t);
2119 getTime: function(ev) {
2120 ev = ev.browserEvent || ev;
2122 var t = new Date().getTime();
2126 this.lastError = ex;
2135 stopEvent: function(ev) {
2136 this.stopPropagation(ev);
2137 this.preventDefault(ev);
2141 stopPropagation: function(ev) {
2142 ev = ev.browserEvent || ev;
2143 if (ev.stopPropagation) {
2144 ev.stopPropagation();
2146 ev.cancelBubble = true;
2151 preventDefault: function(ev) {
2152 ev = ev.browserEvent || ev;
2153 if(ev.preventDefault) {
2154 ev.preventDefault();
2156 ev.returnValue = false;
2161 getEvent: function(e) {
2162 var ev = e || window.event;
2164 var c = this.getEvent.caller;
2166 ev = c.arguments[0];
2167 if (ev && Event == ev.constructor) {
2177 getCharCode: function(ev) {
2178 ev = ev.browserEvent || ev;
2179 return ev.charCode || ev.keyCode || 0;
2183 _getCacheIndex: function(el, eventName, fn) {
2184 for (var i = 0,len = listeners.length; i < len; ++i) {
2185 var li = listeners[i];
2187 li[this.FN] == fn &&
2188 li[this.EL] == el &&
2189 li[this.TYPE] == eventName) {
2201 getEl: function(id) {
2202 return document.getElementById(id);
2206 clearCache: function() {
2210 _load: function(e) {
2211 loadComplete = true;
2212 var EU = Roo.lib.Event;
2216 EU.doRemove(window, "load", EU._load);
2221 _tryPreloadAttach: function() {
2230 var tryAgain = !loadComplete;
2232 tryAgain = (retryCount > 0);
2237 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2238 var item = onAvailStack[i];
2240 var el = this.getEl(item.id);
2243 if (!item.checkReady ||
2246 (document && document.body)) {
2249 if (item.override) {
2250 if (item.override === true) {
2253 scope = item.override;
2256 item.fn.call(scope, item.obj);
2257 onAvailStack[i] = null;
2260 notAvail.push(item);
2265 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2269 this.startInterval();
2271 clearInterval(this._interval);
2272 this._interval = null;
2275 this.locked = false;
2282 purgeElement: function(el, recurse, eventName) {
2283 var elListeners = this.getListeners(el, eventName);
2285 for (var i = 0,len = elListeners.length; i < len; ++i) {
2286 var l = elListeners[i];
2287 this.removeListener(el, l.type, l.fn);
2291 if (recurse && el && el.childNodes) {
2292 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2293 this.purgeElement(el.childNodes[i], recurse, eventName);
2299 getListeners: function(el, eventName) {
2300 var results = [], searchLists;
2302 searchLists = [listeners, unloadListeners];
2303 } else if (eventName == "unload") {
2304 searchLists = [unloadListeners];
2306 searchLists = [listeners];
2309 for (var j = 0; j < searchLists.length; ++j) {
2310 var searchList = searchLists[j];
2311 if (searchList && searchList.length > 0) {
2312 for (var i = 0,len = searchList.length; i < len; ++i) {
2313 var l = searchList[i];
2314 if (l && l[this.EL] === el &&
2315 (!eventName || eventName === l[this.TYPE])) {
2320 adjust: l[this.ADJ_SCOPE],
2328 return (results.length) ? results : null;
2332 _unload: function(e) {
2334 var EU = Roo.lib.Event, i, j, l, len, index;
2336 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2337 l = unloadListeners[i];
2340 if (l[EU.ADJ_SCOPE]) {
2341 if (l[EU.ADJ_SCOPE] === true) {
2344 scope = l[EU.ADJ_SCOPE];
2347 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2348 unloadListeners[i] = null;
2354 unloadListeners = null;
2356 if (listeners && listeners.length > 0) {
2357 j = listeners.length;
2360 l = listeners[index];
2362 EU.removeListener(l[EU.EL], l[EU.TYPE],
2372 EU.doRemove(window, "unload", EU._unload);
2377 getScroll: function() {
2378 var dd = document.documentElement, db = document.body;
2379 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2380 return [dd.scrollTop, dd.scrollLeft];
2382 return [db.scrollTop, db.scrollLeft];
2389 doAdd: function () {
2390 if (window.addEventListener) {
2391 return function(el, eventName, fn, capture) {
2392 el.addEventListener(eventName, fn, (capture));
2394 } else if (window.attachEvent) {
2395 return function(el, eventName, fn, capture) {
2396 el.attachEvent("on" + eventName, fn);
2405 doRemove: function() {
2406 if (window.removeEventListener) {
2407 return function (el, eventName, fn, capture) {
2408 el.removeEventListener(eventName, fn, (capture));
2410 } else if (window.detachEvent) {
2411 return function (el, eventName, fn) {
2412 el.detachEvent("on" + eventName, fn);
2424 var E = Roo.lib.Event;
2425 E.on = E.addListener;
2426 E.un = E.removeListener;
2428 if (document && document.body) {
2431 E.doAdd(window, "load", E._load);
2433 E.doAdd(window, "unload", E._unload);
2434 E._tryPreloadAttach();
2438 * Portions of this file are based on pieces of Yahoo User Interface Library
2439 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2440 * YUI licensed under the BSD License:
2441 * http://developer.yahoo.net/yui/license.txt
2442 * <script type="text/javascript">
2449 request : function(method, uri, cb, data, options) {
2451 var hs = options.headers;
2454 if(hs.hasOwnProperty(h)){
2455 this.initHeader(h, hs[h], false);
2459 if(options.xmlData){
2460 this.initHeader('Content-Type', 'text/xml', false);
2462 data = options.xmlData;
2466 return this.asyncRequest(method, uri, cb, data);
2469 serializeForm : function(form) {
2470 if(typeof form == 'string') {
2471 form = (document.getElementById(form) || document.forms[form]);
2474 var el, name, val, disabled, data = '', hasSubmit = false;
2475 for (var i = 0; i < form.elements.length; i++) {
2476 el = form.elements[i];
2477 disabled = form.elements[i].disabled;
2478 name = form.elements[i].name;
2479 val = form.elements[i].value;
2481 if (!disabled && name){
2485 case 'select-multiple':
2486 for (var j = 0; j < el.options.length; j++) {
2487 if (el.options[j].selected) {
2489 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2492 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2500 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2513 if(hasSubmit == false) {
2514 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2519 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2524 data = data.substr(0, data.length - 1);
2532 useDefaultHeader:true,
2534 defaultPostHeader:'application/x-www-form-urlencoded',
2536 useDefaultXhrHeader:true,
2538 defaultXhrHeader:'XMLHttpRequest',
2540 hasDefaultHeaders:true,
2552 setProgId:function(id)
2554 this.activeX.unshift(id);
2557 setDefaultPostHeader:function(b)
2559 this.useDefaultHeader = b;
2562 setDefaultXhrHeader:function(b)
2564 this.useDefaultXhrHeader = b;
2567 setPollingInterval:function(i)
2569 if (typeof i == 'number' && isFinite(i)) {
2570 this.pollInterval = i;
2574 createXhrObject:function(transactionId)
2580 http = new XMLHttpRequest();
2582 obj = { conn:http, tId:transactionId };
2586 for (var i = 0; i < this.activeX.length; ++i) {
2590 http = new ActiveXObject(this.activeX[i]);
2592 obj = { conn:http, tId:transactionId };
2605 getConnectionObject:function()
2608 var tId = this.transactionId;
2612 o = this.createXhrObject(tId);
2614 this.transactionId++;
2625 asyncRequest:function(method, uri, callback, postData)
2627 var o = this.getConnectionObject();
2633 o.conn.open(method, uri, true);
2635 if (this.useDefaultXhrHeader) {
2636 if (!this.defaultHeaders['X-Requested-With']) {
2637 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2641 if(postData && this.useDefaultHeader){
2642 this.initHeader('Content-Type', this.defaultPostHeader);
2645 if (this.hasDefaultHeaders || this.hasHeaders) {
2649 this.handleReadyState(o, callback);
2650 o.conn.send(postData || null);
2656 handleReadyState:function(o, callback)
2660 if (callback && callback.timeout) {
2661 this.timeout[o.tId] = window.setTimeout(function() {
2662 oConn.abort(o, callback, true);
2663 }, callback.timeout);
2666 this.poll[o.tId] = window.setInterval(
2668 if (o.conn && o.conn.readyState == 4) {
2669 window.clearInterval(oConn.poll[o.tId]);
2670 delete oConn.poll[o.tId];
2672 if(callback && callback.timeout) {
2673 window.clearTimeout(oConn.timeout[o.tId]);
2674 delete oConn.timeout[o.tId];
2677 oConn.handleTransactionResponse(o, callback);
2680 , this.pollInterval);
2683 handleTransactionResponse:function(o, callback, isAbort)
2687 this.releaseObject(o);
2691 var httpStatus, responseObject;
2695 if (o.conn.status !== undefined && o.conn.status != 0) {
2696 httpStatus = o.conn.status;
2708 if (httpStatus >= 200 && httpStatus < 300) {
2709 responseObject = this.createResponseObject(o, callback.argument);
2710 if (callback.success) {
2711 if (!callback.scope) {
2712 callback.success(responseObject);
2717 callback.success.apply(callback.scope, [responseObject]);
2722 switch (httpStatus) {
2730 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2731 if (callback.failure) {
2732 if (!callback.scope) {
2733 callback.failure(responseObject);
2736 callback.failure.apply(callback.scope, [responseObject]);
2741 responseObject = this.createResponseObject(o, callback.argument);
2742 if (callback.failure) {
2743 if (!callback.scope) {
2744 callback.failure(responseObject);
2747 callback.failure.apply(callback.scope, [responseObject]);
2753 this.releaseObject(o);
2754 responseObject = null;
2757 createResponseObject:function(o, callbackArg)
2764 var headerStr = o.conn.getAllResponseHeaders();
2765 var header = headerStr.split('\n');
2766 for (var i = 0; i < header.length; i++) {
2767 var delimitPos = header[i].indexOf(':');
2768 if (delimitPos != -1) {
2769 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2777 obj.status = o.conn.status;
2778 obj.statusText = o.conn.statusText;
2779 obj.getResponseHeader = headerObj;
2780 obj.getAllResponseHeaders = headerStr;
2781 obj.responseText = o.conn.responseText;
2782 obj.responseXML = o.conn.responseXML;
2784 if (typeof callbackArg !== undefined) {
2785 obj.argument = callbackArg;
2791 createExceptionObject:function(tId, callbackArg, isAbort)
2794 var COMM_ERROR = 'communication failure';
2795 var ABORT_CODE = -1;
2796 var ABORT_ERROR = 'transaction aborted';
2802 obj.status = ABORT_CODE;
2803 obj.statusText = ABORT_ERROR;
2806 obj.status = COMM_CODE;
2807 obj.statusText = COMM_ERROR;
2811 obj.argument = callbackArg;
2817 initHeader:function(label, value, isDefault)
2819 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2821 if (headerObj[label] === undefined) {
2822 headerObj[label] = value;
2827 headerObj[label] = value + "," + headerObj[label];
2831 this.hasDefaultHeaders = true;
2834 this.hasHeaders = true;
2839 setHeader:function(o)
2841 if (this.hasDefaultHeaders) {
2842 for (var prop in this.defaultHeaders) {
2843 if (this.defaultHeaders.hasOwnProperty(prop)) {
2844 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2849 if (this.hasHeaders) {
2850 for (var prop in this.headers) {
2851 if (this.headers.hasOwnProperty(prop)) {
2852 o.conn.setRequestHeader(prop, this.headers[prop]);
2856 this.hasHeaders = false;
2860 resetDefaultHeaders:function() {
2861 delete this.defaultHeaders;
2862 this.defaultHeaders = {};
2863 this.hasDefaultHeaders = false;
2866 abort:function(o, callback, isTimeout)
2868 if(this.isCallInProgress(o)) {
2870 window.clearInterval(this.poll[o.tId]);
2871 delete this.poll[o.tId];
2873 delete this.timeout[o.tId];
2876 this.handleTransactionResponse(o, callback, true);
2886 isCallInProgress:function(o)
2889 return o.conn.readyState != 4 && o.conn.readyState != 0;
2898 releaseObject:function(o)
2907 'MSXML2.XMLHTTP.3.0',
2915 * Portions of this file are based on pieces of Yahoo User Interface Library
2916 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2917 * YUI licensed under the BSD License:
2918 * http://developer.yahoo.net/yui/license.txt
2919 * <script type="text/javascript">
2923 Roo.lib.Region = function(t, r, b, l) {
2933 Roo.lib.Region.prototype = {
2934 contains : function(region) {
2935 return ( region.left >= this.left &&
2936 region.right <= this.right &&
2937 region.top >= this.top &&
2938 region.bottom <= this.bottom );
2942 getArea : function() {
2943 return ( (this.bottom - this.top) * (this.right - this.left) );
2946 intersect : function(region) {
2947 var t = Math.max(this.top, region.top);
2948 var r = Math.min(this.right, region.right);
2949 var b = Math.min(this.bottom, region.bottom);
2950 var l = Math.max(this.left, region.left);
2952 if (b >= t && r >= l) {
2953 return new Roo.lib.Region(t, r, b, l);
2958 union : function(region) {
2959 var t = Math.min(this.top, region.top);
2960 var r = Math.max(this.right, region.right);
2961 var b = Math.max(this.bottom, region.bottom);
2962 var l = Math.min(this.left, region.left);
2964 return new Roo.lib.Region(t, r, b, l);
2967 adjust : function(t, l, b, r) {
2976 Roo.lib.Region.getRegion = function(el) {
2977 var p = Roo.lib.Dom.getXY(el);
2980 var r = p[0] + el.offsetWidth;
2981 var b = p[1] + el.offsetHeight;
2984 return new Roo.lib.Region(t, r, b, l);
2987 * Portions of this file are based on pieces of Yahoo User Interface Library
2988 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2989 * YUI licensed under the BSD License:
2990 * http://developer.yahoo.net/yui/license.txt
2991 * <script type="text/javascript">
2994 //@@dep Roo.lib.Region
2997 Roo.lib.Point = function(x, y) {
2998 if (x instanceof Array) {
3002 this.x = this.right = this.left = this[0] = x;
3003 this.y = this.top = this.bottom = this[1] = y;
3006 Roo.lib.Point.prototype = new Roo.lib.Region();
3008 * Portions of this file are based on pieces of Yahoo User Interface Library
3009 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3010 * YUI licensed under the BSD License:
3011 * http://developer.yahoo.net/yui/license.txt
3012 * <script type="text/javascript">
3019 scroll : function(el, args, duration, easing, cb, scope) {
3020 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3023 motion : function(el, args, duration, easing, cb, scope) {
3024 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3027 color : function(el, args, duration, easing, cb, scope) {
3028 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3031 run : function(el, args, duration, easing, cb, scope, type) {
3032 type = type || Roo.lib.AnimBase;
3033 if (typeof easing == "string") {
3034 easing = Roo.lib.Easing[easing];
3036 var anim = new type(el, args, duration, easing);
3037 anim.animateX(function() {
3038 Roo.callback(cb, scope);
3044 * Portions of this file are based on pieces of Yahoo User Interface Library
3045 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3046 * YUI licensed under the BSD License:
3047 * http://developer.yahoo.net/yui/license.txt
3048 * <script type="text/javascript">
3056 if (!libFlyweight) {
3057 libFlyweight = new Roo.Element.Flyweight();
3059 libFlyweight.dom = el;
3060 return libFlyweight;
3063 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3067 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3069 this.init(el, attributes, duration, method);
3073 Roo.lib.AnimBase.fly = fly;
3077 Roo.lib.AnimBase.prototype = {
3079 toString: function() {
3080 var el = this.getEl();
3081 var id = el.id || el.tagName;
3082 return ("Anim " + id);
3086 noNegatives: /width|height|opacity|padding/i,
3087 offsetAttribute: /^((width|height)|(top|left))$/,
3088 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3089 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3093 doMethod: function(attr, start, end) {
3094 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3098 setAttribute: function(attr, val, unit) {
3099 if (this.patterns.noNegatives.test(attr)) {
3100 val = (val > 0) ? val : 0;
3103 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3107 getAttribute: function(attr) {
3108 var el = this.getEl();
3109 var val = fly(el).getStyle(attr);
3111 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3112 return parseFloat(val);
3115 var a = this.patterns.offsetAttribute.exec(attr) || [];
3116 var pos = !!( a[3] );
3117 var box = !!( a[2] );
3120 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3121 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3130 getDefaultUnit: function(attr) {
3131 if (this.patterns.defaultUnit.test(attr)) {
3138 animateX : function(callback, scope) {
3139 var f = function() {
3140 this.onComplete.removeListener(f);
3141 if (typeof callback == "function") {
3142 callback.call(scope || this, this);
3145 this.onComplete.addListener(f, this);
3150 setRuntimeAttribute: function(attr) {
3153 var attributes = this.attributes;
3155 this.runtimeAttributes[attr] = {};
3157 var isset = function(prop) {
3158 return (typeof prop !== 'undefined');
3161 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3165 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3168 if (isset(attributes[attr]['to'])) {
3169 end = attributes[attr]['to'];
3170 } else if (isset(attributes[attr]['by'])) {
3171 if (start.constructor == Array) {
3173 for (var i = 0, len = start.length; i < len; ++i) {
3174 end[i] = start[i] + attributes[attr]['by'][i];
3177 end = start + attributes[attr]['by'];
3181 this.runtimeAttributes[attr].start = start;
3182 this.runtimeAttributes[attr].end = end;
3185 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3189 init: function(el, attributes, duration, method) {
3191 var isAnimated = false;
3194 var startTime = null;
3197 var actualFrames = 0;
3200 el = Roo.getDom(el);
3203 this.attributes = attributes || {};
3206 this.duration = duration || 1;
3209 this.method = method || Roo.lib.Easing.easeNone;
3212 this.useSeconds = true;
3215 this.currentFrame = 0;
3218 this.totalFrames = Roo.lib.AnimMgr.fps;
3221 this.getEl = function() {
3226 this.isAnimated = function() {
3231 this.getStartTime = function() {
3235 this.runtimeAttributes = {};
3238 this.animate = function() {
3239 if (this.isAnimated()) {
3243 this.currentFrame = 0;
3245 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3247 Roo.lib.AnimMgr.registerElement(this);
3251 this.stop = function(finish) {
3253 this.currentFrame = this.totalFrames;
3254 this._onTween.fire();
3256 Roo.lib.AnimMgr.stop(this);
3259 var onStart = function() {
3260 this.onStart.fire();
3262 this.runtimeAttributes = {};
3263 for (var attr in this.attributes) {
3264 this.setRuntimeAttribute(attr);
3269 startTime = new Date();
3273 var onTween = function() {
3275 duration: new Date() - this.getStartTime(),
3276 currentFrame: this.currentFrame
3279 data.toString = function() {
3281 'duration: ' + data.duration +
3282 ', currentFrame: ' + data.currentFrame
3286 this.onTween.fire(data);
3288 var runtimeAttributes = this.runtimeAttributes;
3290 for (var attr in runtimeAttributes) {
3291 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3297 var onComplete = function() {
3298 var actual_duration = (new Date() - startTime) / 1000 ;
3301 duration: actual_duration,
3302 frames: actualFrames,
3303 fps: actualFrames / actual_duration
3306 data.toString = function() {
3308 'duration: ' + data.duration +
3309 ', frames: ' + data.frames +
3310 ', fps: ' + data.fps
3316 this.onComplete.fire(data);
3320 this._onStart = new Roo.util.Event(this);
3321 this.onStart = new Roo.util.Event(this);
3322 this.onTween = new Roo.util.Event(this);
3323 this._onTween = new Roo.util.Event(this);
3324 this.onComplete = new Roo.util.Event(this);
3325 this._onComplete = new Roo.util.Event(this);
3326 this._onStart.addListener(onStart);
3327 this._onTween.addListener(onTween);
3328 this._onComplete.addListener(onComplete);
3333 * Portions of this file are based on pieces of Yahoo User Interface Library
3334 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3335 * YUI licensed under the BSD License:
3336 * http://developer.yahoo.net/yui/license.txt
3337 * <script type="text/javascript">
3341 Roo.lib.AnimMgr = new function() {
3358 this.registerElement = function(tween) {
3359 queue[queue.length] = tween;
3361 tween._onStart.fire();
3366 this.unRegister = function(tween, index) {
3367 tween._onComplete.fire();
3368 index = index || getIndex(tween);
3370 queue.splice(index, 1);
3374 if (tweenCount <= 0) {
3380 this.start = function() {
3381 if (thread === null) {
3382 thread = setInterval(this.run, this.delay);
3387 this.stop = function(tween) {
3389 clearInterval(thread);
3391 for (var i = 0, len = queue.length; i < len; ++i) {
3392 if (queue[0].isAnimated()) {
3393 this.unRegister(queue[0], 0);
3402 this.unRegister(tween);
3407 this.run = function() {
3408 for (var i = 0, len = queue.length; i < len; ++i) {
3409 var tween = queue[i];
3410 if (!tween || !tween.isAnimated()) {
3414 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3416 tween.currentFrame += 1;
3418 if (tween.useSeconds) {
3419 correctFrame(tween);
3421 tween._onTween.fire();
3424 Roo.lib.AnimMgr.stop(tween, i);
3429 var getIndex = function(anim) {
3430 for (var i = 0, len = queue.length; i < len; ++i) {
3431 if (queue[i] == anim) {
3439 var correctFrame = function(tween) {
3440 var frames = tween.totalFrames;
3441 var frame = tween.currentFrame;
3442 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3443 var elapsed = (new Date() - tween.getStartTime());
3446 if (elapsed < tween.duration * 1000) {
3447 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3449 tweak = frames - (frame + 1);
3451 if (tweak > 0 && isFinite(tweak)) {
3452 if (tween.currentFrame + tweak >= frames) {
3453 tweak = frames - (frame + 1);
3456 tween.currentFrame += tweak;
3460 * Portions of this file are based on pieces of Yahoo User Interface Library
3461 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3462 * YUI licensed under the BSD License:
3463 * http://developer.yahoo.net/yui/license.txt
3464 * <script type="text/javascript">
3467 Roo.lib.Bezier = new function() {
3469 this.getPosition = function(points, t) {
3470 var n = points.length;
3473 for (var i = 0; i < n; ++i) {
3474 tmp[i] = [points[i][0], points[i][1]];
3477 for (var j = 1; j < n; ++j) {
3478 for (i = 0; i < n - j; ++i) {
3479 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3480 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3484 return [ tmp[0][0], tmp[0][1] ];
3488 * Portions of this file are based on pieces of Yahoo User Interface Library
3489 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3490 * YUI licensed under the BSD License:
3491 * http://developer.yahoo.net/yui/license.txt
3492 * <script type="text/javascript">
3497 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3498 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3501 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3503 var fly = Roo.lib.AnimBase.fly;
3505 var superclass = Y.ColorAnim.superclass;
3506 var proto = Y.ColorAnim.prototype;
3508 proto.toString = function() {
3509 var el = this.getEl();
3510 var id = el.id || el.tagName;
3511 return ("ColorAnim " + id);
3514 proto.patterns.color = /color$/i;
3515 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3516 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3517 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3518 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3521 proto.parseColor = function(s) {
3522 if (s.length == 3) {
3526 var c = this.patterns.hex.exec(s);
3527 if (c && c.length == 4) {
3528 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3531 c = this.patterns.rgb.exec(s);
3532 if (c && c.length == 4) {
3533 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3536 c = this.patterns.hex3.exec(s);
3537 if (c && c.length == 4) {
3538 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3543 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3544 proto.getAttribute = function(attr) {
3545 var el = this.getEl();
3546 if (this.patterns.color.test(attr)) {
3547 var val = fly(el).getStyle(attr);
3549 if (this.patterns.transparent.test(val)) {
3550 var parent = el.parentNode;
3551 val = fly(parent).getStyle(attr);
3553 while (parent && this.patterns.transparent.test(val)) {
3554 parent = parent.parentNode;
3555 val = fly(parent).getStyle(attr);
3556 if (parent.tagName.toUpperCase() == 'HTML') {
3562 val = superclass.getAttribute.call(this, attr);
3567 proto.getAttribute = function(attr) {
3568 var el = this.getEl();
3569 if (this.patterns.color.test(attr)) {
3570 var val = fly(el).getStyle(attr);
3572 if (this.patterns.transparent.test(val)) {
3573 var parent = el.parentNode;
3574 val = fly(parent).getStyle(attr);
3576 while (parent && this.patterns.transparent.test(val)) {
3577 parent = parent.parentNode;
3578 val = fly(parent).getStyle(attr);
3579 if (parent.tagName.toUpperCase() == 'HTML') {
3585 val = superclass.getAttribute.call(this, attr);
3591 proto.doMethod = function(attr, start, end) {
3594 if (this.patterns.color.test(attr)) {
3596 for (var i = 0, len = start.length; i < len; ++i) {
3597 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3600 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3603 val = superclass.doMethod.call(this, attr, start, end);
3609 proto.setRuntimeAttribute = function(attr) {
3610 superclass.setRuntimeAttribute.call(this, attr);
3612 if (this.patterns.color.test(attr)) {
3613 var attributes = this.attributes;
3614 var start = this.parseColor(this.runtimeAttributes[attr].start);
3615 var end = this.parseColor(this.runtimeAttributes[attr].end);
3617 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3618 end = this.parseColor(attributes[attr].by);
3620 for (var i = 0, len = start.length; i < len; ++i) {
3621 end[i] = start[i] + end[i];
3625 this.runtimeAttributes[attr].start = start;
3626 this.runtimeAttributes[attr].end = end;
3632 * Portions of this file are based on pieces of Yahoo User Interface Library
3633 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3634 * YUI licensed under the BSD License:
3635 * http://developer.yahoo.net/yui/license.txt
3636 * <script type="text/javascript">
3642 easeNone: function (t, b, c, d) {
3643 return c * t / d + b;
3647 easeIn: function (t, b, c, d) {
3648 return c * (t /= d) * t + b;
3652 easeOut: function (t, b, c, d) {
3653 return -c * (t /= d) * (t - 2) + b;
3657 easeBoth: function (t, b, c, d) {
3658 if ((t /= d / 2) < 1) {
3659 return c / 2 * t * t + b;
3662 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3666 easeInStrong: function (t, b, c, d) {
3667 return c * (t /= d) * t * t * t + b;
3671 easeOutStrong: function (t, b, c, d) {
3672 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3676 easeBothStrong: function (t, b, c, d) {
3677 if ((t /= d / 2) < 1) {
3678 return c / 2 * t * t * t * t + b;
3681 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3686 elasticIn: function (t, b, c, d, a, p) {
3690 if ((t /= d) == 1) {
3697 if (!a || a < Math.abs(c)) {
3702 var s = p / (2 * Math.PI) * Math.asin(c / a);
3705 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3709 elasticOut: function (t, b, c, d, a, p) {
3713 if ((t /= d) == 1) {
3720 if (!a || a < Math.abs(c)) {
3725 var s = p / (2 * Math.PI) * Math.asin(c / a);
3728 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3732 elasticBoth: function (t, b, c, d, a, p) {
3737 if ((t /= d / 2) == 2) {
3745 if (!a || a < Math.abs(c)) {
3750 var s = p / (2 * Math.PI) * Math.asin(c / a);
3754 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3755 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3757 return a * Math.pow(2, -10 * (t -= 1)) *
3758 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3763 backIn: function (t, b, c, d, s) {
3764 if (typeof s == 'undefined') {
3767 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3771 backOut: function (t, b, c, d, s) {
3772 if (typeof s == 'undefined') {
3775 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3779 backBoth: function (t, b, c, d, s) {
3780 if (typeof s == 'undefined') {
3784 if ((t /= d / 2 ) < 1) {
3785 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3787 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3791 bounceIn: function (t, b, c, d) {
3792 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3796 bounceOut: function (t, b, c, d) {
3797 if ((t /= d) < (1 / 2.75)) {
3798 return c * (7.5625 * t * t) + b;
3799 } else if (t < (2 / 2.75)) {
3800 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3801 } else if (t < (2.5 / 2.75)) {
3802 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3804 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3808 bounceBoth: function (t, b, c, d) {
3810 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3812 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3815 * Portions of this file are based on pieces of Yahoo User Interface Library
3816 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3817 * YUI licensed under the BSD License:
3818 * http://developer.yahoo.net/yui/license.txt
3819 * <script type="text/javascript">
3823 Roo.lib.Motion = function(el, attributes, duration, method) {
3825 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3829 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3833 var superclass = Y.Motion.superclass;
3834 var proto = Y.Motion.prototype;
3836 proto.toString = function() {
3837 var el = this.getEl();
3838 var id = el.id || el.tagName;
3839 return ("Motion " + id);
3842 proto.patterns.points = /^points$/i;
3844 proto.setAttribute = function(attr, val, unit) {
3845 if (this.patterns.points.test(attr)) {
3846 unit = unit || 'px';
3847 superclass.setAttribute.call(this, 'left', val[0], unit);
3848 superclass.setAttribute.call(this, 'top', val[1], unit);
3850 superclass.setAttribute.call(this, attr, val, unit);
3854 proto.getAttribute = function(attr) {
3855 if (this.patterns.points.test(attr)) {
3857 superclass.getAttribute.call(this, 'left'),
3858 superclass.getAttribute.call(this, 'top')
3861 val = superclass.getAttribute.call(this, attr);
3867 proto.doMethod = function(attr, start, end) {
3870 if (this.patterns.points.test(attr)) {
3871 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3872 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3874 val = superclass.doMethod.call(this, attr, start, end);
3879 proto.setRuntimeAttribute = function(attr) {
3880 if (this.patterns.points.test(attr)) {
3881 var el = this.getEl();
3882 var attributes = this.attributes;
3884 var control = attributes['points']['control'] || [];
3888 if (control.length > 0 && !(control[0] instanceof Array)) {
3889 control = [control];
3892 for (i = 0,len = control.length; i < len; ++i) {
3893 tmp[i] = control[i];
3898 Roo.fly(el).position();
3900 if (isset(attributes['points']['from'])) {
3901 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3904 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3907 start = this.getAttribute('points');
3910 if (isset(attributes['points']['to'])) {
3911 end = translateValues.call(this, attributes['points']['to'], start);
3913 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3914 for (i = 0,len = control.length; i < len; ++i) {
3915 control[i] = translateValues.call(this, control[i], start);
3919 } else if (isset(attributes['points']['by'])) {
3920 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3922 for (i = 0,len = control.length; i < len; ++i) {
3923 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3927 this.runtimeAttributes[attr] = [start];
3929 if (control.length > 0) {
3930 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3933 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3936 superclass.setRuntimeAttribute.call(this, attr);
3940 var translateValues = function(val, start) {
3941 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3942 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3947 var isset = function(prop) {
3948 return (typeof prop !== 'undefined');
3952 * Portions of this file are based on pieces of Yahoo User Interface Library
3953 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3954 * YUI licensed under the BSD License:
3955 * http://developer.yahoo.net/yui/license.txt
3956 * <script type="text/javascript">
3960 Roo.lib.Scroll = function(el, attributes, duration, method) {
3962 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3966 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3970 var superclass = Y.Scroll.superclass;
3971 var proto = Y.Scroll.prototype;
3973 proto.toString = function() {
3974 var el = this.getEl();
3975 var id = el.id || el.tagName;
3976 return ("Scroll " + id);
3979 proto.doMethod = function(attr, start, end) {
3982 if (attr == 'scroll') {
3984 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3985 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3989 val = superclass.doMethod.call(this, attr, start, end);
3994 proto.getAttribute = function(attr) {
3996 var el = this.getEl();
3998 if (attr == 'scroll') {
3999 val = [ el.scrollLeft, el.scrollTop ];
4001 val = superclass.getAttribute.call(this, attr);
4007 proto.setAttribute = function(attr, val, unit) {
4008 var el = this.getEl();
4010 if (attr == 'scroll') {
4011 el.scrollLeft = val[0];
4012 el.scrollTop = val[1];
4014 superclass.setAttribute.call(this, attr, val, unit);
4020 * Ext JS Library 1.1.1
4021 * Copyright(c) 2006-2007, Ext JS, LLC.
4023 * Originally Released Under LGPL - original licence link has changed is not relivant.
4026 * <script type="text/javascript">
4030 // nasty IE9 hack - what a pile of crap that is..
4032 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4033 Range.prototype.createContextualFragment = function (html) {
4034 var doc = window.document;
4035 var container = doc.createElement("div");
4036 container.innerHTML = html;
4037 var frag = doc.createDocumentFragment(), n;
4038 while ((n = container.firstChild)) {
4039 frag.appendChild(n);
4046 * @class Roo.DomHelper
4047 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4048 * 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>.
4051 Roo.DomHelper = function(){
4052 var tempTableEl = null;
4053 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4054 var tableRe = /^table|tbody|tr|td$/i;
4056 // build as innerHTML where available
4058 var createHtml = function(o){
4059 if(typeof o == 'string'){
4068 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4069 if(attr == "style"){
4071 if(typeof s == "function"){
4074 if(typeof s == "string"){
4075 b += ' style="' + s + '"';
4076 }else if(typeof s == "object"){
4079 if(typeof s[key] != "function"){
4080 b += key + ":" + s[key] + ";";
4087 b += ' class="' + o["cls"] + '"';
4088 }else if(attr == "htmlFor"){
4089 b += ' for="' + o["htmlFor"] + '"';
4091 b += " " + attr + '="' + o[attr] + '"';
4095 if(emptyTags.test(o.tag)){
4099 var cn = o.children || o.cn;
4101 //http://bugs.kde.org/show_bug.cgi?id=71506
4102 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4103 for(var i = 0, len = cn.length; i < len; i++) {
4104 b += createHtml(cn[i], b);
4107 b += createHtml(cn, b);
4113 b += "</" + o.tag + ">";
4120 var createDom = function(o, parentNode){
4122 // defininition craeted..
4124 if (o.ns && o.ns != 'html') {
4126 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4127 xmlns[o.ns] = o.xmlns;
4130 if (typeof(xmlns[o.ns]) == 'undefined') {
4131 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4137 if (typeof(o) == 'string') {
4138 return parentNode.appendChild(document.createTextNode(o));
4140 o.tag = o.tag || div;
4141 if (o.ns && Roo.isIE) {
4143 o.tag = o.ns + ':' + o.tag;
4146 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4147 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4150 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4151 attr == "style" || typeof o[attr] == "function") continue;
4153 if(attr=="cls" && Roo.isIE){
4154 el.className = o["cls"];
4156 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4157 else el[attr] = o[attr];
4160 Roo.DomHelper.applyStyles(el, o.style);
4161 var cn = o.children || o.cn;
4163 //http://bugs.kde.org/show_bug.cgi?id=71506
4164 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4165 for(var i = 0, len = cn.length; i < len; i++) {
4166 createDom(cn[i], el);
4173 el.innerHTML = o.html;
4176 parentNode.appendChild(el);
4181 var ieTable = function(depth, s, h, e){
4182 tempTableEl.innerHTML = [s, h, e].join('');
4183 var i = -1, el = tempTableEl;
4190 // kill repeat to save bytes
4194 tbe = '</tbody>'+te,
4200 * Nasty code for IE's broken table implementation
4202 var insertIntoTable = function(tag, where, el, html){
4204 tempTableEl = document.createElement('div');
4209 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4212 if(where == 'beforebegin'){
4216 before = el.nextSibling;
4219 node = ieTable(4, trs, html, tre);
4221 else if(tag == 'tr'){
4222 if(where == 'beforebegin'){
4225 node = ieTable(3, tbs, html, tbe);
4226 } else if(where == 'afterend'){
4227 before = el.nextSibling;
4229 node = ieTable(3, tbs, html, tbe);
4230 } else{ // INTO a TR
4231 if(where == 'afterbegin'){
4232 before = el.firstChild;
4234 node = ieTable(4, trs, html, tre);
4236 } else if(tag == 'tbody'){
4237 if(where == 'beforebegin'){
4240 node = ieTable(2, ts, html, te);
4241 } else if(where == 'afterend'){
4242 before = el.nextSibling;
4244 node = ieTable(2, ts, html, te);
4246 if(where == 'afterbegin'){
4247 before = el.firstChild;
4249 node = ieTable(3, tbs, html, tbe);
4252 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4255 if(where == 'afterbegin'){
4256 before = el.firstChild;
4258 node = ieTable(2, ts, html, te);
4260 el.insertBefore(node, before);
4265 /** True to force the use of DOM instead of html fragments @type Boolean */
4269 * Returns the markup for the passed Element(s) config
4270 * @param {Object} o The Dom object spec (and children)
4273 markup : function(o){
4274 return createHtml(o);
4278 * Applies a style specification to an element
4279 * @param {String/HTMLElement} el The element to apply styles to
4280 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4281 * a function which returns such a specification.
4283 applyStyles : function(el, styles){
4286 if(typeof styles == "string"){
4287 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4289 while ((matches = re.exec(styles)) != null){
4290 el.setStyle(matches[1], matches[2]);
4292 }else if (typeof styles == "object"){
4293 for (var style in styles){
4294 el.setStyle(style, styles[style]);
4296 }else if (typeof styles == "function"){
4297 Roo.DomHelper.applyStyles(el, styles.call());
4303 * Inserts an HTML fragment into the Dom
4304 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4305 * @param {HTMLElement} el The context element
4306 * @param {String} html The HTML fragmenet
4307 * @return {HTMLElement} The new node
4309 insertHtml : function(where, el, html){
4310 where = where.toLowerCase();
4311 if(el.insertAdjacentHTML){
4312 if(tableRe.test(el.tagName)){
4314 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4320 el.insertAdjacentHTML('BeforeBegin', html);
4321 return el.previousSibling;
4323 el.insertAdjacentHTML('AfterBegin', html);
4324 return el.firstChild;
4326 el.insertAdjacentHTML('BeforeEnd', html);
4327 return el.lastChild;
4329 el.insertAdjacentHTML('AfterEnd', html);
4330 return el.nextSibling;
4332 throw 'Illegal insertion point -> "' + where + '"';
4334 var range = el.ownerDocument.createRange();
4338 range.setStartBefore(el);
4339 frag = range.createContextualFragment(html);
4340 el.parentNode.insertBefore(frag, el);
4341 return el.previousSibling;
4344 range.setStartBefore(el.firstChild);
4345 frag = range.createContextualFragment(html);
4346 el.insertBefore(frag, el.firstChild);
4347 return el.firstChild;
4349 el.innerHTML = html;
4350 return el.firstChild;
4354 range.setStartAfter(el.lastChild);
4355 frag = range.createContextualFragment(html);
4356 el.appendChild(frag);
4357 return el.lastChild;
4359 el.innerHTML = html;
4360 return el.lastChild;
4363 range.setStartAfter(el);
4364 frag = range.createContextualFragment(html);
4365 el.parentNode.insertBefore(frag, el.nextSibling);
4366 return el.nextSibling;
4368 throw 'Illegal insertion point -> "' + where + '"';
4372 * Creates new Dom element(s) and inserts them before el
4373 * @param {String/HTMLElement/Element} el The context element
4374 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4375 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4376 * @return {HTMLElement/Roo.Element} The new node
4378 insertBefore : function(el, o, returnElement){
4379 return this.doInsert(el, o, returnElement, "beforeBegin");
4383 * Creates new Dom element(s) and inserts them after el
4384 * @param {String/HTMLElement/Element} el The context element
4385 * @param {Object} o The Dom object spec (and children)
4386 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4387 * @return {HTMLElement/Roo.Element} The new node
4389 insertAfter : function(el, o, returnElement){
4390 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4394 * Creates new Dom element(s) and inserts them as the first child of el
4395 * @param {String/HTMLElement/Element} el The context element
4396 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4397 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4398 * @return {HTMLElement/Roo.Element} The new node
4400 insertFirst : function(el, o, returnElement){
4401 return this.doInsert(el, o, returnElement, "afterBegin");
4405 doInsert : function(el, o, returnElement, pos, sibling){
4406 el = Roo.getDom(el);
4408 if(this.useDom || o.ns){
4409 newNode = createDom(o, null);
4410 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4412 var html = createHtml(o);
4413 newNode = this.insertHtml(pos, el, html);
4415 return returnElement ? Roo.get(newNode, true) : newNode;
4419 * Creates new Dom element(s) and appends them to el
4420 * @param {String/HTMLElement/Element} el The context element
4421 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4422 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4423 * @return {HTMLElement/Roo.Element} The new node
4425 append : function(el, o, returnElement){
4426 el = Roo.getDom(el);
4428 if(this.useDom || o.ns){
4429 newNode = createDom(o, null);
4430 el.appendChild(newNode);
4432 var html = createHtml(o);
4433 newNode = this.insertHtml("beforeEnd", el, html);
4435 return returnElement ? Roo.get(newNode, true) : newNode;
4439 * Creates new Dom element(s) and overwrites the contents of el with them
4440 * @param {String/HTMLElement/Element} el The context element
4441 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4442 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4443 * @return {HTMLElement/Roo.Element} The new node
4445 overwrite : function(el, o, returnElement){
4446 el = Roo.getDom(el);
4449 while (el.childNodes.length) {
4450 el.removeChild(el.firstChild);
4454 el.innerHTML = createHtml(o);
4457 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4461 * Creates a new Roo.DomHelper.Template from the Dom object spec
4462 * @param {Object} o The Dom object spec (and children)
4463 * @return {Roo.DomHelper.Template} The new template
4465 createTemplate : function(o){
4466 var html = createHtml(o);
4467 return new Roo.Template(html);
4473 * Ext JS Library 1.1.1
4474 * Copyright(c) 2006-2007, Ext JS, LLC.
4476 * Originally Released Under LGPL - original licence link has changed is not relivant.
4479 * <script type="text/javascript">
4483 * @class Roo.Template
4484 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4485 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4488 var t = new Roo.Template({
4489 html : '<div name="{id}">' +
4490 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4492 myformat: function (value, allValues) {
4493 return 'XX' + value;
4496 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4498 * 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>.
4500 * @param {Object} cfg - Configuration object.
4502 Roo.Template = function(cfg){
4504 if(cfg instanceof Array){
4506 }else if(arguments.length > 1){
4507 cfg = Array.prototype.join.call(arguments, "");
4511 if (typeof(cfg) == 'object') {
4520 Roo.Template.prototype = {
4523 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4527 * Returns an HTML fragment of this template with the specified values applied.
4528 * @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'})
4529 * @return {String} The HTML fragment
4531 applyTemplate : function(values){
4535 return this.compiled(values);
4537 var useF = this.disableFormats !== true;
4538 var fm = Roo.util.Format, tpl = this;
4539 var fn = function(m, name, format, args){
4541 if(format.substr(0, 5) == "this."){
4542 return tpl.call(format.substr(5), values[name], values);
4545 // quoted values are required for strings in compiled templates,
4546 // but for non compiled we need to strip them
4547 // quoted reversed for jsmin
4548 var re = /^\s*['"](.*)["']\s*$/;
4549 args = args.split(',');
4550 for(var i = 0, len = args.length; i < len; i++){
4551 args[i] = args[i].replace(re, "$1");
4553 args = [values[name]].concat(args);
4555 args = [values[name]];
4557 return fm[format].apply(fm, args);
4560 return values[name] !== undefined ? values[name] : "";
4563 return this.html.replace(this.re, fn);
4572 * Sets the HTML used as the template and optionally compiles it.
4573 * @param {String} html
4574 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4575 * @return {Roo.Template} this
4577 set : function(html, compile){
4579 this.compiled = null;
4587 * True to disable format functions (defaults to false)
4590 disableFormats : false,
4593 * The regular expression used to match template variables
4597 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4600 * Compiles the template into an internal function, eliminating the RegEx overhead.
4601 * @return {Roo.Template} this
4603 compile : function(){
4604 var fm = Roo.util.Format;
4605 var useF = this.disableFormats !== true;
4606 var sep = Roo.isGecko ? "+" : ",";
4607 var fn = function(m, name, format, args){
4609 args = args ? ',' + args : "";
4610 if(format.substr(0, 5) != "this."){
4611 format = "fm." + format + '(';
4613 format = 'this.call("'+ format.substr(5) + '", ';
4617 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4619 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4622 // branched to use + in gecko and [].join() in others
4624 body = "this.compiled = function(values){ return '" +
4625 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4628 body = ["this.compiled = function(values){ return ['"];
4629 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4630 body.push("'].join('');};");
4631 body = body.join('');
4641 // private function used to call members
4642 call : function(fnName, value, allValues){
4643 return this[fnName](value, allValues);
4647 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4648 * @param {String/HTMLElement/Roo.Element} el The context element
4649 * @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'})
4650 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4651 * @return {HTMLElement/Roo.Element} The new node or Element
4653 insertFirst: function(el, values, returnElement){
4654 return this.doInsert('afterBegin', el, values, returnElement);
4658 * Applies the supplied values to the template and inserts the new node(s) before el.
4659 * @param {String/HTMLElement/Roo.Element} el The context element
4660 * @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'})
4661 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4662 * @return {HTMLElement/Roo.Element} The new node or Element
4664 insertBefore: function(el, values, returnElement){
4665 return this.doInsert('beforeBegin', el, values, returnElement);
4669 * Applies the supplied values to the template and inserts the new node(s) after el.
4670 * @param {String/HTMLElement/Roo.Element} el The context element
4671 * @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'})
4672 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4673 * @return {HTMLElement/Roo.Element} The new node or Element
4675 insertAfter : function(el, values, returnElement){
4676 return this.doInsert('afterEnd', el, values, returnElement);
4680 * Applies the supplied values to the template and appends the new node(s) to el.
4681 * @param {String/HTMLElement/Roo.Element} el The context element
4682 * @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'})
4683 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4684 * @return {HTMLElement/Roo.Element} The new node or Element
4686 append : function(el, values, returnElement){
4687 return this.doInsert('beforeEnd', el, values, returnElement);
4690 doInsert : function(where, el, values, returnEl){
4691 el = Roo.getDom(el);
4692 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4693 return returnEl ? Roo.get(newNode, true) : newNode;
4697 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4698 * @param {String/HTMLElement/Roo.Element} el The context element
4699 * @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'})
4700 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4701 * @return {HTMLElement/Roo.Element} The new node or Element
4703 overwrite : function(el, values, returnElement){
4704 el = Roo.getDom(el);
4705 el.innerHTML = this.applyTemplate(values);
4706 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4710 * Alias for {@link #applyTemplate}
4713 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4716 Roo.DomHelper.Template = Roo.Template;
4719 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4720 * @param {String/HTMLElement} el A DOM element or its id
4721 * @returns {Roo.Template} The created template
4724 Roo.Template.from = function(el){
4725 el = Roo.getDom(el);
4726 return new Roo.Template(el.value || el.innerHTML);
4729 * Ext JS Library 1.1.1
4730 * Copyright(c) 2006-2007, Ext JS, LLC.
4732 * Originally Released Under LGPL - original licence link has changed is not relivant.
4735 * <script type="text/javascript">
4740 * This is code is also distributed under MIT license for use
4741 * with jQuery and prototype JavaScript libraries.
4744 * @class Roo.DomQuery
4745 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).
4747 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>
4750 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.
4752 <h4>Element Selectors:</h4>
4754 <li> <b>*</b> any element</li>
4755 <li> <b>E</b> an element with the tag E</li>
4756 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4757 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4758 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4759 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4761 <h4>Attribute Selectors:</h4>
4762 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4764 <li> <b>E[foo]</b> has an attribute "foo"</li>
4765 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4766 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4767 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4768 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4769 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4770 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4772 <h4>Pseudo Classes:</h4>
4774 <li> <b>E:first-child</b> E is the first child of its parent</li>
4775 <li> <b>E:last-child</b> E is the last child of its parent</li>
4776 <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>
4777 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4778 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4779 <li> <b>E:only-child</b> E is the only child of its parent</li>
4780 <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>
4781 <li> <b>E:first</b> the first E in the resultset</li>
4782 <li> <b>E:last</b> the last E in the resultset</li>
4783 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4784 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4785 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4786 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4787 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4788 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4789 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4790 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4791 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4793 <h4>CSS Value Selectors:</h4>
4795 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4796 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4797 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4798 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4799 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4800 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4804 Roo.DomQuery = function(){
4805 var cache = {}, simpleCache = {}, valueCache = {};
4806 var nonSpace = /\S/;
4807 var trimRe = /^\s+|\s+$/g;
4808 var tplRe = /\{(\d+)\}/g;
4809 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4810 var tagTokenRe = /^(#)?([\w-\*]+)/;
4811 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4813 function child(p, index){
4815 var n = p.firstChild;
4817 if(n.nodeType == 1){
4828 while((n = n.nextSibling) && n.nodeType != 1);
4833 while((n = n.previousSibling) && n.nodeType != 1);
4837 function children(d){
4838 var n = d.firstChild, ni = -1;
4840 var nx = n.nextSibling;
4841 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4851 function byClassName(c, a, v){
4855 var r = [], ri = -1, cn;
4856 for(var i = 0, ci; ci = c[i]; i++){
4857 if((' '+ci.className+' ').indexOf(v) != -1){
4864 function attrValue(n, attr){
4865 if(!n.tagName && typeof n.length != "undefined"){
4874 if(attr == "class" || attr == "className"){
4877 return n.getAttribute(attr) || n[attr];
4881 function getNodes(ns, mode, tagName){
4882 var result = [], ri = -1, cs;
4886 tagName = tagName || "*";
4887 if(typeof ns.getElementsByTagName != "undefined"){
4891 for(var i = 0, ni; ni = ns[i]; i++){
4892 cs = ni.getElementsByTagName(tagName);
4893 for(var j = 0, ci; ci = cs[j]; j++){
4897 }else if(mode == "/" || mode == ">"){
4898 var utag = tagName.toUpperCase();
4899 for(var i = 0, ni, cn; ni = ns[i]; i++){
4900 cn = ni.children || ni.childNodes;
4901 for(var j = 0, cj; cj = cn[j]; j++){
4902 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4907 }else if(mode == "+"){
4908 var utag = tagName.toUpperCase();
4909 for(var i = 0, n; n = ns[i]; i++){
4910 while((n = n.nextSibling) && n.nodeType != 1);
4911 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4915 }else if(mode == "~"){
4916 for(var i = 0, n; n = ns[i]; i++){
4917 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4926 function concat(a, b){
4930 for(var i = 0, l = b.length; i < l; i++){
4936 function byTag(cs, tagName){
4937 if(cs.tagName || cs == document){
4943 var r = [], ri = -1;
4944 tagName = tagName.toLowerCase();
4945 for(var i = 0, ci; ci = cs[i]; i++){
4946 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4953 function byId(cs, attr, id){
4954 if(cs.tagName || cs == document){
4960 var r = [], ri = -1;
4961 for(var i = 0,ci; ci = cs[i]; i++){
4962 if(ci && ci.id == id){
4970 function byAttribute(cs, attr, value, op, custom){
4971 var r = [], ri = -1, st = custom=="{";
4972 var f = Roo.DomQuery.operators[op];
4973 for(var i = 0, ci; ci = cs[i]; i++){
4976 a = Roo.DomQuery.getStyle(ci, attr);
4978 else if(attr == "class" || attr == "className"){
4980 }else if(attr == "for"){
4982 }else if(attr == "href"){
4983 a = ci.getAttribute("href", 2);
4985 a = ci.getAttribute(attr);
4987 if((f && f(a, value)) || (!f && a)){
4994 function byPseudo(cs, name, value){
4995 return Roo.DomQuery.pseudos[name](cs, value);
4998 // This is for IE MSXML which does not support expandos.
4999 // IE runs the same speed using setAttribute, however FF slows way down
5000 // and Safari completely fails so they need to continue to use expandos.
5001 var isIE = window.ActiveXObject ? true : false;
5003 // this eval is stop the compressor from
5004 // renaming the variable to something shorter
5006 /** eval:var:batch */
5011 function nodupIEXml(cs){
5013 cs[0].setAttribute("_nodup", d);
5015 for(var i = 1, len = cs.length; i < len; i++){
5017 if(!c.getAttribute("_nodup") != d){
5018 c.setAttribute("_nodup", d);
5022 for(var i = 0, len = cs.length; i < len; i++){
5023 cs[i].removeAttribute("_nodup");
5032 var len = cs.length, c, i, r = cs, cj, ri = -1;
5033 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5036 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5037 return nodupIEXml(cs);
5041 for(i = 1; c = cs[i]; i++){
5046 for(var j = 0; j < i; j++){
5049 for(j = i+1; cj = cs[j]; j++){
5061 function quickDiffIEXml(c1, c2){
5063 for(var i = 0, len = c1.length; i < len; i++){
5064 c1[i].setAttribute("_qdiff", d);
5067 for(var i = 0, len = c2.length; i < len; i++){
5068 if(c2[i].getAttribute("_qdiff") != d){
5069 r[r.length] = c2[i];
5072 for(var i = 0, len = c1.length; i < len; i++){
5073 c1[i].removeAttribute("_qdiff");
5078 function quickDiff(c1, c2){
5079 var len1 = c1.length;
5083 if(isIE && c1[0].selectSingleNode){
5084 return quickDiffIEXml(c1, c2);
5087 for(var i = 0; i < len1; i++){
5091 for(var i = 0, len = c2.length; i < len; i++){
5092 if(c2[i]._qdiff != d){
5093 r[r.length] = c2[i];
5099 function quickId(ns, mode, root, id){
5101 var d = root.ownerDocument || root;
5102 return d.getElementById(id);
5104 ns = getNodes(ns, mode, "*");
5105 return byId(ns, null, id);
5109 getStyle : function(el, name){
5110 return Roo.fly(el).getStyle(name);
5113 * Compiles a selector/xpath query into a reusable function. The returned function
5114 * takes one parameter "root" (optional), which is the context node from where the query should start.
5115 * @param {String} selector The selector/xpath query
5116 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5117 * @return {Function}
5119 compile : function(path, type){
5120 type = type || "select";
5122 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5123 var q = path, mode, lq;
5124 var tk = Roo.DomQuery.matchers;
5125 var tklen = tk.length;
5128 // accept leading mode switch
5129 var lmode = q.match(modeRe);
5130 if(lmode && lmode[1]){
5131 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5132 q = q.replace(lmode[1], "");
5134 // strip leading slashes
5135 while(path.substr(0, 1)=="/"){
5136 path = path.substr(1);
5139 while(q && lq != q){
5141 var tm = q.match(tagTokenRe);
5142 if(type == "select"){
5145 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5147 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5149 q = q.replace(tm[0], "");
5150 }else if(q.substr(0, 1) != '@'){
5151 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5156 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5158 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5160 q = q.replace(tm[0], "");
5163 while(!(mm = q.match(modeRe))){
5164 var matched = false;
5165 for(var j = 0; j < tklen; j++){
5167 var m = q.match(t.re);
5169 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5172 q = q.replace(m[0], "");
5177 // prevent infinite loop on bad selector
5179 throw 'Error parsing selector, parsing failed at "' + q + '"';
5183 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5184 q = q.replace(mm[1], "");
5187 fn[fn.length] = "return nodup(n);\n}";
5190 * list of variables that need from compression as they are used by eval.
5200 * eval:var:byClassName
5202 * eval:var:byAttribute
5203 * eval:var:attrValue
5211 * Selects a group of elements.
5212 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5213 * @param {Node} root (optional) The start of the query (defaults to document).
5216 select : function(path, root, type){
5217 if(!root || root == document){
5220 if(typeof root == "string"){
5221 root = document.getElementById(root);
5223 var paths = path.split(",");
5225 for(var i = 0, len = paths.length; i < len; i++){
5226 var p = paths[i].replace(trimRe, "");
5228 cache[p] = Roo.DomQuery.compile(p);
5230 throw p + " is not a valid selector";
5233 var result = cache[p](root);
5234 if(result && result != document){
5235 results = results.concat(result);
5238 if(paths.length > 1){
5239 return nodup(results);
5245 * Selects a single element.
5246 * @param {String} selector The selector/xpath query
5247 * @param {Node} root (optional) The start of the query (defaults to document).
5250 selectNode : function(path, root){
5251 return Roo.DomQuery.select(path, root)[0];
5255 * Selects the value of a node, optionally replacing null with the defaultValue.
5256 * @param {String} selector The selector/xpath query
5257 * @param {Node} root (optional) The start of the query (defaults to document).
5258 * @param {String} defaultValue
5260 selectValue : function(path, root, defaultValue){
5261 path = path.replace(trimRe, "");
5262 if(!valueCache[path]){
5263 valueCache[path] = Roo.DomQuery.compile(path, "select");
5265 var n = valueCache[path](root);
5266 n = n[0] ? n[0] : n;
5267 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5268 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5272 * Selects the value of a node, parsing integers and floats.
5273 * @param {String} selector The selector/xpath query
5274 * @param {Node} root (optional) The start of the query (defaults to document).
5275 * @param {Number} defaultValue
5278 selectNumber : function(path, root, defaultValue){
5279 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5280 return parseFloat(v);
5284 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5285 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5286 * @param {String} selector The simple selector to test
5289 is : function(el, ss){
5290 if(typeof el == "string"){
5291 el = document.getElementById(el);
5293 var isArray = (el instanceof Array);
5294 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5295 return isArray ? (result.length == el.length) : (result.length > 0);
5299 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5300 * @param {Array} el An array of elements to filter
5301 * @param {String} selector The simple selector to test
5302 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5303 * the selector instead of the ones that match
5306 filter : function(els, ss, nonMatches){
5307 ss = ss.replace(trimRe, "");
5308 if(!simpleCache[ss]){
5309 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5311 var result = simpleCache[ss](els);
5312 return nonMatches ? quickDiff(result, els) : result;
5316 * Collection of matching regular expressions and code snippets.
5320 select: 'n = byClassName(n, null, " {1} ");'
5322 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5323 select: 'n = byPseudo(n, "{1}", "{2}");'
5325 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5326 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5329 select: 'n = byId(n, null, "{1}");'
5332 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5337 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5338 * 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, > <.
5341 "=" : function(a, v){
5344 "!=" : function(a, v){
5347 "^=" : function(a, v){
5348 return a && a.substr(0, v.length) == v;
5350 "$=" : function(a, v){
5351 return a && a.substr(a.length-v.length) == v;
5353 "*=" : function(a, v){
5354 return a && a.indexOf(v) !== -1;
5356 "%=" : function(a, v){
5357 return (a % v) == 0;
5359 "|=" : function(a, v){
5360 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5362 "~=" : function(a, v){
5363 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5368 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5369 * and the argument (if any) supplied in the selector.
5372 "first-child" : function(c){
5373 var r = [], ri = -1, n;
5374 for(var i = 0, ci; ci = n = c[i]; i++){
5375 while((n = n.previousSibling) && n.nodeType != 1);
5383 "last-child" : function(c){
5384 var r = [], ri = -1, n;
5385 for(var i = 0, ci; ci = n = c[i]; i++){
5386 while((n = n.nextSibling) && n.nodeType != 1);
5394 "nth-child" : function(c, a) {
5395 var r = [], ri = -1;
5396 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5397 var f = (m[1] || 1) - 0, l = m[2] - 0;
5398 for(var i = 0, n; n = c[i]; i++){
5399 var pn = n.parentNode;
5400 if (batch != pn._batch) {
5402 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5403 if(cn.nodeType == 1){
5410 if (l == 0 || n.nodeIndex == l){
5413 } else if ((n.nodeIndex + l) % f == 0){
5421 "only-child" : function(c){
5422 var r = [], ri = -1;;
5423 for(var i = 0, ci; ci = c[i]; i++){
5424 if(!prev(ci) && !next(ci)){
5431 "empty" : function(c){
5432 var r = [], ri = -1;
5433 for(var i = 0, ci; ci = c[i]; i++){
5434 var cns = ci.childNodes, j = 0, cn, empty = true;
5437 if(cn.nodeType == 1 || cn.nodeType == 3){
5449 "contains" : function(c, v){
5450 var r = [], ri = -1;
5451 for(var i = 0, ci; ci = c[i]; i++){
5452 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5459 "nodeValue" : function(c, v){
5460 var r = [], ri = -1;
5461 for(var i = 0, ci; ci = c[i]; i++){
5462 if(ci.firstChild && ci.firstChild.nodeValue == v){
5469 "checked" : function(c){
5470 var r = [], ri = -1;
5471 for(var i = 0, ci; ci = c[i]; i++){
5472 if(ci.checked == true){
5479 "not" : function(c, ss){
5480 return Roo.DomQuery.filter(c, ss, true);
5483 "odd" : function(c){
5484 return this["nth-child"](c, "odd");
5487 "even" : function(c){
5488 return this["nth-child"](c, "even");
5491 "nth" : function(c, a){
5492 return c[a-1] || [];
5495 "first" : function(c){
5499 "last" : function(c){
5500 return c[c.length-1] || [];
5503 "has" : function(c, ss){
5504 var s = Roo.DomQuery.select;
5505 var r = [], ri = -1;
5506 for(var i = 0, ci; ci = c[i]; i++){
5507 if(s(ss, ci).length > 0){
5514 "next" : function(c, ss){
5515 var is = Roo.DomQuery.is;
5516 var r = [], ri = -1;
5517 for(var i = 0, ci; ci = c[i]; i++){
5526 "prev" : function(c, ss){
5527 var is = Roo.DomQuery.is;
5528 var r = [], ri = -1;
5529 for(var i = 0, ci; ci = c[i]; i++){
5542 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5543 * @param {String} path The selector/xpath query
5544 * @param {Node} root (optional) The start of the query (defaults to document).
5549 Roo.query = Roo.DomQuery.select;
5552 * Ext JS Library 1.1.1
5553 * Copyright(c) 2006-2007, Ext JS, LLC.
5555 * Originally Released Under LGPL - original licence link has changed is not relivant.
5558 * <script type="text/javascript">
5562 * @class Roo.util.Observable
5563 * Base class that provides a common interface for publishing events. Subclasses are expected to
5564 * to have a property "events" with all the events defined.<br>
5567 Employee = function(name){
5574 Roo.extend(Employee, Roo.util.Observable);
5576 * @param {Object} config properties to use (incuding events / listeners)
5579 Roo.util.Observable = function(cfg){
5582 this.addEvents(cfg.events || {});
5584 delete cfg.events; // make sure
5587 Roo.apply(this, cfg);
5590 this.on(this.listeners);
5591 delete this.listeners;
5594 Roo.util.Observable.prototype = {
5596 * @cfg {Object} listeners list of events and functions to call for this object,
5600 'click' : function(e) {
5610 * Fires the specified event with the passed parameters (minus the event name).
5611 * @param {String} eventName
5612 * @param {Object...} args Variable number of parameters are passed to handlers
5613 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5615 fireEvent : function(){
5616 var ce = this.events[arguments[0].toLowerCase()];
5617 if(typeof ce == "object"){
5618 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5625 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5628 * Appends an event handler to this component
5629 * @param {String} eventName The type of event to listen for
5630 * @param {Function} handler The method the event invokes
5631 * @param {Object} scope (optional) The scope in which to execute the handler
5632 * function. The handler function's "this" context.
5633 * @param {Object} options (optional) An object containing handler configuration
5634 * properties. This may contain any of the following properties:<ul>
5635 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5636 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5637 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5638 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5639 * by the specified number of milliseconds. If the event fires again within that time, the original
5640 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5643 * <b>Combining Options</b><br>
5644 * Using the options argument, it is possible to combine different types of listeners:<br>
5646 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5648 el.on('click', this.onClick, this, {
5655 * <b>Attaching multiple handlers in 1 call</b><br>
5656 * The method also allows for a single argument to be passed which is a config object containing properties
5657 * which specify multiple handlers.
5666 fn: this.onMouseOver,
5670 fn: this.onMouseOut,
5676 * Or a shorthand syntax which passes the same scope object to all handlers:
5679 'click': this.onClick,
5680 'mouseover': this.onMouseOver,
5681 'mouseout': this.onMouseOut,
5686 addListener : function(eventName, fn, scope, o){
5687 if(typeof eventName == "object"){
5690 if(this.filterOptRe.test(e)){
5693 if(typeof o[e] == "function"){
5695 this.addListener(e, o[e], o.scope, o);
5697 // individual options
5698 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5703 o = (!o || typeof o == "boolean") ? {} : o;
5704 eventName = eventName.toLowerCase();
5705 var ce = this.events[eventName] || true;
5706 if(typeof ce == "boolean"){
5707 ce = new Roo.util.Event(this, eventName);
5708 this.events[eventName] = ce;
5710 ce.addListener(fn, scope, o);
5714 * Removes a listener
5715 * @param {String} eventName The type of event to listen for
5716 * @param {Function} handler The handler to remove
5717 * @param {Object} scope (optional) The scope (this object) for the handler
5719 removeListener : function(eventName, fn, scope){
5720 var ce = this.events[eventName.toLowerCase()];
5721 if(typeof ce == "object"){
5722 ce.removeListener(fn, scope);
5727 * Removes all listeners for this object
5729 purgeListeners : function(){
5730 for(var evt in this.events){
5731 if(typeof this.events[evt] == "object"){
5732 this.events[evt].clearListeners();
5737 relayEvents : function(o, events){
5738 var createHandler = function(ename){
5740 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5743 for(var i = 0, len = events.length; i < len; i++){
5744 var ename = events[i];
5745 if(!this.events[ename]){ this.events[ename] = true; };
5746 o.on(ename, createHandler(ename), this);
5751 * Used to define events on this Observable
5752 * @param {Object} object The object with the events defined
5754 addEvents : function(o){
5758 Roo.applyIf(this.events, o);
5762 * Checks to see if this object has any listeners for a specified event
5763 * @param {String} eventName The name of the event to check for
5764 * @return {Boolean} True if the event is being listened for, else false
5766 hasListener : function(eventName){
5767 var e = this.events[eventName];
5768 return typeof e == "object" && e.listeners.length > 0;
5772 * Appends an event handler to this element (shorthand for addListener)
5773 * @param {String} eventName The type of event to listen for
5774 * @param {Function} handler The method the event invokes
5775 * @param {Object} scope (optional) The scope in which to execute the handler
5776 * function. The handler function's "this" context.
5777 * @param {Object} options (optional)
5780 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5782 * Removes a listener (shorthand for removeListener)
5783 * @param {String} eventName The type of event to listen for
5784 * @param {Function} handler The handler to remove
5785 * @param {Object} scope (optional) The scope (this object) for the handler
5788 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5791 * Starts capture on the specified Observable. All events will be passed
5792 * to the supplied function with the event name + standard signature of the event
5793 * <b>before</b> the event is fired. If the supplied function returns false,
5794 * the event will not fire.
5795 * @param {Observable} o The Observable to capture
5796 * @param {Function} fn The function to call
5797 * @param {Object} scope (optional) The scope (this object) for the fn
5800 Roo.util.Observable.capture = function(o, fn, scope){
5801 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5805 * Removes <b>all</b> added captures from the Observable.
5806 * @param {Observable} o The Observable to release
5809 Roo.util.Observable.releaseCapture = function(o){
5810 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5815 var createBuffered = function(h, o, scope){
5816 var task = new Roo.util.DelayedTask();
5818 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5822 var createSingle = function(h, e, fn, scope){
5824 e.removeListener(fn, scope);
5825 return h.apply(scope, arguments);
5829 var createDelayed = function(h, o, scope){
5831 var args = Array.prototype.slice.call(arguments, 0);
5832 setTimeout(function(){
5833 h.apply(scope, args);
5838 Roo.util.Event = function(obj, name){
5841 this.listeners = [];
5844 Roo.util.Event.prototype = {
5845 addListener : function(fn, scope, options){
5846 var o = options || {};
5847 scope = scope || this.obj;
5848 if(!this.isListening(fn, scope)){
5849 var l = {fn: fn, scope: scope, options: o};
5852 h = createDelayed(h, o, scope);
5855 h = createSingle(h, this, fn, scope);
5858 h = createBuffered(h, o, scope);
5861 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5862 this.listeners.push(l);
5864 this.listeners = this.listeners.slice(0);
5865 this.listeners.push(l);
5870 findListener : function(fn, scope){
5871 scope = scope || this.obj;
5872 var ls = this.listeners;
5873 for(var i = 0, len = ls.length; i < len; i++){
5875 if(l.fn == fn && l.scope == scope){
5882 isListening : function(fn, scope){
5883 return this.findListener(fn, scope) != -1;
5886 removeListener : function(fn, scope){
5888 if((index = this.findListener(fn, scope)) != -1){
5890 this.listeners.splice(index, 1);
5892 this.listeners = this.listeners.slice(0);
5893 this.listeners.splice(index, 1);
5900 clearListeners : function(){
5901 this.listeners = [];
5905 var ls = this.listeners, scope, len = ls.length;
5908 var args = Array.prototype.slice.call(arguments, 0);
5909 for(var i = 0; i < len; i++){
5911 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5912 this.firing = false;
5916 this.firing = false;
5923 * Ext JS Library 1.1.1
5924 * Copyright(c) 2006-2007, Ext JS, LLC.
5926 * Originally Released Under LGPL - original licence link has changed is not relivant.
5929 * <script type="text/javascript">
5933 * @class Roo.EventManager
5934 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5935 * several useful events directly.
5936 * See {@link Roo.EventObject} for more details on normalized event objects.
5939 Roo.EventManager = function(){
5940 var docReadyEvent, docReadyProcId, docReadyState = false;
5941 var resizeEvent, resizeTask, textEvent, textSize;
5942 var E = Roo.lib.Event;
5943 var D = Roo.lib.Dom;
5946 var fireDocReady = function(){
5948 docReadyState = true;
5951 clearInterval(docReadyProcId);
5953 if(Roo.isGecko || Roo.isOpera) {
5954 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5957 var defer = document.getElementById("ie-deferred-loader");
5959 defer.onreadystatechange = null;
5960 defer.parentNode.removeChild(defer);
5964 docReadyEvent.fire();
5965 docReadyEvent.clearListeners();
5970 var initDocReady = function(){
5971 docReadyEvent = new Roo.util.Event();
5972 if(Roo.isGecko || Roo.isOpera) {
5973 document.addEventListener("DOMContentLoaded", fireDocReady, false);
5975 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5976 var defer = document.getElementById("ie-deferred-loader");
5977 defer.onreadystatechange = function(){
5978 if(this.readyState == "complete"){
5982 }else if(Roo.isSafari){
5983 docReadyProcId = setInterval(function(){
5984 var rs = document.readyState;
5985 if(rs == "complete") {
5990 // no matter what, make sure it fires on load
5991 E.on(window, "load", fireDocReady);
5994 var createBuffered = function(h, o){
5995 var task = new Roo.util.DelayedTask(h);
5997 // create new event object impl so new events don't wipe out properties
5998 e = new Roo.EventObjectImpl(e);
5999 task.delay(o.buffer, h, null, [e]);
6003 var createSingle = function(h, el, ename, fn){
6005 Roo.EventManager.removeListener(el, ename, fn);
6010 var createDelayed = function(h, o){
6012 // create new event object impl so new events don't wipe out properties
6013 e = new Roo.EventObjectImpl(e);
6014 setTimeout(function(){
6020 var listen = function(element, ename, opt, fn, scope){
6021 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6022 fn = fn || o.fn; scope = scope || o.scope;
6023 var el = Roo.getDom(element);
6025 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6027 var h = function(e){
6028 e = Roo.EventObject.setEvent(e);
6031 t = e.getTarget(o.delegate, el);
6038 if(o.stopEvent === true){
6041 if(o.preventDefault === true){
6044 if(o.stopPropagation === true){
6045 e.stopPropagation();
6048 if(o.normalized === false){
6052 fn.call(scope || el, e, t, o);
6055 h = createDelayed(h, o);
6058 h = createSingle(h, el, ename, fn);
6061 h = createBuffered(h, o);
6063 fn._handlers = fn._handlers || [];
6064 fn._handlers.push([Roo.id(el), ename, h]);
6067 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6068 el.addEventListener("DOMMouseScroll", h, false);
6069 E.on(window, 'unload', function(){
6070 el.removeEventListener("DOMMouseScroll", h, false);
6073 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6074 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6079 var stopListening = function(el, ename, fn){
6080 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6082 for(var i = 0, len = hds.length; i < len; i++){
6084 if(h[0] == id && h[1] == ename){
6091 E.un(el, ename, hd);
6092 el = Roo.getDom(el);
6093 if(ename == "mousewheel" && el.addEventListener){
6094 el.removeEventListener("DOMMouseScroll", hd, false);
6096 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6097 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6101 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6108 * @scope Roo.EventManager
6113 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6114 * object with a Roo.EventObject
6115 * @param {Function} fn The method the event invokes
6116 * @param {Object} scope An object that becomes the scope of the handler
6117 * @param {boolean} override If true, the obj passed in becomes
6118 * the execution scope of the listener
6119 * @return {Function} The wrapped function
6122 wrap : function(fn, scope, override){
6124 Roo.EventObject.setEvent(e);
6125 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6130 * Appends an event handler to an element (shorthand for addListener)
6131 * @param {String/HTMLElement} element The html element or id to assign the
6132 * @param {String} eventName The type of event to listen for
6133 * @param {Function} handler The method the event invokes
6134 * @param {Object} scope (optional) The scope in which to execute the handler
6135 * function. The handler function's "this" context.
6136 * @param {Object} options (optional) An object containing handler configuration
6137 * properties. This may contain any of the following properties:<ul>
6138 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6139 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6140 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6141 * <li>preventDefault {Boolean} True to prevent the default action</li>
6142 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6143 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6144 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6145 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6146 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6147 * by the specified number of milliseconds. If the event fires again within that time, the original
6148 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6151 * <b>Combining Options</b><br>
6152 * Using the options argument, it is possible to combine different types of listeners:<br>
6154 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6156 el.on('click', this.onClick, this, {
6163 * <b>Attaching multiple handlers in 1 call</b><br>
6164 * The method also allows for a single argument to be passed which is a config object containing properties
6165 * which specify multiple handlers.
6175 fn: this.onMouseOver
6184 * Or a shorthand syntax:<br>
6187 'click' : this.onClick,
6188 'mouseover' : this.onMouseOver,
6189 'mouseout' : this.onMouseOut
6193 addListener : function(element, eventName, fn, scope, options){
6194 if(typeof eventName == "object"){
6200 if(typeof o[e] == "function"){
6202 listen(element, e, o, o[e], o.scope);
6204 // individual options
6205 listen(element, e, o[e]);
6210 return listen(element, eventName, options, fn, scope);
6214 * Removes an event handler
6216 * @param {String/HTMLElement} element The id or html element to remove the
6218 * @param {String} eventName The type of event
6219 * @param {Function} fn
6220 * @return {Boolean} True if a listener was actually removed
6222 removeListener : function(element, eventName, fn){
6223 return stopListening(element, eventName, fn);
6227 * Fires when the document is ready (before onload and before images are loaded). Can be
6228 * accessed shorthanded Roo.onReady().
6229 * @param {Function} fn The method the event invokes
6230 * @param {Object} scope An object that becomes the scope of the handler
6231 * @param {boolean} options
6233 onDocumentReady : function(fn, scope, options){
6234 if(docReadyState){ // if it already fired
6235 docReadyEvent.addListener(fn, scope, options);
6236 docReadyEvent.fire();
6237 docReadyEvent.clearListeners();
6243 docReadyEvent.addListener(fn, scope, options);
6247 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6248 * @param {Function} fn The method the event invokes
6249 * @param {Object} scope An object that becomes the scope of the handler
6250 * @param {boolean} options
6252 onWindowResize : function(fn, scope, options){
6254 resizeEvent = new Roo.util.Event();
6255 resizeTask = new Roo.util.DelayedTask(function(){
6256 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6258 E.on(window, "resize", function(){
6260 resizeTask.delay(50);
6262 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6266 resizeEvent.addListener(fn, scope, options);
6270 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6271 * @param {Function} fn The method the event invokes
6272 * @param {Object} scope An object that becomes the scope of the handler
6273 * @param {boolean} options
6275 onTextResize : function(fn, scope, options){
6277 textEvent = new Roo.util.Event();
6278 var textEl = new Roo.Element(document.createElement('div'));
6279 textEl.dom.className = 'x-text-resize';
6280 textEl.dom.innerHTML = 'X';
6281 textEl.appendTo(document.body);
6282 textSize = textEl.dom.offsetHeight;
6283 setInterval(function(){
6284 if(textEl.dom.offsetHeight != textSize){
6285 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6287 }, this.textResizeInterval);
6289 textEvent.addListener(fn, scope, options);
6293 * Removes the passed window resize listener.
6294 * @param {Function} fn The method the event invokes
6295 * @param {Object} scope The scope of handler
6297 removeResizeListener : function(fn, scope){
6299 resizeEvent.removeListener(fn, scope);
6304 fireResize : function(){
6306 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6310 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6314 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6316 textResizeInterval : 50
6321 * @scopeAlias pub=Roo.EventManager
6325 * Appends an event handler to an element (shorthand for addListener)
6326 * @param {String/HTMLElement} element The html element or id to assign the
6327 * @param {String} eventName The type of event to listen for
6328 * @param {Function} handler The method the event invokes
6329 * @param {Object} scope (optional) The scope in which to execute the handler
6330 * function. The handler function's "this" context.
6331 * @param {Object} options (optional) An object containing handler configuration
6332 * properties. This may contain any of the following properties:<ul>
6333 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6334 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6335 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6336 * <li>preventDefault {Boolean} True to prevent the default action</li>
6337 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6338 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6339 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6340 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6341 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6342 * by the specified number of milliseconds. If the event fires again within that time, the original
6343 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6346 * <b>Combining Options</b><br>
6347 * Using the options argument, it is possible to combine different types of listeners:<br>
6349 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6351 el.on('click', this.onClick, this, {
6358 * <b>Attaching multiple handlers in 1 call</b><br>
6359 * The method also allows for a single argument to be passed which is a config object containing properties
6360 * which specify multiple handlers.
6370 fn: this.onMouseOver
6379 * Or a shorthand syntax:<br>
6382 'click' : this.onClick,
6383 'mouseover' : this.onMouseOver,
6384 'mouseout' : this.onMouseOut
6388 pub.on = pub.addListener;
6389 pub.un = pub.removeListener;
6391 pub.stoppedMouseDownEvent = new Roo.util.Event();
6395 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6396 * @param {Function} fn The method the event invokes
6397 * @param {Object} scope An object that becomes the scope of the handler
6398 * @param {boolean} override If true, the obj passed in becomes
6399 * the execution scope of the listener
6403 Roo.onReady = Roo.EventManager.onDocumentReady;
6405 Roo.onReady(function(){
6406 var bd = Roo.get(document.body);
6411 : Roo.isGecko ? "roo-gecko"
6412 : Roo.isOpera ? "roo-opera"
6413 : Roo.isSafari ? "roo-safari" : ""];
6416 cls.push("roo-mac");
6419 cls.push("roo-linux");
6421 if(Roo.isBorderBox){
6422 cls.push('roo-border-box');
6424 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6425 var p = bd.dom.parentNode;
6427 p.className += ' roo-strict';
6430 bd.addClass(cls.join(' '));
6434 * @class Roo.EventObject
6435 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6436 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6439 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6441 var target = e.getTarget();
6444 var myDiv = Roo.get("myDiv");
6445 myDiv.on("click", handleClick);
6447 Roo.EventManager.on("myDiv", 'click', handleClick);
6448 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6452 Roo.EventObject = function(){
6454 var E = Roo.lib.Event;
6456 // safari keypress events for special keys return bad keycodes
6459 63235 : 39, // right
6462 63276 : 33, // page up
6463 63277 : 34, // page down
6464 63272 : 46, // delete
6469 // normalize button clicks
6470 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6471 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6473 Roo.EventObjectImpl = function(e){
6475 this.setEvent(e.browserEvent || e);
6478 Roo.EventObjectImpl.prototype = {
6480 * Used to fix doc tools.
6481 * @scope Roo.EventObject.prototype
6487 /** The normal browser event */
6488 browserEvent : null,
6489 /** The button pressed in a mouse event */
6491 /** True if the shift key was down during the event */
6493 /** True if the control key was down during the event */
6495 /** True if the alt key was down during the event */
6554 setEvent : function(e){
6555 if(e == this || (e && e.browserEvent)){ // already wrapped
6558 this.browserEvent = e;
6560 // normalize buttons
6561 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6562 if(e.type == 'click' && this.button == -1){
6566 this.shiftKey = e.shiftKey;
6567 // mac metaKey behaves like ctrlKey
6568 this.ctrlKey = e.ctrlKey || e.metaKey;
6569 this.altKey = e.altKey;
6570 // in getKey these will be normalized for the mac
6571 this.keyCode = e.keyCode;
6572 // keyup warnings on firefox.
6573 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6574 // cache the target for the delayed and or buffered events
6575 this.target = E.getTarget(e);
6577 this.xy = E.getXY(e);
6580 this.shiftKey = false;
6581 this.ctrlKey = false;
6582 this.altKey = false;
6592 * Stop the event (preventDefault and stopPropagation)
6594 stopEvent : function(){
6595 if(this.browserEvent){
6596 if(this.browserEvent.type == 'mousedown'){
6597 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6599 E.stopEvent(this.browserEvent);
6604 * Prevents the browsers default handling of the event.
6606 preventDefault : function(){
6607 if(this.browserEvent){
6608 E.preventDefault(this.browserEvent);
6613 isNavKeyPress : function(){
6614 var k = this.keyCode;
6615 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6616 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6619 isSpecialKey : function(){
6620 var k = this.keyCode;
6621 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6622 (k == 16) || (k == 17) ||
6623 (k >= 18 && k <= 20) ||
6624 (k >= 33 && k <= 35) ||
6625 (k >= 36 && k <= 39) ||
6626 (k >= 44 && k <= 45);
6629 * Cancels bubbling of the event.
6631 stopPropagation : function(){
6632 if(this.browserEvent){
6633 if(this.type == 'mousedown'){
6634 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6636 E.stopPropagation(this.browserEvent);
6641 * Gets the key code for the event.
6644 getCharCode : function(){
6645 return this.charCode || this.keyCode;
6649 * Returns a normalized keyCode for the event.
6650 * @return {Number} The key code
6652 getKey : function(){
6653 var k = this.keyCode || this.charCode;
6654 return Roo.isSafari ? (safariKeys[k] || k) : k;
6658 * Gets the x coordinate of the event.
6661 getPageX : function(){
6666 * Gets the y coordinate of the event.
6669 getPageY : function(){
6674 * Gets the time of the event.
6677 getTime : function(){
6678 if(this.browserEvent){
6679 return E.getTime(this.browserEvent);
6685 * Gets the page coordinates of the event.
6686 * @return {Array} The xy values like [x, y]
6693 * Gets the target for the event.
6694 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6695 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6696 search as a number or element (defaults to 10 || document.body)
6697 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6698 * @return {HTMLelement}
6700 getTarget : function(selector, maxDepth, returnEl){
6701 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6704 * Gets the related target.
6705 * @return {HTMLElement}
6707 getRelatedTarget : function(){
6708 if(this.browserEvent){
6709 return E.getRelatedTarget(this.browserEvent);
6715 * Normalizes mouse wheel delta across browsers
6716 * @return {Number} The delta
6718 getWheelDelta : function(){
6719 var e = this.browserEvent;
6721 if(e.wheelDelta){ /* IE/Opera. */
6722 delta = e.wheelDelta/120;
6723 }else if(e.detail){ /* Mozilla case. */
6724 delta = -e.detail/3;
6730 * Returns true if the control, meta, shift or alt key was pressed during this event.
6733 hasModifier : function(){
6734 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6738 * Returns true if the target of this event equals el or is a child of el
6739 * @param {String/HTMLElement/Element} el
6740 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6743 within : function(el, related){
6744 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6745 return t && Roo.fly(el).contains(t);
6748 getPoint : function(){
6749 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6753 return new Roo.EventObjectImpl();
6758 * Ext JS Library 1.1.1
6759 * Copyright(c) 2006-2007, Ext JS, LLC.
6761 * Originally Released Under LGPL - original licence link has changed is not relivant.
6764 * <script type="text/javascript">
6768 // was in Composite Element!??!?!
6771 var D = Roo.lib.Dom;
6772 var E = Roo.lib.Event;
6773 var A = Roo.lib.Anim;
6775 // local style camelizing for speed
6777 var camelRe = /(-[a-z])/gi;
6778 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6779 var view = document.defaultView;
6782 * @class Roo.Element
6783 * Represents an Element in the DOM.<br><br>
6786 var el = Roo.get("my-div");
6789 var el = getEl("my-div");
6791 // or with a DOM element
6792 var el = Roo.get(myDivElement);
6794 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6795 * each call instead of constructing a new one.<br><br>
6796 * <b>Animations</b><br />
6797 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6798 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6800 Option Default Description
6801 --------- -------- ---------------------------------------------
6802 duration .35 The duration of the animation in seconds
6803 easing easeOut The YUI easing method
6804 callback none A function to execute when the anim completes
6805 scope this The scope (this) of the callback function
6807 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6808 * manipulate the animation. Here's an example:
6810 var el = Roo.get("my-div");
6815 // default animation
6816 el.setWidth(100, true);
6818 // animation with some options set
6825 // using the "anim" property to get the Anim object
6831 el.setWidth(100, opt);
6833 if(opt.anim.isAnimated()){
6837 * <b> Composite (Collections of) Elements</b><br />
6838 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6839 * @constructor Create a new Element directly.
6840 * @param {String/HTMLElement} element
6841 * @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).
6843 Roo.Element = function(element, forceNew){
6844 var dom = typeof element == "string" ?
6845 document.getElementById(element) : element;
6846 if(!dom){ // invalid id/element
6850 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6851 return Roo.Element.cache[id];
6861 * The DOM element ID
6864 this.id = id || Roo.id(dom);
6867 var El = Roo.Element;
6871 * The element's default display mode (defaults to "")
6874 originalDisplay : "",
6878 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6883 * Sets the element's visibility mode. When setVisible() is called it
6884 * will use this to determine whether to set the visibility or the display property.
6885 * @param visMode Element.VISIBILITY or Element.DISPLAY
6886 * @return {Roo.Element} this
6888 setVisibilityMode : function(visMode){
6889 this.visibilityMode = visMode;
6893 * Convenience method for setVisibilityMode(Element.DISPLAY)
6894 * @param {String} display (optional) What to set display to when visible
6895 * @return {Roo.Element} this
6897 enableDisplayMode : function(display){
6898 this.setVisibilityMode(El.DISPLAY);
6899 if(typeof display != "undefined") this.originalDisplay = display;
6904 * 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)
6905 * @param {String} selector The simple selector to test
6906 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6907 search as a number or element (defaults to 10 || document.body)
6908 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6909 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6911 findParent : function(simpleSelector, maxDepth, returnEl){
6912 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6913 maxDepth = maxDepth || 50;
6914 if(typeof maxDepth != "number"){
6915 stopEl = Roo.getDom(maxDepth);
6918 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6919 if(dq.is(p, simpleSelector)){
6920 return returnEl ? Roo.get(p) : p;
6930 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6931 * @param {String} selector The simple selector to test
6932 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6933 search as a number or element (defaults to 10 || document.body)
6934 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6935 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6937 findParentNode : function(simpleSelector, maxDepth, returnEl){
6938 var p = Roo.fly(this.dom.parentNode, '_internal');
6939 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6943 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6944 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6945 * @param {String} selector The simple selector to test
6946 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6947 search as a number or element (defaults to 10 || document.body)
6948 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6950 up : function(simpleSelector, maxDepth){
6951 return this.findParentNode(simpleSelector, maxDepth, true);
6957 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6958 * @param {String} selector The simple selector to test
6959 * @return {Boolean} True if this element matches the selector, else false
6961 is : function(simpleSelector){
6962 return Roo.DomQuery.is(this.dom, simpleSelector);
6966 * Perform animation on this element.
6967 * @param {Object} args The YUI animation control args
6968 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6969 * @param {Function} onComplete (optional) Function to call when animation completes
6970 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6971 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6972 * @return {Roo.Element} this
6974 animate : function(args, duration, onComplete, easing, animType){
6975 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6980 * @private Internal animation call
6982 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6983 animType = animType || 'run';
6985 var anim = Roo.lib.Anim[animType](
6987 (opt.duration || defaultDur) || .35,
6988 (opt.easing || defaultEase) || 'easeOut',
6990 Roo.callback(cb, this);
6991 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6999 // private legacy anim prep
7000 preanim : function(a, i){
7001 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7005 * Removes worthless text nodes
7006 * @param {Boolean} forceReclean (optional) By default the element
7007 * keeps track if it has been cleaned already so
7008 * you can call this over and over. However, if you update the element and
7009 * need to force a reclean, you can pass true.
7011 clean : function(forceReclean){
7012 if(this.isCleaned && forceReclean !== true){
7016 var d = this.dom, n = d.firstChild, ni = -1;
7018 var nx = n.nextSibling;
7019 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7026 this.isCleaned = true;
7031 calcOffsetsTo : function(el){
7034 var restorePos = false;
7035 if(el.getStyle('position') == 'static'){
7036 el.position('relative');
7041 while(op && op != d && op.tagName != 'HTML'){
7044 op = op.offsetParent;
7047 el.position('static');
7053 * Scrolls this element into view within the passed container.
7054 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7055 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7056 * @return {Roo.Element} this
7058 scrollIntoView : function(container, hscroll){
7059 var c = Roo.getDom(container) || document.body;
7062 var o = this.calcOffsetsTo(c),
7065 b = t+el.offsetHeight,
7066 r = l+el.offsetWidth;
7068 var ch = c.clientHeight;
7069 var ct = parseInt(c.scrollTop, 10);
7070 var cl = parseInt(c.scrollLeft, 10);
7072 var cr = cl + c.clientWidth;
7080 if(hscroll !== false){
7084 c.scrollLeft = r-c.clientWidth;
7091 scrollChildIntoView : function(child, hscroll){
7092 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7096 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7097 * the new height may not be available immediately.
7098 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7099 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7100 * @param {Function} onComplete (optional) Function to call when animation completes
7101 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7102 * @return {Roo.Element} this
7104 autoHeight : function(animate, duration, onComplete, easing){
7105 var oldHeight = this.getHeight();
7107 this.setHeight(1); // force clipping
7108 setTimeout(function(){
7109 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7111 this.setHeight(height);
7113 if(typeof onComplete == "function"){
7117 this.setHeight(oldHeight); // restore original height
7118 this.setHeight(height, animate, duration, function(){
7120 if(typeof onComplete == "function") onComplete();
7121 }.createDelegate(this), easing);
7123 }.createDelegate(this), 0);
7128 * Returns true if this element is an ancestor of the passed element
7129 * @param {HTMLElement/String} el The element to check
7130 * @return {Boolean} True if this element is an ancestor of el, else false
7132 contains : function(el){
7133 if(!el){return false;}
7134 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7138 * Checks whether the element is currently visible using both visibility and display properties.
7139 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7140 * @return {Boolean} True if the element is currently visible, else false
7142 isVisible : function(deep) {
7143 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7144 if(deep !== true || !vis){
7147 var p = this.dom.parentNode;
7148 while(p && p.tagName.toLowerCase() != "body"){
7149 if(!Roo.fly(p, '_isVisible').isVisible()){
7158 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7159 * @param {String} selector The CSS selector
7160 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7161 * @return {CompositeElement/CompositeElementLite} The composite element
7163 select : function(selector, unique){
7164 return El.select(selector, unique, this.dom);
7168 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7169 * @param {String} selector The CSS selector
7170 * @return {Array} An array of the matched nodes
7172 query : function(selector, unique){
7173 return Roo.DomQuery.select(selector, this.dom);
7177 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7178 * @param {String} selector The CSS selector
7179 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7180 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7182 child : function(selector, returnDom){
7183 var n = Roo.DomQuery.selectNode(selector, this.dom);
7184 return returnDom ? n : Roo.get(n);
7188 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7189 * @param {String} selector The CSS selector
7190 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7191 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7193 down : function(selector, returnDom){
7194 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7195 return returnDom ? n : Roo.get(n);
7199 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7200 * @param {String} group The group the DD object is member of
7201 * @param {Object} config The DD config object
7202 * @param {Object} overrides An object containing methods to override/implement on the DD object
7203 * @return {Roo.dd.DD} The DD object
7205 initDD : function(group, config, overrides){
7206 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7207 return Roo.apply(dd, overrides);
7211 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7212 * @param {String} group The group the DDProxy object is member of
7213 * @param {Object} config The DDProxy config object
7214 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7215 * @return {Roo.dd.DDProxy} The DDProxy object
7217 initDDProxy : function(group, config, overrides){
7218 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7219 return Roo.apply(dd, overrides);
7223 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7224 * @param {String} group The group the DDTarget object is member of
7225 * @param {Object} config The DDTarget config object
7226 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7227 * @return {Roo.dd.DDTarget} The DDTarget object
7229 initDDTarget : function(group, config, overrides){
7230 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7231 return Roo.apply(dd, overrides);
7235 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7236 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7237 * @param {Boolean} visible Whether the element is visible
7238 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7239 * @return {Roo.Element} this
7241 setVisible : function(visible, animate){
7243 if(this.visibilityMode == El.DISPLAY){
7244 this.setDisplayed(visible);
7247 this.dom.style.visibility = visible ? "visible" : "hidden";
7250 // closure for composites
7252 var visMode = this.visibilityMode;
7254 this.setOpacity(.01);
7255 this.setVisible(true);
7257 this.anim({opacity: { to: (visible?1:0) }},
7258 this.preanim(arguments, 1),
7259 null, .35, 'easeIn', function(){
7261 if(visMode == El.DISPLAY){
7262 dom.style.display = "none";
7264 dom.style.visibility = "hidden";
7266 Roo.get(dom).setOpacity(1);
7274 * Returns true if display is not "none"
7277 isDisplayed : function() {
7278 return this.getStyle("display") != "none";
7282 * Toggles the element's visibility or display, depending on visibility mode.
7283 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7284 * @return {Roo.Element} this
7286 toggle : function(animate){
7287 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7292 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7293 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7294 * @return {Roo.Element} this
7296 setDisplayed : function(value) {
7297 if(typeof value == "boolean"){
7298 value = value ? this.originalDisplay : "none";
7300 this.setStyle("display", value);
7305 * Tries to focus the element. Any exceptions are caught and ignored.
7306 * @return {Roo.Element} this
7308 focus : function() {
7316 * Tries to blur the element. Any exceptions are caught and ignored.
7317 * @return {Roo.Element} this
7327 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7328 * @param {String/Array} className The CSS class to add, or an array of classes
7329 * @return {Roo.Element} this
7331 addClass : function(className){
7332 if(className instanceof Array){
7333 for(var i = 0, len = className.length; i < len; i++) {
7334 this.addClass(className[i]);
7337 if(className && !this.hasClass(className)){
7338 this.dom.className = this.dom.className + " " + className;
7345 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7346 * @param {String/Array} className The CSS class to add, or an array of classes
7347 * @return {Roo.Element} this
7349 radioClass : function(className){
7350 var siblings = this.dom.parentNode.childNodes;
7351 for(var i = 0; i < siblings.length; i++) {
7352 var s = siblings[i];
7353 if(s.nodeType == 1){
7354 Roo.get(s).removeClass(className);
7357 this.addClass(className);
7362 * Removes one or more CSS classes from the element.
7363 * @param {String/Array} className The CSS class to remove, or an array of classes
7364 * @return {Roo.Element} this
7366 removeClass : function(className){
7367 if(!className || !this.dom.className){
7370 if(className instanceof Array){
7371 for(var i = 0, len = className.length; i < len; i++) {
7372 this.removeClass(className[i]);
7375 if(this.hasClass(className)){
7376 var re = this.classReCache[className];
7378 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7379 this.classReCache[className] = re;
7381 this.dom.className =
7382 this.dom.className.replace(re, " ");
7392 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7393 * @param {String} className The CSS class to toggle
7394 * @return {Roo.Element} this
7396 toggleClass : function(className){
7397 if(this.hasClass(className)){
7398 this.removeClass(className);
7400 this.addClass(className);
7406 * Checks if the specified CSS class exists on this element's DOM node.
7407 * @param {String} className The CSS class to check for
7408 * @return {Boolean} True if the class exists, else false
7410 hasClass : function(className){
7411 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7415 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7416 * @param {String} oldClassName The CSS class to replace
7417 * @param {String} newClassName The replacement CSS class
7418 * @return {Roo.Element} this
7420 replaceClass : function(oldClassName, newClassName){
7421 this.removeClass(oldClassName);
7422 this.addClass(newClassName);
7427 * Returns an object with properties matching the styles requested.
7428 * For example, el.getStyles('color', 'font-size', 'width') might return
7429 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7430 * @param {String} style1 A style name
7431 * @param {String} style2 A style name
7432 * @param {String} etc.
7433 * @return {Object} The style object
7435 getStyles : function(){
7436 var a = arguments, len = a.length, r = {};
7437 for(var i = 0; i < len; i++){
7438 r[a[i]] = this.getStyle(a[i]);
7444 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7445 * @param {String} property The style property whose value is returned.
7446 * @return {String} The current value of the style property for this element.
7448 getStyle : function(){
7449 return view && view.getComputedStyle ?
7451 var el = this.dom, v, cs, camel;
7452 if(prop == 'float'){
7455 if(el.style && (v = el.style[prop])){
7458 if(cs = view.getComputedStyle(el, "")){
7459 if(!(camel = propCache[prop])){
7460 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7467 var el = this.dom, v, cs, camel;
7468 if(prop == 'opacity'){
7469 if(typeof el.style.filter == 'string'){
7470 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7472 var fv = parseFloat(m[1]);
7474 return fv ? fv / 100 : 0;
7479 }else if(prop == 'float'){
7480 prop = "styleFloat";
7482 if(!(camel = propCache[prop])){
7483 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7485 if(v = el.style[camel]){
7488 if(cs = el.currentStyle){
7496 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7497 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7498 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7499 * @return {Roo.Element} this
7501 setStyle : function(prop, value){
7502 if(typeof prop == "string"){
7504 if (prop == 'float') {
7505 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7510 if(!(camel = propCache[prop])){
7511 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7514 if(camel == 'opacity') {
7515 this.setOpacity(value);
7517 this.dom.style[camel] = value;
7520 for(var style in prop){
7521 if(typeof prop[style] != "function"){
7522 this.setStyle(style, prop[style]);
7530 * More flexible version of {@link #setStyle} for setting style properties.
7531 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7532 * a function which returns such a specification.
7533 * @return {Roo.Element} this
7535 applyStyles : function(style){
7536 Roo.DomHelper.applyStyles(this.dom, style);
7541 * 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).
7542 * @return {Number} The X position of the element
7545 return D.getX(this.dom);
7549 * 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).
7550 * @return {Number} The Y position of the element
7553 return D.getY(this.dom);
7557 * 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).
7558 * @return {Array} The XY position of the element
7561 return D.getXY(this.dom);
7565 * 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).
7566 * @param {Number} The X position of the element
7567 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7568 * @return {Roo.Element} this
7570 setX : function(x, animate){
7572 D.setX(this.dom, x);
7574 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7580 * 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).
7581 * @param {Number} The Y position of the element
7582 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7583 * @return {Roo.Element} this
7585 setY : function(y, animate){
7587 D.setY(this.dom, y);
7589 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7595 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7596 * @param {String} left The left CSS property value
7597 * @return {Roo.Element} this
7599 setLeft : function(left){
7600 this.setStyle("left", this.addUnits(left));
7605 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7606 * @param {String} top The top CSS property value
7607 * @return {Roo.Element} this
7609 setTop : function(top){
7610 this.setStyle("top", this.addUnits(top));
7615 * Sets the element's CSS right style.
7616 * @param {String} right The right CSS property value
7617 * @return {Roo.Element} this
7619 setRight : function(right){
7620 this.setStyle("right", this.addUnits(right));
7625 * Sets the element's CSS bottom style.
7626 * @param {String} bottom The bottom CSS property value
7627 * @return {Roo.Element} this
7629 setBottom : function(bottom){
7630 this.setStyle("bottom", this.addUnits(bottom));
7635 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7636 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7637 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7638 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7639 * @return {Roo.Element} this
7641 setXY : function(pos, animate){
7643 D.setXY(this.dom, pos);
7645 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7651 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7652 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7653 * @param {Number} x X value for new position (coordinates are page-based)
7654 * @param {Number} y Y value for new position (coordinates are page-based)
7655 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7656 * @return {Roo.Element} this
7658 setLocation : function(x, y, animate){
7659 this.setXY([x, y], this.preanim(arguments, 2));
7664 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7665 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7666 * @param {Number} x X value for new position (coordinates are page-based)
7667 * @param {Number} y Y value for new position (coordinates are page-based)
7668 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7669 * @return {Roo.Element} this
7671 moveTo : function(x, y, animate){
7672 this.setXY([x, y], this.preanim(arguments, 2));
7677 * Returns the region of the given element.
7678 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7679 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7681 getRegion : function(){
7682 return D.getRegion(this.dom);
7686 * Returns the offset height of the element
7687 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7688 * @return {Number} The element's height
7690 getHeight : function(contentHeight){
7691 var h = this.dom.offsetHeight || 0;
7692 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7696 * Returns the offset width of the element
7697 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7698 * @return {Number} The element's width
7700 getWidth : function(contentWidth){
7701 var w = this.dom.offsetWidth || 0;
7702 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7706 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7707 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7708 * if a height has not been set using CSS.
7711 getComputedHeight : function(){
7712 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7714 h = parseInt(this.getStyle('height'), 10) || 0;
7715 if(!this.isBorderBox()){
7716 h += this.getFrameWidth('tb');
7723 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7724 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7725 * if a width has not been set using CSS.
7728 getComputedWidth : function(){
7729 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7731 w = parseInt(this.getStyle('width'), 10) || 0;
7732 if(!this.isBorderBox()){
7733 w += this.getFrameWidth('lr');
7740 * Returns the size of the element.
7741 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7742 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7744 getSize : function(contentSize){
7745 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7749 * Returns the width and height of the viewport.
7750 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7752 getViewSize : function(){
7753 var d = this.dom, doc = document, aw = 0, ah = 0;
7754 if(d == doc || d == doc.body){
7755 return {width : D.getViewWidth(), height: D.getViewHeight()};
7758 width : d.clientWidth,
7759 height: d.clientHeight
7765 * Returns the value of the "value" attribute
7766 * @param {Boolean} asNumber true to parse the value as a number
7767 * @return {String/Number}
7769 getValue : function(asNumber){
7770 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7774 adjustWidth : function(width){
7775 if(typeof width == "number"){
7776 if(this.autoBoxAdjust && !this.isBorderBox()){
7777 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7787 adjustHeight : function(height){
7788 if(typeof height == "number"){
7789 if(this.autoBoxAdjust && !this.isBorderBox()){
7790 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7800 * Set the width of the element
7801 * @param {Number} width The new width
7802 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7803 * @return {Roo.Element} this
7805 setWidth : function(width, animate){
7806 width = this.adjustWidth(width);
7808 this.dom.style.width = this.addUnits(width);
7810 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7816 * Set the height of the element
7817 * @param {Number} height The new height
7818 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7819 * @return {Roo.Element} this
7821 setHeight : function(height, animate){
7822 height = this.adjustHeight(height);
7824 this.dom.style.height = this.addUnits(height);
7826 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7832 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7833 * @param {Number} width The new width
7834 * @param {Number} height The new height
7835 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7836 * @return {Roo.Element} this
7838 setSize : function(width, height, animate){
7839 if(typeof width == "object"){ // in case of object from getSize()
7840 height = width.height; width = width.width;
7842 width = this.adjustWidth(width); height = this.adjustHeight(height);
7844 this.dom.style.width = this.addUnits(width);
7845 this.dom.style.height = this.addUnits(height);
7847 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7853 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7854 * @param {Number} x X value for new position (coordinates are page-based)
7855 * @param {Number} y Y value for new position (coordinates are page-based)
7856 * @param {Number} width The new width
7857 * @param {Number} height The new height
7858 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7859 * @return {Roo.Element} this
7861 setBounds : function(x, y, width, height, animate){
7863 this.setSize(width, height);
7864 this.setLocation(x, y);
7866 width = this.adjustWidth(width); height = this.adjustHeight(height);
7867 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7868 this.preanim(arguments, 4), 'motion');
7874 * 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.
7875 * @param {Roo.lib.Region} region The region to fill
7876 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7877 * @return {Roo.Element} this
7879 setRegion : function(region, animate){
7880 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7885 * Appends an event handler
7887 * @param {String} eventName The type of event to append
7888 * @param {Function} fn The method the event invokes
7889 * @param {Object} scope (optional) The scope (this object) of the fn
7890 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7892 addListener : function(eventName, fn, scope, options){
7894 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7899 * Removes an event handler from this element
7900 * @param {String} eventName the type of event to remove
7901 * @param {Function} fn the method the event invokes
7902 * @return {Roo.Element} this
7904 removeListener : function(eventName, fn){
7905 Roo.EventManager.removeListener(this.dom, eventName, fn);
7910 * Removes all previous added listeners from this element
7911 * @return {Roo.Element} this
7913 removeAllListeners : function(){
7914 E.purgeElement(this.dom);
7918 relayEvent : function(eventName, observable){
7919 this.on(eventName, function(e){
7920 observable.fireEvent(eventName, e);
7925 * Set the opacity of the element
7926 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7927 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7928 * @return {Roo.Element} this
7930 setOpacity : function(opacity, animate){
7932 var s = this.dom.style;
7935 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7936 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7938 s.opacity = opacity;
7941 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7947 * Gets the left X coordinate
7948 * @param {Boolean} local True to get the local css position instead of page coordinate
7951 getLeft : function(local){
7955 return parseInt(this.getStyle("left"), 10) || 0;
7960 * Gets the right X coordinate of the element (element X position + element width)
7961 * @param {Boolean} local True to get the local css position instead of page coordinate
7964 getRight : function(local){
7966 return this.getX() + this.getWidth();
7968 return (this.getLeft(true) + this.getWidth()) || 0;
7973 * Gets the top Y coordinate
7974 * @param {Boolean} local True to get the local css position instead of page coordinate
7977 getTop : function(local) {
7981 return parseInt(this.getStyle("top"), 10) || 0;
7986 * Gets the bottom Y coordinate of the element (element Y position + element height)
7987 * @param {Boolean} local True to get the local css position instead of page coordinate
7990 getBottom : function(local){
7992 return this.getY() + this.getHeight();
7994 return (this.getTop(true) + this.getHeight()) || 0;
7999 * Initializes positioning on this element. If a desired position is not passed, it will make the
8000 * the element positioned relative IF it is not already positioned.
8001 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8002 * @param {Number} zIndex (optional) The zIndex to apply
8003 * @param {Number} x (optional) Set the page X position
8004 * @param {Number} y (optional) Set the page Y position
8006 position : function(pos, zIndex, x, y){
8008 if(this.getStyle('position') == 'static'){
8009 this.setStyle('position', 'relative');
8012 this.setStyle("position", pos);
8015 this.setStyle("z-index", zIndex);
8017 if(x !== undefined && y !== undefined){
8019 }else if(x !== undefined){
8021 }else if(y !== undefined){
8027 * Clear positioning back to the default when the document was loaded
8028 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8029 * @return {Roo.Element} this
8031 clearPositioning : function(value){
8039 "position" : "static"
8045 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8046 * snapshot before performing an update and then restoring the element.
8049 getPositioning : function(){
8050 var l = this.getStyle("left");
8051 var t = this.getStyle("top");
8053 "position" : this.getStyle("position"),
8055 "right" : l ? "" : this.getStyle("right"),
8057 "bottom" : t ? "" : this.getStyle("bottom"),
8058 "z-index" : this.getStyle("z-index")
8063 * Gets the width of the border(s) for the specified side(s)
8064 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8065 * passing lr would get the border (l)eft width + the border (r)ight width.
8066 * @return {Number} The width of the sides passed added together
8068 getBorderWidth : function(side){
8069 return this.addStyles(side, El.borders);
8073 * Gets the width of the padding(s) for the specified side(s)
8074 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8075 * passing lr would get the padding (l)eft + the padding (r)ight.
8076 * @return {Number} The padding of the sides passed added together
8078 getPadding : function(side){
8079 return this.addStyles(side, El.paddings);
8083 * Set positioning with an object returned by getPositioning().
8084 * @param {Object} posCfg
8085 * @return {Roo.Element} this
8087 setPositioning : function(pc){
8088 this.applyStyles(pc);
8089 if(pc.right == "auto"){
8090 this.dom.style.right = "";
8092 if(pc.bottom == "auto"){
8093 this.dom.style.bottom = "";
8099 fixDisplay : function(){
8100 if(this.getStyle("display") == "none"){
8101 this.setStyle("visibility", "hidden");
8102 this.setStyle("display", this.originalDisplay); // first try reverting to default
8103 if(this.getStyle("display") == "none"){ // if that fails, default to block
8104 this.setStyle("display", "block");
8110 * Quick set left and top adding default units
8111 * @param {String} left The left CSS property value
8112 * @param {String} top The top CSS property value
8113 * @return {Roo.Element} this
8115 setLeftTop : function(left, top){
8116 this.dom.style.left = this.addUnits(left);
8117 this.dom.style.top = this.addUnits(top);
8122 * Move this element relative to its current position.
8123 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8124 * @param {Number} distance How far to move the element in pixels
8125 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8126 * @return {Roo.Element} this
8128 move : function(direction, distance, animate){
8129 var xy = this.getXY();
8130 direction = direction.toLowerCase();
8134 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8138 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8143 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8148 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8155 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8156 * @return {Roo.Element} this
8159 if(!this.isClipped){
8160 this.isClipped = true;
8161 this.originalClip = {
8162 "o": this.getStyle("overflow"),
8163 "x": this.getStyle("overflow-x"),
8164 "y": this.getStyle("overflow-y")
8166 this.setStyle("overflow", "hidden");
8167 this.setStyle("overflow-x", "hidden");
8168 this.setStyle("overflow-y", "hidden");
8174 * Return clipping (overflow) to original clipping before clip() was called
8175 * @return {Roo.Element} this
8177 unclip : function(){
8179 this.isClipped = false;
8180 var o = this.originalClip;
8181 if(o.o){this.setStyle("overflow", o.o);}
8182 if(o.x){this.setStyle("overflow-x", o.x);}
8183 if(o.y){this.setStyle("overflow-y", o.y);}
8190 * Gets the x,y coordinates specified by the anchor position on the element.
8191 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8192 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8193 * {width: (target width), height: (target height)} (defaults to the element's current size)
8194 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8195 * @return {Array} [x, y] An array containing the element's x and y coordinates
8197 getAnchorXY : function(anchor, local, s){
8198 //Passing a different size is useful for pre-calculating anchors,
8199 //especially for anchored animations that change the el size.
8201 var w, h, vp = false;
8204 if(d == document.body || d == document){
8206 w = D.getViewWidth(); h = D.getViewHeight();
8208 w = this.getWidth(); h = this.getHeight();
8211 w = s.width; h = s.height;
8213 var x = 0, y = 0, r = Math.round;
8214 switch((anchor || "tl").toLowerCase()){
8256 var sc = this.getScroll();
8257 return [x + sc.left, y + sc.top];
8259 //Add the element's offset xy
8260 var o = this.getXY();
8261 return [x+o[0], y+o[1]];
8265 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8266 * supported position values.
8267 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8268 * @param {String} position The position to align to.
8269 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8270 * @return {Array} [x, y]
8272 getAlignToXY : function(el, p, o){
8276 throw "Element.alignTo with an element that doesn't exist";
8278 var c = false; //constrain to viewport
8279 var p1 = "", p2 = "";
8286 }else if(p.indexOf("-") == -1){
8289 p = p.toLowerCase();
8290 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8292 throw "Element.alignTo with an invalid alignment " + p;
8294 p1 = m[1]; p2 = m[2]; c = !!m[3];
8296 //Subtract the aligned el's internal xy from the target's offset xy
8297 //plus custom offset to get the aligned el's new offset xy
8298 var a1 = this.getAnchorXY(p1, true);
8299 var a2 = el.getAnchorXY(p2, false);
8300 var x = a2[0] - a1[0] + o[0];
8301 var y = a2[1] - a1[1] + o[1];
8303 //constrain the aligned el to viewport if necessary
8304 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8305 // 5px of margin for ie
8306 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8308 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8309 //perpendicular to the vp border, allow the aligned el to slide on that border,
8310 //otherwise swap the aligned el to the opposite border of the target.
8311 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8312 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8313 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8314 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8317 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8318 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8320 if((x+w) > dw + scrollX){
8321 x = swapX ? r.left-w : dw+scrollX-w;
8324 x = swapX ? r.right : scrollX;
8326 if((y+h) > dh + scrollY){
8327 y = swapY ? r.top-h : dh+scrollY-h;
8330 y = swapY ? r.bottom : scrollY;
8337 getConstrainToXY : function(){
8338 var os = {top:0, left:0, bottom:0, right: 0};
8340 return function(el, local, offsets, proposedXY){
8342 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8344 var vw, vh, vx = 0, vy = 0;
8345 if(el.dom == document.body || el.dom == document){
8346 vw = Roo.lib.Dom.getViewWidth();
8347 vh = Roo.lib.Dom.getViewHeight();
8349 vw = el.dom.clientWidth;
8350 vh = el.dom.clientHeight;
8352 var vxy = el.getXY();
8358 var s = el.getScroll();
8360 vx += offsets.left + s.left;
8361 vy += offsets.top + s.top;
8363 vw -= offsets.right;
8364 vh -= offsets.bottom;
8369 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8370 var x = xy[0], y = xy[1];
8371 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8373 // only move it if it needs it
8376 // first validate right/bottom
8385 // then make sure top/left isn't negative
8394 return moved ? [x, y] : false;
8399 adjustForConstraints : function(xy, parent, offsets){
8400 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8404 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8405 * document it aligns it to the viewport.
8406 * The position parameter is optional, and can be specified in any one of the following formats:
8408 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8409 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8410 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8411 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8412 * <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
8413 * element's anchor point, and the second value is used as the target's anchor point.</li>
8415 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8416 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8417 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8418 * that specified in order to enforce the viewport constraints.
8419 * Following are all of the supported anchor positions:
8422 ----- -----------------------------
8423 tl The top left corner (default)
8424 t The center of the top edge
8425 tr The top right corner
8426 l The center of the left edge
8427 c In the center of the element
8428 r The center of the right edge
8429 bl The bottom left corner
8430 b The center of the bottom edge
8431 br The bottom right corner
8435 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8436 el.alignTo("other-el");
8438 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8439 el.alignTo("other-el", "tr?");
8441 // align the bottom right corner of el with the center left edge of other-el
8442 el.alignTo("other-el", "br-l?");
8444 // align the center of el with the bottom left corner of other-el and
8445 // adjust the x position by -6 pixels (and the y position by 0)
8446 el.alignTo("other-el", "c-bl", [-6, 0]);
8448 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8449 * @param {String} position The position to align to.
8450 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8451 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8452 * @return {Roo.Element} this
8454 alignTo : function(element, position, offsets, animate){
8455 var xy = this.getAlignToXY(element, position, offsets);
8456 this.setXY(xy, this.preanim(arguments, 3));
8461 * Anchors an element to another element and realigns it when the window is resized.
8462 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8463 * @param {String} position The position to align to.
8464 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8465 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8466 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8467 * is a number, it is used as the buffer delay (defaults to 50ms).
8468 * @param {Function} callback The function to call after the animation finishes
8469 * @return {Roo.Element} this
8471 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8472 var action = function(){
8473 this.alignTo(el, alignment, offsets, animate);
8474 Roo.callback(callback, this);
8476 Roo.EventManager.onWindowResize(action, this);
8477 var tm = typeof monitorScroll;
8478 if(tm != 'undefined'){
8479 Roo.EventManager.on(window, 'scroll', action, this,
8480 {buffer: tm == 'number' ? monitorScroll : 50});
8482 action.call(this); // align immediately
8486 * Clears any opacity settings from this element. Required in some cases for IE.
8487 * @return {Roo.Element} this
8489 clearOpacity : function(){
8490 if (window.ActiveXObject) {
8491 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8492 this.dom.style.filter = "";
8495 this.dom.style.opacity = "";
8496 this.dom.style["-moz-opacity"] = "";
8497 this.dom.style["-khtml-opacity"] = "";
8503 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8504 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8505 * @return {Roo.Element} this
8507 hide : function(animate){
8508 this.setVisible(false, this.preanim(arguments, 0));
8513 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8514 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8515 * @return {Roo.Element} this
8517 show : function(animate){
8518 this.setVisible(true, this.preanim(arguments, 0));
8523 * @private Test if size has a unit, otherwise appends the default
8525 addUnits : function(size){
8526 return Roo.Element.addUnits(size, this.defaultUnit);
8530 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8531 * @return {Roo.Element} this
8533 beginMeasure : function(){
8535 if(el.offsetWidth || el.offsetHeight){
8536 return this; // offsets work already
8539 var p = this.dom, b = document.body; // start with this element
8540 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8541 var pe = Roo.get(p);
8542 if(pe.getStyle('display') == 'none'){
8543 changed.push({el: p, visibility: pe.getStyle("visibility")});
8544 p.style.visibility = "hidden";
8545 p.style.display = "block";
8549 this._measureChanged = changed;
8555 * Restores displays to before beginMeasure was called
8556 * @return {Roo.Element} this
8558 endMeasure : function(){
8559 var changed = this._measureChanged;
8561 for(var i = 0, len = changed.length; i < len; i++) {
8563 r.el.style.visibility = r.visibility;
8564 r.el.style.display = "none";
8566 this._measureChanged = null;
8572 * Update the innerHTML of this element, optionally searching for and processing scripts
8573 * @param {String} html The new HTML
8574 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8575 * @param {Function} callback For async script loading you can be noticed when the update completes
8576 * @return {Roo.Element} this
8578 update : function(html, loadScripts, callback){
8579 if(typeof html == "undefined"){
8582 if(loadScripts !== true){
8583 this.dom.innerHTML = html;
8584 if(typeof callback == "function"){
8592 html += '<span id="' + id + '"></span>';
8594 E.onAvailable(id, function(){
8595 var hd = document.getElementsByTagName("head")[0];
8596 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8597 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8598 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8601 while(match = re.exec(html)){
8602 var attrs = match[1];
8603 var srcMatch = attrs ? attrs.match(srcRe) : false;
8604 if(srcMatch && srcMatch[2]){
8605 var s = document.createElement("script");
8606 s.src = srcMatch[2];
8607 var typeMatch = attrs.match(typeRe);
8608 if(typeMatch && typeMatch[2]){
8609 s.type = typeMatch[2];
8612 }else if(match[2] && match[2].length > 0){
8613 if(window.execScript) {
8614 window.execScript(match[2]);
8622 window.eval(match[2]);
8626 var el = document.getElementById(id);
8627 if(el){el.parentNode.removeChild(el);}
8628 if(typeof callback == "function"){
8632 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8637 * Direct access to the UpdateManager update() method (takes the same parameters).
8638 * @param {String/Function} url The url for this request or a function to call to get the url
8639 * @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}
8640 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8641 * @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.
8642 * @return {Roo.Element} this
8645 var um = this.getUpdateManager();
8646 um.update.apply(um, arguments);
8651 * Gets this element's UpdateManager
8652 * @return {Roo.UpdateManager} The UpdateManager
8654 getUpdateManager : function(){
8655 if(!this.updateManager){
8656 this.updateManager = new Roo.UpdateManager(this);
8658 return this.updateManager;
8662 * Disables text selection for this element (normalized across browsers)
8663 * @return {Roo.Element} this
8665 unselectable : function(){
8666 this.dom.unselectable = "on";
8667 this.swallowEvent("selectstart", true);
8668 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8669 this.addClass("x-unselectable");
8674 * Calculates the x, y to center this element on the screen
8675 * @return {Array} The x, y values [x, y]
8677 getCenterXY : function(){
8678 return this.getAlignToXY(document, 'c-c');
8682 * Centers the Element in either the viewport, or another Element.
8683 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8685 center : function(centerIn){
8686 this.alignTo(centerIn || document, 'c-c');
8691 * Tests various css rules/browsers to determine if this element uses a border box
8694 isBorderBox : function(){
8695 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8699 * Return a box {x, y, width, height} that can be used to set another elements
8700 * size/location to match this element.
8701 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8702 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8703 * @return {Object} box An object in the format {x, y, width, height}
8705 getBox : function(contentBox, local){
8710 var left = parseInt(this.getStyle("left"), 10) || 0;
8711 var top = parseInt(this.getStyle("top"), 10) || 0;
8714 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8716 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8718 var l = this.getBorderWidth("l")+this.getPadding("l");
8719 var r = this.getBorderWidth("r")+this.getPadding("r");
8720 var t = this.getBorderWidth("t")+this.getPadding("t");
8721 var b = this.getBorderWidth("b")+this.getPadding("b");
8722 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)};
8724 bx.right = bx.x + bx.width;
8725 bx.bottom = bx.y + bx.height;
8730 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8731 for more information about the sides.
8732 * @param {String} sides
8735 getFrameWidth : function(sides, onlyContentBox){
8736 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8740 * 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.
8741 * @param {Object} box The box to fill {x, y, width, height}
8742 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8743 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8744 * @return {Roo.Element} this
8746 setBox : function(box, adjust, animate){
8747 var w = box.width, h = box.height;
8748 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8749 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8750 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8752 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8757 * Forces the browser to repaint this element
8758 * @return {Roo.Element} this
8760 repaint : function(){
8762 this.addClass("x-repaint");
8763 setTimeout(function(){
8764 Roo.get(dom).removeClass("x-repaint");
8770 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8771 * then it returns the calculated width of the sides (see getPadding)
8772 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8773 * @return {Object/Number}
8775 getMargins : function(side){
8778 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8779 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8780 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8781 right: parseInt(this.getStyle("margin-right"), 10) || 0
8784 return this.addStyles(side, El.margins);
8789 addStyles : function(sides, styles){
8791 for(var i = 0, len = sides.length; i < len; i++){
8792 v = this.getStyle(styles[sides.charAt(i)]);
8794 w = parseInt(v, 10);
8802 * Creates a proxy element of this element
8803 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8804 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8805 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8806 * @return {Roo.Element} The new proxy element
8808 createProxy : function(config, renderTo, matchBox){
8810 renderTo = Roo.getDom(renderTo);
8812 renderTo = document.body;
8814 config = typeof config == "object" ?
8815 config : {tag : "div", cls: config};
8816 var proxy = Roo.DomHelper.append(renderTo, config, true);
8818 proxy.setBox(this.getBox());
8824 * Puts a mask over this element to disable user interaction. Requires core.css.
8825 * This method can only be applied to elements which accept child nodes.
8826 * @param {String} msg (optional) A message to display in the mask
8827 * @param {String} msgCls (optional) A css class to apply to the msg element
8828 * @return {Element} The mask element
8830 mask : function(msg, msgCls){
8831 if(this.getStyle("position") == "static"){
8832 this.setStyle("position", "relative");
8835 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8837 this.addClass("x-masked");
8838 this._mask.setDisplayed(true);
8839 if(typeof msg == 'string'){
8841 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8843 var mm = this._maskMsg;
8844 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8845 mm.dom.firstChild.innerHTML = msg;
8846 mm.setDisplayed(true);
8849 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8850 this._mask.setHeight(this.getHeight());
8856 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8857 * it is cached for reuse.
8859 unmask : function(removeEl){
8861 if(removeEl === true){
8862 this._mask.remove();
8865 this._maskMsg.remove();
8866 delete this._maskMsg;
8869 this._mask.setDisplayed(false);
8871 this._maskMsg.setDisplayed(false);
8875 this.removeClass("x-masked");
8879 * Returns true if this element is masked
8882 isMasked : function(){
8883 return this._mask && this._mask.isVisible();
8887 * Creates an iframe shim for this element to keep selects and other windowed objects from
8889 * @return {Roo.Element} The new shim element
8891 createShim : function(){
8892 var el = document.createElement('iframe');
8893 el.frameBorder = 'no';
8894 el.className = 'roo-shim';
8895 if(Roo.isIE && Roo.isSecure){
8896 el.src = Roo.SSL_SECURE_URL;
8898 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8899 shim.autoBoxAdjust = false;
8904 * Removes this element from the DOM and deletes it from the cache
8906 remove : function(){
8907 if(this.dom.parentNode){
8908 this.dom.parentNode.removeChild(this.dom);
8910 delete El.cache[this.dom.id];
8914 * Sets up event handlers to add and remove a css class when the mouse is over this element
8915 * @param {String} className
8916 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8917 * mouseout events for children elements
8918 * @return {Roo.Element} this
8920 addClassOnOver : function(className, preventFlicker){
8921 this.on("mouseover", function(){
8922 Roo.fly(this, '_internal').addClass(className);
8924 var removeFn = function(e){
8925 if(preventFlicker !== true || !e.within(this, true)){
8926 Roo.fly(this, '_internal').removeClass(className);
8929 this.on("mouseout", removeFn, this.dom);
8934 * Sets up event handlers to add and remove a css class when this element has the focus
8935 * @param {String} className
8936 * @return {Roo.Element} this
8938 addClassOnFocus : function(className){
8939 this.on("focus", function(){
8940 Roo.fly(this, '_internal').addClass(className);
8942 this.on("blur", function(){
8943 Roo.fly(this, '_internal').removeClass(className);
8948 * 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)
8949 * @param {String} className
8950 * @return {Roo.Element} this
8952 addClassOnClick : function(className){
8954 this.on("mousedown", function(){
8955 Roo.fly(dom, '_internal').addClass(className);
8956 var d = Roo.get(document);
8957 var fn = function(){
8958 Roo.fly(dom, '_internal').removeClass(className);
8959 d.removeListener("mouseup", fn);
8961 d.on("mouseup", fn);
8967 * Stops the specified event from bubbling and optionally prevents the default action
8968 * @param {String} eventName
8969 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8970 * @return {Roo.Element} this
8972 swallowEvent : function(eventName, preventDefault){
8973 var fn = function(e){
8974 e.stopPropagation();
8979 if(eventName instanceof Array){
8980 for(var i = 0, len = eventName.length; i < len; i++){
8981 this.on(eventName[i], fn);
8985 this.on(eventName, fn);
8992 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8995 * Sizes this element to its parent element's dimensions performing
8996 * neccessary box adjustments.
8997 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8998 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8999 * @return {Roo.Element} this
9001 fitToParent : function(monitorResize, targetParent) {
9002 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9003 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9004 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9007 var p = Roo.get(targetParent || this.dom.parentNode);
9008 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9009 if (monitorResize === true) {
9010 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9011 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9017 * Gets the next sibling, skipping text nodes
9018 * @return {HTMLElement} The next sibling or null
9020 getNextSibling : function(){
9021 var n = this.dom.nextSibling;
9022 while(n && n.nodeType != 1){
9029 * Gets the previous sibling, skipping text nodes
9030 * @return {HTMLElement} The previous sibling or null
9032 getPrevSibling : function(){
9033 var n = this.dom.previousSibling;
9034 while(n && n.nodeType != 1){
9035 n = n.previousSibling;
9042 * Appends the passed element(s) to this element
9043 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9044 * @return {Roo.Element} this
9046 appendChild: function(el){
9053 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9054 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9055 * automatically generated with the specified attributes.
9056 * @param {HTMLElement} insertBefore (optional) a child element of this element
9057 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9058 * @return {Roo.Element} The new child element
9060 createChild: function(config, insertBefore, returnDom){
9061 config = config || {tag:'div'};
9063 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9065 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9069 * Appends this element to the passed element
9070 * @param {String/HTMLElement/Element} el The new parent element
9071 * @return {Roo.Element} this
9073 appendTo: function(el){
9074 el = Roo.getDom(el);
9075 el.appendChild(this.dom);
9080 * Inserts this element before the passed element in the DOM
9081 * @param {String/HTMLElement/Element} el The element to insert before
9082 * @return {Roo.Element} this
9084 insertBefore: function(el){
9085 el = Roo.getDom(el);
9086 el.parentNode.insertBefore(this.dom, el);
9091 * Inserts this element after the passed element in the DOM
9092 * @param {String/HTMLElement/Element} el The element to insert after
9093 * @return {Roo.Element} this
9095 insertAfter: function(el){
9096 el = Roo.getDom(el);
9097 el.parentNode.insertBefore(this.dom, el.nextSibling);
9102 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9103 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9104 * @return {Roo.Element} The new child
9106 insertFirst: function(el, returnDom){
9108 if(typeof el == 'object' && !el.nodeType){ // dh config
9109 return this.createChild(el, this.dom.firstChild, returnDom);
9111 el = Roo.getDom(el);
9112 this.dom.insertBefore(el, this.dom.firstChild);
9113 return !returnDom ? Roo.get(el) : el;
9118 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9119 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9120 * @param {String} where (optional) 'before' or 'after' defaults to before
9121 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9122 * @return {Roo.Element} the inserted Element
9124 insertSibling: function(el, where, returnDom){
9125 where = where ? where.toLowerCase() : 'before';
9127 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9129 if(typeof el == 'object' && !el.nodeType){ // dh config
9130 if(where == 'after' && !this.dom.nextSibling){
9131 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9133 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9137 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9138 where == 'before' ? this.dom : this.dom.nextSibling);
9147 * Creates and wraps this element with another element
9148 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9149 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9150 * @return {HTMLElement/Element} The newly created wrapper element
9152 wrap: function(config, returnDom){
9154 config = {tag: "div"};
9156 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9157 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9162 * Replaces the passed element with this element
9163 * @param {String/HTMLElement/Element} el The element to replace
9164 * @return {Roo.Element} this
9166 replace: function(el){
9168 this.insertBefore(el);
9174 * Inserts an html fragment into this element
9175 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9176 * @param {String} html The HTML fragment
9177 * @param {Boolean} returnEl True to return an Roo.Element
9178 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9180 insertHtml : function(where, html, returnEl){
9181 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9182 return returnEl ? Roo.get(el) : el;
9186 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9187 * @param {Object} o The object with the attributes
9188 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9189 * @return {Roo.Element} this
9191 set : function(o, useSet){
9193 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9195 if(attr == "style" || typeof o[attr] == "function") continue;
9197 el.className = o["cls"];
9199 if(useSet) el.setAttribute(attr, o[attr]);
9200 else el[attr] = o[attr];
9204 Roo.DomHelper.applyStyles(el, o.style);
9210 * Convenience method for constructing a KeyMap
9211 * @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:
9212 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9213 * @param {Function} fn The function to call
9214 * @param {Object} scope (optional) The scope of the function
9215 * @return {Roo.KeyMap} The KeyMap created
9217 addKeyListener : function(key, fn, scope){
9219 if(typeof key != "object" || key instanceof Array){
9235 return new Roo.KeyMap(this, config);
9239 * Creates a KeyMap for this element
9240 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9241 * @return {Roo.KeyMap} The KeyMap created
9243 addKeyMap : function(config){
9244 return new Roo.KeyMap(this, config);
9248 * Returns true if this element is scrollable.
9251 isScrollable : function(){
9253 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9257 * 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().
9258 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9259 * @param {Number} value The new scroll value
9260 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9261 * @return {Element} this
9264 scrollTo : function(side, value, animate){
9265 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9267 this.dom[prop] = value;
9269 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9270 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9276 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9277 * within this element's scrollable range.
9278 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9279 * @param {Number} distance How far to scroll the element in pixels
9280 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9281 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9282 * was scrolled as far as it could go.
9284 scroll : function(direction, distance, animate){
9285 if(!this.isScrollable()){
9289 var l = el.scrollLeft, t = el.scrollTop;
9290 var w = el.scrollWidth, h = el.scrollHeight;
9291 var cw = el.clientWidth, ch = el.clientHeight;
9292 direction = direction.toLowerCase();
9293 var scrolled = false;
9294 var a = this.preanim(arguments, 2);
9299 var v = Math.min(l + distance, w-cw);
9300 this.scrollTo("left", v, a);
9307 var v = Math.max(l - distance, 0);
9308 this.scrollTo("left", v, a);
9316 var v = Math.max(t - distance, 0);
9317 this.scrollTo("top", v, a);
9325 var v = Math.min(t + distance, h-ch);
9326 this.scrollTo("top", v, a);
9335 * Translates the passed page coordinates into left/top css values for this element
9336 * @param {Number/Array} x The page x or an array containing [x, y]
9337 * @param {Number} y The page y
9338 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9340 translatePoints : function(x, y){
9341 if(typeof x == 'object' || x instanceof Array){
9344 var p = this.getStyle('position');
9345 var o = this.getXY();
9347 var l = parseInt(this.getStyle('left'), 10);
9348 var t = parseInt(this.getStyle('top'), 10);
9351 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9354 t = (p == "relative") ? 0 : this.dom.offsetTop;
9357 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9361 * Returns the current scroll position of the element.
9362 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9364 getScroll : function(){
9365 var d = this.dom, doc = document;
9366 if(d == doc || d == doc.body){
9367 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9368 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9369 return {left: l, top: t};
9371 return {left: d.scrollLeft, top: d.scrollTop};
9376 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9377 * are convert to standard 6 digit hex color.
9378 * @param {String} attr The css attribute
9379 * @param {String} defaultValue The default value to use when a valid color isn't found
9380 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9383 getColor : function(attr, defaultValue, prefix){
9384 var v = this.getStyle(attr);
9385 if(!v || v == "transparent" || v == "inherit") {
9386 return defaultValue;
9388 var color = typeof prefix == "undefined" ? "#" : prefix;
9389 if(v.substr(0, 4) == "rgb("){
9390 var rvs = v.slice(4, v.length -1).split(",");
9391 for(var i = 0; i < 3; i++){
9392 var h = parseInt(rvs[i]).toString(16);
9399 if(v.substr(0, 1) == "#"){
9401 for(var i = 1; i < 4; i++){
9402 var c = v.charAt(i);
9405 }else if(v.length == 7){
9406 color += v.substr(1);
9410 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9414 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9415 * gradient background, rounded corners and a 4-way shadow.
9416 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9417 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9418 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9419 * @return {Roo.Element} this
9421 boxWrap : function(cls){
9422 cls = cls || 'x-box';
9423 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9424 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9429 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9430 * @param {String} namespace The namespace in which to look for the attribute
9431 * @param {String} name The attribute name
9432 * @return {String} The attribute value
9434 getAttributeNS : Roo.isIE ? function(ns, name){
9436 var type = typeof d[ns+":"+name];
9437 if(type != 'undefined' && type != 'unknown'){
9438 return d[ns+":"+name];
9441 } : function(ns, name){
9443 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9447 var ep = El.prototype;
9450 * Appends an event handler (Shorthand for addListener)
9451 * @param {String} eventName The type of event to append
9452 * @param {Function} fn The method the event invokes
9453 * @param {Object} scope (optional) The scope (this object) of the fn
9454 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9457 ep.on = ep.addListener;
9459 ep.mon = ep.addListener;
9462 * Removes an event handler from this element (shorthand for removeListener)
9463 * @param {String} eventName the type of event to remove
9464 * @param {Function} fn the method the event invokes
9465 * @return {Roo.Element} this
9468 ep.un = ep.removeListener;
9471 * true to automatically adjust width and height settings for box-model issues (default to true)
9473 ep.autoBoxAdjust = true;
9476 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9479 El.addUnits = function(v, defaultUnit){
9480 if(v === "" || v == "auto"){
9483 if(v === undefined){
9486 if(typeof v == "number" || !El.unitPattern.test(v)){
9487 return v + (defaultUnit || 'px');
9492 // special markup used throughout Roo when box wrapping elements
9493 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>';
9495 * Visibility mode constant - Use visibility to hide element
9501 * Visibility mode constant - Use display to hide element
9507 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9508 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9509 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9521 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9522 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9523 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9524 * @return {Element} The Element object
9527 El.get = function(el){
9529 if(!el){ return null; }
9530 if(typeof el == "string"){ // element id
9531 if(!(elm = document.getElementById(el))){
9534 if(ex = El.cache[el]){
9537 ex = El.cache[el] = new El(elm);
9540 }else if(el.tagName){ // dom element
9544 if(ex = El.cache[id]){
9547 ex = El.cache[id] = new El(el);
9550 }else if(el instanceof El){
9552 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9553 // catch case where it hasn't been appended
9554 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9557 }else if(el.isComposite){
9559 }else if(el instanceof Array){
9560 return El.select(el);
9561 }else if(el == document){
9562 // create a bogus element object representing the document object
9564 var f = function(){};
9565 f.prototype = El.prototype;
9567 docEl.dom = document;
9575 El.uncache = function(el){
9576 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9578 delete El.cache[a[i].id || a[i]];
9584 // Garbage collection - uncache elements/purge listeners on orphaned elements
9585 // so we don't hold a reference and cause the browser to retain them
9586 El.garbageCollect = function(){
9587 if(!Roo.enableGarbageCollector){
9588 clearInterval(El.collectorThread);
9591 for(var eid in El.cache){
9592 var el = El.cache[eid], d = el.dom;
9593 // -------------------------------------------------------
9594 // Determining what is garbage:
9595 // -------------------------------------------------------
9597 // dom node is null, definitely garbage
9598 // -------------------------------------------------------
9600 // no parentNode == direct orphan, definitely garbage
9601 // -------------------------------------------------------
9602 // !d.offsetParent && !document.getElementById(eid)
9603 // display none elements have no offsetParent so we will
9604 // also try to look it up by it's id. However, check
9605 // offsetParent first so we don't do unneeded lookups.
9606 // This enables collection of elements that are not orphans
9607 // directly, but somewhere up the line they have an orphan
9609 // -------------------------------------------------------
9610 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9611 delete El.cache[eid];
9612 if(d && Roo.enableListenerCollection){
9618 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9622 El.Flyweight = function(dom){
9625 El.Flyweight.prototype = El.prototype;
9627 El._flyweights = {};
9629 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9630 * the dom node can be overwritten by other code.
9631 * @param {String/HTMLElement} el The dom node or id
9632 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9633 * prevent conflicts (e.g. internally Roo uses "_internal")
9635 * @return {Element} The shared Element object
9637 El.fly = function(el, named){
9638 named = named || '_global';
9639 el = Roo.getDom(el);
9643 if(!El._flyweights[named]){
9644 El._flyweights[named] = new El.Flyweight();
9646 El._flyweights[named].dom = el;
9647 return El._flyweights[named];
9651 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9652 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9653 * Shorthand of {@link Roo.Element#get}
9654 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9655 * @return {Element} The Element object
9661 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9662 * the dom node can be overwritten by other code.
9663 * Shorthand of {@link Roo.Element#fly}
9664 * @param {String/HTMLElement} el The dom node or id
9665 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9666 * prevent conflicts (e.g. internally Roo uses "_internal")
9668 * @return {Element} The shared Element object
9674 // speedy lookup for elements never to box adjust
9675 var noBoxAdjust = Roo.isStrict ? {
9678 input:1, select:1, textarea:1
9680 if(Roo.isIE || Roo.isGecko){
9681 noBoxAdjust['button'] = 1;
9685 Roo.EventManager.on(window, 'unload', function(){
9687 delete El._flyweights;
9695 Roo.Element.selectorFunction = Roo.DomQuery.select;
9698 Roo.Element.select = function(selector, unique, root){
9700 if(typeof selector == "string"){
9701 els = Roo.Element.selectorFunction(selector, root);
9702 }else if(selector.length !== undefined){
9705 throw "Invalid selector";
9707 if(unique === true){
9708 return new Roo.CompositeElement(els);
9710 return new Roo.CompositeElementLite(els);
9714 * Selects elements based on the passed CSS selector to enable working on them as 1.
9715 * @param {String/Array} selector The CSS selector or an array of elements
9716 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9717 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9718 * @return {CompositeElementLite/CompositeElement}
9722 Roo.select = Roo.Element.select;
9739 * Ext JS Library 1.1.1
9740 * Copyright(c) 2006-2007, Ext JS, LLC.
9742 * Originally Released Under LGPL - original licence link has changed is not relivant.
9745 * <script type="text/javascript">
9750 //Notifies Element that fx methods are available
9751 Roo.enableFx = true;
9755 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9756 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9757 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9758 * Element effects to work.</p><br/>
9760 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9761 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9762 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9763 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9764 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9765 * expected results and should be done with care.</p><br/>
9767 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9768 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9771 ----- -----------------------------
9772 tl The top left corner
9773 t The center of the top edge
9774 tr The top right corner
9775 l The center of the left edge
9776 r The center of the right edge
9777 bl The bottom left corner
9778 b The center of the bottom edge
9779 br The bottom right corner
9781 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9782 * below are common options that can be passed to any Fx method.</b>
9783 * @cfg {Function} callback A function called when the effect is finished
9784 * @cfg {Object} scope The scope of the effect function
9785 * @cfg {String} easing A valid Easing value for the effect
9786 * @cfg {String} afterCls A css class to apply after the effect
9787 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9788 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9789 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9790 * effects that end with the element being visually hidden, ignored otherwise)
9791 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9792 * a function which returns such a specification that will be applied to the Element after the effect finishes
9793 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9794 * @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
9795 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9799 * Slides the element into view. An anchor point can be optionally passed to set the point of
9800 * origin for the slide effect. This function automatically handles wrapping the element with
9801 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9804 // default: slide the element in from the top
9807 // custom: slide the element in from the right with a 2-second duration
9808 el.slideIn('r', { duration: 2 });
9810 // common config options shown with default values
9816 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9817 * @param {Object} options (optional) Object literal with any of the Fx config options
9818 * @return {Roo.Element} The Element
9820 slideIn : function(anchor, o){
9821 var el = this.getFxEl();
9824 el.queueFx(o, function(){
9826 anchor = anchor || "t";
9828 // fix display to visibility
9831 // restore values after effect
9832 var r = this.getFxRestore();
9833 var b = this.getBox();
9834 // fixed size for slide
9838 var wrap = this.fxWrap(r.pos, o, "hidden");
9840 var st = this.dom.style;
9841 st.visibility = "visible";
9842 st.position = "absolute";
9844 // clear out temp styles after slide and unwrap
9845 var after = function(){
9846 el.fxUnwrap(wrap, r.pos, o);
9848 st.height = r.height;
9851 // time to calc the positions
9852 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9854 switch(anchor.toLowerCase()){
9856 wrap.setSize(b.width, 0);
9857 st.left = st.bottom = "0";
9861 wrap.setSize(0, b.height);
9862 st.right = st.top = "0";
9866 wrap.setSize(0, b.height);
9868 st.left = st.top = "0";
9869 a = {width: bw, points: pt};
9872 wrap.setSize(b.width, 0);
9873 wrap.setY(b.bottom);
9874 st.left = st.top = "0";
9875 a = {height: bh, points: pt};
9879 st.right = st.bottom = "0";
9880 a = {width: bw, height: bh};
9884 wrap.setY(b.y+b.height);
9885 st.right = st.top = "0";
9886 a = {width: bw, height: bh, points: pt};
9890 wrap.setXY([b.right, b.bottom]);
9891 st.left = st.top = "0";
9892 a = {width: bw, height: bh, points: pt};
9896 wrap.setX(b.x+b.width);
9897 st.left = st.bottom = "0";
9898 a = {width: bw, height: bh, points: pt};
9901 this.dom.style.visibility = "visible";
9904 arguments.callee.anim = wrap.fxanim(a,
9914 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9915 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9916 * 'hidden') but block elements will still take up space in the document. The element must be removed
9917 * from the DOM using the 'remove' config option if desired. This function automatically handles
9918 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9921 // default: slide the element out to the top
9924 // custom: slide the element out to the right with a 2-second duration
9925 el.slideOut('r', { duration: 2 });
9927 // common config options shown with default values
9935 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9936 * @param {Object} options (optional) Object literal with any of the Fx config options
9937 * @return {Roo.Element} The Element
9939 slideOut : function(anchor, o){
9940 var el = this.getFxEl();
9943 el.queueFx(o, function(){
9945 anchor = anchor || "t";
9947 // restore values after effect
9948 var r = this.getFxRestore();
9950 var b = this.getBox();
9951 // fixed size for slide
9955 var wrap = this.fxWrap(r.pos, o, "visible");
9957 var st = this.dom.style;
9958 st.visibility = "visible";
9959 st.position = "absolute";
9963 var after = function(){
9965 el.setDisplayed(false);
9970 el.fxUnwrap(wrap, r.pos, o);
9973 st.height = r.height;
9978 var a, zero = {to: 0};
9979 switch(anchor.toLowerCase()){
9981 st.left = st.bottom = "0";
9985 st.right = st.top = "0";
9989 st.left = st.top = "0";
9990 a = {width: zero, points: {to:[b.right, b.y]}};
9993 st.left = st.top = "0";
9994 a = {height: zero, points: {to:[b.x, b.bottom]}};
9997 st.right = st.bottom = "0";
9998 a = {width: zero, height: zero};
10001 st.right = st.top = "0";
10002 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10005 st.left = st.top = "0";
10006 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10009 st.left = st.bottom = "0";
10010 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10014 arguments.callee.anim = wrap.fxanim(a,
10024 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10025 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10026 * The element must be removed from the DOM using the 'remove' config option if desired.
10032 // common config options shown with default values
10040 * @param {Object} options (optional) Object literal with any of the Fx config options
10041 * @return {Roo.Element} The Element
10043 puff : function(o){
10044 var el = this.getFxEl();
10047 el.queueFx(o, function(){
10048 this.clearOpacity();
10051 // restore values after effect
10052 var r = this.getFxRestore();
10053 var st = this.dom.style;
10055 var after = function(){
10057 el.setDisplayed(false);
10064 el.setPositioning(r.pos);
10065 st.width = r.width;
10066 st.height = r.height;
10071 var width = this.getWidth();
10072 var height = this.getHeight();
10074 arguments.callee.anim = this.fxanim({
10075 width : {to: this.adjustWidth(width * 2)},
10076 height : {to: this.adjustHeight(height * 2)},
10077 points : {by: [-(width * .5), -(height * .5)]},
10079 fontSize: {to:200, unit: "%"}
10090 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10091 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10092 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10098 // all config options shown with default values
10106 * @param {Object} options (optional) Object literal with any of the Fx config options
10107 * @return {Roo.Element} The Element
10109 switchOff : function(o){
10110 var el = this.getFxEl();
10113 el.queueFx(o, function(){
10114 this.clearOpacity();
10117 // restore values after effect
10118 var r = this.getFxRestore();
10119 var st = this.dom.style;
10121 var after = function(){
10123 el.setDisplayed(false);
10129 el.setPositioning(r.pos);
10130 st.width = r.width;
10131 st.height = r.height;
10136 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10137 this.clearOpacity();
10141 points:{by:[0, this.getHeight() * .5]}
10142 }, o, 'motion', 0.3, 'easeIn', after);
10143 }).defer(100, this);
10150 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10151 * changed using the "attr" config option) and then fading back to the original color. If no original
10152 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10155 // default: highlight background to yellow
10158 // custom: highlight foreground text to blue for 2 seconds
10159 el.highlight("0000ff", { attr: 'color', duration: 2 });
10161 // common config options shown with default values
10162 el.highlight("ffff9c", {
10163 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10164 endColor: (current color) or "ffffff",
10169 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10170 * @param {Object} options (optional) Object literal with any of the Fx config options
10171 * @return {Roo.Element} The Element
10173 highlight : function(color, o){
10174 var el = this.getFxEl();
10177 el.queueFx(o, function(){
10178 color = color || "ffff9c";
10179 attr = o.attr || "backgroundColor";
10181 this.clearOpacity();
10184 var origColor = this.getColor(attr);
10185 var restoreColor = this.dom.style[attr];
10186 endColor = (o.endColor || origColor) || "ffffff";
10188 var after = function(){
10189 el.dom.style[attr] = restoreColor;
10194 a[attr] = {from: color, to: endColor};
10195 arguments.callee.anim = this.fxanim(a,
10205 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10208 // default: a single light blue ripple
10211 // custom: 3 red ripples lasting 3 seconds total
10212 el.frame("ff0000", 3, { duration: 3 });
10214 // common config options shown with default values
10215 el.frame("C3DAF9", 1, {
10216 duration: 1 //duration of entire animation (not each individual ripple)
10217 // Note: Easing is not configurable and will be ignored if included
10220 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10221 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10222 * @param {Object} options (optional) Object literal with any of the Fx config options
10223 * @return {Roo.Element} The Element
10225 frame : function(color, count, o){
10226 var el = this.getFxEl();
10229 el.queueFx(o, function(){
10230 color = color || "#C3DAF9";
10231 if(color.length == 6){
10232 color = "#" + color;
10234 count = count || 1;
10235 duration = o.duration || 1;
10238 var b = this.getBox();
10239 var animFn = function(){
10240 var proxy = this.createProxy({
10243 visbility:"hidden",
10244 position:"absolute",
10245 "z-index":"35000", // yee haw
10246 border:"0px solid " + color
10249 var scale = Roo.isBorderBox ? 2 : 1;
10251 top:{from:b.y, to:b.y - 20},
10252 left:{from:b.x, to:b.x - 20},
10253 borderWidth:{from:0, to:10},
10254 opacity:{from:1, to:0},
10255 height:{from:b.height, to:(b.height + (20*scale))},
10256 width:{from:b.width, to:(b.width + (20*scale))}
10257 }, duration, function(){
10261 animFn.defer((duration/2)*1000, this);
10272 * Creates a pause before any subsequent queued effects begin. If there are
10273 * no effects queued after the pause it will have no effect.
10278 * @param {Number} seconds The length of time to pause (in seconds)
10279 * @return {Roo.Element} The Element
10281 pause : function(seconds){
10282 var el = this.getFxEl();
10285 el.queueFx(o, function(){
10286 setTimeout(function(){
10288 }, seconds * 1000);
10294 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10295 * using the "endOpacity" config option.
10298 // default: fade in from opacity 0 to 100%
10301 // custom: fade in from opacity 0 to 75% over 2 seconds
10302 el.fadeIn({ endOpacity: .75, duration: 2});
10304 // common config options shown with default values
10306 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10311 * @param {Object} options (optional) Object literal with any of the Fx config options
10312 * @return {Roo.Element} The Element
10314 fadeIn : function(o){
10315 var el = this.getFxEl();
10317 el.queueFx(o, function(){
10318 this.setOpacity(0);
10320 this.dom.style.visibility = 'visible';
10321 var to = o.endOpacity || 1;
10322 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10323 o, null, .5, "easeOut", function(){
10325 this.clearOpacity();
10334 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10335 * using the "endOpacity" config option.
10338 // default: fade out from the element's current opacity to 0
10341 // custom: fade out from the element's current opacity to 25% over 2 seconds
10342 el.fadeOut({ endOpacity: .25, duration: 2});
10344 // common config options shown with default values
10346 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10353 * @param {Object} options (optional) Object literal with any of the Fx config options
10354 * @return {Roo.Element} The Element
10356 fadeOut : function(o){
10357 var el = this.getFxEl();
10359 el.queueFx(o, function(){
10360 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10361 o, null, .5, "easeOut", function(){
10362 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10363 this.dom.style.display = "none";
10365 this.dom.style.visibility = "hidden";
10367 this.clearOpacity();
10375 * Animates the transition of an element's dimensions from a starting height/width
10376 * to an ending height/width.
10379 // change height and width to 100x100 pixels
10380 el.scale(100, 100);
10382 // common config options shown with default values. The height and width will default to
10383 // the element's existing values if passed as null.
10386 [element's height], {
10391 * @param {Number} width The new width (pass undefined to keep the original width)
10392 * @param {Number} height The new height (pass undefined to keep the original height)
10393 * @param {Object} options (optional) Object literal with any of the Fx config options
10394 * @return {Roo.Element} The Element
10396 scale : function(w, h, o){
10397 this.shift(Roo.apply({}, o, {
10405 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10406 * Any of these properties not specified in the config object will not be changed. This effect
10407 * requires that at least one new dimension, position or opacity setting must be passed in on
10408 * the config object in order for the function to have any effect.
10411 // slide the element horizontally to x position 200 while changing the height and opacity
10412 el.shift({ x: 200, height: 50, opacity: .8 });
10414 // common config options shown with default values.
10416 width: [element's width],
10417 height: [element's height],
10418 x: [element's x position],
10419 y: [element's y position],
10420 opacity: [element's opacity],
10425 * @param {Object} options Object literal with any of the Fx config options
10426 * @return {Roo.Element} The Element
10428 shift : function(o){
10429 var el = this.getFxEl();
10431 el.queueFx(o, function(){
10432 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10433 if(w !== undefined){
10434 a.width = {to: this.adjustWidth(w)};
10436 if(h !== undefined){
10437 a.height = {to: this.adjustHeight(h)};
10439 if(x !== undefined || y !== undefined){
10441 x !== undefined ? x : this.getX(),
10442 y !== undefined ? y : this.getY()
10445 if(op !== undefined){
10446 a.opacity = {to: op};
10448 if(o.xy !== undefined){
10449 a.points = {to: o.xy};
10451 arguments.callee.anim = this.fxanim(a,
10452 o, 'motion', .35, "easeOut", function(){
10460 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10461 * ending point of the effect.
10464 // default: slide the element downward while fading out
10467 // custom: slide the element out to the right with a 2-second duration
10468 el.ghost('r', { duration: 2 });
10470 // common config options shown with default values
10478 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10479 * @param {Object} options (optional) Object literal with any of the Fx config options
10480 * @return {Roo.Element} The Element
10482 ghost : function(anchor, o){
10483 var el = this.getFxEl();
10486 el.queueFx(o, function(){
10487 anchor = anchor || "b";
10489 // restore values after effect
10490 var r = this.getFxRestore();
10491 var w = this.getWidth(),
10492 h = this.getHeight();
10494 var st = this.dom.style;
10496 var after = function(){
10498 el.setDisplayed(false);
10504 el.setPositioning(r.pos);
10505 st.width = r.width;
10506 st.height = r.height;
10511 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10512 switch(anchor.toLowerCase()){
10539 arguments.callee.anim = this.fxanim(a,
10549 * Ensures that all effects queued after syncFx is called on the element are
10550 * run concurrently. This is the opposite of {@link #sequenceFx}.
10551 * @return {Roo.Element} The Element
10553 syncFx : function(){
10554 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10563 * Ensures that all effects queued after sequenceFx is called on the element are
10564 * run in sequence. This is the opposite of {@link #syncFx}.
10565 * @return {Roo.Element} The Element
10567 sequenceFx : function(){
10568 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10570 concurrent : false,
10577 nextFx : function(){
10578 var ef = this.fxQueue[0];
10585 * Returns true if the element has any effects actively running or queued, else returns false.
10586 * @return {Boolean} True if element has active effects, else false
10588 hasActiveFx : function(){
10589 return this.fxQueue && this.fxQueue[0];
10593 * Stops any running effects and clears the element's internal effects queue if it contains
10594 * any additional effects that haven't started yet.
10595 * @return {Roo.Element} The Element
10597 stopFx : function(){
10598 if(this.hasActiveFx()){
10599 var cur = this.fxQueue[0];
10600 if(cur && cur.anim && cur.anim.isAnimated()){
10601 this.fxQueue = [cur]; // clear out others
10602 cur.anim.stop(true);
10609 beforeFx : function(o){
10610 if(this.hasActiveFx() && !o.concurrent){
10621 * Returns true if the element is currently blocking so that no other effect can be queued
10622 * until this effect is finished, else returns false if blocking is not set. This is commonly
10623 * used to ensure that an effect initiated by a user action runs to completion prior to the
10624 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10625 * @return {Boolean} True if blocking, else false
10627 hasFxBlock : function(){
10628 var q = this.fxQueue;
10629 return q && q[0] && q[0].block;
10633 queueFx : function(o, fn){
10637 if(!this.hasFxBlock()){
10638 Roo.applyIf(o, this.fxDefaults);
10640 var run = this.beforeFx(o);
10641 fn.block = o.block;
10642 this.fxQueue.push(fn);
10654 fxWrap : function(pos, o, vis){
10656 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10659 wrapXY = this.getXY();
10661 var div = document.createElement("div");
10662 div.style.visibility = vis;
10663 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10664 wrap.setPositioning(pos);
10665 if(wrap.getStyle("position") == "static"){
10666 wrap.position("relative");
10668 this.clearPositioning('auto');
10670 wrap.dom.appendChild(this.dom);
10672 wrap.setXY(wrapXY);
10679 fxUnwrap : function(wrap, pos, o){
10680 this.clearPositioning();
10681 this.setPositioning(pos);
10683 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10689 getFxRestore : function(){
10690 var st = this.dom.style;
10691 return {pos: this.getPositioning(), width: st.width, height : st.height};
10695 afterFx : function(o){
10697 this.applyStyles(o.afterStyle);
10700 this.addClass(o.afterCls);
10702 if(o.remove === true){
10705 Roo.callback(o.callback, o.scope, [this]);
10707 this.fxQueue.shift();
10713 getFxEl : function(){ // support for composite element fx
10714 return Roo.get(this.dom);
10718 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10719 animType = animType || 'run';
10721 var anim = Roo.lib.Anim[animType](
10723 (opt.duration || defaultDur) || .35,
10724 (opt.easing || defaultEase) || 'easeOut',
10726 Roo.callback(cb, this);
10735 // backwords compat
10736 Roo.Fx.resize = Roo.Fx.scale;
10738 //When included, Roo.Fx is automatically applied to Element so that all basic
10739 //effects are available directly via the Element API
10740 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10742 * Ext JS Library 1.1.1
10743 * Copyright(c) 2006-2007, Ext JS, LLC.
10745 * Originally Released Under LGPL - original licence link has changed is not relivant.
10748 * <script type="text/javascript">
10753 * @class Roo.CompositeElement
10754 * Standard composite class. Creates a Roo.Element for every element in the collection.
10756 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10757 * actions will be performed on all the elements in this collection.</b>
10759 * All methods return <i>this</i> and can be chained.
10761 var els = Roo.select("#some-el div.some-class", true);
10762 // or select directly from an existing element
10763 var el = Roo.get('some-el');
10764 el.select('div.some-class', true);
10766 els.setWidth(100); // all elements become 100 width
10767 els.hide(true); // all elements fade out and hide
10769 els.setWidth(100).hide(true);
10772 Roo.CompositeElement = function(els){
10773 this.elements = [];
10774 this.addElements(els);
10776 Roo.CompositeElement.prototype = {
10778 addElements : function(els){
10779 if(!els) return this;
10780 if(typeof els == "string"){
10781 els = Roo.Element.selectorFunction(els);
10783 var yels = this.elements;
10784 var index = yels.length-1;
10785 for(var i = 0, len = els.length; i < len; i++) {
10786 yels[++index] = Roo.get(els[i]);
10792 * Clears this composite and adds the elements returned by the passed selector.
10793 * @param {String/Array} els A string CSS selector, an array of elements or an element
10794 * @return {CompositeElement} this
10796 fill : function(els){
10797 this.elements = [];
10803 * Filters this composite to only elements that match the passed selector.
10804 * @param {String} selector A string CSS selector
10805 * @return {CompositeElement} this
10807 filter : function(selector){
10809 this.each(function(el){
10810 if(el.is(selector)){
10811 els[els.length] = el.dom;
10818 invoke : function(fn, args){
10819 var els = this.elements;
10820 for(var i = 0, len = els.length; i < len; i++) {
10821 Roo.Element.prototype[fn].apply(els[i], args);
10826 * Adds elements to this composite.
10827 * @param {String/Array} els A string CSS selector, an array of elements or an element
10828 * @return {CompositeElement} this
10830 add : function(els){
10831 if(typeof els == "string"){
10832 this.addElements(Roo.Element.selectorFunction(els));
10833 }else if(els.length !== undefined){
10834 this.addElements(els);
10836 this.addElements([els]);
10841 * Calls the passed function passing (el, this, index) for each element in this composite.
10842 * @param {Function} fn The function to call
10843 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10844 * @return {CompositeElement} this
10846 each : function(fn, scope){
10847 var els = this.elements;
10848 for(var i = 0, len = els.length; i < len; i++){
10849 if(fn.call(scope || els[i], els[i], this, i) === false) {
10857 * Returns the Element object at the specified index
10858 * @param {Number} index
10859 * @return {Roo.Element}
10861 item : function(index){
10862 return this.elements[index] || null;
10866 * Returns the first Element
10867 * @return {Roo.Element}
10869 first : function(){
10870 return this.item(0);
10874 * Returns the last Element
10875 * @return {Roo.Element}
10878 return this.item(this.elements.length-1);
10882 * Returns the number of elements in this composite
10885 getCount : function(){
10886 return this.elements.length;
10890 * Returns true if this composite contains the passed element
10893 contains : function(el){
10894 return this.indexOf(el) !== -1;
10898 * Returns true if this composite contains the passed element
10901 indexOf : function(el){
10902 return this.elements.indexOf(Roo.get(el));
10907 * Removes the specified element(s).
10908 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10909 * or an array of any of those.
10910 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10911 * @return {CompositeElement} this
10913 removeElement : function(el, removeDom){
10914 if(el instanceof Array){
10915 for(var i = 0, len = el.length; i < len; i++){
10916 this.removeElement(el[i]);
10920 var index = typeof el == 'number' ? el : this.indexOf(el);
10923 var d = this.elements[index];
10927 d.parentNode.removeChild(d);
10930 this.elements.splice(index, 1);
10936 * Replaces the specified element with the passed element.
10937 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10939 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10940 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10941 * @return {CompositeElement} this
10943 replaceElement : function(el, replacement, domReplace){
10944 var index = typeof el == 'number' ? el : this.indexOf(el);
10947 this.elements[index].replaceWith(replacement);
10949 this.elements.splice(index, 1, Roo.get(replacement))
10956 * Removes all elements.
10958 clear : function(){
10959 this.elements = [];
10963 Roo.CompositeElement.createCall = function(proto, fnName){
10964 if(!proto[fnName]){
10965 proto[fnName] = function(){
10966 return this.invoke(fnName, arguments);
10970 for(var fnName in Roo.Element.prototype){
10971 if(typeof Roo.Element.prototype[fnName] == "function"){
10972 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10978 * Ext JS Library 1.1.1
10979 * Copyright(c) 2006-2007, Ext JS, LLC.
10981 * Originally Released Under LGPL - original licence link has changed is not relivant.
10984 * <script type="text/javascript">
10988 * @class Roo.CompositeElementLite
10989 * @extends Roo.CompositeElement
10990 * Flyweight composite class. Reuses the same Roo.Element for element operations.
10992 var els = Roo.select("#some-el div.some-class");
10993 // or select directly from an existing element
10994 var el = Roo.get('some-el');
10995 el.select('div.some-class');
10997 els.setWidth(100); // all elements become 100 width
10998 els.hide(true); // all elements fade out and hide
11000 els.setWidth(100).hide(true);
11001 </code></pre><br><br>
11002 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11003 * actions will be performed on all the elements in this collection.</b>
11005 Roo.CompositeElementLite = function(els){
11006 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11007 this.el = new Roo.Element.Flyweight();
11009 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11010 addElements : function(els){
11012 if(els instanceof Array){
11013 this.elements = this.elements.concat(els);
11015 var yels = this.elements;
11016 var index = yels.length-1;
11017 for(var i = 0, len = els.length; i < len; i++) {
11018 yels[++index] = els[i];
11024 invoke : function(fn, args){
11025 var els = this.elements;
11027 for(var i = 0, len = els.length; i < len; i++) {
11029 Roo.Element.prototype[fn].apply(el, args);
11034 * Returns a flyweight Element of the dom element object at the specified index
11035 * @param {Number} index
11036 * @return {Roo.Element}
11038 item : function(index){
11039 if(!this.elements[index]){
11042 this.el.dom = this.elements[index];
11046 // fixes scope with flyweight
11047 addListener : function(eventName, handler, scope, opt){
11048 var els = this.elements;
11049 for(var i = 0, len = els.length; i < len; i++) {
11050 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11056 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11057 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11058 * a reference to the dom node, use el.dom.</b>
11059 * @param {Function} fn The function to call
11060 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11061 * @return {CompositeElement} this
11063 each : function(fn, scope){
11064 var els = this.elements;
11066 for(var i = 0, len = els.length; i < len; i++){
11068 if(fn.call(scope || el, el, this, i) === false){
11075 indexOf : function(el){
11076 return this.elements.indexOf(Roo.getDom(el));
11079 replaceElement : function(el, replacement, domReplace){
11080 var index = typeof el == 'number' ? el : this.indexOf(el);
11082 replacement = Roo.getDom(replacement);
11084 var d = this.elements[index];
11085 d.parentNode.insertBefore(replacement, d);
11086 d.parentNode.removeChild(d);
11088 this.elements.splice(index, 1, replacement);
11093 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11097 * Ext JS Library 1.1.1
11098 * Copyright(c) 2006-2007, Ext JS, LLC.
11100 * Originally Released Under LGPL - original licence link has changed is not relivant.
11103 * <script type="text/javascript">
11109 * @class Roo.data.Connection
11110 * @extends Roo.util.Observable
11111 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11112 * either to a configured URL, or to a URL specified at request time.<br><br>
11114 * Requests made by this class are asynchronous, and will return immediately. No data from
11115 * the server will be available to the statement immediately following the {@link #request} call.
11116 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11118 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11119 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11120 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11121 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11122 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11123 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11124 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11125 * standard DOM methods.
11127 * @param {Object} config a configuration object.
11129 Roo.data.Connection = function(config){
11130 Roo.apply(this, config);
11133 * @event beforerequest
11134 * Fires before a network request is made to retrieve a data object.
11135 * @param {Connection} conn This Connection object.
11136 * @param {Object} options The options config object passed to the {@link #request} method.
11138 "beforerequest" : true,
11140 * @event requestcomplete
11141 * Fires if the request was successfully completed.
11142 * @param {Connection} conn This Connection object.
11143 * @param {Object} response The XHR object containing the response data.
11144 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11145 * @param {Object} options The options config object passed to the {@link #request} method.
11147 "requestcomplete" : true,
11149 * @event requestexception
11150 * Fires if an error HTTP status was returned from the server.
11151 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11152 * @param {Connection} conn This Connection object.
11153 * @param {Object} response The XHR object containing the response data.
11154 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11155 * @param {Object} options The options config object passed to the {@link #request} method.
11157 "requestexception" : true
11159 Roo.data.Connection.superclass.constructor.call(this);
11162 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11164 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11167 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11168 * extra parameters to each request made by this object. (defaults to undefined)
11171 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11172 * to each request made by this object. (defaults to undefined)
11175 * @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)
11178 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11182 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11188 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11191 disableCaching: true,
11194 * Sends an HTTP request to a remote server.
11195 * @param {Object} options An object which may contain the following properties:<ul>
11196 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11197 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11198 * request, a url encoded string or a function to call to get either.</li>
11199 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11200 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11201 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11202 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11203 * <li>options {Object} The parameter to the request call.</li>
11204 * <li>success {Boolean} True if the request succeeded.</li>
11205 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11207 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11208 * The callback is passed the following parameters:<ul>
11209 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11210 * <li>options {Object} The parameter to the request call.</li>
11212 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11213 * The callback is passed the following parameters:<ul>
11214 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11215 * <li>options {Object} The parameter to the request call.</li>
11217 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11218 * for the callback function. Defaults to the browser window.</li>
11219 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11220 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11221 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11222 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11223 * params for the post data. Any params will be appended to the URL.</li>
11224 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11226 * @return {Number} transactionId
11228 request : function(o){
11229 if(this.fireEvent("beforerequest", this, o) !== false){
11232 if(typeof p == "function"){
11233 p = p.call(o.scope||window, o);
11235 if(typeof p == "object"){
11236 p = Roo.urlEncode(o.params);
11238 if(this.extraParams){
11239 var extras = Roo.urlEncode(this.extraParams);
11240 p = p ? (p + '&' + extras) : extras;
11243 var url = o.url || this.url;
11244 if(typeof url == 'function'){
11245 url = url.call(o.scope||window, o);
11249 var form = Roo.getDom(o.form);
11250 url = url || form.action;
11252 var enctype = form.getAttribute("enctype");
11253 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11254 return this.doFormUpload(o, p, url);
11256 var f = Roo.lib.Ajax.serializeForm(form);
11257 p = p ? (p + '&' + f) : f;
11260 var hs = o.headers;
11261 if(this.defaultHeaders){
11262 hs = Roo.apply(hs || {}, this.defaultHeaders);
11269 success: this.handleResponse,
11270 failure: this.handleFailure,
11272 argument: {options: o},
11273 timeout : this.timeout
11276 var method = o.method||this.method||(p ? "POST" : "GET");
11278 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11279 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11282 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11286 }else if(this.autoAbort !== false){
11290 if((method == 'GET' && p) || o.xmlData){
11291 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11294 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11295 return this.transId;
11297 Roo.callback(o.callback, o.scope, [o, null, null]);
11303 * Determine whether this object has a request outstanding.
11304 * @param {Number} transactionId (Optional) defaults to the last transaction
11305 * @return {Boolean} True if there is an outstanding request.
11307 isLoading : function(transId){
11309 return Roo.lib.Ajax.isCallInProgress(transId);
11311 return this.transId ? true : false;
11316 * Aborts any outstanding request.
11317 * @param {Number} transactionId (Optional) defaults to the last transaction
11319 abort : function(transId){
11320 if(transId || this.isLoading()){
11321 Roo.lib.Ajax.abort(transId || this.transId);
11326 handleResponse : function(response){
11327 this.transId = false;
11328 var options = response.argument.options;
11329 response.argument = options ? options.argument : null;
11330 this.fireEvent("requestcomplete", this, response, options);
11331 Roo.callback(options.success, options.scope, [response, options]);
11332 Roo.callback(options.callback, options.scope, [options, true, response]);
11336 handleFailure : function(response, e){
11337 this.transId = false;
11338 var options = response.argument.options;
11339 response.argument = options ? options.argument : null;
11340 this.fireEvent("requestexception", this, response, options, e);
11341 Roo.callback(options.failure, options.scope, [response, options]);
11342 Roo.callback(options.callback, options.scope, [options, false, response]);
11346 doFormUpload : function(o, ps, url){
11348 var frame = document.createElement('iframe');
11351 frame.className = 'x-hidden';
11353 frame.src = Roo.SSL_SECURE_URL;
11355 document.body.appendChild(frame);
11358 document.frames[id].name = id;
11361 var form = Roo.getDom(o.form);
11363 form.method = 'POST';
11364 form.enctype = form.encoding = 'multipart/form-data';
11370 if(ps){ // add dynamic params
11372 ps = Roo.urlDecode(ps, false);
11374 if(ps.hasOwnProperty(k)){
11375 hd = document.createElement('input');
11376 hd.type = 'hidden';
11379 form.appendChild(hd);
11386 var r = { // bogus response object
11391 r.argument = o ? o.argument : null;
11396 doc = frame.contentWindow.document;
11398 doc = (frame.contentDocument || window.frames[id].document);
11400 if(doc && doc.body){
11401 r.responseText = doc.body.innerHTML;
11403 if(doc && doc.XMLDocument){
11404 r.responseXML = doc.XMLDocument;
11406 r.responseXML = doc;
11413 Roo.EventManager.removeListener(frame, 'load', cb, this);
11415 this.fireEvent("requestcomplete", this, r, o);
11416 Roo.callback(o.success, o.scope, [r, o]);
11417 Roo.callback(o.callback, o.scope, [o, true, r]);
11419 setTimeout(function(){document.body.removeChild(frame);}, 100);
11422 Roo.EventManager.on(frame, 'load', cb, this);
11425 if(hiddens){ // remove dynamic params
11426 for(var i = 0, len = hiddens.length; i < len; i++){
11427 form.removeChild(hiddens[i]);
11435 * @extends Roo.data.Connection
11436 * Global Ajax request class.
11440 Roo.Ajax = new Roo.data.Connection({
11443 * @cfg {String} url @hide
11446 * @cfg {Object} extraParams @hide
11449 * @cfg {Object} defaultHeaders @hide
11452 * @cfg {String} method (Optional) @hide
11455 * @cfg {Number} timeout (Optional) @hide
11458 * @cfg {Boolean} autoAbort (Optional) @hide
11462 * @cfg {Boolean} disableCaching (Optional) @hide
11466 * @property disableCaching
11467 * True to add a unique cache-buster param to GET requests. (defaults to true)
11472 * The default URL to be used for requests to the server. (defaults to undefined)
11476 * @property extraParams
11477 * An object containing properties which are used as
11478 * extra parameters to each request made by this object. (defaults to undefined)
11482 * @property defaultHeaders
11483 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11488 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11492 * @property timeout
11493 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11498 * @property autoAbort
11499 * Whether a new request should abort any pending requests. (defaults to false)
11505 * Serialize the passed form into a url encoded string
11506 * @param {String/HTMLElement} form
11509 serializeForm : function(form){
11510 return Roo.lib.Ajax.serializeForm(form);
11514 * Ext JS Library 1.1.1
11515 * Copyright(c) 2006-2007, Ext JS, LLC.
11517 * Originally Released Under LGPL - original licence link has changed is not relivant.
11520 * <script type="text/javascript">
11525 * @extends Roo.data.Connection
11526 * Global Ajax request class.
11528 * @instanceOf Roo.data.Connection
11530 Roo.Ajax = new Roo.data.Connection({
11539 * @cfg {String} url @hide
11542 * @cfg {Object} extraParams @hide
11545 * @cfg {Object} defaultHeaders @hide
11548 * @cfg {String} method (Optional) @hide
11551 * @cfg {Number} timeout (Optional) @hide
11554 * @cfg {Boolean} autoAbort (Optional) @hide
11558 * @cfg {Boolean} disableCaching (Optional) @hide
11562 * @property disableCaching
11563 * True to add a unique cache-buster param to GET requests. (defaults to true)
11568 * The default URL to be used for requests to the server. (defaults to undefined)
11572 * @property extraParams
11573 * An object containing properties which are used as
11574 * extra parameters to each request made by this object. (defaults to undefined)
11578 * @property defaultHeaders
11579 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11584 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11588 * @property timeout
11589 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11594 * @property autoAbort
11595 * Whether a new request should abort any pending requests. (defaults to false)
11601 * Serialize the passed form into a url encoded string
11602 * @param {String/HTMLElement} form
11605 serializeForm : function(form){
11606 return Roo.lib.Ajax.serializeForm(form);
11610 * Ext JS Library 1.1.1
11611 * Copyright(c) 2006-2007, Ext JS, LLC.
11613 * Originally Released Under LGPL - original licence link has changed is not relivant.
11616 * <script type="text/javascript">
11621 * @class Roo.UpdateManager
11622 * @extends Roo.util.Observable
11623 * Provides AJAX-style update for Element object.<br><br>
11626 * // Get it from a Roo.Element object
11627 * var el = Roo.get("foo");
11628 * var mgr = el.getUpdateManager();
11629 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11631 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11633 * // or directly (returns the same UpdateManager instance)
11634 * var mgr = new Roo.UpdateManager("myElementId");
11635 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11636 * mgr.on("update", myFcnNeedsToKnow);
11638 // short handed call directly from the element object
11639 Roo.get("foo").load({
11643 text: "Loading Foo..."
11647 * Create new UpdateManager directly.
11648 * @param {String/HTMLElement/Roo.Element} el The element to update
11649 * @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).
11651 Roo.UpdateManager = function(el, forceNew){
11653 if(!forceNew && el.updateManager){
11654 return el.updateManager;
11657 * The Element object
11658 * @type Roo.Element
11662 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11665 this.defaultUrl = null;
11669 * @event beforeupdate
11670 * Fired before an update is made, return false from your handler and the update is cancelled.
11671 * @param {Roo.Element} el
11672 * @param {String/Object/Function} url
11673 * @param {String/Object} params
11675 "beforeupdate": true,
11678 * Fired after successful update is made.
11679 * @param {Roo.Element} el
11680 * @param {Object} oResponseObject The response Object
11685 * Fired on update failure.
11686 * @param {Roo.Element} el
11687 * @param {Object} oResponseObject The response Object
11691 var d = Roo.UpdateManager.defaults;
11693 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11696 this.sslBlankUrl = d.sslBlankUrl;
11698 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11701 this.disableCaching = d.disableCaching;
11703 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11706 this.indicatorText = d.indicatorText;
11708 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11711 this.showLoadIndicator = d.showLoadIndicator;
11713 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11716 this.timeout = d.timeout;
11719 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11722 this.loadScripts = d.loadScripts;
11725 * Transaction object of current executing transaction
11727 this.transaction = null;
11732 this.autoRefreshProcId = null;
11734 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11737 this.refreshDelegate = this.refresh.createDelegate(this);
11739 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11742 this.updateDelegate = this.update.createDelegate(this);
11744 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11747 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11751 this.successDelegate = this.processSuccess.createDelegate(this);
11755 this.failureDelegate = this.processFailure.createDelegate(this);
11757 if(!this.renderer){
11759 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11761 this.renderer = new Roo.UpdateManager.BasicRenderer();
11764 Roo.UpdateManager.superclass.constructor.call(this);
11767 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11769 * Get the Element this UpdateManager is bound to
11770 * @return {Roo.Element} The element
11772 getEl : function(){
11776 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11777 * @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:
11780 url: "your-url.php",<br/>
11781 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11782 callback: yourFunction,<br/>
11783 scope: yourObject, //(optional scope) <br/>
11784 discardUrl: false, <br/>
11785 nocache: false,<br/>
11786 text: "Loading...",<br/>
11788 scripts: false<br/>
11791 * The only required property is url. The optional properties nocache, text and scripts
11792 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11793 * @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}
11794 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11795 * @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.
11797 update : function(url, params, callback, discardUrl){
11798 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11799 var method = this.method, cfg;
11800 if(typeof url == "object"){ // must be config object
11803 params = params || cfg.params;
11804 callback = callback || cfg.callback;
11805 discardUrl = discardUrl || cfg.discardUrl;
11806 if(callback && cfg.scope){
11807 callback = callback.createDelegate(cfg.scope);
11809 if(typeof cfg.method != "undefined"){method = cfg.method;};
11810 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11811 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11812 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11813 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11815 this.showLoading();
11817 this.defaultUrl = url;
11819 if(typeof url == "function"){
11820 url = url.call(this);
11823 method = method || (params ? "POST" : "GET");
11824 if(method == "GET"){
11825 url = this.prepareUrl(url);
11828 var o = Roo.apply(cfg ||{}, {
11831 success: this.successDelegate,
11832 failure: this.failureDelegate,
11833 callback: undefined,
11834 timeout: (this.timeout*1000),
11835 argument: {"url": url, "form": null, "callback": callback, "params": params}
11838 this.transaction = Roo.Ajax.request(o);
11843 * 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.
11844 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11845 * @param {String/HTMLElement} form The form Id or form element
11846 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11847 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11848 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11850 formUpdate : function(form, url, reset, callback){
11851 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11852 if(typeof url == "function"){
11853 url = url.call(this);
11855 form = Roo.getDom(form);
11856 this.transaction = Roo.Ajax.request({
11859 success: this.successDelegate,
11860 failure: this.failureDelegate,
11861 timeout: (this.timeout*1000),
11862 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11864 this.showLoading.defer(1, this);
11869 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11870 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11872 refresh : function(callback){
11873 if(this.defaultUrl == null){
11876 this.update(this.defaultUrl, null, callback, true);
11880 * Set this element to auto refresh.
11881 * @param {Number} interval How often to update (in seconds).
11882 * @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)
11883 * @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}
11884 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11885 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11887 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11889 this.update(url || this.defaultUrl, params, callback, true);
11891 if(this.autoRefreshProcId){
11892 clearInterval(this.autoRefreshProcId);
11894 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11898 * Stop auto refresh on this element.
11900 stopAutoRefresh : function(){
11901 if(this.autoRefreshProcId){
11902 clearInterval(this.autoRefreshProcId);
11903 delete this.autoRefreshProcId;
11907 isAutoRefreshing : function(){
11908 return this.autoRefreshProcId ? true : false;
11911 * Called to update the element to "Loading" state. Override to perform custom action.
11913 showLoading : function(){
11914 if(this.showLoadIndicator){
11915 this.el.update(this.indicatorText);
11920 * Adds unique parameter to query string if disableCaching = true
11923 prepareUrl : function(url){
11924 if(this.disableCaching){
11925 var append = "_dc=" + (new Date().getTime());
11926 if(url.indexOf("?") !== -1){
11927 url += "&" + append;
11929 url += "?" + append;
11938 processSuccess : function(response){
11939 this.transaction = null;
11940 if(response.argument.form && response.argument.reset){
11941 try{ // put in try/catch since some older FF releases had problems with this
11942 response.argument.form.reset();
11945 if(this.loadScripts){
11946 this.renderer.render(this.el, response, this,
11947 this.updateComplete.createDelegate(this, [response]));
11949 this.renderer.render(this.el, response, this);
11950 this.updateComplete(response);
11954 updateComplete : function(response){
11955 this.fireEvent("update", this.el, response);
11956 if(typeof response.argument.callback == "function"){
11957 response.argument.callback(this.el, true, response);
11964 processFailure : function(response){
11965 this.transaction = null;
11966 this.fireEvent("failure", this.el, response);
11967 if(typeof response.argument.callback == "function"){
11968 response.argument.callback(this.el, false, response);
11973 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11974 * @param {Object} renderer The object implementing the render() method
11976 setRenderer : function(renderer){
11977 this.renderer = renderer;
11980 getRenderer : function(){
11981 return this.renderer;
11985 * Set the defaultUrl used for updates
11986 * @param {String/Function} defaultUrl The url or a function to call to get the url
11988 setDefaultUrl : function(defaultUrl){
11989 this.defaultUrl = defaultUrl;
11993 * Aborts the executing transaction
11995 abort : function(){
11996 if(this.transaction){
11997 Roo.Ajax.abort(this.transaction);
12002 * Returns true if an update is in progress
12003 * @return {Boolean}
12005 isUpdating : function(){
12006 if(this.transaction){
12007 return Roo.Ajax.isLoading(this.transaction);
12014 * @class Roo.UpdateManager.defaults
12015 * @static (not really - but it helps the doc tool)
12016 * The defaults collection enables customizing the default properties of UpdateManager
12018 Roo.UpdateManager.defaults = {
12020 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12026 * True to process scripts by default (Defaults to false).
12029 loadScripts : false,
12032 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12035 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12037 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12040 disableCaching : false,
12042 * Whether to show indicatorText when loading (Defaults to true).
12045 showLoadIndicator : true,
12047 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12050 indicatorText : '<div class="loading-indicator">Loading...</div>'
12054 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12056 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12057 * @param {String/HTMLElement/Roo.Element} el The element to update
12058 * @param {String} url The url
12059 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12060 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12063 * @member Roo.UpdateManager
12065 Roo.UpdateManager.updateElement = function(el, url, params, options){
12066 var um = Roo.get(el, true).getUpdateManager();
12067 Roo.apply(um, options);
12068 um.update(url, params, options ? options.callback : null);
12070 // alias for backwards compat
12071 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12073 * @class Roo.UpdateManager.BasicRenderer
12074 * Default Content renderer. Updates the elements innerHTML with the responseText.
12076 Roo.UpdateManager.BasicRenderer = function(){};
12078 Roo.UpdateManager.BasicRenderer.prototype = {
12080 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12081 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12082 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12083 * @param {Roo.Element} el The element being rendered
12084 * @param {Object} response The YUI Connect response object
12085 * @param {UpdateManager} updateManager The calling update manager
12086 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12088 render : function(el, response, updateManager, callback){
12089 el.update(response.responseText, updateManager.loadScripts, callback);
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">
12104 * @class Roo.util.DelayedTask
12105 * Provides a convenient method of performing setTimeout where a new
12106 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12107 * You can use this class to buffer
12108 * the keypress events for a certain number of milliseconds, and perform only if they stop
12109 * for that amount of time.
12110 * @constructor The parameters to this constructor serve as defaults and are not required.
12111 * @param {Function} fn (optional) The default function to timeout
12112 * @param {Object} scope (optional) The default scope of that timeout
12113 * @param {Array} args (optional) The default Array of arguments
12115 Roo.util.DelayedTask = function(fn, scope, args){
12116 var id = null, d, t;
12118 var call = function(){
12119 var now = new Date().getTime();
12123 fn.apply(scope, args || []);
12127 * Cancels any pending timeout and queues a new one
12128 * @param {Number} delay The milliseconds to delay
12129 * @param {Function} newFn (optional) Overrides function passed to constructor
12130 * @param {Object} newScope (optional) Overrides scope passed to constructor
12131 * @param {Array} newArgs (optional) Overrides args passed to constructor
12133 this.delay = function(delay, newFn, newScope, newArgs){
12134 if(id && delay != d){
12138 t = new Date().getTime();
12140 scope = newScope || scope;
12141 args = newArgs || args;
12143 id = setInterval(call, d);
12148 * Cancel the last queued timeout
12150 this.cancel = function(){
12158 * Ext JS Library 1.1.1
12159 * Copyright(c) 2006-2007, Ext JS, LLC.
12161 * Originally Released Under LGPL - original licence link has changed is not relivant.
12164 * <script type="text/javascript">
12168 Roo.util.TaskRunner = function(interval){
12169 interval = interval || 10;
12170 var tasks = [], removeQueue = [];
12172 var running = false;
12174 var stopThread = function(){
12180 var startThread = function(){
12183 id = setInterval(runTasks, interval);
12187 var removeTask = function(task){
12188 removeQueue.push(task);
12194 var runTasks = function(){
12195 if(removeQueue.length > 0){
12196 for(var i = 0, len = removeQueue.length; i < len; i++){
12197 tasks.remove(removeQueue[i]);
12200 if(tasks.length < 1){
12205 var now = new Date().getTime();
12206 for(var i = 0, len = tasks.length; i < len; ++i){
12208 var itime = now - t.taskRunTime;
12209 if(t.interval <= itime){
12210 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12211 t.taskRunTime = now;
12212 if(rt === false || t.taskRunCount === t.repeat){
12217 if(t.duration && t.duration <= (now - t.taskStartTime)){
12224 * Queues a new task.
12225 * @param {Object} task
12227 this.start = function(task){
12229 task.taskStartTime = new Date().getTime();
12230 task.taskRunTime = 0;
12231 task.taskRunCount = 0;
12236 this.stop = function(task){
12241 this.stopAll = function(){
12243 for(var i = 0, len = tasks.length; i < len; i++){
12244 if(tasks[i].onStop){
12253 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12255 * Ext JS Library 1.1.1
12256 * Copyright(c) 2006-2007, Ext JS, LLC.
12258 * Originally Released Under LGPL - original licence link has changed is not relivant.
12261 * <script type="text/javascript">
12266 * @class Roo.util.MixedCollection
12267 * @extends Roo.util.Observable
12268 * A Collection class that maintains both numeric indexes and keys and exposes events.
12270 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12271 * collection (defaults to false)
12272 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12273 * and return the key value for that item. This is used when available to look up the key on items that
12274 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12275 * equivalent to providing an implementation for the {@link #getKey} method.
12277 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12285 * Fires when the collection is cleared.
12290 * Fires when an item is added to the collection.
12291 * @param {Number} index The index at which the item was added.
12292 * @param {Object} o The item added.
12293 * @param {String} key The key associated with the added item.
12298 * Fires when an item is replaced in the collection.
12299 * @param {String} key he key associated with the new added.
12300 * @param {Object} old The item being replaced.
12301 * @param {Object} new The new item.
12306 * Fires when an item is removed from the collection.
12307 * @param {Object} o The item being removed.
12308 * @param {String} key (optional) The key associated with the removed item.
12313 this.allowFunctions = allowFunctions === true;
12315 this.getKey = keyFn;
12317 Roo.util.MixedCollection.superclass.constructor.call(this);
12320 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12321 allowFunctions : false,
12324 * Adds an item to the collection.
12325 * @param {String} key The key to associate with the item
12326 * @param {Object} o The item to add.
12327 * @return {Object} The item added.
12329 add : function(key, o){
12330 if(arguments.length == 1){
12332 key = this.getKey(o);
12334 if(typeof key == "undefined" || key === null){
12336 this.items.push(o);
12337 this.keys.push(null);
12339 var old = this.map[key];
12341 return this.replace(key, o);
12344 this.items.push(o);
12346 this.keys.push(key);
12348 this.fireEvent("add", this.length-1, o, key);
12353 * MixedCollection has a generic way to fetch keys if you implement getKey.
12356 var mc = new Roo.util.MixedCollection();
12357 mc.add(someEl.dom.id, someEl);
12358 mc.add(otherEl.dom.id, otherEl);
12362 var mc = new Roo.util.MixedCollection();
12363 mc.getKey = function(el){
12369 // or via the constructor
12370 var mc = new Roo.util.MixedCollection(false, function(el){
12376 * @param o {Object} The item for which to find the key.
12377 * @return {Object} The key for the passed item.
12379 getKey : function(o){
12384 * Replaces an item in the collection.
12385 * @param {String} key The key associated with the item to replace, or the item to replace.
12386 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12387 * @return {Object} The new item.
12389 replace : function(key, o){
12390 if(arguments.length == 1){
12392 key = this.getKey(o);
12394 var old = this.item(key);
12395 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12396 return this.add(key, o);
12398 var index = this.indexOfKey(key);
12399 this.items[index] = o;
12401 this.fireEvent("replace", key, old, o);
12406 * Adds all elements of an Array or an Object to the collection.
12407 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12408 * an Array of values, each of which are added to the collection.
12410 addAll : function(objs){
12411 if(arguments.length > 1 || objs instanceof Array){
12412 var args = arguments.length > 1 ? arguments : objs;
12413 for(var i = 0, len = args.length; i < len; i++){
12417 for(var key in objs){
12418 if(this.allowFunctions || typeof objs[key] != "function"){
12419 this.add(key, objs[key]);
12426 * Executes the specified function once for every item in the collection, passing each
12427 * item as the first and only parameter. returning false from the function will stop the iteration.
12428 * @param {Function} fn The function to execute for each item.
12429 * @param {Object} scope (optional) The scope in which to execute the function.
12431 each : function(fn, scope){
12432 var items = [].concat(this.items); // each safe for removal
12433 for(var i = 0, len = items.length; i < len; i++){
12434 if(fn.call(scope || items[i], items[i], i, len) === false){
12441 * Executes the specified function once for every key in the collection, passing each
12442 * key, and its associated item as the first two parameters.
12443 * @param {Function} fn The function to execute for each item.
12444 * @param {Object} scope (optional) The scope in which to execute the function.
12446 eachKey : function(fn, scope){
12447 for(var i = 0, len = this.keys.length; i < len; i++){
12448 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12453 * Returns the first item in the collection which elicits a true return value from the
12454 * passed selection function.
12455 * @param {Function} fn The selection function to execute for each item.
12456 * @param {Object} scope (optional) The scope in which to execute the function.
12457 * @return {Object} The first item in the collection which returned true from the selection function.
12459 find : function(fn, scope){
12460 for(var i = 0, len = this.items.length; i < len; i++){
12461 if(fn.call(scope || window, this.items[i], this.keys[i])){
12462 return this.items[i];
12469 * Inserts an item at the specified index in the collection.
12470 * @param {Number} index The index to insert the item at.
12471 * @param {String} key The key to associate with the new item, or the item itself.
12472 * @param {Object} o (optional) If the second parameter was a key, the new item.
12473 * @return {Object} The item inserted.
12475 insert : function(index, key, o){
12476 if(arguments.length == 2){
12478 key = this.getKey(o);
12480 if(index >= this.length){
12481 return this.add(key, o);
12484 this.items.splice(index, 0, o);
12485 if(typeof key != "undefined" && key != null){
12488 this.keys.splice(index, 0, key);
12489 this.fireEvent("add", index, o, key);
12494 * Removed an item from the collection.
12495 * @param {Object} o The item to remove.
12496 * @return {Object} The item removed.
12498 remove : function(o){
12499 return this.removeAt(this.indexOf(o));
12503 * Remove an item from a specified index in the collection.
12504 * @param {Number} index The index within the collection of the item to remove.
12506 removeAt : function(index){
12507 if(index < this.length && index >= 0){
12509 var o = this.items[index];
12510 this.items.splice(index, 1);
12511 var key = this.keys[index];
12512 if(typeof key != "undefined"){
12513 delete this.map[key];
12515 this.keys.splice(index, 1);
12516 this.fireEvent("remove", o, key);
12521 * Removed an item associated with the passed key fom the collection.
12522 * @param {String} key The key of the item to remove.
12524 removeKey : function(key){
12525 return this.removeAt(this.indexOfKey(key));
12529 * Returns the number of items in the collection.
12530 * @return {Number} the number of items in the collection.
12532 getCount : function(){
12533 return this.length;
12537 * Returns index within the collection of the passed Object.
12538 * @param {Object} o The item to find the index of.
12539 * @return {Number} index of the item.
12541 indexOf : function(o){
12542 if(!this.items.indexOf){
12543 for(var i = 0, len = this.items.length; i < len; i++){
12544 if(this.items[i] == o) return i;
12548 return this.items.indexOf(o);
12553 * Returns index within the collection of the passed key.
12554 * @param {String} key The key to find the index of.
12555 * @return {Number} index of the key.
12557 indexOfKey : function(key){
12558 if(!this.keys.indexOf){
12559 for(var i = 0, len = this.keys.length; i < len; i++){
12560 if(this.keys[i] == key) return i;
12564 return this.keys.indexOf(key);
12569 * Returns the item associated with the passed key OR index. Key has priority over index.
12570 * @param {String/Number} key The key or index of the item.
12571 * @return {Object} The item associated with the passed key.
12573 item : function(key){
12574 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12575 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12579 * Returns the item at the specified index.
12580 * @param {Number} index The index of the item.
12583 itemAt : function(index){
12584 return this.items[index];
12588 * Returns the item associated with the passed key.
12589 * @param {String/Number} key The key of the item.
12590 * @return {Object} The item associated with the passed key.
12592 key : function(key){
12593 return this.map[key];
12597 * Returns true if the collection contains the passed Object as an item.
12598 * @param {Object} o The Object to look for in the collection.
12599 * @return {Boolean} True if the collection contains the Object as an item.
12601 contains : function(o){
12602 return this.indexOf(o) != -1;
12606 * Returns true if the collection contains the passed Object as a key.
12607 * @param {String} key The key to look for in the collection.
12608 * @return {Boolean} True if the collection contains the Object as a key.
12610 containsKey : function(key){
12611 return typeof this.map[key] != "undefined";
12615 * Removes all items from the collection.
12617 clear : function(){
12622 this.fireEvent("clear");
12626 * Returns the first item in the collection.
12627 * @return {Object} the first item in the collection..
12629 first : function(){
12630 return this.items[0];
12634 * Returns the last item in the collection.
12635 * @return {Object} the last item in the collection..
12638 return this.items[this.length-1];
12641 _sort : function(property, dir, fn){
12642 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12643 fn = fn || function(a, b){
12646 var c = [], k = this.keys, items = this.items;
12647 for(var i = 0, len = items.length; i < len; i++){
12648 c[c.length] = {key: k[i], value: items[i], index: i};
12650 c.sort(function(a, b){
12651 var v = fn(a[property], b[property]) * dsc;
12653 v = (a.index < b.index ? -1 : 1);
12657 for(var i = 0, len = c.length; i < len; i++){
12658 items[i] = c[i].value;
12661 this.fireEvent("sort", this);
12665 * Sorts this collection with the passed comparison function
12666 * @param {String} direction (optional) "ASC" or "DESC"
12667 * @param {Function} fn (optional) comparison function
12669 sort : function(dir, fn){
12670 this._sort("value", dir, fn);
12674 * Sorts this collection by keys
12675 * @param {String} direction (optional) "ASC" or "DESC"
12676 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12678 keySort : function(dir, fn){
12679 this._sort("key", dir, fn || function(a, b){
12680 return String(a).toUpperCase()-String(b).toUpperCase();
12685 * Returns a range of items in this collection
12686 * @param {Number} startIndex (optional) defaults to 0
12687 * @param {Number} endIndex (optional) default to the last item
12688 * @return {Array} An array of items
12690 getRange : function(start, end){
12691 var items = this.items;
12692 if(items.length < 1){
12695 start = start || 0;
12696 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12699 for(var i = start; i <= end; i++) {
12700 r[r.length] = items[i];
12703 for(var i = start; i >= end; i--) {
12704 r[r.length] = items[i];
12711 * Filter the <i>objects</i> in this collection by a specific property.
12712 * Returns a new collection that has been filtered.
12713 * @param {String} property A property on your objects
12714 * @param {String/RegExp} value Either string that the property values
12715 * should start with or a RegExp to test against the property
12716 * @return {MixedCollection} The new filtered collection
12718 filter : function(property, value){
12719 if(!value.exec){ // not a regex
12720 value = String(value);
12721 if(value.length == 0){
12722 return this.clone();
12724 value = new RegExp("^" + Roo.escapeRe(value), "i");
12726 return this.filterBy(function(o){
12727 return o && value.test(o[property]);
12732 * Filter by a function. * Returns a new collection that has been filtered.
12733 * The passed function will be called with each
12734 * object in the collection. If the function returns true, the value is included
12735 * otherwise it is filtered.
12736 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12737 * @param {Object} scope (optional) The scope of the function (defaults to this)
12738 * @return {MixedCollection} The new filtered collection
12740 filterBy : function(fn, scope){
12741 var r = new Roo.util.MixedCollection();
12742 r.getKey = this.getKey;
12743 var k = this.keys, it = this.items;
12744 for(var i = 0, len = it.length; i < len; i++){
12745 if(fn.call(scope||this, it[i], k[i])){
12746 r.add(k[i], it[i]);
12753 * Creates a duplicate of this collection
12754 * @return {MixedCollection}
12756 clone : function(){
12757 var r = new Roo.util.MixedCollection();
12758 var k = this.keys, it = this.items;
12759 for(var i = 0, len = it.length; i < len; i++){
12760 r.add(k[i], it[i]);
12762 r.getKey = this.getKey;
12767 * Returns the item associated with the passed key or index.
12769 * @param {String/Number} key The key or index of the item.
12770 * @return {Object} The item associated with the passed key.
12772 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12774 * Ext JS Library 1.1.1
12775 * Copyright(c) 2006-2007, Ext JS, LLC.
12777 * Originally Released Under LGPL - original licence link has changed is not relivant.
12780 * <script type="text/javascript">
12783 * @class Roo.util.JSON
12784 * Modified version of Douglas Crockford"s json.js that doesn"t
12785 * mess with the Object prototype
12786 * http://www.json.org/js.html
12789 Roo.util.JSON = new (function(){
12790 var useHasOwn = {}.hasOwnProperty ? true : false;
12792 // crashes Safari in some instances
12793 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12795 var pad = function(n) {
12796 return n < 10 ? "0" + n : n;
12809 var encodeString = function(s){
12810 if (/["\\\x00-\x1f]/.test(s)) {
12811 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12816 c = b.charCodeAt();
12818 Math.floor(c / 16).toString(16) +
12819 (c % 16).toString(16);
12822 return '"' + s + '"';
12825 var encodeArray = function(o){
12826 var a = ["["], b, i, l = o.length, v;
12827 for (i = 0; i < l; i += 1) {
12829 switch (typeof v) {
12838 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12846 var encodeDate = function(o){
12847 return '"' + o.getFullYear() + "-" +
12848 pad(o.getMonth() + 1) + "-" +
12849 pad(o.getDate()) + "T" +
12850 pad(o.getHours()) + ":" +
12851 pad(o.getMinutes()) + ":" +
12852 pad(o.getSeconds()) + '"';
12856 * Encodes an Object, Array or other value
12857 * @param {Mixed} o The variable to encode
12858 * @return {String} The JSON string
12860 this.encode = function(o)
12862 // should this be extended to fully wrap stringify..
12864 if(typeof o == "undefined" || o === null){
12866 }else if(o instanceof Array){
12867 return encodeArray(o);
12868 }else if(o instanceof Date){
12869 return encodeDate(o);
12870 }else if(typeof o == "string"){
12871 return encodeString(o);
12872 }else if(typeof o == "number"){
12873 return isFinite(o) ? String(o) : "null";
12874 }else if(typeof o == "boolean"){
12877 var a = ["{"], b, i, v;
12879 if(!useHasOwn || o.hasOwnProperty(i)) {
12881 switch (typeof v) {
12890 a.push(this.encode(i), ":",
12891 v === null ? "null" : this.encode(v));
12902 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12903 * @param {String} json The JSON string
12904 * @return {Object} The resulting object
12906 this.decode = function(json){
12908 return /** eval:var:json */ eval("(" + json + ')');
12912 * Shorthand for {@link Roo.util.JSON#encode}
12913 * @member Roo encode
12915 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12917 * Shorthand for {@link Roo.util.JSON#decode}
12918 * @member Roo decode
12920 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12923 * Ext JS Library 1.1.1
12924 * Copyright(c) 2006-2007, Ext JS, LLC.
12926 * Originally Released Under LGPL - original licence link has changed is not relivant.
12929 * <script type="text/javascript">
12933 * @class Roo.util.Format
12934 * Reusable data formatting functions
12937 Roo.util.Format = function(){
12938 var trimRe = /^\s+|\s+$/g;
12941 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12942 * @param {String} value The string to truncate
12943 * @param {Number} length The maximum length to allow before truncating
12944 * @return {String} The converted text
12946 ellipsis : function(value, len){
12947 if(value && value.length > len){
12948 return value.substr(0, len-3)+"...";
12954 * Checks a reference and converts it to empty string if it is undefined
12955 * @param {Mixed} value Reference to check
12956 * @return {Mixed} Empty string if converted, otherwise the original value
12958 undef : function(value){
12959 return typeof value != "undefined" ? value : "";
12963 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12964 * @param {String} value The string to encode
12965 * @return {String} The encoded text
12967 htmlEncode : function(value){
12968 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12972 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12973 * @param {String} value The string to decode
12974 * @return {String} The decoded text
12976 htmlDecode : function(value){
12977 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12981 * Trims any whitespace from either side of a string
12982 * @param {String} value The text to trim
12983 * @return {String} The trimmed text
12985 trim : function(value){
12986 return String(value).replace(trimRe, "");
12990 * Returns a substring from within an original string
12991 * @param {String} value The original text
12992 * @param {Number} start The start index of the substring
12993 * @param {Number} length The length of the substring
12994 * @return {String} The substring
12996 substr : function(value, start, length){
12997 return String(value).substr(start, length);
13001 * Converts a string to all lower case letters
13002 * @param {String} value The text to convert
13003 * @return {String} The converted text
13005 lowercase : function(value){
13006 return String(value).toLowerCase();
13010 * Converts a string to all upper case letters
13011 * @param {String} value The text to convert
13012 * @return {String} The converted text
13014 uppercase : function(value){
13015 return String(value).toUpperCase();
13019 * Converts the first character only of a string to upper case
13020 * @param {String} value The text to convert
13021 * @return {String} The converted text
13023 capitalize : function(value){
13024 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13028 call : function(value, fn){
13029 if(arguments.length > 2){
13030 var args = Array.prototype.slice.call(arguments, 2);
13031 args.unshift(value);
13033 return /** eval:var:value */ eval(fn).apply(window, args);
13035 /** eval:var:value */
13036 return /** eval:var:value */ eval(fn).call(window, value);
13042 * safer version of Math.toFixed..??/
13043 * @param {Number/String} value The numeric value to format
13044 * @param {Number/String} value Decimal places
13045 * @return {String} The formatted currency string
13047 toFixed : function(v, n)
13049 // why not use to fixed - precision is buggered???
13051 return Math.round(v-0);
13053 var fact = Math.pow(10,n+1);
13054 v = (Math.round((v-0)*fact))/fact;
13055 var z = (''+fact).substring(2);
13056 if (v == Math.floor(v)) {
13057 return Math.floor(v) + '.' + z;
13060 // now just padd decimals..
13061 var ps = String(v).split('.');
13062 var fd = (ps[1] + z);
13063 var r = fd.substring(0,n);
13064 var rm = fd.substring(n);
13066 return ps[0] + '.' + r;
13068 r*=1; // turn it into a number;
13070 if (String(r).length != n) {
13073 r = String(r).substring(1); // chop the end off.
13076 return ps[0] + '.' + r;
13081 * Format a number as US currency
13082 * @param {Number/String} value The numeric value to format
13083 * @return {String} The formatted currency string
13085 usMoney : function(v){
13086 v = (Math.round((v-0)*100))/100;
13087 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13089 var ps = v.split('.');
13091 var sub = ps[1] ? '.'+ ps[1] : '.00';
13092 var r = /(\d+)(\d{3})/;
13093 while (r.test(whole)) {
13094 whole = whole.replace(r, '$1' + ',' + '$2');
13096 return "$" + whole + sub ;
13100 * Parse a value into a formatted date using the specified format pattern.
13101 * @param {Mixed} value The value to format
13102 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13103 * @return {String} The formatted date string
13105 date : function(v, format){
13109 if(!(v instanceof Date)){
13110 v = new Date(Date.parse(v));
13112 return v.dateFormat(format || "m/d/Y");
13116 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13117 * @param {String} format Any valid date format string
13118 * @return {Function} The date formatting function
13120 dateRenderer : function(format){
13121 return function(v){
13122 return Roo.util.Format.date(v, format);
13127 stripTagsRE : /<\/?[^>]+>/gi,
13130 * Strips all HTML tags
13131 * @param {Mixed} value The text from which to strip tags
13132 * @return {String} The stripped text
13134 stripTags : function(v){
13135 return !v ? v : String(v).replace(this.stripTagsRE, "");
13140 * Ext JS Library 1.1.1
13141 * Copyright(c) 2006-2007, Ext JS, LLC.
13143 * Originally Released Under LGPL - original licence link has changed is not relivant.
13146 * <script type="text/javascript">
13153 * @class Roo.MasterTemplate
13154 * @extends Roo.Template
13155 * Provides a template that can have child templates. The syntax is:
13157 var t = new Roo.MasterTemplate(
13158 '<select name="{name}">',
13159 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13162 t.add('options', {value: 'foo', text: 'bar'});
13163 // or you can add multiple child elements in one shot
13164 t.addAll('options', [
13165 {value: 'foo', text: 'bar'},
13166 {value: 'foo2', text: 'bar2'},
13167 {value: 'foo3', text: 'bar3'}
13169 // then append, applying the master template values
13170 t.append('my-form', {name: 'my-select'});
13172 * A name attribute for the child template is not required if you have only one child
13173 * template or you want to refer to them by index.
13175 Roo.MasterTemplate = function(){
13176 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13177 this.originalHtml = this.html;
13179 var m, re = this.subTemplateRe;
13182 while(m = re.exec(this.html)){
13183 var name = m[1], content = m[2];
13188 tpl : new Roo.Template(content)
13191 st[name] = st[subIndex];
13193 st[subIndex].tpl.compile();
13194 st[subIndex].tpl.call = this.call.createDelegate(this);
13197 this.subCount = subIndex;
13200 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13202 * The regular expression used to match sub templates
13206 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13209 * Applies the passed values to a child template.
13210 * @param {String/Number} name (optional) The name or index of the child template
13211 * @param {Array/Object} values The values to be applied to the template
13212 * @return {MasterTemplate} this
13214 add : function(name, values){
13215 if(arguments.length == 1){
13216 values = arguments[0];
13219 var s = this.subs[name];
13220 s.buffer[s.buffer.length] = s.tpl.apply(values);
13225 * Applies all the passed values to a child template.
13226 * @param {String/Number} name (optional) The name or index of the child template
13227 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13228 * @param {Boolean} reset (optional) True to reset the template first
13229 * @return {MasterTemplate} this
13231 fill : function(name, values, reset){
13233 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13241 for(var i = 0, len = values.length; i < len; i++){
13242 this.add(name, values[i]);
13248 * Resets the template for reuse
13249 * @return {MasterTemplate} this
13251 reset : function(){
13253 for(var i = 0; i < this.subCount; i++){
13259 applyTemplate : function(values){
13261 var replaceIndex = -1;
13262 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13263 return s[++replaceIndex].buffer.join("");
13265 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13268 apply : function(){
13269 return this.applyTemplate.apply(this, arguments);
13272 compile : function(){return this;}
13276 * Alias for fill().
13279 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13281 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13282 * var tpl = Roo.MasterTemplate.from('element-id');
13283 * @param {String/HTMLElement} el
13284 * @param {Object} config
13287 Roo.MasterTemplate.from = function(el, config){
13288 el = Roo.getDom(el);
13289 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13292 * Ext JS Library 1.1.1
13293 * Copyright(c) 2006-2007, Ext JS, LLC.
13295 * Originally Released Under LGPL - original licence link has changed is not relivant.
13298 * <script type="text/javascript">
13303 * @class Roo.util.CSS
13304 * Utility class for manipulating CSS rules
13307 Roo.util.CSS = function(){
13309 var doc = document;
13311 var camelRe = /(-[a-z])/gi;
13312 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13316 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13317 * tag and appended to the HEAD of the document.
13318 * @param {String|Object} cssText The text containing the css rules
13319 * @param {String} id An id to add to the stylesheet for later removal
13320 * @return {StyleSheet}
13322 createStyleSheet : function(cssText, id){
13324 var head = doc.getElementsByTagName("head")[0];
13325 var nrules = doc.createElement("style");
13326 nrules.setAttribute("type", "text/css");
13328 nrules.setAttribute("id", id);
13330 if (typeof(cssText) != 'string') {
13331 // support object maps..
13332 // not sure if this a good idea..
13333 // perhaps it should be merged with the general css handling
13334 // and handle js style props.
13335 var cssTextNew = [];
13336 for(var n in cssText) {
13338 for(var k in cssText[n]) {
13339 citems.push( k + ' : ' +cssText[n][k] + ';' );
13341 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13344 cssText = cssTextNew.join("\n");
13350 head.appendChild(nrules);
13351 ss = nrules.styleSheet;
13352 ss.cssText = cssText;
13355 nrules.appendChild(doc.createTextNode(cssText));
13357 nrules.cssText = cssText;
13359 head.appendChild(nrules);
13360 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13362 this.cacheStyleSheet(ss);
13367 * Removes a style or link tag by id
13368 * @param {String} id The id of the tag
13370 removeStyleSheet : function(id){
13371 var existing = doc.getElementById(id);
13373 existing.parentNode.removeChild(existing);
13378 * Dynamically swaps an existing stylesheet reference for a new one
13379 * @param {String} id The id of an existing link tag to remove
13380 * @param {String} url The href of the new stylesheet to include
13382 swapStyleSheet : function(id, url){
13383 this.removeStyleSheet(id);
13384 var ss = doc.createElement("link");
13385 ss.setAttribute("rel", "stylesheet");
13386 ss.setAttribute("type", "text/css");
13387 ss.setAttribute("id", id);
13388 ss.setAttribute("href", url);
13389 doc.getElementsByTagName("head")[0].appendChild(ss);
13393 * Refresh the rule cache if you have dynamically added stylesheets
13394 * @return {Object} An object (hash) of rules indexed by selector
13396 refreshCache : function(){
13397 return this.getRules(true);
13401 cacheStyleSheet : function(stylesheet){
13405 try{// try catch for cross domain access issue
13406 var ssRules = stylesheet.cssRules || stylesheet.rules;
13407 for(var j = ssRules.length-1; j >= 0; --j){
13408 rules[ssRules[j].selectorText] = ssRules[j];
13414 * Gets all css rules for the document
13415 * @param {Boolean} refreshCache true to refresh the internal cache
13416 * @return {Object} An object (hash) of rules indexed by selector
13418 getRules : function(refreshCache){
13419 if(rules == null || refreshCache){
13421 var ds = doc.styleSheets;
13422 for(var i =0, len = ds.length; i < len; i++){
13424 this.cacheStyleSheet(ds[i]);
13432 * Gets an an individual CSS rule by selector(s)
13433 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13434 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13435 * @return {CSSRule} The CSS rule or null if one is not found
13437 getRule : function(selector, refreshCache){
13438 var rs = this.getRules(refreshCache);
13439 if(!(selector instanceof Array)){
13440 return rs[selector];
13442 for(var i = 0; i < selector.length; i++){
13443 if(rs[selector[i]]){
13444 return rs[selector[i]];
13452 * Updates a rule property
13453 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13454 * @param {String} property The css property
13455 * @param {String} value The new value for the property
13456 * @return {Boolean} true If a rule was found and updated
13458 updateRule : function(selector, property, value){
13459 if(!(selector instanceof Array)){
13460 var rule = this.getRule(selector);
13462 rule.style[property.replace(camelRe, camelFn)] = value;
13466 for(var i = 0; i < selector.length; i++){
13467 if(this.updateRule(selector[i], property, value)){
13477 * Ext JS Library 1.1.1
13478 * Copyright(c) 2006-2007, Ext JS, LLC.
13480 * Originally Released Under LGPL - original licence link has changed is not relivant.
13483 * <script type="text/javascript">
13489 * @class Roo.util.ClickRepeater
13490 * @extends Roo.util.Observable
13492 * A wrapper class which can be applied to any element. Fires a "click" event while the
13493 * mouse is pressed. The interval between firings may be specified in the config but
13494 * defaults to 10 milliseconds.
13496 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13498 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13499 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13500 * Similar to an autorepeat key delay.
13501 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13502 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13503 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13504 * "interval" and "delay" are ignored. "immediate" is honored.
13505 * @cfg {Boolean} preventDefault True to prevent the default click event
13506 * @cfg {Boolean} stopDefault True to stop the default click event
13509 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13510 * 2007-02-02 jvs Renamed to ClickRepeater
13511 * 2007-02-03 jvs Modifications for FF Mac and Safari
13514 * @param {String/HTMLElement/Element} el The element to listen on
13515 * @param {Object} config
13517 Roo.util.ClickRepeater = function(el, config)
13519 this.el = Roo.get(el);
13520 this.el.unselectable();
13522 Roo.apply(this, config);
13527 * Fires when the mouse button is depressed.
13528 * @param {Roo.util.ClickRepeater} this
13530 "mousedown" : true,
13533 * Fires on a specified interval during the time the element is pressed.
13534 * @param {Roo.util.ClickRepeater} this
13539 * Fires when the mouse key is released.
13540 * @param {Roo.util.ClickRepeater} this
13545 this.el.on("mousedown", this.handleMouseDown, this);
13546 if(this.preventDefault || this.stopDefault){
13547 this.el.on("click", function(e){
13548 if(this.preventDefault){
13549 e.preventDefault();
13551 if(this.stopDefault){
13557 // allow inline handler
13559 this.on("click", this.handler, this.scope || this);
13562 Roo.util.ClickRepeater.superclass.constructor.call(this);
13565 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13568 preventDefault : true,
13569 stopDefault : false,
13573 handleMouseDown : function(){
13574 clearTimeout(this.timer);
13576 if(this.pressClass){
13577 this.el.addClass(this.pressClass);
13579 this.mousedownTime = new Date();
13581 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13582 this.el.on("mouseout", this.handleMouseOut, this);
13584 this.fireEvent("mousedown", this);
13585 this.fireEvent("click", this);
13587 this.timer = this.click.defer(this.delay || this.interval, this);
13591 click : function(){
13592 this.fireEvent("click", this);
13593 this.timer = this.click.defer(this.getInterval(), this);
13597 getInterval: function(){
13598 if(!this.accelerate){
13599 return this.interval;
13601 var pressTime = this.mousedownTime.getElapsed();
13602 if(pressTime < 500){
13604 }else if(pressTime < 1700){
13606 }else if(pressTime < 2600){
13608 }else if(pressTime < 3500){
13610 }else if(pressTime < 4400){
13612 }else if(pressTime < 5300){
13614 }else if(pressTime < 6200){
13622 handleMouseOut : function(){
13623 clearTimeout(this.timer);
13624 if(this.pressClass){
13625 this.el.removeClass(this.pressClass);
13627 this.el.on("mouseover", this.handleMouseReturn, this);
13631 handleMouseReturn : function(){
13632 this.el.un("mouseover", this.handleMouseReturn);
13633 if(this.pressClass){
13634 this.el.addClass(this.pressClass);
13640 handleMouseUp : function(){
13641 clearTimeout(this.timer);
13642 this.el.un("mouseover", this.handleMouseReturn);
13643 this.el.un("mouseout", this.handleMouseOut);
13644 Roo.get(document).un("mouseup", this.handleMouseUp);
13645 this.el.removeClass(this.pressClass);
13646 this.fireEvent("mouseup", this);
13650 * Ext JS Library 1.1.1
13651 * Copyright(c) 2006-2007, Ext JS, LLC.
13653 * Originally Released Under LGPL - original licence link has changed is not relivant.
13656 * <script type="text/javascript">
13661 * @class Roo.KeyNav
13662 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13663 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13664 * way to implement custom navigation schemes for any UI component.</p>
13665 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13666 * pageUp, pageDown, del, home, end. Usage:</p>
13668 var nav = new Roo.KeyNav("my-element", {
13669 "left" : function(e){
13670 this.moveLeft(e.ctrlKey);
13672 "right" : function(e){
13673 this.moveRight(e.ctrlKey);
13675 "enter" : function(e){
13682 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13683 * @param {Object} config The config
13685 Roo.KeyNav = function(el, config){
13686 this.el = Roo.get(el);
13687 Roo.apply(this, config);
13688 if(!this.disabled){
13689 this.disabled = true;
13694 Roo.KeyNav.prototype = {
13696 * @cfg {Boolean} disabled
13697 * True to disable this KeyNav instance (defaults to false)
13701 * @cfg {String} defaultEventAction
13702 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13703 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13704 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13706 defaultEventAction: "stopEvent",
13708 * @cfg {Boolean} forceKeyDown
13709 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13710 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13711 * handle keydown instead of keypress.
13713 forceKeyDown : false,
13716 prepareEvent : function(e){
13717 var k = e.getKey();
13718 var h = this.keyToHandler[k];
13719 //if(h && this[h]){
13720 // e.stopPropagation();
13722 if(Roo.isSafari && h && k >= 37 && k <= 40){
13728 relay : function(e){
13729 var k = e.getKey();
13730 var h = this.keyToHandler[k];
13732 if(this.doRelay(e, this[h], h) !== true){
13733 e[this.defaultEventAction]();
13739 doRelay : function(e, h, hname){
13740 return h.call(this.scope || this, e);
13743 // possible handlers
13757 // quick lookup hash
13774 * Enable this KeyNav
13776 enable: function(){
13778 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13779 // the EventObject will normalize Safari automatically
13780 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13781 this.el.on("keydown", this.relay, this);
13783 this.el.on("keydown", this.prepareEvent, this);
13784 this.el.on("keypress", this.relay, this);
13786 this.disabled = false;
13791 * Disable this KeyNav
13793 disable: function(){
13794 if(!this.disabled){
13795 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13796 this.el.un("keydown", this.relay);
13798 this.el.un("keydown", this.prepareEvent);
13799 this.el.un("keypress", this.relay);
13801 this.disabled = true;
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.KeyMap
13818 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13819 * The constructor accepts the same config object as defined by {@link #addBinding}.
13820 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13821 * combination it will call the function with this signature (if the match is a multi-key
13822 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13823 * A KeyMap can also handle a string representation of keys.<br />
13826 // map one key by key code
13827 var map = new Roo.KeyMap("my-element", {
13828 key: 13, // or Roo.EventObject.ENTER
13833 // map multiple keys to one action by string
13834 var map = new Roo.KeyMap("my-element", {
13840 // map multiple keys to multiple actions by strings and array of codes
13841 var map = new Roo.KeyMap("my-element", [
13844 fn: function(){ alert("Return was pressed"); }
13847 fn: function(){ alert('a, b or c was pressed'); }
13852 fn: function(){ alert('Control + shift + tab was pressed.'); }
13856 * <b>Note: A KeyMap starts enabled</b>
13858 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13859 * @param {Object} config The config (see {@link #addBinding})
13860 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13862 Roo.KeyMap = function(el, config, eventName){
13863 this.el = Roo.get(el);
13864 this.eventName = eventName || "keydown";
13865 this.bindings = [];
13867 this.addBinding(config);
13872 Roo.KeyMap.prototype = {
13874 * True to stop the event from bubbling and prevent the default browser action if the
13875 * key was handled by the KeyMap (defaults to false)
13881 * Add a new binding to this KeyMap. The following config object properties are supported:
13883 Property Type Description
13884 ---------- --------------- ----------------------------------------------------------------------
13885 key String/Array A single keycode or an array of keycodes to handle
13886 shift Boolean True to handle key only when shift is pressed (defaults to false)
13887 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13888 alt Boolean True to handle key only when alt is pressed (defaults to false)
13889 fn Function The function to call when KeyMap finds the expected key combination
13890 scope Object The scope of the callback function
13896 var map = new Roo.KeyMap(document, {
13897 key: Roo.EventObject.ENTER,
13902 //Add a new binding to the existing KeyMap later
13910 * @param {Object/Array} config A single KeyMap config or an array of configs
13912 addBinding : function(config){
13913 if(config instanceof Array){
13914 for(var i = 0, len = config.length; i < len; i++){
13915 this.addBinding(config[i]);
13919 var keyCode = config.key,
13920 shift = config.shift,
13921 ctrl = config.ctrl,
13924 scope = config.scope;
13925 if(typeof keyCode == "string"){
13927 var keyString = keyCode.toUpperCase();
13928 for(var j = 0, len = keyString.length; j < len; j++){
13929 ks.push(keyString.charCodeAt(j));
13933 var keyArray = keyCode instanceof Array;
13934 var handler = function(e){
13935 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13936 var k = e.getKey();
13938 for(var i = 0, len = keyCode.length; i < len; i++){
13939 if(keyCode[i] == k){
13940 if(this.stopEvent){
13943 fn.call(scope || window, k, e);
13949 if(this.stopEvent){
13952 fn.call(scope || window, k, e);
13957 this.bindings.push(handler);
13961 * Shorthand for adding a single key listener
13962 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13963 * following options:
13964 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13965 * @param {Function} fn The function to call
13966 * @param {Object} scope (optional) The scope of the function
13968 on : function(key, fn, scope){
13969 var keyCode, shift, ctrl, alt;
13970 if(typeof key == "object" && !(key instanceof Array)){
13989 handleKeyDown : function(e){
13990 if(this.enabled){ //just in case
13991 var b = this.bindings;
13992 for(var i = 0, len = b.length; i < len; i++){
13993 b[i].call(this, e);
13999 * Returns true if this KeyMap is enabled
14000 * @return {Boolean}
14002 isEnabled : function(){
14003 return this.enabled;
14007 * Enables this KeyMap
14009 enable: function(){
14011 this.el.on(this.eventName, this.handleKeyDown, this);
14012 this.enabled = true;
14017 * Disable this KeyMap
14019 disable: function(){
14021 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14022 this.enabled = false;
14027 * Ext JS Library 1.1.1
14028 * Copyright(c) 2006-2007, Ext JS, LLC.
14030 * Originally Released Under LGPL - original licence link has changed is not relivant.
14033 * <script type="text/javascript">
14038 * @class Roo.util.TextMetrics
14039 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14040 * wide, in pixels, a given block of text will be.
14043 Roo.util.TextMetrics = function(){
14047 * Measures the size of the specified text
14048 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14049 * that can affect the size of the rendered text
14050 * @param {String} text The text to measure
14051 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14052 * in order to accurately measure the text height
14053 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14055 measure : function(el, text, fixedWidth){
14057 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14060 shared.setFixedWidth(fixedWidth || 'auto');
14061 return shared.getSize(text);
14065 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14066 * the overhead of multiple calls to initialize the style properties on each measurement.
14067 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14068 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14069 * in order to accurately measure the text height
14070 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14072 createInstance : function(el, fixedWidth){
14073 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14080 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14081 var ml = new Roo.Element(document.createElement('div'));
14082 document.body.appendChild(ml.dom);
14083 ml.position('absolute');
14084 ml.setLeftTop(-1000, -1000);
14088 ml.setWidth(fixedWidth);
14093 * Returns the size of the specified text based on the internal element's style and width properties
14094 * @memberOf Roo.util.TextMetrics.Instance#
14095 * @param {String} text The text to measure
14096 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14098 getSize : function(text){
14100 var s = ml.getSize();
14106 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14107 * that can affect the size of the rendered text
14108 * @memberOf Roo.util.TextMetrics.Instance#
14109 * @param {String/HTMLElement} el The element, dom node or id
14111 bind : function(el){
14113 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14118 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14119 * to set a fixed width in order to accurately measure the text height.
14120 * @memberOf Roo.util.TextMetrics.Instance#
14121 * @param {Number} width The width to set on the element
14123 setFixedWidth : function(width){
14124 ml.setWidth(width);
14128 * Returns the measured width of the specified text
14129 * @memberOf Roo.util.TextMetrics.Instance#
14130 * @param {String} text The text to measure
14131 * @return {Number} width The width in pixels
14133 getWidth : function(text){
14134 ml.dom.style.width = 'auto';
14135 return this.getSize(text).width;
14139 * Returns the measured height of the specified text. For multiline text, be sure to call
14140 * {@link #setFixedWidth} if necessary.
14141 * @memberOf Roo.util.TextMetrics.Instance#
14142 * @param {String} text The text to measure
14143 * @return {Number} height The height in pixels
14145 getHeight : function(text){
14146 return this.getSize(text).height;
14150 instance.bind(bindTo);
14155 // backwards compat
14156 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14158 * Ext JS Library 1.1.1
14159 * Copyright(c) 2006-2007, Ext JS, LLC.
14161 * Originally Released Under LGPL - original licence link has changed is not relivant.
14164 * <script type="text/javascript">
14168 * @class Roo.state.Provider
14169 * Abstract base class for state provider implementations. This class provides methods
14170 * for encoding and decoding <b>typed</b> variables including dates and defines the
14171 * Provider interface.
14173 Roo.state.Provider = function(){
14175 * @event statechange
14176 * Fires when a state change occurs.
14177 * @param {Provider} this This state provider
14178 * @param {String} key The state key which was changed
14179 * @param {String} value The encoded value for the state
14182 "statechange": true
14185 Roo.state.Provider.superclass.constructor.call(this);
14187 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14189 * Returns the current value for a key
14190 * @param {String} name The key name
14191 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14192 * @return {Mixed} The state data
14194 get : function(name, defaultValue){
14195 return typeof this.state[name] == "undefined" ?
14196 defaultValue : this.state[name];
14200 * Clears a value from the state
14201 * @param {String} name The key name
14203 clear : function(name){
14204 delete this.state[name];
14205 this.fireEvent("statechange", this, name, null);
14209 * Sets the value for a key
14210 * @param {String} name The key name
14211 * @param {Mixed} value The value to set
14213 set : function(name, value){
14214 this.state[name] = value;
14215 this.fireEvent("statechange", this, name, value);
14219 * Decodes a string previously encoded with {@link #encodeValue}.
14220 * @param {String} value The value to decode
14221 * @return {Mixed} The decoded value
14223 decodeValue : function(cookie){
14224 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14225 var matches = re.exec(unescape(cookie));
14226 if(!matches || !matches[1]) return; // non state cookie
14227 var type = matches[1];
14228 var v = matches[2];
14231 return parseFloat(v);
14233 return new Date(Date.parse(v));
14238 var values = v.split("^");
14239 for(var i = 0, len = values.length; i < len; i++){
14240 all.push(this.decodeValue(values[i]));
14245 var values = v.split("^");
14246 for(var i = 0, len = values.length; i < len; i++){
14247 var kv = values[i].split("=");
14248 all[kv[0]] = this.decodeValue(kv[1]);
14257 * Encodes a value including type information. Decode with {@link #decodeValue}.
14258 * @param {Mixed} value The value to encode
14259 * @return {String} The encoded value
14261 encodeValue : function(v){
14263 if(typeof v == "number"){
14265 }else if(typeof v == "boolean"){
14266 enc = "b:" + (v ? "1" : "0");
14267 }else if(v instanceof Date){
14268 enc = "d:" + v.toGMTString();
14269 }else if(v instanceof Array){
14271 for(var i = 0, len = v.length; i < len; i++){
14272 flat += this.encodeValue(v[i]);
14273 if(i != len-1) flat += "^";
14276 }else if(typeof v == "object"){
14279 if(typeof v[key] != "function"){
14280 flat += key + "=" + this.encodeValue(v[key]) + "^";
14283 enc = "o:" + flat.substring(0, flat.length-1);
14287 return escape(enc);
14293 * Ext JS Library 1.1.1
14294 * Copyright(c) 2006-2007, Ext JS, LLC.
14296 * Originally Released Under LGPL - original licence link has changed is not relivant.
14299 * <script type="text/javascript">
14302 * @class Roo.state.Manager
14303 * This is the global state manager. By default all components that are "state aware" check this class
14304 * for state information if you don't pass them a custom state provider. In order for this class
14305 * to be useful, it must be initialized with a provider when your application initializes.
14307 // in your initialization function
14309 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14311 // supposed you have a {@link Roo.BorderLayout}
14312 var layout = new Roo.BorderLayout(...);
14313 layout.restoreState();
14314 // or a {Roo.BasicDialog}
14315 var dialog = new Roo.BasicDialog(...);
14316 dialog.restoreState();
14320 Roo.state.Manager = function(){
14321 var provider = new Roo.state.Provider();
14325 * Configures the default state provider for your application
14326 * @param {Provider} stateProvider The state provider to set
14328 setProvider : function(stateProvider){
14329 provider = stateProvider;
14333 * Returns the current value for a key
14334 * @param {String} name The key name
14335 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14336 * @return {Mixed} The state data
14338 get : function(key, defaultValue){
14339 return provider.get(key, defaultValue);
14343 * Sets the value for a key
14344 * @param {String} name The key name
14345 * @param {Mixed} value The state data
14347 set : function(key, value){
14348 provider.set(key, value);
14352 * Clears a value from the state
14353 * @param {String} name The key name
14355 clear : function(key){
14356 provider.clear(key);
14360 * Gets the currently configured state provider
14361 * @return {Provider} The state provider
14363 getProvider : function(){
14370 * Ext JS Library 1.1.1
14371 * Copyright(c) 2006-2007, Ext JS, LLC.
14373 * Originally Released Under LGPL - original licence link has changed is not relivant.
14376 * <script type="text/javascript">
14379 * @class Roo.state.CookieProvider
14380 * @extends Roo.state.Provider
14381 * The default Provider implementation which saves state via cookies.
14384 var cp = new Roo.state.CookieProvider({
14386 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14387 domain: "roojs.com"
14389 Roo.state.Manager.setProvider(cp);
14391 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14392 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14393 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14394 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14395 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14396 * domain the page is running on including the 'www' like 'www.roojs.com')
14397 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14399 * Create a new CookieProvider
14400 * @param {Object} config The configuration object
14402 Roo.state.CookieProvider = function(config){
14403 Roo.state.CookieProvider.superclass.constructor.call(this);
14405 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14406 this.domain = null;
14407 this.secure = false;
14408 Roo.apply(this, config);
14409 this.state = this.readCookies();
14412 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14414 set : function(name, value){
14415 if(typeof value == "undefined" || value === null){
14419 this.setCookie(name, value);
14420 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14424 clear : function(name){
14425 this.clearCookie(name);
14426 Roo.state.CookieProvider.superclass.clear.call(this, name);
14430 readCookies : function(){
14432 var c = document.cookie + ";";
14433 var re = /\s?(.*?)=(.*?);/g;
14435 while((matches = re.exec(c)) != null){
14436 var name = matches[1];
14437 var value = matches[2];
14438 if(name && name.substring(0,3) == "ys-"){
14439 cookies[name.substr(3)] = this.decodeValue(value);
14446 setCookie : function(name, value){
14447 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14448 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14449 ((this.path == null) ? "" : ("; path=" + this.path)) +
14450 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14451 ((this.secure == true) ? "; secure" : "");
14455 clearCookie : function(name){
14456 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14457 ((this.path == null) ? "" : ("; path=" + this.path)) +
14458 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14459 ((this.secure == true) ? "; secure" : "");
14463 * Ext JS Library 1.1.1
14464 * Copyright(c) 2006-2007, Ext JS, LLC.
14466 * Originally Released Under LGPL - original licence link has changed is not relivant.
14469 * <script type="text/javascript">
14475 * These classes are derivatives of the similarly named classes in the YUI Library.
14476 * The original license:
14477 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14478 * Code licensed under the BSD License:
14479 * http://developer.yahoo.net/yui/license.txt
14484 var Event=Roo.EventManager;
14485 var Dom=Roo.lib.Dom;
14488 * @class Roo.dd.DragDrop
14489 * @extends Roo.util.Observable
14490 * Defines the interface and base operation of items that that can be
14491 * dragged or can be drop targets. It was designed to be extended, overriding
14492 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14493 * Up to three html elements can be associated with a DragDrop instance:
14495 * <li>linked element: the element that is passed into the constructor.
14496 * This is the element which defines the boundaries for interaction with
14497 * other DragDrop objects.</li>
14498 * <li>handle element(s): The drag operation only occurs if the element that
14499 * was clicked matches a handle element. By default this is the linked
14500 * element, but there are times that you will want only a portion of the
14501 * linked element to initiate the drag operation, and the setHandleElId()
14502 * method provides a way to define this.</li>
14503 * <li>drag element: this represents the element that would be moved along
14504 * with the cursor during a drag operation. By default, this is the linked
14505 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14506 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14509 * This class should not be instantiated until the onload event to ensure that
14510 * the associated elements are available.
14511 * The following would define a DragDrop obj that would interact with any
14512 * other DragDrop obj in the "group1" group:
14514 * dd = new Roo.dd.DragDrop("div1", "group1");
14516 * Since none of the event handlers have been implemented, nothing would
14517 * actually happen if you were to run the code above. Normally you would
14518 * override this class or one of the default implementations, but you can
14519 * also override the methods you want on an instance of the class...
14521 * dd.onDragDrop = function(e, id) {
14522 * alert("dd was dropped on " + id);
14526 * @param {String} id of the element that is linked to this instance
14527 * @param {String} sGroup the group of related DragDrop objects
14528 * @param {object} config an object containing configurable attributes
14529 * Valid properties for DragDrop:
14530 * padding, isTarget, maintainOffset, primaryButtonOnly
14532 Roo.dd.DragDrop = function(id, sGroup, config) {
14534 this.init(id, sGroup, config);
14539 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
14542 * The id of the element associated with this object. This is what we
14543 * refer to as the "linked element" because the size and position of
14544 * this element is used to determine when the drag and drop objects have
14552 * Configuration attributes passed into the constructor
14559 * The id of the element that will be dragged. By default this is same
14560 * as the linked element , but could be changed to another element. Ex:
14562 * @property dragElId
14569 * the id of the element that initiates the drag operation. By default
14570 * this is the linked element, but could be changed to be a child of this
14571 * element. This lets us do things like only starting the drag when the
14572 * header element within the linked html element is clicked.
14573 * @property handleElId
14580 * An associative array of HTML tags that will be ignored if clicked.
14581 * @property invalidHandleTypes
14582 * @type {string: string}
14584 invalidHandleTypes: null,
14587 * An associative array of ids for elements that will be ignored if clicked
14588 * @property invalidHandleIds
14589 * @type {string: string}
14591 invalidHandleIds: null,
14594 * An indexted array of css class names for elements that will be ignored
14596 * @property invalidHandleClasses
14599 invalidHandleClasses: null,
14602 * The linked element's absolute X position at the time the drag was
14604 * @property startPageX
14611 * The linked element's absolute X position at the time the drag was
14613 * @property startPageY
14620 * The group defines a logical collection of DragDrop objects that are
14621 * related. Instances only get events when interacting with other
14622 * DragDrop object in the same group. This lets us define multiple
14623 * groups using a single DragDrop subclass if we want.
14625 * @type {string: string}
14630 * Individual drag/drop instances can be locked. This will prevent
14631 * onmousedown start drag.
14639 * Lock this instance
14642 lock: function() { this.locked = true; },
14645 * Unlock this instace
14648 unlock: function() { this.locked = false; },
14651 * By default, all insances can be a drop target. This can be disabled by
14652 * setting isTarget to false.
14659 * The padding configured for this drag and drop object for calculating
14660 * the drop zone intersection with this object.
14667 * Cached reference to the linked element
14668 * @property _domRef
14674 * Internal typeof flag
14675 * @property __ygDragDrop
14678 __ygDragDrop: true,
14681 * Set to true when horizontal contraints are applied
14682 * @property constrainX
14689 * Set to true when vertical contraints are applied
14690 * @property constrainY
14697 * The left constraint
14705 * The right constraint
14713 * The up constraint
14722 * The down constraint
14730 * Maintain offsets when we resetconstraints. Set to true when you want
14731 * the position of the element relative to its parent to stay the same
14732 * when the page changes
14734 * @property maintainOffset
14737 maintainOffset: false,
14740 * Array of pixel locations the element will snap to if we specified a
14741 * horizontal graduation/interval. This array is generated automatically
14742 * when you define a tick interval.
14749 * Array of pixel locations the element will snap to if we specified a
14750 * vertical graduation/interval. This array is generated automatically
14751 * when you define a tick interval.
14758 * By default the drag and drop instance will only respond to the primary
14759 * button click (left button for a right-handed mouse). Set to true to
14760 * allow drag and drop to start with any mouse click that is propogated
14762 * @property primaryButtonOnly
14765 primaryButtonOnly: true,
14768 * The availabe property is false until the linked dom element is accessible.
14769 * @property available
14775 * By default, drags can only be initiated if the mousedown occurs in the
14776 * region the linked element is. This is done in part to work around a
14777 * bug in some browsers that mis-report the mousedown if the previous
14778 * mouseup happened outside of the window. This property is set to true
14779 * if outer handles are defined.
14781 * @property hasOuterHandles
14785 hasOuterHandles: false,
14788 * Code that executes immediately before the startDrag event
14789 * @method b4StartDrag
14792 b4StartDrag: function(x, y) { },
14795 * Abstract method called after a drag/drop object is clicked
14796 * and the drag or mousedown time thresholds have beeen met.
14797 * @method startDrag
14798 * @param {int} X click location
14799 * @param {int} Y click location
14801 startDrag: function(x, y) { /* override this */ },
14804 * Code that executes immediately before the onDrag event
14808 b4Drag: function(e) { },
14811 * Abstract method called during the onMouseMove event while dragging an
14814 * @param {Event} e the mousemove event
14816 onDrag: function(e) { /* override this */ },
14819 * Abstract method called when this element fist begins hovering over
14820 * another DragDrop obj
14821 * @method onDragEnter
14822 * @param {Event} e the mousemove event
14823 * @param {String|DragDrop[]} id In POINT mode, the element
14824 * id this is hovering over. In INTERSECT mode, an array of one or more
14825 * dragdrop items being hovered over.
14827 onDragEnter: function(e, id) { /* override this */ },
14830 * Code that executes immediately before the onDragOver event
14831 * @method b4DragOver
14834 b4DragOver: function(e) { },
14837 * Abstract method called when this element is hovering over another
14839 * @method onDragOver
14840 * @param {Event} e the mousemove event
14841 * @param {String|DragDrop[]} id In POINT mode, the element
14842 * id this is hovering over. In INTERSECT mode, an array of dd items
14843 * being hovered over.
14845 onDragOver: function(e, id) { /* override this */ },
14848 * Code that executes immediately before the onDragOut event
14849 * @method b4DragOut
14852 b4DragOut: function(e) { },
14855 * Abstract method called when we are no longer hovering over an element
14856 * @method onDragOut
14857 * @param {Event} e the mousemove event
14858 * @param {String|DragDrop[]} id In POINT mode, the element
14859 * id this was hovering over. In INTERSECT mode, an array of dd items
14860 * that the mouse is no longer over.
14862 onDragOut: function(e, id) { /* override this */ },
14865 * Code that executes immediately before the onDragDrop event
14866 * @method b4DragDrop
14869 b4DragDrop: function(e) { },
14872 * Abstract method called when this item is dropped on another DragDrop
14874 * @method onDragDrop
14875 * @param {Event} e the mouseup event
14876 * @param {String|DragDrop[]} id In POINT mode, the element
14877 * id this was dropped on. In INTERSECT mode, an array of dd items this
14880 onDragDrop: function(e, id) { /* override this */ },
14883 * Abstract method called when this item is dropped on an area with no
14885 * @method onInvalidDrop
14886 * @param {Event} e the mouseup event
14888 onInvalidDrop: function(e) { /* override this */ },
14891 * Code that executes immediately before the endDrag event
14892 * @method b4EndDrag
14895 b4EndDrag: function(e) { },
14898 * Fired when we are done dragging the object
14900 * @param {Event} e the mouseup event
14902 endDrag: function(e) { /* override this */ },
14905 * Code executed immediately before the onMouseDown event
14906 * @method b4MouseDown
14907 * @param {Event} e the mousedown event
14910 b4MouseDown: function(e) { },
14913 * Event handler that fires when a drag/drop obj gets a mousedown
14914 * @method onMouseDown
14915 * @param {Event} e the mousedown event
14917 onMouseDown: function(e) { /* override this */ },
14920 * Event handler that fires when a drag/drop obj gets a mouseup
14921 * @method onMouseUp
14922 * @param {Event} e the mouseup event
14924 onMouseUp: function(e) { /* override this */ },
14927 * Override the onAvailable method to do what is needed after the initial
14928 * position was determined.
14929 * @method onAvailable
14931 onAvailable: function () {
14935 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14938 defaultPadding : {left:0, right:0, top:0, bottom:0},
14941 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14945 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14946 { dragElId: "existingProxyDiv" });
14947 dd.startDrag = function(){
14948 this.constrainTo("parent-id");
14951 * Or you can initalize it using the {@link Roo.Element} object:
14953 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14954 startDrag : function(){
14955 this.constrainTo("parent-id");
14959 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14960 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14961 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14962 * an object containing the sides to pad. For example: {right:10, bottom:10}
14963 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14965 constrainTo : function(constrainTo, pad, inContent){
14966 if(typeof pad == "number"){
14967 pad = {left: pad, right:pad, top:pad, bottom:pad};
14969 pad = pad || this.defaultPadding;
14970 var b = Roo.get(this.getEl()).getBox();
14971 var ce = Roo.get(constrainTo);
14972 var s = ce.getScroll();
14973 var c, cd = ce.dom;
14974 if(cd == document.body){
14975 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14978 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14982 var topSpace = b.y - c.y;
14983 var leftSpace = b.x - c.x;
14985 this.resetConstraints();
14986 this.setXConstraint(leftSpace - (pad.left||0), // left
14987 c.width - leftSpace - b.width - (pad.right||0) //right
14989 this.setYConstraint(topSpace - (pad.top||0), //top
14990 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14995 * Returns a reference to the linked element
14997 * @return {HTMLElement} the html element
14999 getEl: function() {
15000 if (!this._domRef) {
15001 this._domRef = Roo.getDom(this.id);
15004 return this._domRef;
15008 * Returns a reference to the actual element to drag. By default this is
15009 * the same as the html element, but it can be assigned to another
15010 * element. An example of this can be found in Roo.dd.DDProxy
15011 * @method getDragEl
15012 * @return {HTMLElement} the html element
15014 getDragEl: function() {
15015 return Roo.getDom(this.dragElId);
15019 * Sets up the DragDrop object. Must be called in the constructor of any
15020 * Roo.dd.DragDrop subclass
15022 * @param id the id of the linked element
15023 * @param {String} sGroup the group of related items
15024 * @param {object} config configuration attributes
15026 init: function(id, sGroup, config) {
15027 this.initTarget(id, sGroup, config);
15028 Event.on(this.id, "mousedown", this.handleMouseDown, this);
15029 // Event.on(this.id, "selectstart", Event.preventDefault);
15033 * Initializes Targeting functionality only... the object does not
15034 * get a mousedown handler.
15035 * @method initTarget
15036 * @param id the id of the linked element
15037 * @param {String} sGroup the group of related items
15038 * @param {object} config configuration attributes
15040 initTarget: function(id, sGroup, config) {
15042 // configuration attributes
15043 this.config = config || {};
15045 // create a local reference to the drag and drop manager
15046 this.DDM = Roo.dd.DDM;
15047 // initialize the groups array
15050 // assume that we have an element reference instead of an id if the
15051 // parameter is not a string
15052 if (typeof id !== "string") {
15059 // add to an interaction group
15060 this.addToGroup((sGroup) ? sGroup : "default");
15062 // We don't want to register this as the handle with the manager
15063 // so we just set the id rather than calling the setter.
15064 this.handleElId = id;
15066 // the linked element is the element that gets dragged by default
15067 this.setDragElId(id);
15069 // by default, clicked anchors will not start drag operations.
15070 this.invalidHandleTypes = { A: "A" };
15071 this.invalidHandleIds = {};
15072 this.invalidHandleClasses = [];
15074 this.applyConfig();
15076 this.handleOnAvailable();
15080 * Applies the configuration parameters that were passed into the constructor.
15081 * This is supposed to happen at each level through the inheritance chain. So
15082 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15083 * DragDrop in order to get all of the parameters that are available in
15085 * @method applyConfig
15087 applyConfig: function() {
15089 // configurable properties:
15090 // padding, isTarget, maintainOffset, primaryButtonOnly
15091 this.padding = this.config.padding || [0, 0, 0, 0];
15092 this.isTarget = (this.config.isTarget !== false);
15093 this.maintainOffset = (this.config.maintainOffset);
15094 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15099 * Executed when the linked element is available
15100 * @method handleOnAvailable
15103 handleOnAvailable: function() {
15104 this.available = true;
15105 this.resetConstraints();
15106 this.onAvailable();
15110 * Configures the padding for the target zone in px. Effectively expands
15111 * (or reduces) the virtual object size for targeting calculations.
15112 * Supports css-style shorthand; if only one parameter is passed, all sides
15113 * will have that padding, and if only two are passed, the top and bottom
15114 * will have the first param, the left and right the second.
15115 * @method setPadding
15116 * @param {int} iTop Top pad
15117 * @param {int} iRight Right pad
15118 * @param {int} iBot Bot pad
15119 * @param {int} iLeft Left pad
15121 setPadding: function(iTop, iRight, iBot, iLeft) {
15122 // this.padding = [iLeft, iRight, iTop, iBot];
15123 if (!iRight && 0 !== iRight) {
15124 this.padding = [iTop, iTop, iTop, iTop];
15125 } else if (!iBot && 0 !== iBot) {
15126 this.padding = [iTop, iRight, iTop, iRight];
15128 this.padding = [iTop, iRight, iBot, iLeft];
15133 * Stores the initial placement of the linked element.
15134 * @method setInitialPosition
15135 * @param {int} diffX the X offset, default 0
15136 * @param {int} diffY the Y offset, default 0
15138 setInitPosition: function(diffX, diffY) {
15139 var el = this.getEl();
15141 if (!this.DDM.verifyEl(el)) {
15145 var dx = diffX || 0;
15146 var dy = diffY || 0;
15148 var p = Dom.getXY( el );
15150 this.initPageX = p[0] - dx;
15151 this.initPageY = p[1] - dy;
15153 this.lastPageX = p[0];
15154 this.lastPageY = p[1];
15157 this.setStartPosition(p);
15161 * Sets the start position of the element. This is set when the obj
15162 * is initialized, the reset when a drag is started.
15163 * @method setStartPosition
15164 * @param pos current position (from previous lookup)
15167 setStartPosition: function(pos) {
15168 var p = pos || Dom.getXY( this.getEl() );
15169 this.deltaSetXY = null;
15171 this.startPageX = p[0];
15172 this.startPageY = p[1];
15176 * Add this instance to a group of related drag/drop objects. All
15177 * instances belong to at least one group, and can belong to as many
15178 * groups as needed.
15179 * @method addToGroup
15180 * @param sGroup {string} the name of the group
15182 addToGroup: function(sGroup) {
15183 this.groups[sGroup] = true;
15184 this.DDM.regDragDrop(this, sGroup);
15188 * Remove's this instance from the supplied interaction group
15189 * @method removeFromGroup
15190 * @param {string} sGroup The group to drop
15192 removeFromGroup: function(sGroup) {
15193 if (this.groups[sGroup]) {
15194 delete this.groups[sGroup];
15197 this.DDM.removeDDFromGroup(this, sGroup);
15201 * Allows you to specify that an element other than the linked element
15202 * will be moved with the cursor during a drag
15203 * @method setDragElId
15204 * @param id {string} the id of the element that will be used to initiate the drag
15206 setDragElId: function(id) {
15207 this.dragElId = id;
15211 * Allows you to specify a child of the linked element that should be
15212 * used to initiate the drag operation. An example of this would be if
15213 * you have a content div with text and links. Clicking anywhere in the
15214 * content area would normally start the drag operation. Use this method
15215 * to specify that an element inside of the content div is the element
15216 * that starts the drag operation.
15217 * @method setHandleElId
15218 * @param id {string} the id of the element that will be used to
15219 * initiate the drag.
15221 setHandleElId: function(id) {
15222 if (typeof id !== "string") {
15225 this.handleElId = id;
15226 this.DDM.regHandle(this.id, id);
15230 * Allows you to set an element outside of the linked element as a drag
15232 * @method setOuterHandleElId
15233 * @param id the id of the element that will be used to initiate the drag
15235 setOuterHandleElId: function(id) {
15236 if (typeof id !== "string") {
15239 Event.on(id, "mousedown",
15240 this.handleMouseDown, this);
15241 this.setHandleElId(id);
15243 this.hasOuterHandles = true;
15247 * Remove all drag and drop hooks for this element
15250 unreg: function() {
15251 Event.un(this.id, "mousedown",
15252 this.handleMouseDown);
15253 this._domRef = null;
15254 this.DDM._remove(this);
15257 destroy : function(){
15262 * Returns true if this instance is locked, or the drag drop mgr is locked
15263 * (meaning that all drag/drop is disabled on the page.)
15265 * @return {boolean} true if this obj or all drag/drop is locked, else
15268 isLocked: function() {
15269 return (this.DDM.isLocked() || this.locked);
15273 * Fired when this object is clicked
15274 * @method handleMouseDown
15276 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15279 handleMouseDown: function(e, oDD){
15280 if (this.primaryButtonOnly && e.button != 0) {
15284 if (this.isLocked()) {
15288 this.DDM.refreshCache(this.groups);
15290 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15291 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15293 if (this.clickValidator(e)) {
15295 // set the initial element position
15296 this.setStartPosition();
15299 this.b4MouseDown(e);
15300 this.onMouseDown(e);
15302 this.DDM.handleMouseDown(e, this);
15304 this.DDM.stopEvent(e);
15312 clickValidator: function(e) {
15313 var target = e.getTarget();
15314 return ( this.isValidHandleChild(target) &&
15315 (this.id == this.handleElId ||
15316 this.DDM.handleWasClicked(target, this.id)) );
15320 * Allows you to specify a tag name that should not start a drag operation
15321 * when clicked. This is designed to facilitate embedding links within a
15322 * drag handle that do something other than start the drag.
15323 * @method addInvalidHandleType
15324 * @param {string} tagName the type of element to exclude
15326 addInvalidHandleType: function(tagName) {
15327 var type = tagName.toUpperCase();
15328 this.invalidHandleTypes[type] = type;
15332 * Lets you to specify an element id for a child of a drag handle
15333 * that should not initiate a drag
15334 * @method addInvalidHandleId
15335 * @param {string} id the element id of the element you wish to ignore
15337 addInvalidHandleId: function(id) {
15338 if (typeof id !== "string") {
15341 this.invalidHandleIds[id] = id;
15345 * Lets you specify a css class of elements that will not initiate a drag
15346 * @method addInvalidHandleClass
15347 * @param {string} cssClass the class of the elements you wish to ignore
15349 addInvalidHandleClass: function(cssClass) {
15350 this.invalidHandleClasses.push(cssClass);
15354 * Unsets an excluded tag name set by addInvalidHandleType
15355 * @method removeInvalidHandleType
15356 * @param {string} tagName the type of element to unexclude
15358 removeInvalidHandleType: function(tagName) {
15359 var type = tagName.toUpperCase();
15360 // this.invalidHandleTypes[type] = null;
15361 delete this.invalidHandleTypes[type];
15365 * Unsets an invalid handle id
15366 * @method removeInvalidHandleId
15367 * @param {string} id the id of the element to re-enable
15369 removeInvalidHandleId: function(id) {
15370 if (typeof id !== "string") {
15373 delete this.invalidHandleIds[id];
15377 * Unsets an invalid css class
15378 * @method removeInvalidHandleClass
15379 * @param {string} cssClass the class of the element(s) you wish to
15382 removeInvalidHandleClass: function(cssClass) {
15383 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15384 if (this.invalidHandleClasses[i] == cssClass) {
15385 delete this.invalidHandleClasses[i];
15391 * Checks the tag exclusion list to see if this click should be ignored
15392 * @method isValidHandleChild
15393 * @param {HTMLElement} node the HTMLElement to evaluate
15394 * @return {boolean} true if this is a valid tag type, false if not
15396 isValidHandleChild: function(node) {
15399 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15402 nodeName = node.nodeName.toUpperCase();
15404 nodeName = node.nodeName;
15406 valid = valid && !this.invalidHandleTypes[nodeName];
15407 valid = valid && !this.invalidHandleIds[node.id];
15409 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15410 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15419 * Create the array of horizontal tick marks if an interval was specified
15420 * in setXConstraint().
15421 * @method setXTicks
15424 setXTicks: function(iStartX, iTickSize) {
15426 this.xTickSize = iTickSize;
15430 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15432 this.xTicks[this.xTicks.length] = i;
15437 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15439 this.xTicks[this.xTicks.length] = i;
15444 this.xTicks.sort(this.DDM.numericSort) ;
15448 * Create the array of vertical tick marks if an interval was specified in
15449 * setYConstraint().
15450 * @method setYTicks
15453 setYTicks: function(iStartY, iTickSize) {
15455 this.yTickSize = iTickSize;
15459 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15461 this.yTicks[this.yTicks.length] = i;
15466 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15468 this.yTicks[this.yTicks.length] = i;
15473 this.yTicks.sort(this.DDM.numericSort) ;
15477 * By default, the element can be dragged any place on the screen. Use
15478 * this method to limit the horizontal travel of the element. Pass in
15479 * 0,0 for the parameters if you want to lock the drag to the y axis.
15480 * @method setXConstraint
15481 * @param {int} iLeft the number of pixels the element can move to the left
15482 * @param {int} iRight the number of pixels the element can move to the
15484 * @param {int} iTickSize optional parameter for specifying that the
15486 * should move iTickSize pixels at a time.
15488 setXConstraint: function(iLeft, iRight, iTickSize) {
15489 this.leftConstraint = iLeft;
15490 this.rightConstraint = iRight;
15492 this.minX = this.initPageX - iLeft;
15493 this.maxX = this.initPageX + iRight;
15494 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15496 this.constrainX = true;
15500 * Clears any constraints applied to this instance. Also clears ticks
15501 * since they can't exist independent of a constraint at this time.
15502 * @method clearConstraints
15504 clearConstraints: function() {
15505 this.constrainX = false;
15506 this.constrainY = false;
15511 * Clears any tick interval defined for this instance
15512 * @method clearTicks
15514 clearTicks: function() {
15515 this.xTicks = null;
15516 this.yTicks = null;
15517 this.xTickSize = 0;
15518 this.yTickSize = 0;
15522 * By default, the element can be dragged any place on the screen. Set
15523 * this to limit the vertical travel of the element. Pass in 0,0 for the
15524 * parameters if you want to lock the drag to the x axis.
15525 * @method setYConstraint
15526 * @param {int} iUp the number of pixels the element can move up
15527 * @param {int} iDown the number of pixels the element can move down
15528 * @param {int} iTickSize optional parameter for specifying that the
15529 * element should move iTickSize pixels at a time.
15531 setYConstraint: function(iUp, iDown, iTickSize) {
15532 this.topConstraint = iUp;
15533 this.bottomConstraint = iDown;
15535 this.minY = this.initPageY - iUp;
15536 this.maxY = this.initPageY + iDown;
15537 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15539 this.constrainY = true;
15544 * resetConstraints must be called if you manually reposition a dd element.
15545 * @method resetConstraints
15546 * @param {boolean} maintainOffset
15548 resetConstraints: function() {
15551 // Maintain offsets if necessary
15552 if (this.initPageX || this.initPageX === 0) {
15553 // figure out how much this thing has moved
15554 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15555 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15557 this.setInitPosition(dx, dy);
15559 // This is the first time we have detected the element's position
15561 this.setInitPosition();
15564 if (this.constrainX) {
15565 this.setXConstraint( this.leftConstraint,
15566 this.rightConstraint,
15570 if (this.constrainY) {
15571 this.setYConstraint( this.topConstraint,
15572 this.bottomConstraint,
15578 * Normally the drag element is moved pixel by pixel, but we can specify
15579 * that it move a number of pixels at a time. This method resolves the
15580 * location when we have it set up like this.
15582 * @param {int} val where we want to place the object
15583 * @param {int[]} tickArray sorted array of valid points
15584 * @return {int} the closest tick
15587 getTick: function(val, tickArray) {
15590 // If tick interval is not defined, it is effectively 1 pixel,
15591 // so we return the value passed to us.
15593 } else if (tickArray[0] >= val) {
15594 // The value is lower than the first tick, so we return the first
15596 return tickArray[0];
15598 for (var i=0, len=tickArray.length; i<len; ++i) {
15600 if (tickArray[next] && tickArray[next] >= val) {
15601 var diff1 = val - tickArray[i];
15602 var diff2 = tickArray[next] - val;
15603 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15607 // The value is larger than the last tick, so we return the last
15609 return tickArray[tickArray.length - 1];
15616 * @return {string} string representation of the dd obj
15618 toString: function() {
15619 return ("DragDrop " + this.id);
15627 * Ext JS Library 1.1.1
15628 * Copyright(c) 2006-2007, Ext JS, LLC.
15630 * Originally Released Under LGPL - original licence link has changed is not relivant.
15633 * <script type="text/javascript">
15638 * The drag and drop utility provides a framework for building drag and drop
15639 * applications. In addition to enabling drag and drop for specific elements,
15640 * the drag and drop elements are tracked by the manager class, and the
15641 * interactions between the various elements are tracked during the drag and
15642 * the implementing code is notified about these important moments.
15645 // Only load the library once. Rewriting the manager class would orphan
15646 // existing drag and drop instances.
15647 if (!Roo.dd.DragDropMgr) {
15650 * @class Roo.dd.DragDropMgr
15651 * DragDropMgr is a singleton that tracks the element interaction for
15652 * all DragDrop items in the window. Generally, you will not call
15653 * this class directly, but it does have helper methods that could
15654 * be useful in your DragDrop implementations.
15657 Roo.dd.DragDropMgr = function() {
15659 var Event = Roo.EventManager;
15664 * Two dimensional Array of registered DragDrop objects. The first
15665 * dimension is the DragDrop item group, the second the DragDrop
15668 * @type {string: string}
15675 * Array of element ids defined as drag handles. Used to determine
15676 * if the element that generated the mousedown event is actually the
15677 * handle and not the html element itself.
15678 * @property handleIds
15679 * @type {string: string}
15686 * the DragDrop object that is currently being dragged
15687 * @property dragCurrent
15695 * the DragDrop object(s) that are being hovered over
15696 * @property dragOvers
15704 * the X distance between the cursor and the object being dragged
15713 * the Y distance between the cursor and the object being dragged
15722 * Flag to determine if we should prevent the default behavior of the
15723 * events we define. By default this is true, but this can be set to
15724 * false if you need the default behavior (not recommended)
15725 * @property preventDefault
15729 preventDefault: true,
15732 * Flag to determine if we should stop the propagation of the events
15733 * we generate. This is true by default but you may want to set it to
15734 * false if the html element contains other features that require the
15736 * @property stopPropagation
15740 stopPropagation: true,
15743 * Internal flag that is set to true when drag and drop has been
15745 * @property initialized
15752 * All drag and drop can be disabled.
15760 * Called the first time an element is registered.
15766 this.initialized = true;
15770 * In point mode, drag and drop interaction is defined by the
15771 * location of the cursor during the drag/drop
15779 * In intersect mode, drag and drop interactio nis defined by the
15780 * overlap of two or more drag and drop objects.
15781 * @property INTERSECT
15788 * The current drag and drop mode. Default: POINT
15796 * Runs method on all drag and drop objects
15797 * @method _execOnAll
15801 _execOnAll: function(sMethod, args) {
15802 for (var i in this.ids) {
15803 for (var j in this.ids[i]) {
15804 var oDD = this.ids[i][j];
15805 if (! this.isTypeOfDD(oDD)) {
15808 oDD[sMethod].apply(oDD, args);
15814 * Drag and drop initialization. Sets up the global event handlers
15819 _onLoad: function() {
15824 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15825 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15826 Event.on(window, "unload", this._onUnload, this, true);
15827 Event.on(window, "resize", this._onResize, this, true);
15828 // Event.on(window, "mouseout", this._test);
15833 * Reset constraints on all drag and drop objs
15834 * @method _onResize
15838 _onResize: function(e) {
15839 this._execOnAll("resetConstraints", []);
15843 * Lock all drag and drop functionality
15847 lock: function() { this.locked = true; },
15850 * Unlock all drag and drop functionality
15854 unlock: function() { this.locked = false; },
15857 * Is drag and drop locked?
15859 * @return {boolean} True if drag and drop is locked, false otherwise.
15862 isLocked: function() { return this.locked; },
15865 * Location cache that is set for all drag drop objects when a drag is
15866 * initiated, cleared when the drag is finished.
15867 * @property locationCache
15874 * Set useCache to false if you want to force object the lookup of each
15875 * drag and drop linked element constantly during a drag.
15876 * @property useCache
15883 * The number of pixels that the mouse needs to move after the
15884 * mousedown before the drag is initiated. Default=3;
15885 * @property clickPixelThresh
15889 clickPixelThresh: 3,
15892 * The number of milliseconds after the mousedown event to initiate the
15893 * drag if we don't get a mouseup event. Default=1000
15894 * @property clickTimeThresh
15898 clickTimeThresh: 350,
15901 * Flag that indicates that either the drag pixel threshold or the
15902 * mousdown time threshold has been met
15903 * @property dragThreshMet
15908 dragThreshMet: false,
15911 * Timeout used for the click time threshold
15912 * @property clickTimeout
15917 clickTimeout: null,
15920 * The X position of the mousedown event stored for later use when a
15921 * drag threshold is met.
15930 * The Y position of the mousedown event stored for later use when a
15931 * drag threshold is met.
15940 * Each DragDrop instance must be registered with the DragDropMgr.
15941 * This is executed in DragDrop.init()
15942 * @method regDragDrop
15943 * @param {DragDrop} oDD the DragDrop object to register
15944 * @param {String} sGroup the name of the group this element belongs to
15947 regDragDrop: function(oDD, sGroup) {
15948 if (!this.initialized) { this.init(); }
15950 if (!this.ids[sGroup]) {
15951 this.ids[sGroup] = {};
15953 this.ids[sGroup][oDD.id] = oDD;
15957 * Removes the supplied dd instance from the supplied group. Executed
15958 * by DragDrop.removeFromGroup, so don't call this function directly.
15959 * @method removeDDFromGroup
15963 removeDDFromGroup: function(oDD, sGroup) {
15964 if (!this.ids[sGroup]) {
15965 this.ids[sGroup] = {};
15968 var obj = this.ids[sGroup];
15969 if (obj && obj[oDD.id]) {
15970 delete obj[oDD.id];
15975 * Unregisters a drag and drop item. This is executed in
15976 * DragDrop.unreg, use that method instead of calling this directly.
15981 _remove: function(oDD) {
15982 for (var g in oDD.groups) {
15983 if (g && this.ids[g][oDD.id]) {
15984 delete this.ids[g][oDD.id];
15987 delete this.handleIds[oDD.id];
15991 * Each DragDrop handle element must be registered. This is done
15992 * automatically when executing DragDrop.setHandleElId()
15993 * @method regHandle
15994 * @param {String} sDDId the DragDrop id this element is a handle for
15995 * @param {String} sHandleId the id of the element that is the drag
15999 regHandle: function(sDDId, sHandleId) {
16000 if (!this.handleIds[sDDId]) {
16001 this.handleIds[sDDId] = {};
16003 this.handleIds[sDDId][sHandleId] = sHandleId;
16007 * Utility function to determine if a given element has been
16008 * registered as a drag drop item.
16009 * @method isDragDrop
16010 * @param {String} id the element id to check
16011 * @return {boolean} true if this element is a DragDrop item,
16015 isDragDrop: function(id) {
16016 return ( this.getDDById(id) ) ? true : false;
16020 * Returns the drag and drop instances that are in all groups the
16021 * passed in instance belongs to.
16022 * @method getRelated
16023 * @param {DragDrop} p_oDD the obj to get related data for
16024 * @param {boolean} bTargetsOnly if true, only return targetable objs
16025 * @return {DragDrop[]} the related instances
16028 getRelated: function(p_oDD, bTargetsOnly) {
16030 for (var i in p_oDD.groups) {
16031 for (j in this.ids[i]) {
16032 var dd = this.ids[i][j];
16033 if (! this.isTypeOfDD(dd)) {
16036 if (!bTargetsOnly || dd.isTarget) {
16037 oDDs[oDDs.length] = dd;
16046 * Returns true if the specified dd target is a legal target for
16047 * the specifice drag obj
16048 * @method isLegalTarget
16049 * @param {DragDrop} the drag obj
16050 * @param {DragDrop} the target
16051 * @return {boolean} true if the target is a legal target for the
16055 isLegalTarget: function (oDD, oTargetDD) {
16056 var targets = this.getRelated(oDD, true);
16057 for (var i=0, len=targets.length;i<len;++i) {
16058 if (targets[i].id == oTargetDD.id) {
16067 * My goal is to be able to transparently determine if an object is
16068 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16069 * returns "object", oDD.constructor.toString() always returns
16070 * "DragDrop" and not the name of the subclass. So for now it just
16071 * evaluates a well-known variable in DragDrop.
16072 * @method isTypeOfDD
16073 * @param {Object} the object to evaluate
16074 * @return {boolean} true if typeof oDD = DragDrop
16077 isTypeOfDD: function (oDD) {
16078 return (oDD && oDD.__ygDragDrop);
16082 * Utility function to determine if a given element has been
16083 * registered as a drag drop handle for the given Drag Drop object.
16085 * @param {String} id the element id to check
16086 * @return {boolean} true if this element is a DragDrop handle, false
16090 isHandle: function(sDDId, sHandleId) {
16091 return ( this.handleIds[sDDId] &&
16092 this.handleIds[sDDId][sHandleId] );
16096 * Returns the DragDrop instance for a given id
16097 * @method getDDById
16098 * @param {String} id the id of the DragDrop object
16099 * @return {DragDrop} the drag drop object, null if it is not found
16102 getDDById: function(id) {
16103 for (var i in this.ids) {
16104 if (this.ids[i][id]) {
16105 return this.ids[i][id];
16112 * Fired after a registered DragDrop object gets the mousedown event.
16113 * Sets up the events required to track the object being dragged
16114 * @method handleMouseDown
16115 * @param {Event} e the event
16116 * @param oDD the DragDrop object being dragged
16120 handleMouseDown: function(e, oDD) {
16122 Roo.QuickTips.disable();
16124 this.currentTarget = e.getTarget();
16126 this.dragCurrent = oDD;
16128 var el = oDD.getEl();
16130 // track start position
16131 this.startX = e.getPageX();
16132 this.startY = e.getPageY();
16134 this.deltaX = this.startX - el.offsetLeft;
16135 this.deltaY = this.startY - el.offsetTop;
16137 this.dragThreshMet = false;
16139 this.clickTimeout = setTimeout(
16141 var DDM = Roo.dd.DDM;
16142 DDM.startDrag(DDM.startX, DDM.startY);
16144 this.clickTimeThresh );
16148 * Fired when either the drag pixel threshol or the mousedown hold
16149 * time threshold has been met.
16150 * @method startDrag
16151 * @param x {int} the X position of the original mousedown
16152 * @param y {int} the Y position of the original mousedown
16155 startDrag: function(x, y) {
16156 clearTimeout(this.clickTimeout);
16157 if (this.dragCurrent) {
16158 this.dragCurrent.b4StartDrag(x, y);
16159 this.dragCurrent.startDrag(x, y);
16161 this.dragThreshMet = true;
16165 * Internal function to handle the mouseup event. Will be invoked
16166 * from the context of the document.
16167 * @method handleMouseUp
16168 * @param {Event} e the event
16172 handleMouseUp: function(e) {
16175 Roo.QuickTips.enable();
16177 if (! this.dragCurrent) {
16181 clearTimeout(this.clickTimeout);
16183 if (this.dragThreshMet) {
16184 this.fireEvents(e, true);
16194 * Utility to stop event propagation and event default, if these
16195 * features are turned on.
16196 * @method stopEvent
16197 * @param {Event} e the event as returned by this.getEvent()
16200 stopEvent: function(e){
16201 if(this.stopPropagation) {
16202 e.stopPropagation();
16205 if (this.preventDefault) {
16206 e.preventDefault();
16211 * Internal function to clean up event handlers after the drag
16212 * operation is complete
16214 * @param {Event} e the event
16218 stopDrag: function(e) {
16219 // Fire the drag end event for the item that was dragged
16220 if (this.dragCurrent) {
16221 if (this.dragThreshMet) {
16222 this.dragCurrent.b4EndDrag(e);
16223 this.dragCurrent.endDrag(e);
16226 this.dragCurrent.onMouseUp(e);
16229 this.dragCurrent = null;
16230 this.dragOvers = {};
16234 * Internal function to handle the mousemove event. Will be invoked
16235 * from the context of the html element.
16237 * @TODO figure out what we can do about mouse events lost when the
16238 * user drags objects beyond the window boundary. Currently we can
16239 * detect this in internet explorer by verifying that the mouse is
16240 * down during the mousemove event. Firefox doesn't give us the
16241 * button state on the mousemove event.
16242 * @method handleMouseMove
16243 * @param {Event} e the event
16247 handleMouseMove: function(e) {
16248 if (! this.dragCurrent) {
16252 // var button = e.which || e.button;
16254 // check for IE mouseup outside of page boundary
16255 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16257 return this.handleMouseUp(e);
16260 if (!this.dragThreshMet) {
16261 var diffX = Math.abs(this.startX - e.getPageX());
16262 var diffY = Math.abs(this.startY - e.getPageY());
16263 if (diffX > this.clickPixelThresh ||
16264 diffY > this.clickPixelThresh) {
16265 this.startDrag(this.startX, this.startY);
16269 if (this.dragThreshMet) {
16270 this.dragCurrent.b4Drag(e);
16271 this.dragCurrent.onDrag(e);
16272 if(!this.dragCurrent.moveOnly){
16273 this.fireEvents(e, false);
16283 * Iterates over all of the DragDrop elements to find ones we are
16284 * hovering over or dropping on
16285 * @method fireEvents
16286 * @param {Event} e the event
16287 * @param {boolean} isDrop is this a drop op or a mouseover op?
16291 fireEvents: function(e, isDrop) {
16292 var dc = this.dragCurrent;
16294 // If the user did the mouse up outside of the window, we could
16295 // get here even though we have ended the drag.
16296 if (!dc || dc.isLocked()) {
16300 var pt = e.getPoint();
16302 // cache the previous dragOver array
16308 var enterEvts = [];
16310 // Check to see if the object(s) we were hovering over is no longer
16311 // being hovered over so we can fire the onDragOut event
16312 for (var i in this.dragOvers) {
16314 var ddo = this.dragOvers[i];
16316 if (! this.isTypeOfDD(ddo)) {
16320 if (! this.isOverTarget(pt, ddo, this.mode)) {
16321 outEvts.push( ddo );
16324 oldOvers[i] = true;
16325 delete this.dragOvers[i];
16328 for (var sGroup in dc.groups) {
16330 if ("string" != typeof sGroup) {
16334 for (i in this.ids[sGroup]) {
16335 var oDD = this.ids[sGroup][i];
16336 if (! this.isTypeOfDD(oDD)) {
16340 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16341 if (this.isOverTarget(pt, oDD, this.mode)) {
16342 // look for drop interactions
16344 dropEvts.push( oDD );
16345 // look for drag enter and drag over interactions
16348 // initial drag over: dragEnter fires
16349 if (!oldOvers[oDD.id]) {
16350 enterEvts.push( oDD );
16351 // subsequent drag overs: dragOver fires
16353 overEvts.push( oDD );
16356 this.dragOvers[oDD.id] = oDD;
16364 if (outEvts.length) {
16365 dc.b4DragOut(e, outEvts);
16366 dc.onDragOut(e, outEvts);
16369 if (enterEvts.length) {
16370 dc.onDragEnter(e, enterEvts);
16373 if (overEvts.length) {
16374 dc.b4DragOver(e, overEvts);
16375 dc.onDragOver(e, overEvts);
16378 if (dropEvts.length) {
16379 dc.b4DragDrop(e, dropEvts);
16380 dc.onDragDrop(e, dropEvts);
16384 // fire dragout events
16386 for (i=0, len=outEvts.length; i<len; ++i) {
16387 dc.b4DragOut(e, outEvts[i].id);
16388 dc.onDragOut(e, outEvts[i].id);
16391 // fire enter events
16392 for (i=0,len=enterEvts.length; i<len; ++i) {
16393 // dc.b4DragEnter(e, oDD.id);
16394 dc.onDragEnter(e, enterEvts[i].id);
16397 // fire over events
16398 for (i=0,len=overEvts.length; i<len; ++i) {
16399 dc.b4DragOver(e, overEvts[i].id);
16400 dc.onDragOver(e, overEvts[i].id);
16403 // fire drop events
16404 for (i=0, len=dropEvts.length; i<len; ++i) {
16405 dc.b4DragDrop(e, dropEvts[i].id);
16406 dc.onDragDrop(e, dropEvts[i].id);
16411 // notify about a drop that did not find a target
16412 if (isDrop && !dropEvts.length) {
16413 dc.onInvalidDrop(e);
16419 * Helper function for getting the best match from the list of drag
16420 * and drop objects returned by the drag and drop events when we are
16421 * in INTERSECT mode. It returns either the first object that the
16422 * cursor is over, or the object that has the greatest overlap with
16423 * the dragged element.
16424 * @method getBestMatch
16425 * @param {DragDrop[]} dds The array of drag and drop objects
16427 * @return {DragDrop} The best single match
16430 getBestMatch: function(dds) {
16432 // Return null if the input is not what we expect
16433 //if (!dds || !dds.length || dds.length == 0) {
16435 // If there is only one item, it wins
16436 //} else if (dds.length == 1) {
16438 var len = dds.length;
16443 // Loop through the targeted items
16444 for (var i=0; i<len; ++i) {
16446 // If the cursor is over the object, it wins. If the
16447 // cursor is over multiple matches, the first one we come
16449 if (dd.cursorIsOver) {
16452 // Otherwise the object with the most overlap wins
16455 winner.overlap.getArea() < dd.overlap.getArea()) {
16466 * Refreshes the cache of the top-left and bottom-right points of the
16467 * drag and drop objects in the specified group(s). This is in the
16468 * format that is stored in the drag and drop instance, so typical
16471 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16475 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16477 * @TODO this really should be an indexed array. Alternatively this
16478 * method could accept both.
16479 * @method refreshCache
16480 * @param {Object} groups an associative array of groups to refresh
16483 refreshCache: function(groups) {
16484 for (var sGroup in groups) {
16485 if ("string" != typeof sGroup) {
16488 for (var i in this.ids[sGroup]) {
16489 var oDD = this.ids[sGroup][i];
16491 if (this.isTypeOfDD(oDD)) {
16492 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16493 var loc = this.getLocation(oDD);
16495 this.locationCache[oDD.id] = loc;
16497 delete this.locationCache[oDD.id];
16498 // this will unregister the drag and drop object if
16499 // the element is not in a usable state
16508 * This checks to make sure an element exists and is in the DOM. The
16509 * main purpose is to handle cases where innerHTML is used to remove
16510 * drag and drop objects from the DOM. IE provides an 'unspecified
16511 * error' when trying to access the offsetParent of such an element
16513 * @param {HTMLElement} el the element to check
16514 * @return {boolean} true if the element looks usable
16517 verifyEl: function(el) {
16522 parent = el.offsetParent;
16525 parent = el.offsetParent;
16536 * Returns a Region object containing the drag and drop element's position
16537 * and size, including the padding configured for it
16538 * @method getLocation
16539 * @param {DragDrop} oDD the drag and drop object to get the
16541 * @return {Roo.lib.Region} a Region object representing the total area
16542 * the element occupies, including any padding
16543 * the instance is configured for.
16546 getLocation: function(oDD) {
16547 if (! this.isTypeOfDD(oDD)) {
16551 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16554 pos= Roo.lib.Dom.getXY(el);
16562 x2 = x1 + el.offsetWidth;
16564 y2 = y1 + el.offsetHeight;
16566 t = y1 - oDD.padding[0];
16567 r = x2 + oDD.padding[1];
16568 b = y2 + oDD.padding[2];
16569 l = x1 - oDD.padding[3];
16571 return new Roo.lib.Region( t, r, b, l );
16575 * Checks the cursor location to see if it over the target
16576 * @method isOverTarget
16577 * @param {Roo.lib.Point} pt The point to evaluate
16578 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16579 * @return {boolean} true if the mouse is over the target
16583 isOverTarget: function(pt, oTarget, intersect) {
16584 // use cache if available
16585 var loc = this.locationCache[oTarget.id];
16586 if (!loc || !this.useCache) {
16587 loc = this.getLocation(oTarget);
16588 this.locationCache[oTarget.id] = loc;
16596 oTarget.cursorIsOver = loc.contains( pt );
16598 // DragDrop is using this as a sanity check for the initial mousedown
16599 // in this case we are done. In POINT mode, if the drag obj has no
16600 // contraints, we are also done. Otherwise we need to evaluate the
16601 // location of the target as related to the actual location of the
16602 // dragged element.
16603 var dc = this.dragCurrent;
16604 if (!dc || !dc.getTargetCoord ||
16605 (!intersect && !dc.constrainX && !dc.constrainY)) {
16606 return oTarget.cursorIsOver;
16609 oTarget.overlap = null;
16611 // Get the current location of the drag element, this is the
16612 // location of the mouse event less the delta that represents
16613 // where the original mousedown happened on the element. We
16614 // need to consider constraints and ticks as well.
16615 var pos = dc.getTargetCoord(pt.x, pt.y);
16617 var el = dc.getDragEl();
16618 var curRegion = new Roo.lib.Region( pos.y,
16619 pos.x + el.offsetWidth,
16620 pos.y + el.offsetHeight,
16623 var overlap = curRegion.intersect(loc);
16626 oTarget.overlap = overlap;
16627 return (intersect) ? true : oTarget.cursorIsOver;
16634 * unload event handler
16635 * @method _onUnload
16639 _onUnload: function(e, me) {
16640 Roo.dd.DragDropMgr.unregAll();
16644 * Cleans up the drag and drop events and objects.
16649 unregAll: function() {
16651 if (this.dragCurrent) {
16653 this.dragCurrent = null;
16656 this._execOnAll("unreg", []);
16658 for (i in this.elementCache) {
16659 delete this.elementCache[i];
16662 this.elementCache = {};
16667 * A cache of DOM elements
16668 * @property elementCache
16675 * Get the wrapper for the DOM element specified
16676 * @method getElWrapper
16677 * @param {String} id the id of the element to get
16678 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16680 * @deprecated This wrapper isn't that useful
16683 getElWrapper: function(id) {
16684 var oWrapper = this.elementCache[id];
16685 if (!oWrapper || !oWrapper.el) {
16686 oWrapper = this.elementCache[id] =
16687 new this.ElementWrapper(Roo.getDom(id));
16693 * Returns the actual DOM element
16694 * @method getElement
16695 * @param {String} id the id of the elment to get
16696 * @return {Object} The element
16697 * @deprecated use Roo.getDom instead
16700 getElement: function(id) {
16701 return Roo.getDom(id);
16705 * Returns the style property for the DOM element (i.e.,
16706 * document.getElById(id).style)
16708 * @param {String} id the id of the elment to get
16709 * @return {Object} The style property of the element
16710 * @deprecated use Roo.getDom instead
16713 getCss: function(id) {
16714 var el = Roo.getDom(id);
16715 return (el) ? el.style : null;
16719 * Inner class for cached elements
16720 * @class DragDropMgr.ElementWrapper
16725 ElementWrapper: function(el) {
16730 this.el = el || null;
16735 this.id = this.el && el.id;
16737 * A reference to the style property
16740 this.css = this.el && el.style;
16744 * Returns the X position of an html element
16746 * @param el the element for which to get the position
16747 * @return {int} the X coordinate
16749 * @deprecated use Roo.lib.Dom.getX instead
16752 getPosX: function(el) {
16753 return Roo.lib.Dom.getX(el);
16757 * Returns the Y position of an html element
16759 * @param el the element for which to get the position
16760 * @return {int} the Y coordinate
16761 * @deprecated use Roo.lib.Dom.getY instead
16764 getPosY: function(el) {
16765 return Roo.lib.Dom.getY(el);
16769 * Swap two nodes. In IE, we use the native method, for others we
16770 * emulate the IE behavior
16772 * @param n1 the first node to swap
16773 * @param n2 the other node to swap
16776 swapNode: function(n1, n2) {
16780 var p = n2.parentNode;
16781 var s = n2.nextSibling;
16784 p.insertBefore(n1, n2);
16785 } else if (n2 == n1.nextSibling) {
16786 p.insertBefore(n2, n1);
16788 n1.parentNode.replaceChild(n2, n1);
16789 p.insertBefore(n1, s);
16795 * Returns the current scroll position
16796 * @method getScroll
16800 getScroll: function () {
16801 var t, l, dde=document.documentElement, db=document.body;
16802 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16804 l = dde.scrollLeft;
16811 return { top: t, left: l };
16815 * Returns the specified element style property
16817 * @param {HTMLElement} el the element
16818 * @param {string} styleProp the style property
16819 * @return {string} The value of the style property
16820 * @deprecated use Roo.lib.Dom.getStyle
16823 getStyle: function(el, styleProp) {
16824 return Roo.fly(el).getStyle(styleProp);
16828 * Gets the scrollTop
16829 * @method getScrollTop
16830 * @return {int} the document's scrollTop
16833 getScrollTop: function () { return this.getScroll().top; },
16836 * Gets the scrollLeft
16837 * @method getScrollLeft
16838 * @return {int} the document's scrollTop
16841 getScrollLeft: function () { return this.getScroll().left; },
16844 * Sets the x/y position of an element to the location of the
16847 * @param {HTMLElement} moveEl The element to move
16848 * @param {HTMLElement} targetEl The position reference element
16851 moveToEl: function (moveEl, targetEl) {
16852 var aCoord = Roo.lib.Dom.getXY(targetEl);
16853 Roo.lib.Dom.setXY(moveEl, aCoord);
16857 * Numeric array sort function
16858 * @method numericSort
16861 numericSort: function(a, b) { return (a - b); },
16865 * @property _timeoutCount
16872 * Trying to make the load order less important. Without this we get
16873 * an error if this file is loaded before the Event Utility.
16874 * @method _addListeners
16878 _addListeners: function() {
16879 var DDM = Roo.dd.DDM;
16880 if ( Roo.lib.Event && document ) {
16883 if (DDM._timeoutCount > 2000) {
16885 setTimeout(DDM._addListeners, 10);
16886 if (document && document.body) {
16887 DDM._timeoutCount += 1;
16894 * Recursively searches the immediate parent and all child nodes for
16895 * the handle element in order to determine wheter or not it was
16897 * @method handleWasClicked
16898 * @param node the html element to inspect
16901 handleWasClicked: function(node, id) {
16902 if (this.isHandle(id, node.id)) {
16905 // check to see if this is a text node child of the one we want
16906 var p = node.parentNode;
16909 if (this.isHandle(id, p.id)) {
16924 // shorter alias, save a few bytes
16925 Roo.dd.DDM = Roo.dd.DragDropMgr;
16926 Roo.dd.DDM._addListeners();
16930 * Ext JS Library 1.1.1
16931 * Copyright(c) 2006-2007, Ext JS, LLC.
16933 * Originally Released Under LGPL - original licence link has changed is not relivant.
16936 * <script type="text/javascript">
16941 * A DragDrop implementation where the linked element follows the
16942 * mouse cursor during a drag.
16943 * @extends Roo.dd.DragDrop
16945 * @param {String} id the id of the linked element
16946 * @param {String} sGroup the group of related DragDrop items
16947 * @param {object} config an object containing configurable attributes
16948 * Valid properties for DD:
16951 Roo.dd.DD = function(id, sGroup, config) {
16953 this.init(id, sGroup, config);
16957 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16960 * When set to true, the utility automatically tries to scroll the browser
16961 * window wehn a drag and drop element is dragged near the viewport boundary.
16962 * Defaults to true.
16969 * Sets the pointer offset to the distance between the linked element's top
16970 * left corner and the location the element was clicked
16971 * @method autoOffset
16972 * @param {int} iPageX the X coordinate of the click
16973 * @param {int} iPageY the Y coordinate of the click
16975 autoOffset: function(iPageX, iPageY) {
16976 var x = iPageX - this.startPageX;
16977 var y = iPageY - this.startPageY;
16978 this.setDelta(x, y);
16982 * Sets the pointer offset. You can call this directly to force the
16983 * offset to be in a particular location (e.g., pass in 0,0 to set it
16984 * to the center of the object)
16986 * @param {int} iDeltaX the distance from the left
16987 * @param {int} iDeltaY the distance from the top
16989 setDelta: function(iDeltaX, iDeltaY) {
16990 this.deltaX = iDeltaX;
16991 this.deltaY = iDeltaY;
16995 * Sets the drag element to the location of the mousedown or click event,
16996 * maintaining the cursor location relative to the location on the element
16997 * that was clicked. Override this if you want to place the element in a
16998 * location other than where the cursor is.
16999 * @method setDragElPos
17000 * @param {int} iPageX the X coordinate of the mousedown or drag event
17001 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17003 setDragElPos: function(iPageX, iPageY) {
17004 // the first time we do this, we are going to check to make sure
17005 // the element has css positioning
17007 var el = this.getDragEl();
17008 this.alignElWithMouse(el, iPageX, iPageY);
17012 * Sets the element to the location of the mousedown or click event,
17013 * maintaining the cursor location relative to the location on the element
17014 * that was clicked. Override this if you want to place the element in a
17015 * location other than where the cursor is.
17016 * @method alignElWithMouse
17017 * @param {HTMLElement} el the element to move
17018 * @param {int} iPageX the X coordinate of the mousedown or drag event
17019 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17021 alignElWithMouse: function(el, iPageX, iPageY) {
17022 var oCoord = this.getTargetCoord(iPageX, iPageY);
17023 var fly = el.dom ? el : Roo.fly(el);
17024 if (!this.deltaSetXY) {
17025 var aCoord = [oCoord.x, oCoord.y];
17027 var newLeft = fly.getLeft(true);
17028 var newTop = fly.getTop(true);
17029 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
17031 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
17034 this.cachePosition(oCoord.x, oCoord.y);
17035 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
17040 * Saves the most recent position so that we can reset the constraints and
17041 * tick marks on-demand. We need to know this so that we can calculate the
17042 * number of pixels the element is offset from its original position.
17043 * @method cachePosition
17044 * @param iPageX the current x position (optional, this just makes it so we
17045 * don't have to look it up again)
17046 * @param iPageY the current y position (optional, this just makes it so we
17047 * don't have to look it up again)
17049 cachePosition: function(iPageX, iPageY) {
17051 this.lastPageX = iPageX;
17052 this.lastPageY = iPageY;
17054 var aCoord = Roo.lib.Dom.getXY(this.getEl());
17055 this.lastPageX = aCoord[0];
17056 this.lastPageY = aCoord[1];
17061 * Auto-scroll the window if the dragged object has been moved beyond the
17062 * visible window boundary.
17063 * @method autoScroll
17064 * @param {int} x the drag element's x position
17065 * @param {int} y the drag element's y position
17066 * @param {int} h the height of the drag element
17067 * @param {int} w the width of the drag element
17070 autoScroll: function(x, y, h, w) {
17073 // The client height
17074 var clientH = Roo.lib.Dom.getViewWidth();
17076 // The client width
17077 var clientW = Roo.lib.Dom.getViewHeight();
17079 // The amt scrolled down
17080 var st = this.DDM.getScrollTop();
17082 // The amt scrolled right
17083 var sl = this.DDM.getScrollLeft();
17085 // Location of the bottom of the element
17088 // Location of the right of the element
17091 // The distance from the cursor to the bottom of the visible area,
17092 // adjusted so that we don't scroll if the cursor is beyond the
17093 // element drag constraints
17094 var toBot = (clientH + st - y - this.deltaY);
17096 // The distance from the cursor to the right of the visible area
17097 var toRight = (clientW + sl - x - this.deltaX);
17100 // How close to the edge the cursor must be before we scroll
17101 // var thresh = (document.all) ? 100 : 40;
17104 // How many pixels to scroll per autoscroll op. This helps to reduce
17105 // clunky scrolling. IE is more sensitive about this ... it needs this
17106 // value to be higher.
17107 var scrAmt = (document.all) ? 80 : 30;
17109 // Scroll down if we are near the bottom of the visible page and the
17110 // obj extends below the crease
17111 if ( bot > clientH && toBot < thresh ) {
17112 window.scrollTo(sl, st + scrAmt);
17115 // Scroll up if the window is scrolled down and the top of the object
17116 // goes above the top border
17117 if ( y < st && st > 0 && y - st < thresh ) {
17118 window.scrollTo(sl, st - scrAmt);
17121 // Scroll right if the obj is beyond the right border and the cursor is
17122 // near the border.
17123 if ( right > clientW && toRight < thresh ) {
17124 window.scrollTo(sl + scrAmt, st);
17127 // Scroll left if the window has been scrolled to the right and the obj
17128 // extends past the left border
17129 if ( x < sl && sl > 0 && x - sl < thresh ) {
17130 window.scrollTo(sl - scrAmt, st);
17136 * Finds the location the element should be placed if we want to move
17137 * it to where the mouse location less the click offset would place us.
17138 * @method getTargetCoord
17139 * @param {int} iPageX the X coordinate of the click
17140 * @param {int} iPageY the Y coordinate of the click
17141 * @return an object that contains the coordinates (Object.x and Object.y)
17144 getTargetCoord: function(iPageX, iPageY) {
17147 var x = iPageX - this.deltaX;
17148 var y = iPageY - this.deltaY;
17150 if (this.constrainX) {
17151 if (x < this.minX) { x = this.minX; }
17152 if (x > this.maxX) { x = this.maxX; }
17155 if (this.constrainY) {
17156 if (y < this.minY) { y = this.minY; }
17157 if (y > this.maxY) { y = this.maxY; }
17160 x = this.getTick(x, this.xTicks);
17161 y = this.getTick(y, this.yTicks);
17168 * Sets up config options specific to this class. Overrides
17169 * Roo.dd.DragDrop, but all versions of this method through the
17170 * inheritance chain are called
17172 applyConfig: function() {
17173 Roo.dd.DD.superclass.applyConfig.call(this);
17174 this.scroll = (this.config.scroll !== false);
17178 * Event that fires prior to the onMouseDown event. Overrides
17181 b4MouseDown: function(e) {
17182 // this.resetConstraints();
17183 this.autoOffset(e.getPageX(),
17188 * Event that fires prior to the onDrag event. Overrides
17191 b4Drag: function(e) {
17192 this.setDragElPos(e.getPageX(),
17196 toString: function() {
17197 return ("DD " + this.id);
17200 //////////////////////////////////////////////////////////////////////////
17201 // Debugging ygDragDrop events that can be overridden
17202 //////////////////////////////////////////////////////////////////////////
17204 startDrag: function(x, y) {
17207 onDrag: function(e) {
17210 onDragEnter: function(e, id) {
17213 onDragOver: function(e, id) {
17216 onDragOut: function(e, id) {
17219 onDragDrop: function(e, id) {
17222 endDrag: function(e) {
17229 * Ext JS Library 1.1.1
17230 * Copyright(c) 2006-2007, Ext JS, LLC.
17232 * Originally Released Under LGPL - original licence link has changed is not relivant.
17235 * <script type="text/javascript">
17239 * @class Roo.dd.DDProxy
17240 * A DragDrop implementation that inserts an empty, bordered div into
17241 * the document that follows the cursor during drag operations. At the time of
17242 * the click, the frame div is resized to the dimensions of the linked html
17243 * element, and moved to the exact location of the linked element.
17245 * References to the "frame" element refer to the single proxy element that
17246 * was created to be dragged in place of all DDProxy elements on the
17249 * @extends Roo.dd.DD
17251 * @param {String} id the id of the linked html element
17252 * @param {String} sGroup the group of related DragDrop objects
17253 * @param {object} config an object containing configurable attributes
17254 * Valid properties for DDProxy in addition to those in DragDrop:
17255 * resizeFrame, centerFrame, dragElId
17257 Roo.dd.DDProxy = function(id, sGroup, config) {
17259 this.init(id, sGroup, config);
17265 * The default drag frame div id
17266 * @property Roo.dd.DDProxy.dragElId
17270 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17272 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17275 * By default we resize the drag frame to be the same size as the element
17276 * we want to drag (this is to get the frame effect). We can turn it off
17277 * if we want a different behavior.
17278 * @property resizeFrame
17284 * By default the frame is positioned exactly where the drag element is, so
17285 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17286 * you do not have constraints on the obj is to have the drag frame centered
17287 * around the cursor. Set centerFrame to true for this effect.
17288 * @property centerFrame
17291 centerFrame: false,
17294 * Creates the proxy element if it does not yet exist
17295 * @method createFrame
17297 createFrame: function() {
17299 var body = document.body;
17301 if (!body || !body.firstChild) {
17302 setTimeout( function() { self.createFrame(); }, 50 );
17306 var div = this.getDragEl();
17309 div = document.createElement("div");
17310 div.id = this.dragElId;
17313 s.position = "absolute";
17314 s.visibility = "hidden";
17316 s.border = "2px solid #aaa";
17319 // appendChild can blow up IE if invoked prior to the window load event
17320 // while rendering a table. It is possible there are other scenarios
17321 // that would cause this to happen as well.
17322 body.insertBefore(div, body.firstChild);
17327 * Initialization for the drag frame element. Must be called in the
17328 * constructor of all subclasses
17329 * @method initFrame
17331 initFrame: function() {
17332 this.createFrame();
17335 applyConfig: function() {
17336 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17338 this.resizeFrame = (this.config.resizeFrame !== false);
17339 this.centerFrame = (this.config.centerFrame);
17340 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17344 * Resizes the drag frame to the dimensions of the clicked object, positions
17345 * it over the object, and finally displays it
17346 * @method showFrame
17347 * @param {int} iPageX X click position
17348 * @param {int} iPageY Y click position
17351 showFrame: function(iPageX, iPageY) {
17352 var el = this.getEl();
17353 var dragEl = this.getDragEl();
17354 var s = dragEl.style;
17356 this._resizeProxy();
17358 if (this.centerFrame) {
17359 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17360 Math.round(parseInt(s.height, 10)/2) );
17363 this.setDragElPos(iPageX, iPageY);
17365 Roo.fly(dragEl).show();
17369 * The proxy is automatically resized to the dimensions of the linked
17370 * element when a drag is initiated, unless resizeFrame is set to false
17371 * @method _resizeProxy
17374 _resizeProxy: function() {
17375 if (this.resizeFrame) {
17376 var el = this.getEl();
17377 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17381 // overrides Roo.dd.DragDrop
17382 b4MouseDown: function(e) {
17383 var x = e.getPageX();
17384 var y = e.getPageY();
17385 this.autoOffset(x, y);
17386 this.setDragElPos(x, y);
17389 // overrides Roo.dd.DragDrop
17390 b4StartDrag: function(x, y) {
17391 // show the drag frame
17392 this.showFrame(x, y);
17395 // overrides Roo.dd.DragDrop
17396 b4EndDrag: function(e) {
17397 Roo.fly(this.getDragEl()).hide();
17400 // overrides Roo.dd.DragDrop
17401 // By default we try to move the element to the last location of the frame.
17402 // This is so that the default behavior mirrors that of Roo.dd.DD.
17403 endDrag: function(e) {
17405 var lel = this.getEl();
17406 var del = this.getDragEl();
17408 // Show the drag frame briefly so we can get its position
17409 del.style.visibility = "";
17412 // Hide the linked element before the move to get around a Safari
17414 lel.style.visibility = "hidden";
17415 Roo.dd.DDM.moveToEl(lel, del);
17416 del.style.visibility = "hidden";
17417 lel.style.visibility = "";
17422 beforeMove : function(){
17426 afterDrag : function(){
17430 toString: function() {
17431 return ("DDProxy " + this.id);
17437 * Ext JS Library 1.1.1
17438 * Copyright(c) 2006-2007, Ext JS, LLC.
17440 * Originally Released Under LGPL - original licence link has changed is not relivant.
17443 * <script type="text/javascript">
17447 * @class Roo.dd.DDTarget
17448 * A DragDrop implementation that does not move, but can be a drop
17449 * target. You would get the same result by simply omitting implementation
17450 * for the event callbacks, but this way we reduce the processing cost of the
17451 * event listener and the callbacks.
17452 * @extends Roo.dd.DragDrop
17454 * @param {String} id the id of the element that is a drop target
17455 * @param {String} sGroup the group of related DragDrop objects
17456 * @param {object} config an object containing configurable attributes
17457 * Valid properties for DDTarget in addition to those in
17461 Roo.dd.DDTarget = function(id, sGroup, config) {
17463 this.initTarget(id, sGroup, config);
17465 if (config.listeners || config.events) {
17466 Roo.dd.DragDrop.superclass.constructor.call(this, {
17467 listeners : config.listeners || {},
17468 events : config.events || {}
17473 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17474 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17475 toString: function() {
17476 return ("DDTarget " + this.id);
17481 * Ext JS Library 1.1.1
17482 * Copyright(c) 2006-2007, Ext JS, LLC.
17484 * Originally Released Under LGPL - original licence link has changed is not relivant.
17487 * <script type="text/javascript">
17492 * @class Roo.dd.ScrollManager
17493 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17494 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17497 Roo.dd.ScrollManager = function(){
17498 var ddm = Roo.dd.DragDropMgr;
17503 var onStop = function(e){
17508 var triggerRefresh = function(){
17509 if(ddm.dragCurrent){
17510 ddm.refreshCache(ddm.dragCurrent.groups);
17514 var doScroll = function(){
17515 if(ddm.dragCurrent){
17516 var dds = Roo.dd.ScrollManager;
17518 if(proc.el.scroll(proc.dir, dds.increment)){
17522 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17527 var clearProc = function(){
17529 clearInterval(proc.id);
17536 var startProc = function(el, dir){
17540 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17543 var onFire = function(e, isDrop){
17544 if(isDrop || !ddm.dragCurrent){ return; }
17545 var dds = Roo.dd.ScrollManager;
17546 if(!dragEl || dragEl != ddm.dragCurrent){
17547 dragEl = ddm.dragCurrent;
17548 // refresh regions on drag start
17549 dds.refreshCache();
17552 var xy = Roo.lib.Event.getXY(e);
17553 var pt = new Roo.lib.Point(xy[0], xy[1]);
17554 for(var id in els){
17555 var el = els[id], r = el._region;
17556 if(r && r.contains(pt) && el.isScrollable()){
17557 if(r.bottom - pt.y <= dds.thresh){
17559 startProc(el, "down");
17562 }else if(r.right - pt.x <= dds.thresh){
17564 startProc(el, "left");
17567 }else if(pt.y - r.top <= dds.thresh){
17569 startProc(el, "up");
17572 }else if(pt.x - r.left <= dds.thresh){
17574 startProc(el, "right");
17583 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17584 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17588 * Registers new overflow element(s) to auto scroll
17589 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17591 register : function(el){
17592 if(el instanceof Array){
17593 for(var i = 0, len = el.length; i < len; i++) {
17594 this.register(el[i]);
17603 * Unregisters overflow element(s) so they are no longer scrolled
17604 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17606 unregister : function(el){
17607 if(el instanceof Array){
17608 for(var i = 0, len = el.length; i < len; i++) {
17609 this.unregister(el[i]);
17618 * The number of pixels from the edge of a container the pointer needs to be to
17619 * trigger scrolling (defaults to 25)
17625 * The number of pixels to scroll in each scroll increment (defaults to 50)
17631 * The frequency of scrolls in milliseconds (defaults to 500)
17637 * True to animate the scroll (defaults to true)
17643 * The animation duration in seconds -
17644 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17650 * Manually trigger a cache refresh.
17652 refreshCache : function(){
17653 for(var id in els){
17654 if(typeof els[id] == 'object'){ // for people extending the object prototype
17655 els[id]._region = els[id].getRegion();
17662 * Ext JS Library 1.1.1
17663 * Copyright(c) 2006-2007, Ext JS, LLC.
17665 * Originally Released Under LGPL - original licence link has changed is not relivant.
17668 * <script type="text/javascript">
17673 * @class Roo.dd.Registry
17674 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17675 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17678 Roo.dd.Registry = function(){
17681 var autoIdSeed = 0;
17683 var getId = function(el, autogen){
17684 if(typeof el == "string"){
17688 if(!id && autogen !== false){
17689 id = "roodd-" + (++autoIdSeed);
17697 * Register a drag drop element
17698 * @param {String|HTMLElement} element The id or DOM node to register
17699 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17700 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17701 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17702 * populated in the data object (if applicable):
17704 Value Description<br />
17705 --------- ------------------------------------------<br />
17706 handles Array of DOM nodes that trigger dragging<br />
17707 for the element being registered<br />
17708 isHandle True if the element passed in triggers<br />
17709 dragging itself, else false
17712 register : function(el, data){
17714 if(typeof el == "string"){
17715 el = document.getElementById(el);
17718 elements[getId(el)] = data;
17719 if(data.isHandle !== false){
17720 handles[data.ddel.id] = data;
17723 var hs = data.handles;
17724 for(var i = 0, len = hs.length; i < len; i++){
17725 handles[getId(hs[i])] = data;
17731 * Unregister a drag drop element
17732 * @param {String|HTMLElement} element The id or DOM node to unregister
17734 unregister : function(el){
17735 var id = getId(el, false);
17736 var data = elements[id];
17738 delete elements[id];
17740 var hs = data.handles;
17741 for(var i = 0, len = hs.length; i < len; i++){
17742 delete handles[getId(hs[i], false)];
17749 * Returns the handle registered for a DOM Node by id
17750 * @param {String|HTMLElement} id The DOM node or id to look up
17751 * @return {Object} handle The custom handle data
17753 getHandle : function(id){
17754 if(typeof id != "string"){ // must be element?
17757 return handles[id];
17761 * Returns the handle that is registered for the DOM node that is the target of the event
17762 * @param {Event} e The event
17763 * @return {Object} handle The custom handle data
17765 getHandleFromEvent : function(e){
17766 var t = Roo.lib.Event.getTarget(e);
17767 return t ? handles[t.id] : null;
17771 * Returns a custom data object that is registered for a DOM node by id
17772 * @param {String|HTMLElement} id The DOM node or id to look up
17773 * @return {Object} data The custom data
17775 getTarget : function(id){
17776 if(typeof id != "string"){ // must be element?
17779 return elements[id];
17783 * Returns a custom data object that is registered for the DOM node that is the target of the event
17784 * @param {Event} e The event
17785 * @return {Object} data The custom data
17787 getTargetFromEvent : function(e){
17788 var t = Roo.lib.Event.getTarget(e);
17789 return t ? elements[t.id] || handles[t.id] : null;
17794 * Ext JS Library 1.1.1
17795 * Copyright(c) 2006-2007, Ext JS, LLC.
17797 * Originally Released Under LGPL - original licence link has changed is not relivant.
17800 * <script type="text/javascript">
17805 * @class Roo.dd.StatusProxy
17806 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17807 * default drag proxy used by all Roo.dd components.
17809 * @param {Object} config
17811 Roo.dd.StatusProxy = function(config){
17812 Roo.apply(this, config);
17813 this.id = this.id || Roo.id();
17814 this.el = new Roo.Layer({
17816 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17817 {tag: "div", cls: "x-dd-drop-icon"},
17818 {tag: "div", cls: "x-dd-drag-ghost"}
17821 shadow: !config || config.shadow !== false
17823 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17824 this.dropStatus = this.dropNotAllowed;
17827 Roo.dd.StatusProxy.prototype = {
17829 * @cfg {String} dropAllowed
17830 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17832 dropAllowed : "x-dd-drop-ok",
17834 * @cfg {String} dropNotAllowed
17835 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17837 dropNotAllowed : "x-dd-drop-nodrop",
17840 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17841 * over the current target element.
17842 * @param {String} cssClass The css class for the new drop status indicator image
17844 setStatus : function(cssClass){
17845 cssClass = cssClass || this.dropNotAllowed;
17846 if(this.dropStatus != cssClass){
17847 this.el.replaceClass(this.dropStatus, cssClass);
17848 this.dropStatus = cssClass;
17853 * Resets the status indicator to the default dropNotAllowed value
17854 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17856 reset : function(clearGhost){
17857 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17858 this.dropStatus = this.dropNotAllowed;
17860 this.ghost.update("");
17865 * Updates the contents of the ghost element
17866 * @param {String} html The html that will replace the current innerHTML of the ghost element
17868 update : function(html){
17869 if(typeof html == "string"){
17870 this.ghost.update(html);
17872 this.ghost.update("");
17873 html.style.margin = "0";
17874 this.ghost.dom.appendChild(html);
17876 // ensure float = none set?? cant remember why though.
17877 var el = this.ghost.dom.firstChild;
17879 Roo.fly(el).setStyle('float', 'none');
17884 * Returns the underlying proxy {@link Roo.Layer}
17885 * @return {Roo.Layer} el
17887 getEl : function(){
17892 * Returns the ghost element
17893 * @return {Roo.Element} el
17895 getGhost : function(){
17901 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17903 hide : function(clear){
17911 * Stops the repair animation if it's currently running
17914 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17920 * Displays this proxy
17927 * Force the Layer to sync its shadow and shim positions to the element
17934 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17935 * invalid drop operation by the item being dragged.
17936 * @param {Array} xy The XY position of the element ([x, y])
17937 * @param {Function} callback The function to call after the repair is complete
17938 * @param {Object} scope The scope in which to execute the callback
17940 repair : function(xy, callback, scope){
17941 this.callback = callback;
17942 this.scope = scope;
17943 if(xy && this.animRepair !== false){
17944 this.el.addClass("x-dd-drag-repair");
17945 this.el.hideUnders(true);
17946 this.anim = this.el.shift({
17947 duration: this.repairDuration || .5,
17951 callback: this.afterRepair,
17955 this.afterRepair();
17960 afterRepair : function(){
17962 if(typeof this.callback == "function"){
17963 this.callback.call(this.scope || this);
17965 this.callback = null;
17970 * Ext JS Library 1.1.1
17971 * Copyright(c) 2006-2007, Ext JS, LLC.
17973 * Originally Released Under LGPL - original licence link has changed is not relivant.
17976 * <script type="text/javascript">
17980 * @class Roo.dd.DragSource
17981 * @extends Roo.dd.DDProxy
17982 * A simple class that provides the basic implementation needed to make any element draggable.
17984 * @param {String/HTMLElement/Element} el The container element
17985 * @param {Object} config
17987 Roo.dd.DragSource = function(el, config){
17988 this.el = Roo.get(el);
17989 this.dragData = {};
17991 Roo.apply(this, config);
17994 this.proxy = new Roo.dd.StatusProxy();
17997 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
17998 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
18000 this.dragging = false;
18003 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
18005 * @cfg {String} dropAllowed
18006 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18008 dropAllowed : "x-dd-drop-ok",
18010 * @cfg {String} dropNotAllowed
18011 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18013 dropNotAllowed : "x-dd-drop-nodrop",
18016 * Returns the data object associated with this drag source
18017 * @return {Object} data An object containing arbitrary data
18019 getDragData : function(e){
18020 return this.dragData;
18024 onDragEnter : function(e, id){
18025 var target = Roo.dd.DragDropMgr.getDDById(id);
18026 this.cachedTarget = target;
18027 if(this.beforeDragEnter(target, e, id) !== false){
18028 if(target.isNotifyTarget){
18029 var status = target.notifyEnter(this, e, this.dragData);
18030 this.proxy.setStatus(status);
18032 this.proxy.setStatus(this.dropAllowed);
18035 if(this.afterDragEnter){
18037 * An empty function by default, but provided so that you can perform a custom action
18038 * when the dragged item enters the drop target by providing an implementation.
18039 * @param {Roo.dd.DragDrop} target The drop target
18040 * @param {Event} e The event object
18041 * @param {String} id The id of the dragged element
18042 * @method afterDragEnter
18044 this.afterDragEnter(target, e, id);
18050 * An empty function by default, but provided so that you can perform a custom action
18051 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
18052 * @param {Roo.dd.DragDrop} target The drop target
18053 * @param {Event} e The event object
18054 * @param {String} id The id of the dragged element
18055 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18057 beforeDragEnter : function(target, e, id){
18062 alignElWithMouse: function() {
18063 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18068 onDragOver : function(e, id){
18069 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18070 if(this.beforeDragOver(target, e, id) !== false){
18071 if(target.isNotifyTarget){
18072 var status = target.notifyOver(this, e, this.dragData);
18073 this.proxy.setStatus(status);
18076 if(this.afterDragOver){
18078 * An empty function by default, but provided so that you can perform a custom action
18079 * while the dragged item is over the drop target by providing an implementation.
18080 * @param {Roo.dd.DragDrop} target The drop target
18081 * @param {Event} e The event object
18082 * @param {String} id The id of the dragged element
18083 * @method afterDragOver
18085 this.afterDragOver(target, e, id);
18091 * An empty function by default, but provided so that you can perform a custom action
18092 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18093 * @param {Roo.dd.DragDrop} target The drop target
18094 * @param {Event} e The event object
18095 * @param {String} id The id of the dragged element
18096 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18098 beforeDragOver : function(target, e, id){
18103 onDragOut : function(e, id){
18104 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18105 if(this.beforeDragOut(target, e, id) !== false){
18106 if(target.isNotifyTarget){
18107 target.notifyOut(this, e, this.dragData);
18109 this.proxy.reset();
18110 if(this.afterDragOut){
18112 * An empty function by default, but provided so that you can perform a custom action
18113 * after the dragged item is dragged out of the target without dropping.
18114 * @param {Roo.dd.DragDrop} target The drop target
18115 * @param {Event} e The event object
18116 * @param {String} id The id of the dragged element
18117 * @method afterDragOut
18119 this.afterDragOut(target, e, id);
18122 this.cachedTarget = null;
18126 * An empty function by default, but provided so that you can perform a custom action before the dragged
18127 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18128 * @param {Roo.dd.DragDrop} target The drop target
18129 * @param {Event} e The event object
18130 * @param {String} id The id of the dragged element
18131 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18133 beforeDragOut : function(target, e, id){
18138 onDragDrop : function(e, id){
18139 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18140 if(this.beforeDragDrop(target, e, id) !== false){
18141 if(target.isNotifyTarget){
18142 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18143 this.onValidDrop(target, e, id);
18145 this.onInvalidDrop(target, e, id);
18148 this.onValidDrop(target, e, id);
18151 if(this.afterDragDrop){
18153 * An empty function by default, but provided so that you can perform a custom action
18154 * after a valid drag drop has occurred by providing an implementation.
18155 * @param {Roo.dd.DragDrop} target The drop target
18156 * @param {Event} e The event object
18157 * @param {String} id The id of the dropped element
18158 * @method afterDragDrop
18160 this.afterDragDrop(target, e, id);
18163 delete this.cachedTarget;
18167 * An empty function by default, but provided so that you can perform a custom action before the dragged
18168 * item is dropped onto the target and optionally cancel the onDragDrop.
18169 * @param {Roo.dd.DragDrop} target The drop target
18170 * @param {Event} e The event object
18171 * @param {String} id The id of the dragged element
18172 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18174 beforeDragDrop : function(target, e, id){
18179 onValidDrop : function(target, e, id){
18181 if(this.afterValidDrop){
18183 * An empty function by default, but provided so that you can perform a custom action
18184 * after a valid drop has occurred by providing an implementation.
18185 * @param {Object} target The target DD
18186 * @param {Event} e The event object
18187 * @param {String} id The id of the dropped element
18188 * @method afterInvalidDrop
18190 this.afterValidDrop(target, e, id);
18195 getRepairXY : function(e, data){
18196 return this.el.getXY();
18200 onInvalidDrop : function(target, e, id){
18201 this.beforeInvalidDrop(target, e, id);
18202 if(this.cachedTarget){
18203 if(this.cachedTarget.isNotifyTarget){
18204 this.cachedTarget.notifyOut(this, e, this.dragData);
18206 this.cacheTarget = null;
18208 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18210 if(this.afterInvalidDrop){
18212 * An empty function by default, but provided so that you can perform a custom action
18213 * after an invalid drop has occurred by providing an implementation.
18214 * @param {Event} e The event object
18215 * @param {String} id The id of the dropped element
18216 * @method afterInvalidDrop
18218 this.afterInvalidDrop(e, id);
18223 afterRepair : function(){
18225 this.el.highlight(this.hlColor || "c3daf9");
18227 this.dragging = false;
18231 * An empty function by default, but provided so that you can perform a custom action after an invalid
18232 * drop has occurred.
18233 * @param {Roo.dd.DragDrop} target The drop target
18234 * @param {Event} e The event object
18235 * @param {String} id The id of the dragged element
18236 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18238 beforeInvalidDrop : function(target, e, id){
18243 handleMouseDown : function(e){
18244 if(this.dragging) {
18247 var data = this.getDragData(e);
18248 if(data && this.onBeforeDrag(data, e) !== false){
18249 this.dragData = data;
18251 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18256 * An empty function by default, but provided so that you can perform a custom action before the initial
18257 * drag event begins and optionally cancel it.
18258 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18259 * @param {Event} e The event object
18260 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18262 onBeforeDrag : function(data, e){
18267 * An empty function by default, but provided so that you can perform a custom action once the initial
18268 * drag event has begun. The drag cannot be canceled from this function.
18269 * @param {Number} x The x position of the click on the dragged object
18270 * @param {Number} y The y position of the click on the dragged object
18272 onStartDrag : Roo.emptyFn,
18274 // private - YUI override
18275 startDrag : function(x, y){
18276 this.proxy.reset();
18277 this.dragging = true;
18278 this.proxy.update("");
18279 this.onInitDrag(x, y);
18284 onInitDrag : function(x, y){
18285 var clone = this.el.dom.cloneNode(true);
18286 clone.id = Roo.id(); // prevent duplicate ids
18287 this.proxy.update(clone);
18288 this.onStartDrag(x, y);
18293 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18294 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18296 getProxy : function(){
18301 * Hides the drag source's {@link Roo.dd.StatusProxy}
18303 hideProxy : function(){
18305 this.proxy.reset(true);
18306 this.dragging = false;
18310 triggerCacheRefresh : function(){
18311 Roo.dd.DDM.refreshCache(this.groups);
18314 // private - override to prevent hiding
18315 b4EndDrag: function(e) {
18318 // private - override to prevent moving
18319 endDrag : function(e){
18320 this.onEndDrag(this.dragData, e);
18324 onEndDrag : function(data, e){
18327 // private - pin to cursor
18328 autoOffset : function(x, y) {
18329 this.setDelta(-12, -20);
18333 * Ext JS Library 1.1.1
18334 * Copyright(c) 2006-2007, Ext JS, LLC.
18336 * Originally Released Under LGPL - original licence link has changed is not relivant.
18339 * <script type="text/javascript">
18344 * @class Roo.dd.DropTarget
18345 * @extends Roo.dd.DDTarget
18346 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18347 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18349 * @param {String/HTMLElement/Element} el The container element
18350 * @param {Object} config
18352 Roo.dd.DropTarget = function(el, config){
18353 this.el = Roo.get(el);
18355 var listeners = false; ;
18356 if (config && config.listeners) {
18357 listeners= config.listeners;
18358 delete config.listeners;
18360 Roo.apply(this, config);
18362 if(this.containerScroll){
18363 Roo.dd.ScrollManager.register(this.el);
18367 * @scope Roo.dd.DropTarget
18372 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18373 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18374 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18376 * IMPORTANT : it should set this.overClass and this.dropAllowed
18378 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18379 * @param {Event} e The event
18380 * @param {Object} data An object containing arbitrary data supplied by the drag source
18386 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18387 * This method will be called on every mouse movement while the drag source is over the drop target.
18388 * This default implementation simply returns the dropAllowed config value.
18390 * IMPORTANT : it should set this.dropAllowed
18392 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18393 * @param {Event} e The event
18394 * @param {Object} data An object containing arbitrary data supplied by the drag source
18400 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18401 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18402 * overClass (if any) from the drop element.
18403 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18404 * @param {Event} e The event
18405 * @param {Object} data An object containing arbitrary data supplied by the drag source
18411 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18412 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18413 * implementation that does something to process the drop event and returns true so that the drag source's
18414 * repair action does not run.
18416 * IMPORTANT : it should set this.success
18418 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18419 * @param {Event} e The event
18420 * @param {Object} data An object containing arbitrary data supplied by the drag source
18426 Roo.dd.DropTarget.superclass.constructor.call( this,
18428 this.ddGroup || this.group,
18431 listeners : listeners || {}
18439 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18441 * @cfg {String} overClass
18442 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18445 * @cfg {String} ddGroup
18446 * The drag drop group to handle drop events for
18450 * @cfg {String} dropAllowed
18451 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18453 dropAllowed : "x-dd-drop-ok",
18455 * @cfg {String} dropNotAllowed
18456 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18458 dropNotAllowed : "x-dd-drop-nodrop",
18460 * @cfg {boolean} success
18461 * set this after drop listener..
18465 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
18466 * if the drop point is valid for over/enter..
18473 isNotifyTarget : true,
18478 notifyEnter : function(dd, e, data)
18481 this.fireEvent('enter', dd, e, data);
18482 if(this.overClass){
18483 this.el.addClass(this.overClass);
18485 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18486 this.valid ? this.dropAllowed : this.dropNotAllowed
18493 notifyOver : function(dd, e, data)
18496 this.fireEvent('over', dd, e, data);
18497 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18498 this.valid ? this.dropAllowed : this.dropNotAllowed
18505 notifyOut : function(dd, e, data)
18507 this.fireEvent('out', dd, e, data);
18508 if(this.overClass){
18509 this.el.removeClass(this.overClass);
18516 notifyDrop : function(dd, e, data)
18518 this.success = false;
18519 this.fireEvent('drop', dd, e, data);
18520 return this.success;
18524 * Ext JS Library 1.1.1
18525 * Copyright(c) 2006-2007, Ext JS, LLC.
18527 * Originally Released Under LGPL - original licence link has changed is not relivant.
18530 * <script type="text/javascript">
18535 * @class Roo.dd.DragZone
18536 * @extends Roo.dd.DragSource
18537 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18538 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18540 * @param {String/HTMLElement/Element} el The container element
18541 * @param {Object} config
18543 Roo.dd.DragZone = function(el, config){
18544 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18545 if(this.containerScroll){
18546 Roo.dd.ScrollManager.register(this.el);
18550 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18552 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18553 * for auto scrolling during drag operations.
18556 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18557 * method after a failed drop (defaults to "c3daf9" - light blue)
18561 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18562 * for a valid target to drag based on the mouse down. Override this method
18563 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18564 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18565 * @param {EventObject} e The mouse down event
18566 * @return {Object} The dragData
18568 getDragData : function(e){
18569 return Roo.dd.Registry.getHandleFromEvent(e);
18573 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18574 * this.dragData.ddel
18575 * @param {Number} x The x position of the click on the dragged object
18576 * @param {Number} y The y position of the click on the dragged object
18577 * @return {Boolean} true to continue the drag, false to cancel
18579 onInitDrag : function(x, y){
18580 this.proxy.update(this.dragData.ddel.cloneNode(true));
18581 this.onStartDrag(x, y);
18586 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18588 afterRepair : function(){
18590 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18592 this.dragging = false;
18596 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18597 * the XY of this.dragData.ddel
18598 * @param {EventObject} e The mouse up event
18599 * @return {Array} The xy location (e.g. [100, 200])
18601 getRepairXY : function(e){
18602 return Roo.Element.fly(this.dragData.ddel).getXY();
18606 * Ext JS Library 1.1.1
18607 * Copyright(c) 2006-2007, Ext JS, LLC.
18609 * Originally Released Under LGPL - original licence link has changed is not relivant.
18612 * <script type="text/javascript">
18615 * @class Roo.dd.DropZone
18616 * @extends Roo.dd.DropTarget
18617 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18618 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18620 * @param {String/HTMLElement/Element} el The container element
18621 * @param {Object} config
18623 Roo.dd.DropZone = function(el, config){
18624 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18627 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18629 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18630 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18631 * provide your own custom lookup.
18632 * @param {Event} e The event
18633 * @return {Object} data The custom data
18635 getTargetFromEvent : function(e){
18636 return Roo.dd.Registry.getTargetFromEvent(e);
18640 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18641 * that it has registered. This method has no default implementation and should be overridden to provide
18642 * node-specific processing if necessary.
18643 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18644 * {@link #getTargetFromEvent} for this node)
18645 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18646 * @param {Event} e The event
18647 * @param {Object} data An object containing arbitrary data supplied by the drag source
18649 onNodeEnter : function(n, dd, e, data){
18654 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18655 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18656 * overridden to provide the proper feedback.
18657 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18658 * {@link #getTargetFromEvent} for this node)
18659 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18660 * @param {Event} e The event
18661 * @param {Object} data An object containing arbitrary data supplied by the drag source
18662 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18663 * underlying {@link Roo.dd.StatusProxy} can be updated
18665 onNodeOver : function(n, dd, e, data){
18666 return this.dropAllowed;
18670 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18671 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18672 * node-specific processing if necessary.
18673 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18674 * {@link #getTargetFromEvent} for this node)
18675 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18676 * @param {Event} e The event
18677 * @param {Object} data An object containing arbitrary data supplied by the drag source
18679 onNodeOut : function(n, dd, e, data){
18684 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18685 * the drop node. The default implementation returns false, so it should be overridden to provide the
18686 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18687 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18688 * {@link #getTargetFromEvent} for this node)
18689 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18690 * @param {Event} e The event
18691 * @param {Object} data An object containing arbitrary data supplied by the drag source
18692 * @return {Boolean} True if the drop was valid, else false
18694 onNodeDrop : function(n, dd, e, data){
18699 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18700 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18701 * it should be overridden to provide the proper feedback if necessary.
18702 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18703 * @param {Event} e The event
18704 * @param {Object} data An object containing arbitrary data supplied by the drag source
18705 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18706 * underlying {@link Roo.dd.StatusProxy} can be updated
18708 onContainerOver : function(dd, e, data){
18709 return this.dropNotAllowed;
18713 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18714 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18715 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18716 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18717 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18718 * @param {Event} e The event
18719 * @param {Object} data An object containing arbitrary data supplied by the drag source
18720 * @return {Boolean} True if the drop was valid, else false
18722 onContainerDrop : function(dd, e, data){
18727 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18728 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18729 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18730 * you should override this method and provide a custom implementation.
18731 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18732 * @param {Event} e The event
18733 * @param {Object} data An object containing arbitrary data supplied by the drag source
18734 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18735 * underlying {@link Roo.dd.StatusProxy} can be updated
18737 notifyEnter : function(dd, e, data){
18738 return this.dropNotAllowed;
18742 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18743 * This method will be called on every mouse movement while the drag source is over the drop zone.
18744 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18745 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18746 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18747 * registered node, it will call {@link #onContainerOver}.
18748 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18749 * @param {Event} e The event
18750 * @param {Object} data An object containing arbitrary data supplied by the drag source
18751 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18752 * underlying {@link Roo.dd.StatusProxy} can be updated
18754 notifyOver : function(dd, e, data){
18755 var n = this.getTargetFromEvent(e);
18756 if(!n){ // not over valid drop target
18757 if(this.lastOverNode){
18758 this.onNodeOut(this.lastOverNode, dd, e, data);
18759 this.lastOverNode = null;
18761 return this.onContainerOver(dd, e, data);
18763 if(this.lastOverNode != n){
18764 if(this.lastOverNode){
18765 this.onNodeOut(this.lastOverNode, dd, e, data);
18767 this.onNodeEnter(n, dd, e, data);
18768 this.lastOverNode = n;
18770 return this.onNodeOver(n, dd, e, data);
18774 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18775 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18776 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18777 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18778 * @param {Event} e The event
18779 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18781 notifyOut : function(dd, e, data){
18782 if(this.lastOverNode){
18783 this.onNodeOut(this.lastOverNode, dd, e, data);
18784 this.lastOverNode = null;
18789 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18790 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18791 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18792 * otherwise it will call {@link #onContainerDrop}.
18793 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18794 * @param {Event} e The event
18795 * @param {Object} data An object containing arbitrary data supplied by the drag source
18796 * @return {Boolean} True if the drop was valid, else false
18798 notifyDrop : function(dd, e, data){
18799 if(this.lastOverNode){
18800 this.onNodeOut(this.lastOverNode, dd, e, data);
18801 this.lastOverNode = null;
18803 var n = this.getTargetFromEvent(e);
18805 this.onNodeDrop(n, dd, e, data) :
18806 this.onContainerDrop(dd, e, data);
18810 triggerCacheRefresh : function(){
18811 Roo.dd.DDM.refreshCache(this.groups);
18815 * Ext JS Library 1.1.1
18816 * Copyright(c) 2006-2007, Ext JS, LLC.
18818 * Originally Released Under LGPL - original licence link has changed is not relivant.
18821 * <script type="text/javascript">
18826 * @class Roo.data.SortTypes
18828 * Defines the default sorting (casting?) comparison functions used when sorting data.
18830 Roo.data.SortTypes = {
18832 * Default sort that does nothing
18833 * @param {Mixed} s The value being converted
18834 * @return {Mixed} The comparison value
18836 none : function(s){
18841 * The regular expression used to strip tags
18845 stripTagsRE : /<\/?[^>]+>/gi,
18848 * Strips all HTML tags to sort on text only
18849 * @param {Mixed} s The value being converted
18850 * @return {String} The comparison value
18852 asText : function(s){
18853 return String(s).replace(this.stripTagsRE, "");
18857 * Strips all HTML tags to sort on text only - Case insensitive
18858 * @param {Mixed} s The value being converted
18859 * @return {String} The comparison value
18861 asUCText : function(s){
18862 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18866 * Case insensitive string
18867 * @param {Mixed} s The value being converted
18868 * @return {String} The comparison value
18870 asUCString : function(s) {
18871 return String(s).toUpperCase();
18876 * @param {Mixed} s The value being converted
18877 * @return {Number} The comparison value
18879 asDate : function(s) {
18883 if(s instanceof Date){
18884 return s.getTime();
18886 return Date.parse(String(s));
18891 * @param {Mixed} s The value being converted
18892 * @return {Float} The comparison value
18894 asFloat : function(s) {
18895 var val = parseFloat(String(s).replace(/,/g, ""));
18896 if(isNaN(val)) val = 0;
18902 * @param {Mixed} s The value being converted
18903 * @return {Number} The comparison value
18905 asInt : function(s) {
18906 var val = parseInt(String(s).replace(/,/g, ""));
18907 if(isNaN(val)) val = 0;
18912 * Ext JS Library 1.1.1
18913 * Copyright(c) 2006-2007, Ext JS, LLC.
18915 * Originally Released Under LGPL - original licence link has changed is not relivant.
18918 * <script type="text/javascript">
18922 * @class Roo.data.Record
18923 * Instances of this class encapsulate both record <em>definition</em> information, and record
18924 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18925 * to access Records cached in an {@link Roo.data.Store} object.<br>
18927 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18928 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18931 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18933 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18934 * {@link #create}. The parameters are the same.
18935 * @param {Array} data An associative Array of data values keyed by the field name.
18936 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18937 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18938 * not specified an integer id is generated.
18940 Roo.data.Record = function(data, id){
18941 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18946 * Generate a constructor for a specific record layout.
18947 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18948 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18949 * Each field definition object may contain the following properties: <ul>
18950 * <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,
18951 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18952 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18953 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18954 * is being used, then this is a string containing the javascript expression to reference the data relative to
18955 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18956 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18957 * this may be omitted.</p></li>
18958 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18959 * <ul><li>auto (Default, implies no conversion)</li>
18964 * <li>date</li></ul></p></li>
18965 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18966 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18967 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18968 * by the Reader into an object that will be stored in the Record. It is passed the
18969 * following parameters:<ul>
18970 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18972 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18974 * <br>usage:<br><pre><code>
18975 var TopicRecord = Roo.data.Record.create(
18976 {name: 'title', mapping: 'topic_title'},
18977 {name: 'author', mapping: 'username'},
18978 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18979 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18980 {name: 'lastPoster', mapping: 'user2'},
18981 {name: 'excerpt', mapping: 'post_text'}
18984 var myNewRecord = new TopicRecord({
18985 title: 'Do my job please',
18988 lastPost: new Date(),
18989 lastPoster: 'Animal',
18990 excerpt: 'No way dude!'
18992 myStore.add(myNewRecord);
18997 Roo.data.Record.create = function(o){
18998 var f = function(){
18999 f.superclass.constructor.apply(this, arguments);
19001 Roo.extend(f, Roo.data.Record);
19002 var p = f.prototype;
19003 p.fields = new Roo.util.MixedCollection(false, function(field){
19006 for(var i = 0, len = o.length; i < len; i++){
19007 p.fields.add(new Roo.data.Field(o[i]));
19009 f.getField = function(name){
19010 return p.fields.get(name);
19015 Roo.data.Record.AUTO_ID = 1000;
19016 Roo.data.Record.EDIT = 'edit';
19017 Roo.data.Record.REJECT = 'reject';
19018 Roo.data.Record.COMMIT = 'commit';
19020 Roo.data.Record.prototype = {
19022 * Readonly flag - true if this record has been modified.
19031 join : function(store){
19032 this.store = store;
19036 * Set the named field to the specified value.
19037 * @param {String} name The name of the field to set.
19038 * @param {Object} value The value to set the field to.
19040 set : function(name, value){
19041 if(this.data[name] == value){
19045 if(!this.modified){
19046 this.modified = {};
19048 if(typeof this.modified[name] == 'undefined'){
19049 this.modified[name] = this.data[name];
19051 this.data[name] = value;
19053 this.store.afterEdit(this);
19058 * Get the value of the named field.
19059 * @param {String} name The name of the field to get the value of.
19060 * @return {Object} The value of the field.
19062 get : function(name){
19063 return this.data[name];
19067 beginEdit : function(){
19068 this.editing = true;
19069 this.modified = {};
19073 cancelEdit : function(){
19074 this.editing = false;
19075 delete this.modified;
19079 endEdit : function(){
19080 this.editing = false;
19081 if(this.dirty && this.store){
19082 this.store.afterEdit(this);
19087 * Usually called by the {@link Roo.data.Store} which owns the Record.
19088 * Rejects all changes made to the Record since either creation, or the last commit operation.
19089 * Modified fields are reverted to their original values.
19091 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19092 * of reject operations.
19094 reject : function(){
19095 var m = this.modified;
19097 if(typeof m[n] != "function"){
19098 this.data[n] = m[n];
19101 this.dirty = false;
19102 delete this.modified;
19103 this.editing = false;
19105 this.store.afterReject(this);
19110 * Usually called by the {@link Roo.data.Store} which owns the Record.
19111 * Commits all changes made to the Record since either creation, or the last commit operation.
19113 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19114 * of commit operations.
19116 commit : function(){
19117 this.dirty = false;
19118 delete this.modified;
19119 this.editing = false;
19121 this.store.afterCommit(this);
19126 hasError : function(){
19127 return this.error != null;
19131 clearError : function(){
19136 * Creates a copy of this record.
19137 * @param {String} id (optional) A new record id if you don't want to use this record's id
19140 copy : function(newId) {
19141 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19145 * Ext JS Library 1.1.1
19146 * Copyright(c) 2006-2007, Ext JS, LLC.
19148 * Originally Released Under LGPL - original licence link has changed is not relivant.
19151 * <script type="text/javascript">
19157 * @class Roo.data.Store
19158 * @extends Roo.util.Observable
19159 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19160 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19162 * 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
19163 * has no knowledge of the format of the data returned by the Proxy.<br>
19165 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19166 * instances from the data object. These records are cached and made available through accessor functions.
19168 * Creates a new Store.
19169 * @param {Object} config A config object containing the objects needed for the Store to access data,
19170 * and read the data into Records.
19172 Roo.data.Store = function(config){
19173 this.data = new Roo.util.MixedCollection(false);
19174 this.data.getKey = function(o){
19177 this.baseParams = {};
19179 this.paramNames = {
19184 "multisort" : "_multisort"
19187 if(config && config.data){
19188 this.inlineData = config.data;
19189 delete config.data;
19192 Roo.apply(this, config);
19194 if(this.reader){ // reader passed
19195 this.reader = Roo.factory(this.reader, Roo.data);
19196 this.reader.xmodule = this.xmodule || false;
19197 if(!this.recordType){
19198 this.recordType = this.reader.recordType;
19200 if(this.reader.onMetaChange){
19201 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19205 if(this.recordType){
19206 this.fields = this.recordType.prototype.fields;
19208 this.modified = [];
19212 * @event datachanged
19213 * Fires when the data cache has changed, and a widget which is using this Store
19214 * as a Record cache should refresh its view.
19215 * @param {Store} this
19217 datachanged : true,
19219 * @event metachange
19220 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19221 * @param {Store} this
19222 * @param {Object} meta The JSON metadata
19227 * Fires when Records have been added to the Store
19228 * @param {Store} this
19229 * @param {Roo.data.Record[]} records The array of Records added
19230 * @param {Number} index The index at which the record(s) were added
19235 * Fires when a Record has been removed from the Store
19236 * @param {Store} this
19237 * @param {Roo.data.Record} record The Record that was removed
19238 * @param {Number} index The index at which the record was removed
19243 * Fires when a Record has been updated
19244 * @param {Store} this
19245 * @param {Roo.data.Record} record The Record that was updated
19246 * @param {String} operation The update operation being performed. Value may be one of:
19248 Roo.data.Record.EDIT
19249 Roo.data.Record.REJECT
19250 Roo.data.Record.COMMIT
19256 * Fires when the data cache has been cleared.
19257 * @param {Store} this
19261 * @event beforeload
19262 * Fires before a request is made for a new data object. If the beforeload handler returns false
19263 * the load action will be canceled.
19264 * @param {Store} this
19265 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19270 * Fires after a new set of Records has been loaded.
19271 * @param {Store} this
19272 * @param {Roo.data.Record[]} records The Records that were loaded
19273 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19277 * @event loadexception
19278 * Fires if an exception occurs in the Proxy during loading.
19279 * Called with the signature of the Proxy's "loadexception" event.
19280 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19283 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19284 * @param {Object} load options
19285 * @param {Object} jsonData from your request (normally this contains the Exception)
19287 loadexception : true
19291 this.proxy = Roo.factory(this.proxy, Roo.data);
19292 this.proxy.xmodule = this.xmodule || false;
19293 this.relayEvents(this.proxy, ["loadexception"]);
19295 this.sortToggle = {};
19296 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
19298 Roo.data.Store.superclass.constructor.call(this);
19300 if(this.inlineData){
19301 this.loadData(this.inlineData);
19302 delete this.inlineData;
19305 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19307 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19308 * without a remote query - used by combo/forms at present.
19312 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19315 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19318 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19319 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19322 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19323 * on any HTTP request
19326 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19329 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
19333 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19334 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19336 remoteSort : false,
19339 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19340 * loaded or when a record is removed. (defaults to false).
19342 pruneModifiedRecords : false,
19345 lastOptions : null,
19348 * Add Records to the Store and fires the add event.
19349 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19351 add : function(records){
19352 records = [].concat(records);
19353 for(var i = 0, len = records.length; i < len; i++){
19354 records[i].join(this);
19356 var index = this.data.length;
19357 this.data.addAll(records);
19358 this.fireEvent("add", this, records, index);
19362 * Remove a Record from the Store and fires the remove event.
19363 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19365 remove : function(record){
19366 var index = this.data.indexOf(record);
19367 this.data.removeAt(index);
19368 if(this.pruneModifiedRecords){
19369 this.modified.remove(record);
19371 this.fireEvent("remove", this, record, index);
19375 * Remove all Records from the Store and fires the clear event.
19377 removeAll : function(){
19379 if(this.pruneModifiedRecords){
19380 this.modified = [];
19382 this.fireEvent("clear", this);
19386 * Inserts Records to the Store at the given index and fires the add event.
19387 * @param {Number} index The start index at which to insert the passed Records.
19388 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19390 insert : function(index, records){
19391 records = [].concat(records);
19392 for(var i = 0, len = records.length; i < len; i++){
19393 this.data.insert(index, records[i]);
19394 records[i].join(this);
19396 this.fireEvent("add", this, records, index);
19400 * Get the index within the cache of the passed Record.
19401 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19402 * @return {Number} The index of the passed Record. Returns -1 if not found.
19404 indexOf : function(record){
19405 return this.data.indexOf(record);
19409 * Get the index within the cache of the Record with the passed id.
19410 * @param {String} id The id of the Record to find.
19411 * @return {Number} The index of the Record. Returns -1 if not found.
19413 indexOfId : function(id){
19414 return this.data.indexOfKey(id);
19418 * Get the Record with the specified id.
19419 * @param {String} id The id of the Record to find.
19420 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19422 getById : function(id){
19423 return this.data.key(id);
19427 * Get the Record at the specified index.
19428 * @param {Number} index The index of the Record to find.
19429 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19431 getAt : function(index){
19432 return this.data.itemAt(index);
19436 * Returns a range of Records between specified indices.
19437 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19438 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19439 * @return {Roo.data.Record[]} An array of Records
19441 getRange : function(start, end){
19442 return this.data.getRange(start, end);
19446 storeOptions : function(o){
19447 o = Roo.apply({}, o);
19450 this.lastOptions = o;
19454 * Loads the Record cache from the configured Proxy using the configured Reader.
19456 * If using remote paging, then the first load call must specify the <em>start</em>
19457 * and <em>limit</em> properties in the options.params property to establish the initial
19458 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19460 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19461 * and this call will return before the new data has been loaded. Perform any post-processing
19462 * in a callback function, or in a "load" event handler.</strong>
19464 * @param {Object} options An object containing properties which control loading options:<ul>
19465 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19466 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19467 * passed the following arguments:<ul>
19468 * <li>r : Roo.data.Record[]</li>
19469 * <li>options: Options object from the load call</li>
19470 * <li>success: Boolean success indicator</li></ul></li>
19471 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19472 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19475 load : function(options){
19476 options = options || {};
19477 if(this.fireEvent("beforeload", this, options) !== false){
19478 this.storeOptions(options);
19479 var p = Roo.apply(options.params || {}, this.baseParams);
19480 // if meta was not loaded from remote source.. try requesting it.
19481 if (!this.reader.metaFromRemote) {
19482 p._requestMeta = 1;
19484 if(this.sortInfo && this.remoteSort){
19485 var pn = this.paramNames;
19486 p[pn["sort"]] = this.sortInfo.field;
19487 p[pn["dir"]] = this.sortInfo.direction;
19489 if (this.multiSort) {
19490 var pn = this.paramNames;
19491 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
19494 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19499 * Reloads the Record cache from the configured Proxy using the configured Reader and
19500 * the options from the last load operation performed.
19501 * @param {Object} options (optional) An object containing properties which may override the options
19502 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19503 * the most recently used options are reused).
19505 reload : function(options){
19506 this.load(Roo.applyIf(options||{}, this.lastOptions));
19510 // Called as a callback by the Reader during a load operation.
19511 loadRecords : function(o, options, success){
19512 if(!o || success === false){
19513 if(success !== false){
19514 this.fireEvent("load", this, [], options);
19516 if(options.callback){
19517 options.callback.call(options.scope || this, [], options, false);
19521 // if data returned failure - throw an exception.
19522 if (o.success === false) {
19523 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19526 var r = o.records, t = o.totalRecords || r.length;
19527 if(!options || options.add !== true){
19528 if(this.pruneModifiedRecords){
19529 this.modified = [];
19531 for(var i = 0, len = r.length; i < len; i++){
19535 this.data = this.snapshot;
19536 delete this.snapshot;
19539 this.data.addAll(r);
19540 this.totalLength = t;
19542 this.fireEvent("datachanged", this);
19544 this.totalLength = Math.max(t, this.data.length+r.length);
19547 this.fireEvent("load", this, r, options);
19548 if(options.callback){
19549 options.callback.call(options.scope || this, r, options, true);
19554 * Loads data from a passed data block. A Reader which understands the format of the data
19555 * must have been configured in the constructor.
19556 * @param {Object} data The data block from which to read the Records. The format of the data expected
19557 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19558 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19560 loadData : function(o, append){
19561 var r = this.reader.readRecords(o);
19562 this.loadRecords(r, {add: append}, true);
19566 * Gets the number of cached records.
19568 * <em>If using paging, this may not be the total size of the dataset. If the data object
19569 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19570 * the data set size</em>
19572 getCount : function(){
19573 return this.data.length || 0;
19577 * Gets the total number of records in the dataset as returned by the server.
19579 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19580 * the dataset size</em>
19582 getTotalCount : function(){
19583 return this.totalLength || 0;
19587 * Returns the sort state of the Store as an object with two properties:
19589 field {String} The name of the field by which the Records are sorted
19590 direction {String} The sort order, "ASC" or "DESC"
19593 getSortState : function(){
19594 return this.sortInfo;
19598 applySort : function(){
19599 if(this.sortInfo && !this.remoteSort){
19600 var s = this.sortInfo, f = s.field;
19601 var st = this.fields.get(f).sortType;
19602 var fn = function(r1, r2){
19603 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19604 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19606 this.data.sort(s.direction, fn);
19607 if(this.snapshot && this.snapshot != this.data){
19608 this.snapshot.sort(s.direction, fn);
19614 * Sets the default sort column and order to be used by the next load operation.
19615 * @param {String} fieldName The name of the field to sort by.
19616 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19618 setDefaultSort : function(field, dir){
19619 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19623 * Sort the Records.
19624 * If remote sorting is used, the sort is performed on the server, and the cache is
19625 * reloaded. If local sorting is used, the cache is sorted internally.
19626 * @param {String} fieldName The name of the field to sort by.
19627 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19629 sort : function(fieldName, dir){
19630 var f = this.fields.get(fieldName);
19632 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
19634 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
19635 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19640 this.sortToggle[f.name] = dir;
19641 this.sortInfo = {field: f.name, direction: dir};
19642 if(!this.remoteSort){
19644 this.fireEvent("datachanged", this);
19646 this.load(this.lastOptions);
19651 * Calls the specified function for each of the Records in the cache.
19652 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19653 * Returning <em>false</em> aborts and exits the iteration.
19654 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19656 each : function(fn, scope){
19657 this.data.each(fn, scope);
19661 * Gets all records modified since the last commit. Modified records are persisted across load operations
19662 * (e.g., during paging).
19663 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19665 getModifiedRecords : function(){
19666 return this.modified;
19670 createFilterFn : function(property, value, anyMatch){
19671 if(!value.exec){ // not a regex
19672 value = String(value);
19673 if(value.length == 0){
19676 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19678 return function(r){
19679 return value.test(r.data[property]);
19684 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19685 * @param {String} property A field on your records
19686 * @param {Number} start The record index to start at (defaults to 0)
19687 * @param {Number} end The last record index to include (defaults to length - 1)
19688 * @return {Number} The sum
19690 sum : function(property, start, end){
19691 var rs = this.data.items, v = 0;
19692 start = start || 0;
19693 end = (end || end === 0) ? end : rs.length-1;
19695 for(var i = start; i <= end; i++){
19696 v += (rs[i].data[property] || 0);
19702 * Filter the records by a specified property.
19703 * @param {String} field A field on your records
19704 * @param {String/RegExp} value Either a string that the field
19705 * should start with or a RegExp to test against the field
19706 * @param {Boolean} anyMatch True to match any part not just the beginning
19708 filter : function(property, value, anyMatch){
19709 var fn = this.createFilterFn(property, value, anyMatch);
19710 return fn ? this.filterBy(fn) : this.clearFilter();
19714 * Filter by a function. The specified function will be called with each
19715 * record in this data source. If the function returns true the record is included,
19716 * otherwise it is filtered.
19717 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19718 * @param {Object} scope (optional) The scope of the function (defaults to this)
19720 filterBy : function(fn, scope){
19721 this.snapshot = this.snapshot || this.data;
19722 this.data = this.queryBy(fn, scope||this);
19723 this.fireEvent("datachanged", this);
19727 * Query the records by a specified property.
19728 * @param {String} field A field on your records
19729 * @param {String/RegExp} value Either a string that the field
19730 * should start with or a RegExp to test against the field
19731 * @param {Boolean} anyMatch True to match any part not just the beginning
19732 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19734 query : function(property, value, anyMatch){
19735 var fn = this.createFilterFn(property, value, anyMatch);
19736 return fn ? this.queryBy(fn) : this.data.clone();
19740 * Query by a function. The specified function will be called with each
19741 * record in this data source. If the function returns true the record is included
19743 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19744 * @param {Object} scope (optional) The scope of the function (defaults to this)
19745 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19747 queryBy : function(fn, scope){
19748 var data = this.snapshot || this.data;
19749 return data.filterBy(fn, scope||this);
19753 * Collects unique values for a particular dataIndex from this store.
19754 * @param {String} dataIndex The property to collect
19755 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19756 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19757 * @return {Array} An array of the unique values
19759 collect : function(dataIndex, allowNull, bypassFilter){
19760 var d = (bypassFilter === true && this.snapshot) ?
19761 this.snapshot.items : this.data.items;
19762 var v, sv, r = [], l = {};
19763 for(var i = 0, len = d.length; i < len; i++){
19764 v = d[i].data[dataIndex];
19766 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19775 * Revert to a view of the Record cache with no filtering applied.
19776 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19778 clearFilter : function(suppressEvent){
19779 if(this.snapshot && this.snapshot != this.data){
19780 this.data = this.snapshot;
19781 delete this.snapshot;
19782 if(suppressEvent !== true){
19783 this.fireEvent("datachanged", this);
19789 afterEdit : function(record){
19790 if(this.modified.indexOf(record) == -1){
19791 this.modified.push(record);
19793 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19797 afterReject : function(record){
19798 this.modified.remove(record);
19799 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19803 afterCommit : function(record){
19804 this.modified.remove(record);
19805 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19809 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19810 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19812 commitChanges : function(){
19813 var m = this.modified.slice(0);
19814 this.modified = [];
19815 for(var i = 0, len = m.length; i < len; i++){
19821 * Cancel outstanding changes on all changed records.
19823 rejectChanges : function(){
19824 var m = this.modified.slice(0);
19825 this.modified = [];
19826 for(var i = 0, len = m.length; i < len; i++){
19831 onMetaChange : function(meta, rtype, o){
19832 this.recordType = rtype;
19833 this.fields = rtype.prototype.fields;
19834 delete this.snapshot;
19835 this.sortInfo = meta.sortInfo || this.sortInfo;
19836 this.modified = [];
19837 this.fireEvent('metachange', this, this.reader.meta);
19841 * Ext JS Library 1.1.1
19842 * Copyright(c) 2006-2007, Ext JS, LLC.
19844 * Originally Released Under LGPL - original licence link has changed is not relivant.
19847 * <script type="text/javascript">
19851 * @class Roo.data.SimpleStore
19852 * @extends Roo.data.Store
19853 * Small helper class to make creating Stores from Array data easier.
19854 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19855 * @cfg {Array} fields An array of field definition objects, or field name strings.
19856 * @cfg {Array} data The multi-dimensional array of data
19858 * @param {Object} config
19860 Roo.data.SimpleStore = function(config){
19861 Roo.data.SimpleStore.superclass.constructor.call(this, {
19863 reader: new Roo.data.ArrayReader({
19866 Roo.data.Record.create(config.fields)
19868 proxy : new Roo.data.MemoryProxy(config.data)
19872 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19874 * Ext JS Library 1.1.1
19875 * Copyright(c) 2006-2007, Ext JS, LLC.
19877 * Originally Released Under LGPL - original licence link has changed is not relivant.
19880 * <script type="text/javascript">
19885 * @extends Roo.data.Store
19886 * @class Roo.data.JsonStore
19887 * Small helper class to make creating Stores for JSON data easier. <br/>
19889 var store = new Roo.data.JsonStore({
19890 url: 'get-images.php',
19892 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19895 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19896 * JsonReader and HttpProxy (unless inline data is provided).</b>
19897 * @cfg {Array} fields An array of field definition objects, or field name strings.
19899 * @param {Object} config
19901 Roo.data.JsonStore = function(c){
19902 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19903 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19904 reader: new Roo.data.JsonReader(c, c.fields)
19907 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19909 * Ext JS Library 1.1.1
19910 * Copyright(c) 2006-2007, Ext JS, LLC.
19912 * Originally Released Under LGPL - original licence link has changed is not relivant.
19915 * <script type="text/javascript">
19919 Roo.data.Field = function(config){
19920 if(typeof config == "string"){
19921 config = {name: config};
19923 Roo.apply(this, config);
19926 this.type = "auto";
19929 var st = Roo.data.SortTypes;
19930 // named sortTypes are supported, here we look them up
19931 if(typeof this.sortType == "string"){
19932 this.sortType = st[this.sortType];
19935 // set default sortType for strings and dates
19936 if(!this.sortType){
19939 this.sortType = st.asUCString;
19942 this.sortType = st.asDate;
19945 this.sortType = st.none;
19950 var stripRe = /[\$,%]/g;
19952 // prebuilt conversion function for this field, instead of
19953 // switching every time we're reading a value
19955 var cv, dateFormat = this.dateFormat;
19960 cv = function(v){ return v; };
19963 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19967 return v !== undefined && v !== null && v !== '' ?
19968 parseInt(String(v).replace(stripRe, ""), 10) : '';
19973 return v !== undefined && v !== null && v !== '' ?
19974 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19979 cv = function(v){ return v === true || v === "true" || v == 1; };
19986 if(v instanceof Date){
19990 if(dateFormat == "timestamp"){
19991 return new Date(v*1000);
19993 return Date.parseDate(v, dateFormat);
19995 var parsed = Date.parse(v);
19996 return parsed ? new Date(parsed) : null;
20005 Roo.data.Field.prototype = {
20013 * Ext JS Library 1.1.1
20014 * Copyright(c) 2006-2007, Ext JS, LLC.
20016 * Originally Released Under LGPL - original licence link has changed is not relivant.
20019 * <script type="text/javascript">
20022 // Base class for reading structured data from a data source. This class is intended to be
20023 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20026 * @class Roo.data.DataReader
20027 * Base class for reading structured data from a data source. This class is intended to be
20028 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20031 Roo.data.DataReader = function(meta, recordType){
20035 this.recordType = recordType instanceof Array ?
20036 Roo.data.Record.create(recordType) : recordType;
20039 Roo.data.DataReader.prototype = {
20041 * Create an empty record
20042 * @param {Object} data (optional) - overlay some values
20043 * @return {Roo.data.Record} record created.
20045 newRow : function(d) {
20047 this.recordType.prototype.fields.each(function(c) {
20049 case 'int' : da[c.name] = 0; break;
20050 case 'date' : da[c.name] = new Date(); break;
20051 case 'float' : da[c.name] = 0.0; break;
20052 case 'boolean' : da[c.name] = false; break;
20053 default : da[c.name] = ""; break;
20057 return new this.recordType(Roo.apply(da, d));
20062 * Ext JS Library 1.1.1
20063 * Copyright(c) 2006-2007, Ext JS, LLC.
20065 * Originally Released Under LGPL - original licence link has changed is not relivant.
20068 * <script type="text/javascript">
20072 * @class Roo.data.DataProxy
20073 * @extends Roo.data.Observable
20074 * This class is an abstract base class for implementations which provide retrieval of
20075 * unformatted data objects.<br>
20077 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20078 * (of the appropriate type which knows how to parse the data object) to provide a block of
20079 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20081 * Custom implementations must implement the load method as described in
20082 * {@link Roo.data.HttpProxy#load}.
20084 Roo.data.DataProxy = function(){
20087 * @event beforeload
20088 * Fires before a network request is made to retrieve a data object.
20089 * @param {Object} This DataProxy object.
20090 * @param {Object} params The params parameter to the load function.
20095 * Fires before the load method's callback is called.
20096 * @param {Object} This DataProxy object.
20097 * @param {Object} o The data object.
20098 * @param {Object} arg The callback argument object passed to the load function.
20102 * @event loadexception
20103 * Fires if an Exception occurs during data retrieval.
20104 * @param {Object} This DataProxy object.
20105 * @param {Object} o The data object.
20106 * @param {Object} arg The callback argument object passed to the load function.
20107 * @param {Object} e The Exception.
20109 loadexception : true
20111 Roo.data.DataProxy.superclass.constructor.call(this);
20114 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20117 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20121 * Ext JS Library 1.1.1
20122 * Copyright(c) 2006-2007, Ext JS, LLC.
20124 * Originally Released Under LGPL - original licence link has changed is not relivant.
20127 * <script type="text/javascript">
20130 * @class Roo.data.MemoryProxy
20131 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20132 * to the Reader when its load method is called.
20134 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20136 Roo.data.MemoryProxy = function(data){
20140 Roo.data.MemoryProxy.superclass.constructor.call(this);
20144 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20146 * Load data from the requested source (in this case an in-memory
20147 * data object passed to the constructor), read the data object into
20148 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20149 * process that block using the passed callback.
20150 * @param {Object} params This parameter is not used by the MemoryProxy class.
20151 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20152 * object into a block of Roo.data.Records.
20153 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20154 * The function must be passed <ul>
20155 * <li>The Record block object</li>
20156 * <li>The "arg" argument from the load function</li>
20157 * <li>A boolean success indicator</li>
20159 * @param {Object} scope The scope in which to call the callback
20160 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20162 load : function(params, reader, callback, scope, arg){
20163 params = params || {};
20166 result = reader.readRecords(this.data);
20168 this.fireEvent("loadexception", this, arg, null, e);
20169 callback.call(scope, null, arg, false);
20172 callback.call(scope, result, arg, true);
20176 update : function(params, records){
20181 * Ext JS Library 1.1.1
20182 * Copyright(c) 2006-2007, Ext JS, LLC.
20184 * Originally Released Under LGPL - original licence link has changed is not relivant.
20187 * <script type="text/javascript">
20190 * @class Roo.data.HttpProxy
20191 * @extends Roo.data.DataProxy
20192 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20193 * configured to reference a certain URL.<br><br>
20195 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20196 * from which the running page was served.<br><br>
20198 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20200 * Be aware that to enable the browser to parse an XML document, the server must set
20201 * the Content-Type header in the HTTP response to "text/xml".
20203 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20204 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20205 * will be used to make the request.
20207 Roo.data.HttpProxy = function(conn){
20208 Roo.data.HttpProxy.superclass.constructor.call(this);
20209 // is conn a conn config or a real conn?
20211 this.useAjax = !conn || !conn.events;
20215 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20216 // thse are take from connection...
20219 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20222 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20223 * extra parameters to each request made by this object. (defaults to undefined)
20226 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20227 * to each request made by this object. (defaults to undefined)
20230 * @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)
20233 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20236 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20242 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20246 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20247 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20248 * a finer-grained basis than the DataProxy events.
20250 getConnection : function(){
20251 return this.useAjax ? Roo.Ajax : this.conn;
20255 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20256 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20257 * process that block using the passed callback.
20258 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20259 * for the request to the remote server.
20260 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20261 * object into a block of Roo.data.Records.
20262 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20263 * The function must be passed <ul>
20264 * <li>The Record block object</li>
20265 * <li>The "arg" argument from the load function</li>
20266 * <li>A boolean success indicator</li>
20268 * @param {Object} scope The scope in which to call the callback
20269 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20271 load : function(params, reader, callback, scope, arg){
20272 if(this.fireEvent("beforeload", this, params) !== false){
20274 params : params || {},
20276 callback : callback,
20281 callback : this.loadResponse,
20285 Roo.applyIf(o, this.conn);
20286 if(this.activeRequest){
20287 Roo.Ajax.abort(this.activeRequest);
20289 this.activeRequest = Roo.Ajax.request(o);
20291 this.conn.request(o);
20294 callback.call(scope||this, null, arg, false);
20299 loadResponse : function(o, success, response){
20300 delete this.activeRequest;
20302 this.fireEvent("loadexception", this, o, response);
20303 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20308 result = o.reader.read(response);
20310 this.fireEvent("loadexception", this, o, response, e);
20311 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20315 this.fireEvent("load", this, o, o.request.arg);
20316 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20320 update : function(dataSet){
20325 updateResponse : function(dataSet){
20330 * Ext JS Library 1.1.1
20331 * Copyright(c) 2006-2007, Ext JS, LLC.
20333 * Originally Released Under LGPL - original licence link has changed is not relivant.
20336 * <script type="text/javascript">
20340 * @class Roo.data.ScriptTagProxy
20341 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20342 * other than the originating domain of the running page.<br><br>
20344 * <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
20345 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20347 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20348 * source code that is used as the source inside a <script> tag.<br><br>
20350 * In order for the browser to process the returned data, the server must wrap the data object
20351 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20352 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20353 * depending on whether the callback name was passed:
20356 boolean scriptTag = false;
20357 String cb = request.getParameter("callback");
20360 response.setContentType("text/javascript");
20362 response.setContentType("application/x-json");
20364 Writer out = response.getWriter();
20366 out.write(cb + "(");
20368 out.print(dataBlock.toJsonString());
20375 * @param {Object} config A configuration object.
20377 Roo.data.ScriptTagProxy = function(config){
20378 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20379 Roo.apply(this, config);
20380 this.head = document.getElementsByTagName("head")[0];
20383 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20385 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20387 * @cfg {String} url The URL from which to request the data object.
20390 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20394 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20395 * the server the name of the callback function set up by the load call to process the returned data object.
20396 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20397 * javascript output which calls this named function passing the data object as its only parameter.
20399 callbackParam : "callback",
20401 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20402 * name to the request.
20407 * Load data from the configured URL, read the data object into
20408 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20409 * process that block using the passed callback.
20410 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20411 * for the request to the remote server.
20412 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20413 * object into a block of Roo.data.Records.
20414 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20415 * The function must be passed <ul>
20416 * <li>The Record block object</li>
20417 * <li>The "arg" argument from the load function</li>
20418 * <li>A boolean success indicator</li>
20420 * @param {Object} scope The scope in which to call the callback
20421 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20423 load : function(params, reader, callback, scope, arg){
20424 if(this.fireEvent("beforeload", this, params) !== false){
20426 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20428 var url = this.url;
20429 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20431 url += "&_dc=" + (new Date().getTime());
20433 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20436 cb : "stcCallback"+transId,
20437 scriptId : "stcScript"+transId,
20441 callback : callback,
20447 window[trans.cb] = function(o){
20448 conn.handleResponse(o, trans);
20451 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20453 if(this.autoAbort !== false){
20457 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20459 var script = document.createElement("script");
20460 script.setAttribute("src", url);
20461 script.setAttribute("type", "text/javascript");
20462 script.setAttribute("id", trans.scriptId);
20463 this.head.appendChild(script);
20465 this.trans = trans;
20467 callback.call(scope||this, null, arg, false);
20472 isLoading : function(){
20473 return this.trans ? true : false;
20477 * Abort the current server request.
20479 abort : function(){
20480 if(this.isLoading()){
20481 this.destroyTrans(this.trans);
20486 destroyTrans : function(trans, isLoaded){
20487 this.head.removeChild(document.getElementById(trans.scriptId));
20488 clearTimeout(trans.timeoutId);
20490 window[trans.cb] = undefined;
20492 delete window[trans.cb];
20495 // if hasn't been loaded, wait for load to remove it to prevent script error
20496 window[trans.cb] = function(){
20497 window[trans.cb] = undefined;
20499 delete window[trans.cb];
20506 handleResponse : function(o, trans){
20507 this.trans = false;
20508 this.destroyTrans(trans, true);
20511 result = trans.reader.readRecords(o);
20513 this.fireEvent("loadexception", this, o, trans.arg, e);
20514 trans.callback.call(trans.scope||window, null, trans.arg, false);
20517 this.fireEvent("load", this, o, trans.arg);
20518 trans.callback.call(trans.scope||window, result, trans.arg, true);
20522 handleFailure : function(trans){
20523 this.trans = false;
20524 this.destroyTrans(trans, false);
20525 this.fireEvent("loadexception", this, null, trans.arg);
20526 trans.callback.call(trans.scope||window, null, trans.arg, false);
20530 * Ext JS Library 1.1.1
20531 * Copyright(c) 2006-2007, Ext JS, LLC.
20533 * Originally Released Under LGPL - original licence link has changed is not relivant.
20536 * <script type="text/javascript">
20540 * @class Roo.data.JsonReader
20541 * @extends Roo.data.DataReader
20542 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20543 * based on mappings in a provided Roo.data.Record constructor.
20545 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
20546 * in the reply previously.
20551 var RecordDef = Roo.data.Record.create([
20552 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20553 {name: 'occupation'} // This field will use "occupation" as the mapping.
20555 var myReader = new Roo.data.JsonReader({
20556 totalProperty: "results", // The property which contains the total dataset size (optional)
20557 root: "rows", // The property which contains an Array of row objects
20558 id: "id" // The property within each row object that provides an ID for the record (optional)
20562 * This would consume a JSON file like this:
20564 { 'results': 2, 'rows': [
20565 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20566 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20569 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20570 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20571 * paged from the remote server.
20572 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20573 * @cfg {String} root name of the property which contains the Array of row objects.
20574 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20576 * Create a new JsonReader
20577 * @param {Object} meta Metadata configuration options
20578 * @param {Object} recordType Either an Array of field definition objects,
20579 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20581 Roo.data.JsonReader = function(meta, recordType){
20584 // set some defaults:
20585 Roo.applyIf(meta, {
20586 totalProperty: 'total',
20587 successProperty : 'success',
20592 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20594 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20597 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
20598 * Used by Store query builder to append _requestMeta to params.
20601 metaFromRemote : false,
20603 * This method is only used by a DataProxy which has retrieved data from a remote server.
20604 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20605 * @return {Object} data A data block which is used by an Roo.data.Store object as
20606 * a cache of Roo.data.Records.
20608 read : function(response){
20609 var json = response.responseText;
20611 var o = /* eval:var:o */ eval("("+json+")");
20613 throw {message: "JsonReader.read: Json object not found"};
20619 this.metaFromRemote = true;
20620 this.meta = o.metaData;
20621 this.recordType = Roo.data.Record.create(o.metaData.fields);
20622 this.onMetaChange(this.meta, this.recordType, o);
20624 return this.readRecords(o);
20627 // private function a store will implement
20628 onMetaChange : function(meta, recordType, o){
20635 simpleAccess: function(obj, subsc) {
20642 getJsonAccessor: function(){
20644 return function(expr) {
20646 return(re.test(expr))
20647 ? new Function("obj", "return obj." + expr)
20652 return Roo.emptyFn;
20657 * Create a data block containing Roo.data.Records from an XML document.
20658 * @param {Object} o An object which contains an Array of row objects in the property specified
20659 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20660 * which contains the total size of the dataset.
20661 * @return {Object} data A data block which is used by an Roo.data.Store object as
20662 * a cache of Roo.data.Records.
20664 readRecords : function(o){
20666 * After any data loads, the raw JSON data is available for further custom processing.
20670 var s = this.meta, Record = this.recordType,
20671 f = Record.prototype.fields, fi = f.items, fl = f.length;
20673 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20675 if(s.totalProperty) {
20676 this.getTotal = this.getJsonAccessor(s.totalProperty);
20678 if(s.successProperty) {
20679 this.getSuccess = this.getJsonAccessor(s.successProperty);
20681 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20683 var g = this.getJsonAccessor(s.id);
20684 this.getId = function(rec) {
20686 return (r === undefined || r === "") ? null : r;
20689 this.getId = function(){return null;};
20692 for(var jj = 0; jj < fl; jj++){
20694 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20695 this.ef[jj] = this.getJsonAccessor(map);
20699 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20700 if(s.totalProperty){
20701 var vt = parseInt(this.getTotal(o), 10);
20706 if(s.successProperty){
20707 var vs = this.getSuccess(o);
20708 if(vs === false || vs === 'false'){
20713 for(var i = 0; i < c; i++){
20716 var id = this.getId(n);
20717 for(var j = 0; j < fl; j++){
20719 var v = this.ef[j](n);
20721 Roo.log('missing convert for ' + f.name);
20725 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20727 var record = new Record(values, id);
20729 records[i] = record;
20734 totalRecords : totalRecords
20739 * Ext JS Library 1.1.1
20740 * Copyright(c) 2006-2007, Ext JS, LLC.
20742 * Originally Released Under LGPL - original licence link has changed is not relivant.
20745 * <script type="text/javascript">
20749 * @class Roo.data.XmlReader
20750 * @extends Roo.data.DataReader
20751 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20752 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20754 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20755 * header in the HTTP response must be set to "text/xml".</em>
20759 var RecordDef = Roo.data.Record.create([
20760 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20761 {name: 'occupation'} // This field will use "occupation" as the mapping.
20763 var myReader = new Roo.data.XmlReader({
20764 totalRecords: "results", // The element which contains the total dataset size (optional)
20765 record: "row", // The repeated element which contains row information
20766 id: "id" // The element within the row that provides an ID for the record (optional)
20770 * This would consume an XML file like this:
20774 <results>2</results>
20777 <name>Bill</name>
20778 <occupation>Gardener</occupation>
20782 <name>Ben</name>
20783 <occupation>Horticulturalist</occupation>
20787 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20788 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20789 * paged from the remote server.
20790 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20791 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20792 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20793 * a record identifier value.
20795 * Create a new XmlReader
20796 * @param {Object} meta Metadata configuration options
20797 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20798 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20799 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20801 Roo.data.XmlReader = function(meta, recordType){
20803 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20805 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20807 * This method is only used by a DataProxy which has retrieved data from a remote server.
20808 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20809 * to contain a method called 'responseXML' that returns an XML document object.
20810 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20811 * a cache of Roo.data.Records.
20813 read : function(response){
20814 var doc = response.responseXML;
20816 throw {message: "XmlReader.read: XML Document not available"};
20818 return this.readRecords(doc);
20822 * Create a data block containing Roo.data.Records from an XML document.
20823 * @param {Object} doc A parsed XML document.
20824 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20825 * a cache of Roo.data.Records.
20827 readRecords : function(doc){
20829 * After any data loads/reads, the raw XML Document is available for further custom processing.
20830 * @type XMLDocument
20832 this.xmlData = doc;
20833 var root = doc.documentElement || doc;
20834 var q = Roo.DomQuery;
20835 var recordType = this.recordType, fields = recordType.prototype.fields;
20836 var sid = this.meta.id;
20837 var totalRecords = 0, success = true;
20838 if(this.meta.totalRecords){
20839 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20842 if(this.meta.success){
20843 var sv = q.selectValue(this.meta.success, root, true);
20844 success = sv !== false && sv !== 'false';
20847 var ns = q.select(this.meta.record, root);
20848 for(var i = 0, len = ns.length; i < len; i++) {
20851 var id = sid ? q.selectValue(sid, n) : undefined;
20852 for(var j = 0, jlen = fields.length; j < jlen; j++){
20853 var f = fields.items[j];
20854 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20856 values[f.name] = v;
20858 var record = new recordType(values, id);
20860 records[records.length] = record;
20866 totalRecords : totalRecords || records.length
20871 * Ext JS Library 1.1.1
20872 * Copyright(c) 2006-2007, Ext JS, LLC.
20874 * Originally Released Under LGPL - original licence link has changed is not relivant.
20877 * <script type="text/javascript">
20881 * @class Roo.data.ArrayReader
20882 * @extends Roo.data.DataReader
20883 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20884 * Each element of that Array represents a row of data fields. The
20885 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20886 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20890 var RecordDef = Roo.data.Record.create([
20891 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20892 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20894 var myReader = new Roo.data.ArrayReader({
20895 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20899 * This would consume an Array like this:
20901 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20903 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20905 * Create a new JsonReader
20906 * @param {Object} meta Metadata configuration options.
20907 * @param {Object} recordType Either an Array of field definition objects
20908 * as specified to {@link Roo.data.Record#create},
20909 * or an {@link Roo.data.Record} object
20910 * created using {@link Roo.data.Record#create}.
20912 Roo.data.ArrayReader = function(meta, recordType){
20913 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20916 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20918 * Create a data block containing Roo.data.Records from an XML document.
20919 * @param {Object} o An Array of row objects which represents the dataset.
20920 * @return {Object} data A data block which is used by an Roo.data.Store object as
20921 * a cache of Roo.data.Records.
20923 readRecords : function(o){
20924 var sid = this.meta ? this.meta.id : null;
20925 var recordType = this.recordType, fields = recordType.prototype.fields;
20928 for(var i = 0; i < root.length; i++){
20931 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20932 for(var j = 0, jlen = fields.length; j < jlen; j++){
20933 var f = fields.items[j];
20934 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20935 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20937 values[f.name] = v;
20939 var record = new recordType(values, id);
20941 records[records.length] = record;
20945 totalRecords : records.length
20950 * Ext JS Library 1.1.1
20951 * Copyright(c) 2006-2007, Ext JS, LLC.
20953 * Originally Released Under LGPL - original licence link has changed is not relivant.
20956 * <script type="text/javascript">
20961 * @class Roo.data.Tree
20962 * @extends Roo.util.Observable
20963 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20964 * in the tree have most standard DOM functionality.
20966 * @param {Node} root (optional) The root node
20968 Roo.data.Tree = function(root){
20969 this.nodeHash = {};
20971 * The root node for this tree
20976 this.setRootNode(root);
20981 * Fires when a new child node is appended to a node in this tree.
20982 * @param {Tree} tree The owner tree
20983 * @param {Node} parent The parent node
20984 * @param {Node} node The newly appended node
20985 * @param {Number} index The index of the newly appended node
20990 * Fires when a child node is removed from a node in this tree.
20991 * @param {Tree} tree The owner tree
20992 * @param {Node} parent The parent node
20993 * @param {Node} node The child node removed
20998 * Fires when a node is moved to a new location in the tree
20999 * @param {Tree} tree The owner tree
21000 * @param {Node} node The node moved
21001 * @param {Node} oldParent The old parent of this node
21002 * @param {Node} newParent The new parent of this node
21003 * @param {Number} index The index it was moved to
21008 * Fires when a new child node is inserted in a node in this tree.
21009 * @param {Tree} tree The owner tree
21010 * @param {Node} parent The parent node
21011 * @param {Node} node The child node inserted
21012 * @param {Node} refNode The child node the node was inserted before
21016 * @event beforeappend
21017 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21018 * @param {Tree} tree The owner tree
21019 * @param {Node} parent The parent node
21020 * @param {Node} node The child node to be appended
21022 "beforeappend" : true,
21024 * @event beforeremove
21025 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21026 * @param {Tree} tree The owner tree
21027 * @param {Node} parent The parent node
21028 * @param {Node} node The child node to be removed
21030 "beforeremove" : true,
21032 * @event beforemove
21033 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21034 * @param {Tree} tree The owner tree
21035 * @param {Node} node The node being moved
21036 * @param {Node} oldParent The parent of the node
21037 * @param {Node} newParent The new parent the node is moving to
21038 * @param {Number} index The index it is being moved to
21040 "beforemove" : true,
21042 * @event beforeinsert
21043 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21044 * @param {Tree} tree The owner tree
21045 * @param {Node} parent The parent node
21046 * @param {Node} node The child node to be inserted
21047 * @param {Node} refNode The child node the node is being inserted before
21049 "beforeinsert" : true
21052 Roo.data.Tree.superclass.constructor.call(this);
21055 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21056 pathSeparator: "/",
21058 proxyNodeEvent : function(){
21059 return this.fireEvent.apply(this, arguments);
21063 * Returns the root node for this tree.
21066 getRootNode : function(){
21071 * Sets the root node for this tree.
21072 * @param {Node} node
21075 setRootNode : function(node){
21077 node.ownerTree = this;
21078 node.isRoot = true;
21079 this.registerNode(node);
21084 * Gets a node in this tree by its id.
21085 * @param {String} id
21088 getNodeById : function(id){
21089 return this.nodeHash[id];
21092 registerNode : function(node){
21093 this.nodeHash[node.id] = node;
21096 unregisterNode : function(node){
21097 delete this.nodeHash[node.id];
21100 toString : function(){
21101 return "[Tree"+(this.id?" "+this.id:"")+"]";
21106 * @class Roo.data.Node
21107 * @extends Roo.util.Observable
21108 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21109 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21111 * @param {Object} attributes The attributes/config for the node
21113 Roo.data.Node = function(attributes){
21115 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21118 this.attributes = attributes || {};
21119 this.leaf = this.attributes.leaf;
21121 * The node id. @type String
21123 this.id = this.attributes.id;
21125 this.id = Roo.id(null, "ynode-");
21126 this.attributes.id = this.id;
21129 * All child nodes of this node. @type Array
21131 this.childNodes = [];
21132 if(!this.childNodes.indexOf){ // indexOf is a must
21133 this.childNodes.indexOf = function(o){
21134 for(var i = 0, len = this.length; i < len; i++){
21143 * The parent node for this node. @type Node
21145 this.parentNode = null;
21147 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21149 this.firstChild = null;
21151 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21153 this.lastChild = null;
21155 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21157 this.previousSibling = null;
21159 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21161 this.nextSibling = null;
21166 * Fires when a new child node is appended
21167 * @param {Tree} tree The owner tree
21168 * @param {Node} this This node
21169 * @param {Node} node The newly appended node
21170 * @param {Number} index The index of the newly appended node
21175 * Fires when a child node is removed
21176 * @param {Tree} tree The owner tree
21177 * @param {Node} this This node
21178 * @param {Node} node The removed node
21183 * Fires when this node is moved to a new location in the tree
21184 * @param {Tree} tree The owner tree
21185 * @param {Node} this This node
21186 * @param {Node} oldParent The old parent of this node
21187 * @param {Node} newParent The new parent of this node
21188 * @param {Number} index The index it was moved to
21193 * Fires when a new child node is inserted.
21194 * @param {Tree} tree The owner tree
21195 * @param {Node} this This node
21196 * @param {Node} node The child node inserted
21197 * @param {Node} refNode The child node the node was inserted before
21201 * @event beforeappend
21202 * Fires before a new child is appended, return false to cancel the append.
21203 * @param {Tree} tree The owner tree
21204 * @param {Node} this This node
21205 * @param {Node} node The child node to be appended
21207 "beforeappend" : true,
21209 * @event beforeremove
21210 * Fires before a child is removed, return false to cancel the remove.
21211 * @param {Tree} tree The owner tree
21212 * @param {Node} this This node
21213 * @param {Node} node The child node to be removed
21215 "beforeremove" : true,
21217 * @event beforemove
21218 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21219 * @param {Tree} tree The owner tree
21220 * @param {Node} this This node
21221 * @param {Node} oldParent The parent of this node
21222 * @param {Node} newParent The new parent this node is moving to
21223 * @param {Number} index The index it is being moved to
21225 "beforemove" : true,
21227 * @event beforeinsert
21228 * Fires before a new child is inserted, return false to cancel the insert.
21229 * @param {Tree} tree The owner tree
21230 * @param {Node} this This node
21231 * @param {Node} node The child node to be inserted
21232 * @param {Node} refNode The child node the node is being inserted before
21234 "beforeinsert" : true
21236 this.listeners = this.attributes.listeners;
21237 Roo.data.Node.superclass.constructor.call(this);
21240 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21241 fireEvent : function(evtName){
21242 // first do standard event for this node
21243 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21246 // then bubble it up to the tree if the event wasn't cancelled
21247 var ot = this.getOwnerTree();
21249 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21257 * Returns true if this node is a leaf
21258 * @return {Boolean}
21260 isLeaf : function(){
21261 return this.leaf === true;
21265 setFirstChild : function(node){
21266 this.firstChild = node;
21270 setLastChild : function(node){
21271 this.lastChild = node;
21276 * Returns true if this node is the last child of its parent
21277 * @return {Boolean}
21279 isLast : function(){
21280 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21284 * Returns true if this node is the first child of its parent
21285 * @return {Boolean}
21287 isFirst : function(){
21288 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21291 hasChildNodes : function(){
21292 return !this.isLeaf() && this.childNodes.length > 0;
21296 * Insert node(s) as the last child node of this node.
21297 * @param {Node/Array} node The node or Array of nodes to append
21298 * @return {Node} The appended node if single append, or null if an array was passed
21300 appendChild : function(node){
21302 if(node instanceof Array){
21304 }else if(arguments.length > 1){
21307 // if passed an array or multiple args do them one by one
21309 for(var i = 0, len = multi.length; i < len; i++) {
21310 this.appendChild(multi[i]);
21313 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21316 var index = this.childNodes.length;
21317 var oldParent = node.parentNode;
21318 // it's a move, make sure we move it cleanly
21320 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21323 oldParent.removeChild(node);
21325 index = this.childNodes.length;
21327 this.setFirstChild(node);
21329 this.childNodes.push(node);
21330 node.parentNode = this;
21331 var ps = this.childNodes[index-1];
21333 node.previousSibling = ps;
21334 ps.nextSibling = node;
21336 node.previousSibling = null;
21338 node.nextSibling = null;
21339 this.setLastChild(node);
21340 node.setOwnerTree(this.getOwnerTree());
21341 this.fireEvent("append", this.ownerTree, this, node, index);
21343 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21350 * Removes a child node from this node.
21351 * @param {Node} node The node to remove
21352 * @return {Node} The removed node
21354 removeChild : function(node){
21355 var index = this.childNodes.indexOf(node);
21359 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21363 // remove it from childNodes collection
21364 this.childNodes.splice(index, 1);
21367 if(node.previousSibling){
21368 node.previousSibling.nextSibling = node.nextSibling;
21370 if(node.nextSibling){
21371 node.nextSibling.previousSibling = node.previousSibling;
21374 // update child refs
21375 if(this.firstChild == node){
21376 this.setFirstChild(node.nextSibling);
21378 if(this.lastChild == node){
21379 this.setLastChild(node.previousSibling);
21382 node.setOwnerTree(null);
21383 // clear any references from the node
21384 node.parentNode = null;
21385 node.previousSibling = null;
21386 node.nextSibling = null;
21387 this.fireEvent("remove", this.ownerTree, this, node);
21392 * Inserts the first node before the second node in this nodes childNodes collection.
21393 * @param {Node} node The node to insert
21394 * @param {Node} refNode The node to insert before (if null the node is appended)
21395 * @return {Node} The inserted node
21397 insertBefore : function(node, refNode){
21398 if(!refNode){ // like standard Dom, refNode can be null for append
21399 return this.appendChild(node);
21402 if(node == refNode){
21406 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21409 var index = this.childNodes.indexOf(refNode);
21410 var oldParent = node.parentNode;
21411 var refIndex = index;
21413 // when moving internally, indexes will change after remove
21414 if(oldParent == this && this.childNodes.indexOf(node) < index){
21418 // it's a move, make sure we move it cleanly
21420 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21423 oldParent.removeChild(node);
21426 this.setFirstChild(node);
21428 this.childNodes.splice(refIndex, 0, node);
21429 node.parentNode = this;
21430 var ps = this.childNodes[refIndex-1];
21432 node.previousSibling = ps;
21433 ps.nextSibling = node;
21435 node.previousSibling = null;
21437 node.nextSibling = refNode;
21438 refNode.previousSibling = node;
21439 node.setOwnerTree(this.getOwnerTree());
21440 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21442 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21448 * Returns the child node at the specified index.
21449 * @param {Number} index
21452 item : function(index){
21453 return this.childNodes[index];
21457 * Replaces one child node in this node with another.
21458 * @param {Node} newChild The replacement node
21459 * @param {Node} oldChild The node to replace
21460 * @return {Node} The replaced node
21462 replaceChild : function(newChild, oldChild){
21463 this.insertBefore(newChild, oldChild);
21464 this.removeChild(oldChild);
21469 * Returns the index of a child node
21470 * @param {Node} node
21471 * @return {Number} The index of the node or -1 if it was not found
21473 indexOf : function(child){
21474 return this.childNodes.indexOf(child);
21478 * Returns the tree this node is in.
21481 getOwnerTree : function(){
21482 // if it doesn't have one, look for one
21483 if(!this.ownerTree){
21487 this.ownerTree = p.ownerTree;
21493 return this.ownerTree;
21497 * Returns depth of this node (the root node has a depth of 0)
21500 getDepth : function(){
21503 while(p.parentNode){
21511 setOwnerTree : function(tree){
21512 // if it's move, we need to update everyone
21513 if(tree != this.ownerTree){
21514 if(this.ownerTree){
21515 this.ownerTree.unregisterNode(this);
21517 this.ownerTree = tree;
21518 var cs = this.childNodes;
21519 for(var i = 0, len = cs.length; i < len; i++) {
21520 cs[i].setOwnerTree(tree);
21523 tree.registerNode(this);
21529 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21530 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21531 * @return {String} The path
21533 getPath : function(attr){
21534 attr = attr || "id";
21535 var p = this.parentNode;
21536 var b = [this.attributes[attr]];
21538 b.unshift(p.attributes[attr]);
21541 var sep = this.getOwnerTree().pathSeparator;
21542 return sep + b.join(sep);
21546 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21547 * function call will be the scope provided or the current node. The arguments to the function
21548 * will be the args provided or the current node. If the function returns false at any point,
21549 * the bubble is stopped.
21550 * @param {Function} fn The function to call
21551 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21552 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21554 bubble : function(fn, scope, args){
21557 if(fn.call(scope || p, args || p) === false){
21565 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21566 * function call will be the scope provided or the current node. The arguments to the function
21567 * will be the args provided or the current node. If the function returns false at any point,
21568 * the cascade is stopped on that branch.
21569 * @param {Function} fn The function to call
21570 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21571 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21573 cascade : function(fn, scope, args){
21574 if(fn.call(scope || this, args || this) !== false){
21575 var cs = this.childNodes;
21576 for(var i = 0, len = cs.length; i < len; i++) {
21577 cs[i].cascade(fn, scope, args);
21583 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21584 * function call will be the scope provided or the current node. The arguments to the function
21585 * will be the args provided or the current node. If the function returns false at any point,
21586 * the iteration stops.
21587 * @param {Function} fn The function to call
21588 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21589 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21591 eachChild : function(fn, scope, args){
21592 var cs = this.childNodes;
21593 for(var i = 0, len = cs.length; i < len; i++) {
21594 if(fn.call(scope || this, args || cs[i]) === false){
21601 * Finds the first child that has the attribute with the specified value.
21602 * @param {String} attribute The attribute name
21603 * @param {Mixed} value The value to search for
21604 * @return {Node} The found child or null if none was found
21606 findChild : function(attribute, value){
21607 var cs = this.childNodes;
21608 for(var i = 0, len = cs.length; i < len; i++) {
21609 if(cs[i].attributes[attribute] == value){
21617 * Finds the first child by a custom function. The child matches if the function passed
21619 * @param {Function} fn
21620 * @param {Object} scope (optional)
21621 * @return {Node} The found child or null if none was found
21623 findChildBy : function(fn, scope){
21624 var cs = this.childNodes;
21625 for(var i = 0, len = cs.length; i < len; i++) {
21626 if(fn.call(scope||cs[i], cs[i]) === true){
21634 * Sorts this nodes children using the supplied sort function
21635 * @param {Function} fn
21636 * @param {Object} scope (optional)
21638 sort : function(fn, scope){
21639 var cs = this.childNodes;
21640 var len = cs.length;
21642 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21644 for(var i = 0; i < len; i++){
21646 n.previousSibling = cs[i-1];
21647 n.nextSibling = cs[i+1];
21649 this.setFirstChild(n);
21652 this.setLastChild(n);
21659 * Returns true if this node is an ancestor (at any point) of the passed node.
21660 * @param {Node} node
21661 * @return {Boolean}
21663 contains : function(node){
21664 return node.isAncestor(this);
21668 * Returns true if the passed node is an ancestor (at any point) of this node.
21669 * @param {Node} node
21670 * @return {Boolean}
21672 isAncestor : function(node){
21673 var p = this.parentNode;
21683 toString : function(){
21684 return "[Node"+(this.id?" "+this.id:"")+"]";
21688 * Ext JS Library 1.1.1
21689 * Copyright(c) 2006-2007, Ext JS, LLC.
21691 * Originally Released Under LGPL - original licence link has changed is not relivant.
21694 * <script type="text/javascript">
21699 * @class Roo.ComponentMgr
21700 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21703 Roo.ComponentMgr = function(){
21704 var all = new Roo.util.MixedCollection();
21708 * Registers a component.
21709 * @param {Roo.Component} c The component
21711 register : function(c){
21716 * Unregisters a component.
21717 * @param {Roo.Component} c The component
21719 unregister : function(c){
21724 * Returns a component by id
21725 * @param {String} id The component id
21727 get : function(id){
21728 return all.get(id);
21732 * Registers a function that will be called when a specified component is added to ComponentMgr
21733 * @param {String} id The component id
21734 * @param {Funtction} fn The callback function
21735 * @param {Object} scope The scope of the callback
21737 onAvailable : function(id, fn, scope){
21738 all.on("add", function(index, o){
21740 fn.call(scope || o, o);
21741 all.un("add", fn, scope);
21748 * Ext JS Library 1.1.1
21749 * Copyright(c) 2006-2007, Ext JS, LLC.
21751 * Originally Released Under LGPL - original licence link has changed is not relivant.
21754 * <script type="text/javascript">
21758 * @class Roo.Component
21759 * @extends Roo.util.Observable
21760 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21761 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21762 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21763 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21764 * All visual components (widgets) that require rendering into a layout should subclass Component.
21766 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21767 * 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
21768 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21770 Roo.Component = function(config){
21771 config = config || {};
21772 if(config.tagName || config.dom || typeof config == "string"){ // element object
21773 config = {el: config, id: config.id || config};
21775 this.initialConfig = config;
21777 Roo.apply(this, config);
21781 * Fires after the component is disabled.
21782 * @param {Roo.Component} this
21787 * Fires after the component is enabled.
21788 * @param {Roo.Component} this
21792 * @event beforeshow
21793 * Fires before the component is shown. Return false to stop the show.
21794 * @param {Roo.Component} this
21799 * Fires after the component is shown.
21800 * @param {Roo.Component} this
21804 * @event beforehide
21805 * Fires before the component is hidden. Return false to stop the hide.
21806 * @param {Roo.Component} this
21811 * Fires after the component is hidden.
21812 * @param {Roo.Component} this
21816 * @event beforerender
21817 * Fires before the component is rendered. Return false to stop the render.
21818 * @param {Roo.Component} this
21820 beforerender : true,
21823 * Fires after the component is rendered.
21824 * @param {Roo.Component} this
21828 * @event beforedestroy
21829 * Fires before the component is destroyed. Return false to stop the destroy.
21830 * @param {Roo.Component} this
21832 beforedestroy : true,
21835 * Fires after the component is destroyed.
21836 * @param {Roo.Component} this
21841 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21843 Roo.ComponentMgr.register(this);
21844 Roo.Component.superclass.constructor.call(this);
21845 this.initComponent();
21846 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21847 this.render(this.renderTo);
21848 delete this.renderTo;
21853 Roo.Component.AUTO_ID = 1000;
21855 Roo.extend(Roo.Component, Roo.util.Observable, {
21857 * @property {Boolean} hidden
21858 * true if this component is hidden. Read-only.
21862 * true if this component is disabled. Read-only.
21866 * true if this component has been rendered. Read-only.
21870 /** @cfg {String} disableClass
21871 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21873 disabledClass : "x-item-disabled",
21874 /** @cfg {Boolean} allowDomMove
21875 * Whether the component can move the Dom node when rendering (defaults to true).
21877 allowDomMove : true,
21878 /** @cfg {String} hideMode
21879 * How this component should hidden. Supported values are
21880 * "visibility" (css visibility), "offsets" (negative offset position) and
21881 * "display" (css display) - defaults to "display".
21883 hideMode: 'display',
21886 ctype : "Roo.Component",
21888 /** @cfg {String} actionMode
21889 * which property holds the element that used for hide() / show() / disable() / enable()
21895 getActionEl : function(){
21896 return this[this.actionMode];
21899 initComponent : Roo.emptyFn,
21901 * If this is a lazy rendering component, render it to its container element.
21902 * @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.
21904 render : function(container, position){
21905 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21906 if(!container && this.el){
21907 this.el = Roo.get(this.el);
21908 container = this.el.dom.parentNode;
21909 this.allowDomMove = false;
21911 this.container = Roo.get(container);
21912 this.rendered = true;
21913 if(position !== undefined){
21914 if(typeof position == 'number'){
21915 position = this.container.dom.childNodes[position];
21917 position = Roo.getDom(position);
21920 this.onRender(this.container, position || null);
21922 this.el.addClass(this.cls);
21926 this.el.applyStyles(this.style);
21929 this.fireEvent("render", this);
21930 this.afterRender(this.container);
21942 // default function is not really useful
21943 onRender : function(ct, position){
21945 this.el = Roo.get(this.el);
21946 if(this.allowDomMove !== false){
21947 ct.dom.insertBefore(this.el.dom, position);
21953 getAutoCreate : function(){
21954 var cfg = typeof this.autoCreate == "object" ?
21955 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21956 if(this.id && !cfg.id){
21963 afterRender : Roo.emptyFn,
21966 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21967 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21969 destroy : function(){
21970 if(this.fireEvent("beforedestroy", this) !== false){
21971 this.purgeListeners();
21972 this.beforeDestroy();
21974 this.el.removeAllListeners();
21976 if(this.actionMode == "container"){
21977 this.container.remove();
21981 Roo.ComponentMgr.unregister(this);
21982 this.fireEvent("destroy", this);
21987 beforeDestroy : function(){
21992 onDestroy : function(){
21997 * Returns the underlying {@link Roo.Element}.
21998 * @return {Roo.Element} The element
22000 getEl : function(){
22005 * Returns the id of this component.
22008 getId : function(){
22013 * Try to focus this component.
22014 * @param {Boolean} selectText True to also select the text in this component (if applicable)
22015 * @return {Roo.Component} this
22017 focus : function(selectText){
22020 if(selectText === true){
22021 this.el.dom.select();
22036 * Disable this component.
22037 * @return {Roo.Component} this
22039 disable : function(){
22043 this.disabled = true;
22044 this.fireEvent("disable", this);
22049 onDisable : function(){
22050 this.getActionEl().addClass(this.disabledClass);
22051 this.el.dom.disabled = true;
22055 * Enable this component.
22056 * @return {Roo.Component} this
22058 enable : function(){
22062 this.disabled = false;
22063 this.fireEvent("enable", this);
22068 onEnable : function(){
22069 this.getActionEl().removeClass(this.disabledClass);
22070 this.el.dom.disabled = false;
22074 * Convenience function for setting disabled/enabled by boolean.
22075 * @param {Boolean} disabled
22077 setDisabled : function(disabled){
22078 this[disabled ? "disable" : "enable"]();
22082 * Show this component.
22083 * @return {Roo.Component} this
22086 if(this.fireEvent("beforeshow", this) !== false){
22087 this.hidden = false;
22091 this.fireEvent("show", this);
22097 onShow : function(){
22098 var ae = this.getActionEl();
22099 if(this.hideMode == 'visibility'){
22100 ae.dom.style.visibility = "visible";
22101 }else if(this.hideMode == 'offsets'){
22102 ae.removeClass('x-hidden');
22104 ae.dom.style.display = "";
22109 * Hide this component.
22110 * @return {Roo.Component} this
22113 if(this.fireEvent("beforehide", this) !== false){
22114 this.hidden = true;
22118 this.fireEvent("hide", this);
22124 onHide : function(){
22125 var ae = this.getActionEl();
22126 if(this.hideMode == 'visibility'){
22127 ae.dom.style.visibility = "hidden";
22128 }else if(this.hideMode == 'offsets'){
22129 ae.addClass('x-hidden');
22131 ae.dom.style.display = "none";
22136 * Convenience function to hide or show this component by boolean.
22137 * @param {Boolean} visible True to show, false to hide
22138 * @return {Roo.Component} this
22140 setVisible: function(visible){
22150 * Returns true if this component is visible.
22152 isVisible : function(){
22153 return this.getActionEl().isVisible();
22156 cloneConfig : function(overrides){
22157 overrides = overrides || {};
22158 var id = overrides.id || Roo.id();
22159 var cfg = Roo.applyIf(overrides, this.initialConfig);
22160 cfg.id = id; // prevent dup id
22161 return new this.constructor(cfg);
22165 * Ext JS Library 1.1.1
22166 * Copyright(c) 2006-2007, Ext JS, LLC.
22168 * Originally Released Under LGPL - original licence link has changed is not relivant.
22171 * <script type="text/javascript">
22176 * @extends Roo.Element
22177 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22178 * automatic maintaining of shadow/shim positions.
22179 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22180 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22181 * you can pass a string with a CSS class name. False turns off the shadow.
22182 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22183 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22184 * @cfg {String} cls CSS class to add to the element
22185 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22186 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22188 * @param {Object} config An object with config options.
22189 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22192 Roo.Layer = function(config, existingEl){
22193 config = config || {};
22194 var dh = Roo.DomHelper;
22195 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22197 this.dom = Roo.getDom(existingEl);
22200 var o = config.dh || {tag: "div", cls: "x-layer"};
22201 this.dom = dh.append(pel, o);
22204 this.addClass(config.cls);
22206 this.constrain = config.constrain !== false;
22207 this.visibilityMode = Roo.Element.VISIBILITY;
22209 this.id = this.dom.id = config.id;
22211 this.id = Roo.id(this.dom);
22213 this.zindex = config.zindex || this.getZIndex();
22214 this.position("absolute", this.zindex);
22216 this.shadowOffset = config.shadowOffset || 4;
22217 this.shadow = new Roo.Shadow({
22218 offset : this.shadowOffset,
22219 mode : config.shadow
22222 this.shadowOffset = 0;
22224 this.useShim = config.shim !== false && Roo.useShims;
22225 this.useDisplay = config.useDisplay;
22229 var supr = Roo.Element.prototype;
22231 // shims are shared among layer to keep from having 100 iframes
22234 Roo.extend(Roo.Layer, Roo.Element, {
22236 getZIndex : function(){
22237 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22240 getShim : function(){
22247 var shim = shims.shift();
22249 shim = this.createShim();
22250 shim.enableDisplayMode('block');
22251 shim.dom.style.display = 'none';
22252 shim.dom.style.visibility = 'visible';
22254 var pn = this.dom.parentNode;
22255 if(shim.dom.parentNode != pn){
22256 pn.insertBefore(shim.dom, this.dom);
22258 shim.setStyle('z-index', this.getZIndex()-2);
22263 hideShim : function(){
22265 this.shim.setDisplayed(false);
22266 shims.push(this.shim);
22271 disableShadow : function(){
22273 this.shadowDisabled = true;
22274 this.shadow.hide();
22275 this.lastShadowOffset = this.shadowOffset;
22276 this.shadowOffset = 0;
22280 enableShadow : function(show){
22282 this.shadowDisabled = false;
22283 this.shadowOffset = this.lastShadowOffset;
22284 delete this.lastShadowOffset;
22292 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22293 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22294 sync : function(doShow){
22295 var sw = this.shadow;
22296 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22297 var sh = this.getShim();
22299 var w = this.getWidth(),
22300 h = this.getHeight();
22302 var l = this.getLeft(true),
22303 t = this.getTop(true);
22305 if(sw && !this.shadowDisabled){
22306 if(doShow && !sw.isVisible()){
22309 sw.realign(l, t, w, h);
22315 // fit the shim behind the shadow, so it is shimmed too
22316 var a = sw.adjusts, s = sh.dom.style;
22317 s.left = (Math.min(l, l+a.l))+"px";
22318 s.top = (Math.min(t, t+a.t))+"px";
22319 s.width = (w+a.w)+"px";
22320 s.height = (h+a.h)+"px";
22327 sh.setLeftTop(l, t);
22334 destroy : function(){
22337 this.shadow.hide();
22339 this.removeAllListeners();
22340 var pn = this.dom.parentNode;
22342 pn.removeChild(this.dom);
22344 Roo.Element.uncache(this.id);
22347 remove : function(){
22352 beginUpdate : function(){
22353 this.updating = true;
22357 endUpdate : function(){
22358 this.updating = false;
22363 hideUnders : function(negOffset){
22365 this.shadow.hide();
22371 constrainXY : function(){
22372 if(this.constrain){
22373 var vw = Roo.lib.Dom.getViewWidth(),
22374 vh = Roo.lib.Dom.getViewHeight();
22375 var s = Roo.get(document).getScroll();
22377 var xy = this.getXY();
22378 var x = xy[0], y = xy[1];
22379 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22380 // only move it if it needs it
22382 // first validate right/bottom
22383 if((x + w) > vw+s.left){
22384 x = vw - w - this.shadowOffset;
22387 if((y + h) > vh+s.top){
22388 y = vh - h - this.shadowOffset;
22391 // then make sure top/left isn't negative
22402 var ay = this.avoidY;
22403 if(y <= ay && (y+h) >= ay){
22409 supr.setXY.call(this, xy);
22415 isVisible : function(){
22416 return this.visible;
22420 showAction : function(){
22421 this.visible = true; // track visibility to prevent getStyle calls
22422 if(this.useDisplay === true){
22423 this.setDisplayed("");
22424 }else if(this.lastXY){
22425 supr.setXY.call(this, this.lastXY);
22426 }else if(this.lastLT){
22427 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22432 hideAction : function(){
22433 this.visible = false;
22434 if(this.useDisplay === true){
22435 this.setDisplayed(false);
22437 this.setLeftTop(-10000,-10000);
22441 // overridden Element method
22442 setVisible : function(v, a, d, c, e){
22447 var cb = function(){
22452 }.createDelegate(this);
22453 supr.setVisible.call(this, true, true, d, cb, e);
22456 this.hideUnders(true);
22465 }.createDelegate(this);
22467 supr.setVisible.call(this, v, a, d, cb, e);
22476 storeXY : function(xy){
22477 delete this.lastLT;
22481 storeLeftTop : function(left, top){
22482 delete this.lastXY;
22483 this.lastLT = [left, top];
22487 beforeFx : function(){
22488 this.beforeAction();
22489 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22493 afterFx : function(){
22494 Roo.Layer.superclass.afterFx.apply(this, arguments);
22495 this.sync(this.isVisible());
22499 beforeAction : function(){
22500 if(!this.updating && this.shadow){
22501 this.shadow.hide();
22505 // overridden Element method
22506 setLeft : function(left){
22507 this.storeLeftTop(left, this.getTop(true));
22508 supr.setLeft.apply(this, arguments);
22512 setTop : function(top){
22513 this.storeLeftTop(this.getLeft(true), top);
22514 supr.setTop.apply(this, arguments);
22518 setLeftTop : function(left, top){
22519 this.storeLeftTop(left, top);
22520 supr.setLeftTop.apply(this, arguments);
22524 setXY : function(xy, a, d, c, e){
22526 this.beforeAction();
22528 var cb = this.createCB(c);
22529 supr.setXY.call(this, xy, a, d, cb, e);
22536 createCB : function(c){
22547 // overridden Element method
22548 setX : function(x, a, d, c, e){
22549 this.setXY([x, this.getY()], a, d, c, e);
22552 // overridden Element method
22553 setY : function(y, a, d, c, e){
22554 this.setXY([this.getX(), y], a, d, c, e);
22557 // overridden Element method
22558 setSize : function(w, h, a, d, c, e){
22559 this.beforeAction();
22560 var cb = this.createCB(c);
22561 supr.setSize.call(this, w, h, a, d, cb, e);
22567 // overridden Element method
22568 setWidth : function(w, a, d, c, e){
22569 this.beforeAction();
22570 var cb = this.createCB(c);
22571 supr.setWidth.call(this, w, a, d, cb, e);
22577 // overridden Element method
22578 setHeight : function(h, a, d, c, e){
22579 this.beforeAction();
22580 var cb = this.createCB(c);
22581 supr.setHeight.call(this, h, a, d, cb, e);
22587 // overridden Element method
22588 setBounds : function(x, y, w, h, a, d, c, e){
22589 this.beforeAction();
22590 var cb = this.createCB(c);
22592 this.storeXY([x, y]);
22593 supr.setXY.call(this, [x, y]);
22594 supr.setSize.call(this, w, h, a, d, cb, e);
22597 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22603 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22604 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22605 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22606 * @param {Number} zindex The new z-index to set
22607 * @return {this} The Layer
22609 setZIndex : function(zindex){
22610 this.zindex = zindex;
22611 this.setStyle("z-index", zindex + 2);
22613 this.shadow.setZIndex(zindex + 1);
22616 this.shim.setStyle("z-index", zindex);
22622 * Ext JS Library 1.1.1
22623 * Copyright(c) 2006-2007, Ext JS, LLC.
22625 * Originally Released Under LGPL - original licence link has changed is not relivant.
22628 * <script type="text/javascript">
22633 * @class Roo.Shadow
22634 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22635 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22636 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22638 * Create a new Shadow
22639 * @param {Object} config The config object
22641 Roo.Shadow = function(config){
22642 Roo.apply(this, config);
22643 if(typeof this.mode != "string"){
22644 this.mode = this.defaultMode;
22646 var o = this.offset, a = {h: 0};
22647 var rad = Math.floor(this.offset/2);
22648 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22654 a.l -= this.offset + rad;
22655 a.t -= this.offset + rad;
22666 a.l -= (this.offset - rad);
22667 a.t -= this.offset + rad;
22669 a.w -= (this.offset - rad)*2;
22680 a.l -= (this.offset - rad);
22681 a.t -= (this.offset - rad);
22683 a.w -= (this.offset + rad + 1);
22684 a.h -= (this.offset + rad);
22693 Roo.Shadow.prototype = {
22695 * @cfg {String} mode
22696 * The shadow display mode. Supports the following options:<br />
22697 * sides: Shadow displays on both sides and bottom only<br />
22698 * frame: Shadow displays equally on all four sides<br />
22699 * drop: Traditional bottom-right drop shadow (default)
22702 * @cfg {String} offset
22703 * The number of pixels to offset the shadow from the element (defaults to 4)
22708 defaultMode: "drop",
22711 * Displays the shadow under the target element
22712 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22714 show : function(target){
22715 target = Roo.get(target);
22717 this.el = Roo.Shadow.Pool.pull();
22718 if(this.el.dom.nextSibling != target.dom){
22719 this.el.insertBefore(target);
22722 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22724 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22727 target.getLeft(true),
22728 target.getTop(true),
22732 this.el.dom.style.display = "block";
22736 * Returns true if the shadow is visible, else false
22738 isVisible : function(){
22739 return this.el ? true : false;
22743 * Direct alignment when values are already available. Show must be called at least once before
22744 * calling this method to ensure it is initialized.
22745 * @param {Number} left The target element left position
22746 * @param {Number} top The target element top position
22747 * @param {Number} width The target element width
22748 * @param {Number} height The target element height
22750 realign : function(l, t, w, h){
22754 var a = this.adjusts, d = this.el.dom, s = d.style;
22756 s.left = (l+a.l)+"px";
22757 s.top = (t+a.t)+"px";
22758 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22760 if(s.width != sws || s.height != shs){
22764 var cn = d.childNodes;
22765 var sww = Math.max(0, (sw-12))+"px";
22766 cn[0].childNodes[1].style.width = sww;
22767 cn[1].childNodes[1].style.width = sww;
22768 cn[2].childNodes[1].style.width = sww;
22769 cn[1].style.height = Math.max(0, (sh-12))+"px";
22775 * Hides this shadow
22779 this.el.dom.style.display = "none";
22780 Roo.Shadow.Pool.push(this.el);
22786 * Adjust the z-index of this shadow
22787 * @param {Number} zindex The new z-index
22789 setZIndex : function(z){
22792 this.el.setStyle("z-index", z);
22797 // Private utility class that manages the internal Shadow cache
22798 Roo.Shadow.Pool = function(){
22800 var markup = Roo.isIE ?
22801 '<div class="x-ie-shadow"></div>' :
22802 '<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>';
22805 var sh = p.shift();
22807 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22808 sh.autoBoxAdjust = false;
22813 push : function(sh){
22819 * Ext JS Library 1.1.1
22820 * Copyright(c) 2006-2007, Ext JS, LLC.
22822 * Originally Released Under LGPL - original licence link has changed is not relivant.
22825 * <script type="text/javascript">
22829 * @class Roo.BoxComponent
22830 * @extends Roo.Component
22831 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22832 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22833 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22834 * layout containers.
22836 * @param {Roo.Element/String/Object} config The configuration options.
22838 Roo.BoxComponent = function(config){
22839 Roo.Component.call(this, config);
22843 * Fires after the component is resized.
22844 * @param {Roo.Component} this
22845 * @param {Number} adjWidth The box-adjusted width that was set
22846 * @param {Number} adjHeight The box-adjusted height that was set
22847 * @param {Number} rawWidth The width that was originally specified
22848 * @param {Number} rawHeight The height that was originally specified
22853 * Fires after the component is moved.
22854 * @param {Roo.Component} this
22855 * @param {Number} x The new x position
22856 * @param {Number} y The new y position
22862 Roo.extend(Roo.BoxComponent, Roo.Component, {
22863 // private, set in afterRender to signify that the component has been rendered
22865 // private, used to defer height settings to subclasses
22866 deferHeight: false,
22867 /** @cfg {Number} width
22868 * width (optional) size of component
22870 /** @cfg {Number} height
22871 * height (optional) size of component
22875 * Sets the width and height of the component. This method fires the resize event. This method can accept
22876 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22877 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22878 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22879 * @return {Roo.BoxComponent} this
22881 setSize : function(w, h){
22882 // support for standard size objects
22883 if(typeof w == 'object'){
22888 if(!this.boxReady){
22894 // prevent recalcs when not needed
22895 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22898 this.lastSize = {width: w, height: h};
22900 var adj = this.adjustSize(w, h);
22901 var aw = adj.width, ah = adj.height;
22902 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22903 var rz = this.getResizeEl();
22904 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22905 rz.setSize(aw, ah);
22906 }else if(!this.deferHeight && ah !== undefined){
22908 }else if(aw !== undefined){
22911 this.onResize(aw, ah, w, h);
22912 this.fireEvent('resize', this, aw, ah, w, h);
22918 * Gets the current size of the component's underlying element.
22919 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22921 getSize : function(){
22922 return this.el.getSize();
22926 * Gets the current XY position of the component's underlying element.
22927 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22928 * @return {Array} The XY position of the element (e.g., [100, 200])
22930 getPosition : function(local){
22931 if(local === true){
22932 return [this.el.getLeft(true), this.el.getTop(true)];
22934 return this.xy || this.el.getXY();
22938 * Gets the current box measurements of the component's underlying element.
22939 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22940 * @returns {Object} box An object in the format {x, y, width, height}
22942 getBox : function(local){
22943 var s = this.el.getSize();
22945 s.x = this.el.getLeft(true);
22946 s.y = this.el.getTop(true);
22948 var xy = this.xy || this.el.getXY();
22956 * Sets the current box measurements of the component's underlying element.
22957 * @param {Object} box An object in the format {x, y, width, height}
22958 * @returns {Roo.BoxComponent} this
22960 updateBox : function(box){
22961 this.setSize(box.width, box.height);
22962 this.setPagePosition(box.x, box.y);
22967 getResizeEl : function(){
22968 return this.resizeEl || this.el;
22972 getPositionEl : function(){
22973 return this.positionEl || this.el;
22977 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22978 * This method fires the move event.
22979 * @param {Number} left The new left
22980 * @param {Number} top The new top
22981 * @returns {Roo.BoxComponent} this
22983 setPosition : function(x, y){
22986 if(!this.boxReady){
22989 var adj = this.adjustPosition(x, y);
22990 var ax = adj.x, ay = adj.y;
22992 var el = this.getPositionEl();
22993 if(ax !== undefined || ay !== undefined){
22994 if(ax !== undefined && ay !== undefined){
22995 el.setLeftTop(ax, ay);
22996 }else if(ax !== undefined){
22998 }else if(ay !== undefined){
23001 this.onPosition(ax, ay);
23002 this.fireEvent('move', this, ax, ay);
23008 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
23009 * This method fires the move event.
23010 * @param {Number} x The new x position
23011 * @param {Number} y The new y position
23012 * @returns {Roo.BoxComponent} this
23014 setPagePosition : function(x, y){
23017 if(!this.boxReady){
23020 if(x === undefined || y === undefined){ // cannot translate undefined points
23023 var p = this.el.translatePoints(x, y);
23024 this.setPosition(p.left, p.top);
23029 onRender : function(ct, position){
23030 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23032 this.resizeEl = Roo.get(this.resizeEl);
23034 if(this.positionEl){
23035 this.positionEl = Roo.get(this.positionEl);
23040 afterRender : function(){
23041 Roo.BoxComponent.superclass.afterRender.call(this);
23042 this.boxReady = true;
23043 this.setSize(this.width, this.height);
23044 if(this.x || this.y){
23045 this.setPosition(this.x, this.y);
23047 if(this.pageX || this.pageY){
23048 this.setPagePosition(this.pageX, this.pageY);
23053 * Force the component's size to recalculate based on the underlying element's current height and width.
23054 * @returns {Roo.BoxComponent} this
23056 syncSize : function(){
23057 delete this.lastSize;
23058 this.setSize(this.el.getWidth(), this.el.getHeight());
23063 * Called after the component is resized, this method is empty by default but can be implemented by any
23064 * subclass that needs to perform custom logic after a resize occurs.
23065 * @param {Number} adjWidth The box-adjusted width that was set
23066 * @param {Number} adjHeight The box-adjusted height that was set
23067 * @param {Number} rawWidth The width that was originally specified
23068 * @param {Number} rawHeight The height that was originally specified
23070 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23075 * Called after the component is moved, this method is empty by default but can be implemented by any
23076 * subclass that needs to perform custom logic after a move occurs.
23077 * @param {Number} x The new x position
23078 * @param {Number} y The new y position
23080 onPosition : function(x, y){
23085 adjustSize : function(w, h){
23086 if(this.autoWidth){
23089 if(this.autoHeight){
23092 return {width : w, height: h};
23096 adjustPosition : function(x, y){
23097 return {x : x, y: y};
23101 * Ext JS Library 1.1.1
23102 * Copyright(c) 2006-2007, Ext JS, LLC.
23104 * Originally Released Under LGPL - original licence link has changed is not relivant.
23107 * <script type="text/javascript">
23112 * @class Roo.SplitBar
23113 * @extends Roo.util.Observable
23114 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23118 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23119 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23120 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23121 split.minSize = 100;
23122 split.maxSize = 600;
23123 split.animate = true;
23124 split.on('moved', splitterMoved);
23127 * Create a new SplitBar
23128 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23129 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23130 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23131 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23132 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23133 position of the SplitBar).
23135 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23138 this.el = Roo.get(dragElement, true);
23139 this.el.dom.unselectable = "on";
23141 this.resizingEl = Roo.get(resizingElement, true);
23145 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23146 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23149 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23152 * The minimum size of the resizing element. (Defaults to 0)
23158 * The maximum size of the resizing element. (Defaults to 2000)
23161 this.maxSize = 2000;
23164 * Whether to animate the transition to the new size
23167 this.animate = false;
23170 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23173 this.useShim = false;
23178 if(!existingProxy){
23180 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23182 this.proxy = Roo.get(existingProxy).dom;
23185 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23188 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23191 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23194 this.dragSpecs = {};
23197 * @private The adapter to use to positon and resize elements
23199 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23200 this.adapter.init(this);
23202 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23204 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23205 this.el.addClass("x-splitbar-h");
23208 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23209 this.el.addClass("x-splitbar-v");
23215 * Fires when the splitter is moved (alias for {@link #event-moved})
23216 * @param {Roo.SplitBar} this
23217 * @param {Number} newSize the new width or height
23222 * Fires when the splitter is moved
23223 * @param {Roo.SplitBar} this
23224 * @param {Number} newSize the new width or height
23228 * @event beforeresize
23229 * Fires before the splitter is dragged
23230 * @param {Roo.SplitBar} this
23232 "beforeresize" : true,
23234 "beforeapply" : true
23237 Roo.util.Observable.call(this);
23240 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23241 onStartProxyDrag : function(x, y){
23242 this.fireEvent("beforeresize", this);
23244 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23246 o.enableDisplayMode("block");
23247 // all splitbars share the same overlay
23248 Roo.SplitBar.prototype.overlay = o;
23250 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23251 this.overlay.show();
23252 Roo.get(this.proxy).setDisplayed("block");
23253 var size = this.adapter.getElementSize(this);
23254 this.activeMinSize = this.getMinimumSize();;
23255 this.activeMaxSize = this.getMaximumSize();;
23256 var c1 = size - this.activeMinSize;
23257 var c2 = Math.max(this.activeMaxSize - size, 0);
23258 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23259 this.dd.resetConstraints();
23260 this.dd.setXConstraint(
23261 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23262 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23264 this.dd.setYConstraint(0, 0);
23266 this.dd.resetConstraints();
23267 this.dd.setXConstraint(0, 0);
23268 this.dd.setYConstraint(
23269 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23270 this.placement == Roo.SplitBar.TOP ? c2 : c1
23273 this.dragSpecs.startSize = size;
23274 this.dragSpecs.startPoint = [x, y];
23275 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23279 * @private Called after the drag operation by the DDProxy
23281 onEndProxyDrag : function(e){
23282 Roo.get(this.proxy).setDisplayed(false);
23283 var endPoint = Roo.lib.Event.getXY(e);
23285 this.overlay.hide();
23288 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23289 newSize = this.dragSpecs.startSize +
23290 (this.placement == Roo.SplitBar.LEFT ?
23291 endPoint[0] - this.dragSpecs.startPoint[0] :
23292 this.dragSpecs.startPoint[0] - endPoint[0]
23295 newSize = this.dragSpecs.startSize +
23296 (this.placement == Roo.SplitBar.TOP ?
23297 endPoint[1] - this.dragSpecs.startPoint[1] :
23298 this.dragSpecs.startPoint[1] - endPoint[1]
23301 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23302 if(newSize != this.dragSpecs.startSize){
23303 if(this.fireEvent('beforeapply', this, newSize) !== false){
23304 this.adapter.setElementSize(this, newSize);
23305 this.fireEvent("moved", this, newSize);
23306 this.fireEvent("resize", this, newSize);
23312 * Get the adapter this SplitBar uses
23313 * @return The adapter object
23315 getAdapter : function(){
23316 return this.adapter;
23320 * Set the adapter this SplitBar uses
23321 * @param {Object} adapter A SplitBar adapter object
23323 setAdapter : function(adapter){
23324 this.adapter = adapter;
23325 this.adapter.init(this);
23329 * Gets the minimum size for the resizing element
23330 * @return {Number} The minimum size
23332 getMinimumSize : function(){
23333 return this.minSize;
23337 * Sets the minimum size for the resizing element
23338 * @param {Number} minSize The minimum size
23340 setMinimumSize : function(minSize){
23341 this.minSize = minSize;
23345 * Gets the maximum size for the resizing element
23346 * @return {Number} The maximum size
23348 getMaximumSize : function(){
23349 return this.maxSize;
23353 * Sets the maximum size for the resizing element
23354 * @param {Number} maxSize The maximum size
23356 setMaximumSize : function(maxSize){
23357 this.maxSize = maxSize;
23361 * Sets the initialize size for the resizing element
23362 * @param {Number} size The initial size
23364 setCurrentSize : function(size){
23365 var oldAnimate = this.animate;
23366 this.animate = false;
23367 this.adapter.setElementSize(this, size);
23368 this.animate = oldAnimate;
23372 * Destroy this splitbar.
23373 * @param {Boolean} removeEl True to remove the element
23375 destroy : function(removeEl){
23377 this.shim.remove();
23380 this.proxy.parentNode.removeChild(this.proxy);
23388 * @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.
23390 Roo.SplitBar.createProxy = function(dir){
23391 var proxy = new Roo.Element(document.createElement("div"));
23392 proxy.unselectable();
23393 var cls = 'x-splitbar-proxy';
23394 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23395 document.body.appendChild(proxy.dom);
23400 * @class Roo.SplitBar.BasicLayoutAdapter
23401 * Default Adapter. It assumes the splitter and resizing element are not positioned
23402 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23404 Roo.SplitBar.BasicLayoutAdapter = function(){
23407 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23408 // do nothing for now
23409 init : function(s){
23413 * Called before drag operations to get the current size of the resizing element.
23414 * @param {Roo.SplitBar} s The SplitBar using this adapter
23416 getElementSize : function(s){
23417 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23418 return s.resizingEl.getWidth();
23420 return s.resizingEl.getHeight();
23425 * Called after drag operations to set the size of the resizing element.
23426 * @param {Roo.SplitBar} s The SplitBar using this adapter
23427 * @param {Number} newSize The new size to set
23428 * @param {Function} onComplete A function to be invoked when resizing is complete
23430 setElementSize : function(s, newSize, onComplete){
23431 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23433 s.resizingEl.setWidth(newSize);
23435 onComplete(s, newSize);
23438 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23443 s.resizingEl.setHeight(newSize);
23445 onComplete(s, newSize);
23448 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23455 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23456 * @extends Roo.SplitBar.BasicLayoutAdapter
23457 * Adapter that moves the splitter element to align with the resized sizing element.
23458 * Used with an absolute positioned SplitBar.
23459 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23460 * document.body, make sure you assign an id to the body element.
23462 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23463 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23464 this.container = Roo.get(container);
23467 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23468 init : function(s){
23469 this.basic.init(s);
23472 getElementSize : function(s){
23473 return this.basic.getElementSize(s);
23476 setElementSize : function(s, newSize, onComplete){
23477 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23480 moveSplitter : function(s){
23481 var yes = Roo.SplitBar;
23482 switch(s.placement){
23484 s.el.setX(s.resizingEl.getRight());
23487 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23490 s.el.setY(s.resizingEl.getBottom());
23493 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23500 * Orientation constant - Create a vertical SplitBar
23504 Roo.SplitBar.VERTICAL = 1;
23507 * Orientation constant - Create a horizontal SplitBar
23511 Roo.SplitBar.HORIZONTAL = 2;
23514 * Placement constant - The resizing element is to the left of the splitter element
23518 Roo.SplitBar.LEFT = 1;
23521 * Placement constant - The resizing element is to the right of the splitter element
23525 Roo.SplitBar.RIGHT = 2;
23528 * Placement constant - The resizing element is positioned above the splitter element
23532 Roo.SplitBar.TOP = 3;
23535 * Placement constant - The resizing element is positioned under splitter element
23539 Roo.SplitBar.BOTTOM = 4;
23542 * Ext JS Library 1.1.1
23543 * Copyright(c) 2006-2007, Ext JS, LLC.
23545 * Originally Released Under LGPL - original licence link has changed is not relivant.
23548 * <script type="text/javascript">
23553 * @extends Roo.util.Observable
23554 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23555 * This class also supports single and multi selection modes. <br>
23556 * Create a data model bound view:
23558 var store = new Roo.data.Store(...);
23560 var view = new Roo.View({
23562 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
23564 singleSelect: true,
23565 selectedClass: "ydataview-selected",
23569 // listen for node click?
23570 view.on("click", function(vw, index, node, e){
23571 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23575 dataModel.load("foobar.xml");
23577 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23579 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23580 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23582 * Note: old style constructor is still suported (container, template, config)
23585 * Create a new View
23586 * @param {Object} config The config object
23589 Roo.View = function(config, depreciated_tpl, depreciated_config){
23591 if (typeof(depreciated_tpl) == 'undefined') {
23592 // new way.. - universal constructor.
23593 Roo.apply(this, config);
23594 this.el = Roo.get(this.el);
23597 this.el = Roo.get(config);
23598 this.tpl = depreciated_tpl;
23599 Roo.apply(this, depreciated_config);
23603 if(typeof(this.tpl) == "string"){
23604 this.tpl = new Roo.Template(this.tpl);
23606 // support xtype ctors..
23607 this.tpl = new Roo.factory(this.tpl, Roo);
23611 this.tpl.compile();
23618 * @event beforeclick
23619 * Fires before a click is processed. Returns false to cancel the default action.
23620 * @param {Roo.View} this
23621 * @param {Number} index The index of the target node
23622 * @param {HTMLElement} node The target node
23623 * @param {Roo.EventObject} e The raw event object
23625 "beforeclick" : true,
23628 * Fires when a template node is clicked.
23629 * @param {Roo.View} this
23630 * @param {Number} index The index of the target node
23631 * @param {HTMLElement} node The target node
23632 * @param {Roo.EventObject} e The raw event object
23637 * Fires when a template node is double clicked.
23638 * @param {Roo.View} this
23639 * @param {Number} index The index of the target node
23640 * @param {HTMLElement} node The target node
23641 * @param {Roo.EventObject} e The raw event object
23645 * @event contextmenu
23646 * Fires when a template node is right clicked.
23647 * @param {Roo.View} this
23648 * @param {Number} index The index of the target node
23649 * @param {HTMLElement} node The target node
23650 * @param {Roo.EventObject} e The raw event object
23652 "contextmenu" : true,
23654 * @event selectionchange
23655 * Fires when the selected nodes change.
23656 * @param {Roo.View} this
23657 * @param {Array} selections Array of the selected nodes
23659 "selectionchange" : true,
23662 * @event beforeselect
23663 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23664 * @param {Roo.View} this
23665 * @param {HTMLElement} node The node to be selected
23666 * @param {Array} selections Array of currently selected nodes
23668 "beforeselect" : true
23672 "click": this.onClick,
23673 "dblclick": this.onDblClick,
23674 "contextmenu": this.onContextMenu,
23678 this.selections = [];
23680 this.cmp = new Roo.CompositeElementLite([]);
23682 this.store = Roo.factory(this.store, Roo.data);
23683 this.setStore(this.store, true);
23685 Roo.View.superclass.constructor.call(this);
23688 Roo.extend(Roo.View, Roo.util.Observable, {
23691 * @cfg {Roo.data.Store} store Data store to load data from.
23696 * @cfg {String|Roo.Element} el The container element.
23701 * @cfg {String|Roo.Template} tpl The template used by this View
23706 * @cfg {String} selectedClass The css class to add to selected nodes
23708 selectedClass : "x-view-selected",
23710 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23714 * @cfg {Boolean} multiSelect Allow multiple selection
23717 multiSelect : false,
23719 * @cfg {Boolean} singleSelect Allow single selection
23721 singleSelect: false,
23724 * Returns the element this view is bound to.
23725 * @return {Roo.Element}
23727 getEl : function(){
23732 * Refreshes the view.
23734 refresh : function(){
23736 this.clearSelections();
23737 this.el.update("");
23739 var records = this.store.getRange();
23740 if(records.length < 1){
23741 this.el.update(this.emptyText);
23744 for(var i = 0, len = records.length; i < len; i++){
23745 var data = this.prepareData(records[i].data, i, records[i]);
23746 html[html.length] = t.apply(data);
23748 this.el.update(html.join(""));
23749 this.nodes = this.el.dom.childNodes;
23750 this.updateIndexes(0);
23754 * Function to override to reformat the data that is sent to
23755 * the template for each node.
23756 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23757 * a JSON object for an UpdateManager bound view).
23759 prepareData : function(data){
23763 onUpdate : function(ds, record){
23764 this.clearSelections();
23765 var index = this.store.indexOf(record);
23766 var n = this.nodes[index];
23767 this.tpl.insertBefore(n, this.prepareData(record.data));
23768 n.parentNode.removeChild(n);
23769 this.updateIndexes(index, index);
23772 onAdd : function(ds, records, index){
23773 this.clearSelections();
23774 if(this.nodes.length == 0){
23778 var n = this.nodes[index];
23779 for(var i = 0, len = records.length; i < len; i++){
23780 var d = this.prepareData(records[i].data);
23782 this.tpl.insertBefore(n, d);
23784 this.tpl.append(this.el, d);
23787 this.updateIndexes(index);
23790 onRemove : function(ds, record, index){
23791 this.clearSelections();
23792 this.el.dom.removeChild(this.nodes[index]);
23793 this.updateIndexes(index);
23797 * Refresh an individual node.
23798 * @param {Number} index
23800 refreshNode : function(index){
23801 this.onUpdate(this.store, this.store.getAt(index));
23804 updateIndexes : function(startIndex, endIndex){
23805 var ns = this.nodes;
23806 startIndex = startIndex || 0;
23807 endIndex = endIndex || ns.length - 1;
23808 for(var i = startIndex; i <= endIndex; i++){
23809 ns[i].nodeIndex = i;
23814 * Changes the data store this view uses and refresh the view.
23815 * @param {Store} store
23817 setStore : function(store, initial){
23818 if(!initial && this.store){
23819 this.store.un("datachanged", this.refresh);
23820 this.store.un("add", this.onAdd);
23821 this.store.un("remove", this.onRemove);
23822 this.store.un("update", this.onUpdate);
23823 this.store.un("clear", this.refresh);
23827 store.on("datachanged", this.refresh, this);
23828 store.on("add", this.onAdd, this);
23829 store.on("remove", this.onRemove, this);
23830 store.on("update", this.onUpdate, this);
23831 store.on("clear", this.refresh, this);
23840 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23841 * @param {HTMLElement} node
23842 * @return {HTMLElement} The template node
23844 findItemFromChild : function(node){
23845 var el = this.el.dom;
23846 if(!node || node.parentNode == el){
23849 var p = node.parentNode;
23850 while(p && p != el){
23851 if(p.parentNode == el){
23860 onClick : function(e){
23861 var item = this.findItemFromChild(e.getTarget());
23863 var index = this.indexOf(item);
23864 if(this.onItemClick(item, index, e) !== false){
23865 this.fireEvent("click", this, index, item, e);
23868 this.clearSelections();
23873 onContextMenu : function(e){
23874 var item = this.findItemFromChild(e.getTarget());
23876 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23881 onDblClick : function(e){
23882 var item = this.findItemFromChild(e.getTarget());
23884 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23888 onItemClick : function(item, index, e){
23889 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23892 if(this.multiSelect || this.singleSelect){
23893 if(this.multiSelect && e.shiftKey && this.lastSelection){
23894 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23896 this.select(item, this.multiSelect && e.ctrlKey);
23897 this.lastSelection = item;
23899 e.preventDefault();
23905 * Get the number of selected nodes.
23908 getSelectionCount : function(){
23909 return this.selections.length;
23913 * Get the currently selected nodes.
23914 * @return {Array} An array of HTMLElements
23916 getSelectedNodes : function(){
23917 return this.selections;
23921 * Get the indexes of the selected nodes.
23924 getSelectedIndexes : function(){
23925 var indexes = [], s = this.selections;
23926 for(var i = 0, len = s.length; i < len; i++){
23927 indexes.push(s[i].nodeIndex);
23933 * Clear all selections
23934 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23936 clearSelections : function(suppressEvent){
23937 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23938 this.cmp.elements = this.selections;
23939 this.cmp.removeClass(this.selectedClass);
23940 this.selections = [];
23941 if(!suppressEvent){
23942 this.fireEvent("selectionchange", this, this.selections);
23948 * Returns true if the passed node is selected
23949 * @param {HTMLElement/Number} node The node or node index
23950 * @return {Boolean}
23952 isSelected : function(node){
23953 var s = this.selections;
23957 node = this.getNode(node);
23958 return s.indexOf(node) !== -1;
23963 * @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
23964 * @param {Boolean} keepExisting (optional) true to keep existing selections
23965 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23967 select : function(nodeInfo, keepExisting, suppressEvent){
23968 if(nodeInfo instanceof Array){
23970 this.clearSelections(true);
23972 for(var i = 0, len = nodeInfo.length; i < len; i++){
23973 this.select(nodeInfo[i], true, true);
23976 var node = this.getNode(nodeInfo);
23977 if(node && !this.isSelected(node)){
23979 this.clearSelections(true);
23981 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23982 Roo.fly(node).addClass(this.selectedClass);
23983 this.selections.push(node);
23984 if(!suppressEvent){
23985 this.fireEvent("selectionchange", this, this.selections);
23993 * Gets a template node.
23994 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23995 * @return {HTMLElement} The node or null if it wasn't found
23997 getNode : function(nodeInfo){
23998 if(typeof nodeInfo == "string"){
23999 return document.getElementById(nodeInfo);
24000 }else if(typeof nodeInfo == "number"){
24001 return this.nodes[nodeInfo];
24007 * Gets a range template nodes.
24008 * @param {Number} startIndex
24009 * @param {Number} endIndex
24010 * @return {Array} An array of nodes
24012 getNodes : function(start, end){
24013 var ns = this.nodes;
24014 start = start || 0;
24015 end = typeof end == "undefined" ? ns.length - 1 : end;
24018 for(var i = start; i <= end; i++){
24022 for(var i = start; i >= end; i--){
24030 * Finds the index of the passed node
24031 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24032 * @return {Number} The index of the node or -1
24034 indexOf : function(node){
24035 node = this.getNode(node);
24036 if(typeof node.nodeIndex == "number"){
24037 return node.nodeIndex;
24039 var ns = this.nodes;
24040 for(var i = 0, len = ns.length; i < len; i++){
24050 * Ext JS Library 1.1.1
24051 * Copyright(c) 2006-2007, Ext JS, LLC.
24053 * Originally Released Under LGPL - original licence link has changed is not relivant.
24056 * <script type="text/javascript">
24060 * @class Roo.JsonView
24061 * @extends Roo.View
24062 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24064 var view = new Roo.JsonView({
24065 container: "my-element",
24066 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24071 // listen for node click?
24072 view.on("click", function(vw, index, node, e){
24073 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24076 // direct load of JSON data
24077 view.load("foobar.php");
24079 // Example from my blog list
24080 var tpl = new Roo.Template(
24081 '<div class="entry">' +
24082 '<a class="entry-title" href="{link}">{title}</a>' +
24083 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24084 "</div><hr />"
24087 var moreView = new Roo.JsonView({
24088 container : "entry-list",
24092 moreView.on("beforerender", this.sortEntries, this);
24094 url: "/blog/get-posts.php",
24095 params: "allposts=true",
24096 text: "Loading Blog Entries..."
24100 * Note: old code is supported with arguments : (container, template, config)
24104 * Create a new JsonView
24106 * @param {Object} config The config object
24109 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24112 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24114 var um = this.el.getUpdateManager();
24115 um.setRenderer(this);
24116 um.on("update", this.onLoad, this);
24117 um.on("failure", this.onLoadException, this);
24120 * @event beforerender
24121 * Fires before rendering of the downloaded JSON data.
24122 * @param {Roo.JsonView} this
24123 * @param {Object} data The JSON data loaded
24127 * Fires when data is loaded.
24128 * @param {Roo.JsonView} this
24129 * @param {Object} data The JSON data loaded
24130 * @param {Object} response The raw Connect response object
24133 * @event loadexception
24134 * Fires when loading fails.
24135 * @param {Roo.JsonView} this
24136 * @param {Object} response The raw Connect response object
24139 'beforerender' : true,
24141 'loadexception' : true
24144 Roo.extend(Roo.JsonView, Roo.View, {
24146 * @type {String} The root property in the loaded JSON object that contains the data
24151 * Refreshes the view.
24153 refresh : function(){
24154 this.clearSelections();
24155 this.el.update("");
24157 var o = this.jsonData;
24158 if(o && o.length > 0){
24159 for(var i = 0, len = o.length; i < len; i++){
24160 var data = this.prepareData(o[i], i, o);
24161 html[html.length] = this.tpl.apply(data);
24164 html.push(this.emptyText);
24166 this.el.update(html.join(""));
24167 this.nodes = this.el.dom.childNodes;
24168 this.updateIndexes(0);
24172 * 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.
24173 * @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:
24176 url: "your-url.php",
24177 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24178 callback: yourFunction,
24179 scope: yourObject, //(optional scope)
24182 text: "Loading...",
24187 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24188 * 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.
24189 * @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}
24190 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24191 * @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.
24194 var um = this.el.getUpdateManager();
24195 um.update.apply(um, arguments);
24198 render : function(el, response){
24199 this.clearSelections();
24200 this.el.update("");
24203 o = Roo.util.JSON.decode(response.responseText);
24206 o = o[this.jsonRoot];
24211 * The current JSON data or null
24214 this.beforeRender();
24219 * Get the number of records in the current JSON dataset
24222 getCount : function(){
24223 return this.jsonData ? this.jsonData.length : 0;
24227 * Returns the JSON object for the specified node(s)
24228 * @param {HTMLElement/Array} node The node or an array of nodes
24229 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24230 * you get the JSON object for the node
24232 getNodeData : function(node){
24233 if(node instanceof Array){
24235 for(var i = 0, len = node.length; i < len; i++){
24236 data.push(this.getNodeData(node[i]));
24240 return this.jsonData[this.indexOf(node)] || null;
24243 beforeRender : function(){
24244 this.snapshot = this.jsonData;
24246 this.sort.apply(this, this.sortInfo);
24248 this.fireEvent("beforerender", this, this.jsonData);
24251 onLoad : function(el, o){
24252 this.fireEvent("load", this, this.jsonData, o);
24255 onLoadException : function(el, o){
24256 this.fireEvent("loadexception", this, o);
24260 * Filter the data by a specific property.
24261 * @param {String} property A property on your JSON objects
24262 * @param {String/RegExp} value Either string that the property values
24263 * should start with, or a RegExp to test against the property
24265 filter : function(property, value){
24268 var ss = this.snapshot;
24269 if(typeof value == "string"){
24270 var vlen = value.length;
24272 this.clearFilter();
24275 value = value.toLowerCase();
24276 for(var i = 0, len = ss.length; i < len; i++){
24278 if(o[property].substr(0, vlen).toLowerCase() == value){
24282 } else if(value.exec){ // regex?
24283 for(var i = 0, len = ss.length; i < len; i++){
24285 if(value.test(o[property])){
24292 this.jsonData = data;
24298 * Filter by a function. The passed function will be called with each
24299 * object in the current dataset. If the function returns true the value is kept,
24300 * otherwise it is filtered.
24301 * @param {Function} fn
24302 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24304 filterBy : function(fn, scope){
24307 var ss = this.snapshot;
24308 for(var i = 0, len = ss.length; i < len; i++){
24310 if(fn.call(scope || this, o)){
24314 this.jsonData = data;
24320 * Clears the current filter.
24322 clearFilter : function(){
24323 if(this.snapshot && this.jsonData != this.snapshot){
24324 this.jsonData = this.snapshot;
24331 * Sorts the data for this view and refreshes it.
24332 * @param {String} property A property on your JSON objects to sort on
24333 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24334 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24336 sort : function(property, dir, sortType){
24337 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24340 var dsc = dir && dir.toLowerCase() == "desc";
24341 var f = function(o1, o2){
24342 var v1 = sortType ? sortType(o1[p]) : o1[p];
24343 var v2 = sortType ? sortType(o2[p]) : o2[p];
24346 return dsc ? +1 : -1;
24347 } else if(v1 > v2){
24348 return dsc ? -1 : +1;
24353 this.jsonData.sort(f);
24355 if(this.jsonData != this.snapshot){
24356 this.snapshot.sort(f);
24362 * Ext JS Library 1.1.1
24363 * Copyright(c) 2006-2007, Ext JS, LLC.
24365 * Originally Released Under LGPL - original licence link has changed is not relivant.
24368 * <script type="text/javascript">
24373 * @class Roo.ColorPalette
24374 * @extends Roo.Component
24375 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24376 * Here's an example of typical usage:
24378 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24379 cp.render('my-div');
24381 cp.on('select', function(palette, selColor){
24382 // do something with selColor
24386 * Create a new ColorPalette
24387 * @param {Object} config The config object
24389 Roo.ColorPalette = function(config){
24390 Roo.ColorPalette.superclass.constructor.call(this, config);
24394 * Fires when a color is selected
24395 * @param {ColorPalette} this
24396 * @param {String} color The 6-digit color hex code (without the # symbol)
24402 this.on("select", this.handler, this.scope, true);
24405 Roo.extend(Roo.ColorPalette, Roo.Component, {
24407 * @cfg {String} itemCls
24408 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24410 itemCls : "x-color-palette",
24412 * @cfg {String} value
24413 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24414 * the hex codes are case-sensitive.
24417 clickEvent:'click',
24419 ctype: "Roo.ColorPalette",
24422 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24424 allowReselect : false,
24427 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24428 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24429 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24430 * of colors with the width setting until the box is symmetrical.</p>
24431 * <p>You can override individual colors if needed:</p>
24433 var cp = new Roo.ColorPalette();
24434 cp.colors[0] = "FF0000"; // change the first box to red
24437 Or you can provide a custom array of your own for complete control:
24439 var cp = new Roo.ColorPalette();
24440 cp.colors = ["000000", "993300", "333300"];
24445 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24446 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24447 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24448 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24449 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24453 onRender : function(container, position){
24454 var t = new Roo.MasterTemplate(
24455 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24457 var c = this.colors;
24458 for(var i = 0, len = c.length; i < len; i++){
24461 var el = document.createElement("div");
24462 el.className = this.itemCls;
24464 container.dom.insertBefore(el, position);
24465 this.el = Roo.get(el);
24466 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24467 if(this.clickEvent != 'click'){
24468 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24473 afterRender : function(){
24474 Roo.ColorPalette.superclass.afterRender.call(this);
24476 var s = this.value;
24483 handleClick : function(e, t){
24484 e.preventDefault();
24485 if(!this.disabled){
24486 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24487 this.select(c.toUpperCase());
24492 * Selects the specified color in the palette (fires the select event)
24493 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24495 select : function(color){
24496 color = color.replace("#", "");
24497 if(color != this.value || this.allowReselect){
24500 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24502 el.child("a.color-"+color).addClass("x-color-palette-sel");
24503 this.value = color;
24504 this.fireEvent("select", this, color);
24509 * Ext JS Library 1.1.1
24510 * Copyright(c) 2006-2007, Ext JS, LLC.
24512 * Originally Released Under LGPL - original licence link has changed is not relivant.
24515 * <script type="text/javascript">
24519 * @class Roo.DatePicker
24520 * @extends Roo.Component
24521 * Simple date picker class.
24523 * Create a new DatePicker
24524 * @param {Object} config The config object
24526 Roo.DatePicker = function(config){
24527 Roo.DatePicker.superclass.constructor.call(this, config);
24529 this.value = config && config.value ?
24530 config.value.clearTime() : new Date().clearTime();
24535 * Fires when a date is selected
24536 * @param {DatePicker} this
24537 * @param {Date} date The selected date
24543 this.on("select", this.handler, this.scope || this);
24545 // build the disabledDatesRE
24546 if(!this.disabledDatesRE && this.disabledDates){
24547 var dd = this.disabledDates;
24549 for(var i = 0; i < dd.length; i++){
24551 if(i != dd.length-1) re += "|";
24553 this.disabledDatesRE = new RegExp(re + ")");
24557 Roo.extend(Roo.DatePicker, Roo.Component, {
24559 * @cfg {String} todayText
24560 * The text to display on the button that selects the current date (defaults to "Today")
24562 todayText : "Today",
24564 * @cfg {String} okText
24565 * The text to display on the ok button
24567 okText : " OK ", //   to give the user extra clicking room
24569 * @cfg {String} cancelText
24570 * The text to display on the cancel button
24572 cancelText : "Cancel",
24574 * @cfg {String} todayTip
24575 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24577 todayTip : "{0} (Spacebar)",
24579 * @cfg {Date} minDate
24580 * Minimum allowable date (JavaScript date object, defaults to null)
24584 * @cfg {Date} maxDate
24585 * Maximum allowable date (JavaScript date object, defaults to null)
24589 * @cfg {String} minText
24590 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24592 minText : "This date is before the minimum date",
24594 * @cfg {String} maxText
24595 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24597 maxText : "This date is after the maximum date",
24599 * @cfg {String} format
24600 * The default date format string which can be overriden for localization support. The format must be
24601 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24605 * @cfg {Array} disabledDays
24606 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24608 disabledDays : null,
24610 * @cfg {String} disabledDaysText
24611 * The tooltip to display when the date falls on a disabled day (defaults to "")
24613 disabledDaysText : "",
24615 * @cfg {RegExp} disabledDatesRE
24616 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24618 disabledDatesRE : null,
24620 * @cfg {String} disabledDatesText
24621 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24623 disabledDatesText : "",
24625 * @cfg {Boolean} constrainToViewport
24626 * True to constrain the date picker to the viewport (defaults to true)
24628 constrainToViewport : true,
24630 * @cfg {Array} monthNames
24631 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24633 monthNames : Date.monthNames,
24635 * @cfg {Array} dayNames
24636 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24638 dayNames : Date.dayNames,
24640 * @cfg {String} nextText
24641 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24643 nextText: 'Next Month (Control+Right)',
24645 * @cfg {String} prevText
24646 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24648 prevText: 'Previous Month (Control+Left)',
24650 * @cfg {String} monthYearText
24651 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24653 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24655 * @cfg {Number} startDay
24656 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24660 * @cfg {Bool} showClear
24661 * Show a clear button (usefull for date form elements that can be blank.)
24667 * Sets the value of the date field
24668 * @param {Date} value The date to set
24670 setValue : function(value){
24671 var old = this.value;
24672 this.value = value.clearTime(true);
24674 this.update(this.value);
24679 * Gets the current selected value of the date field
24680 * @return {Date} The selected date
24682 getValue : function(){
24687 focus : function(){
24689 this.update(this.activeDate);
24694 onRender : function(container, position){
24696 '<table cellspacing="0">',
24697 '<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>',
24698 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24699 var dn = this.dayNames;
24700 for(var i = 0; i < 7; i++){
24701 var d = this.startDay+i;
24705 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24707 m[m.length] = "</tr></thead><tbody><tr>";
24708 for(var i = 0; i < 42; i++) {
24709 if(i % 7 == 0 && i != 0){
24710 m[m.length] = "</tr><tr>";
24712 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24714 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24715 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24717 var el = document.createElement("div");
24718 el.className = "x-date-picker";
24719 el.innerHTML = m.join("");
24721 container.dom.insertBefore(el, position);
24723 this.el = Roo.get(el);
24724 this.eventEl = Roo.get(el.firstChild);
24726 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24727 handler: this.showPrevMonth,
24729 preventDefault:true,
24733 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24734 handler: this.showNextMonth,
24736 preventDefault:true,
24740 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24742 this.monthPicker = this.el.down('div.x-date-mp');
24743 this.monthPicker.enableDisplayMode('block');
24745 var kn = new Roo.KeyNav(this.eventEl, {
24746 "left" : function(e){
24748 this.showPrevMonth() :
24749 this.update(this.activeDate.add("d", -1));
24752 "right" : function(e){
24754 this.showNextMonth() :
24755 this.update(this.activeDate.add("d", 1));
24758 "up" : function(e){
24760 this.showNextYear() :
24761 this.update(this.activeDate.add("d", -7));
24764 "down" : function(e){
24766 this.showPrevYear() :
24767 this.update(this.activeDate.add("d", 7));
24770 "pageUp" : function(e){
24771 this.showNextMonth();
24774 "pageDown" : function(e){
24775 this.showPrevMonth();
24778 "enter" : function(e){
24779 e.stopPropagation();
24786 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24788 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24790 this.el.unselectable();
24792 this.cells = this.el.select("table.x-date-inner tbody td");
24793 this.textNodes = this.el.query("table.x-date-inner tbody span");
24795 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24797 tooltip: this.monthYearText
24800 this.mbtn.on('click', this.showMonthPicker, this);
24801 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24804 var today = (new Date()).dateFormat(this.format);
24806 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24807 if (this.showClear) {
24808 baseTb.add( new Roo.Toolbar.Fill());
24811 text: String.format(this.todayText, today),
24812 tooltip: String.format(this.todayTip, today),
24813 handler: this.selectToday,
24817 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24820 if (this.showClear) {
24822 baseTb.add( new Roo.Toolbar.Fill());
24825 cls: 'x-btn-icon x-btn-clear',
24826 handler: function() {
24828 this.fireEvent("select", this, '');
24838 this.update(this.value);
24841 createMonthPicker : function(){
24842 if(!this.monthPicker.dom.firstChild){
24843 var buf = ['<table border="0" cellspacing="0">'];
24844 for(var i = 0; i < 6; i++){
24846 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24847 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24849 '<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>' :
24850 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24854 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24856 '</button><button type="button" class="x-date-mp-cancel">',
24858 '</button></td></tr>',
24861 this.monthPicker.update(buf.join(''));
24862 this.monthPicker.on('click', this.onMonthClick, this);
24863 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24865 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24866 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24868 this.mpMonths.each(function(m, a, i){
24871 m.dom.xmonth = 5 + Math.round(i * .5);
24873 m.dom.xmonth = Math.round((i-1) * .5);
24879 showMonthPicker : function(){
24880 this.createMonthPicker();
24881 var size = this.el.getSize();
24882 this.monthPicker.setSize(size);
24883 this.monthPicker.child('table').setSize(size);
24885 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24886 this.updateMPMonth(this.mpSelMonth);
24887 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24888 this.updateMPYear(this.mpSelYear);
24890 this.monthPicker.slideIn('t', {duration:.2});
24893 updateMPYear : function(y){
24895 var ys = this.mpYears.elements;
24896 for(var i = 1; i <= 10; i++){
24897 var td = ys[i-1], y2;
24899 y2 = y + Math.round(i * .5);
24900 td.firstChild.innerHTML = y2;
24903 y2 = y - (5-Math.round(i * .5));
24904 td.firstChild.innerHTML = y2;
24907 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24911 updateMPMonth : function(sm){
24912 this.mpMonths.each(function(m, a, i){
24913 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24917 selectMPMonth: function(m){
24921 onMonthClick : function(e, t){
24923 var el = new Roo.Element(t), pn;
24924 if(el.is('button.x-date-mp-cancel')){
24925 this.hideMonthPicker();
24927 else if(el.is('button.x-date-mp-ok')){
24928 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24929 this.hideMonthPicker();
24931 else if(pn = el.up('td.x-date-mp-month', 2)){
24932 this.mpMonths.removeClass('x-date-mp-sel');
24933 pn.addClass('x-date-mp-sel');
24934 this.mpSelMonth = pn.dom.xmonth;
24936 else if(pn = el.up('td.x-date-mp-year', 2)){
24937 this.mpYears.removeClass('x-date-mp-sel');
24938 pn.addClass('x-date-mp-sel');
24939 this.mpSelYear = pn.dom.xyear;
24941 else if(el.is('a.x-date-mp-prev')){
24942 this.updateMPYear(this.mpyear-10);
24944 else if(el.is('a.x-date-mp-next')){
24945 this.updateMPYear(this.mpyear+10);
24949 onMonthDblClick : function(e, t){
24951 var el = new Roo.Element(t), pn;
24952 if(pn = el.up('td.x-date-mp-month', 2)){
24953 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24954 this.hideMonthPicker();
24956 else if(pn = el.up('td.x-date-mp-year', 2)){
24957 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24958 this.hideMonthPicker();
24962 hideMonthPicker : function(disableAnim){
24963 if(this.monthPicker){
24964 if(disableAnim === true){
24965 this.monthPicker.hide();
24967 this.monthPicker.slideOut('t', {duration:.2});
24973 showPrevMonth : function(e){
24974 this.update(this.activeDate.add("mo", -1));
24978 showNextMonth : function(e){
24979 this.update(this.activeDate.add("mo", 1));
24983 showPrevYear : function(){
24984 this.update(this.activeDate.add("y", -1));
24988 showNextYear : function(){
24989 this.update(this.activeDate.add("y", 1));
24993 handleMouseWheel : function(e){
24994 var delta = e.getWheelDelta();
24996 this.showPrevMonth();
24998 } else if(delta < 0){
24999 this.showNextMonth();
25005 handleDateClick : function(e, t){
25007 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25008 this.setValue(new Date(t.dateValue));
25009 this.fireEvent("select", this, this.value);
25014 selectToday : function(){
25015 this.setValue(new Date().clearTime());
25016 this.fireEvent("select", this, this.value);
25020 update : function(date){
25021 var vd = this.activeDate;
25022 this.activeDate = date;
25024 var t = date.getTime();
25025 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25026 this.cells.removeClass("x-date-selected");
25027 this.cells.each(function(c){
25028 if(c.dom.firstChild.dateValue == t){
25029 c.addClass("x-date-selected");
25030 setTimeout(function(){
25031 try{c.dom.firstChild.focus();}catch(e){}
25039 var days = date.getDaysInMonth();
25040 var firstOfMonth = date.getFirstDateOfMonth();
25041 var startingPos = firstOfMonth.getDay()-this.startDay;
25043 if(startingPos <= this.startDay){
25047 var pm = date.add("mo", -1);
25048 var prevStart = pm.getDaysInMonth()-startingPos;
25050 var cells = this.cells.elements;
25051 var textEls = this.textNodes;
25052 days += startingPos;
25054 // convert everything to numbers so it's fast
25055 var day = 86400000;
25056 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25057 var today = new Date().clearTime().getTime();
25058 var sel = date.clearTime().getTime();
25059 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25060 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25061 var ddMatch = this.disabledDatesRE;
25062 var ddText = this.disabledDatesText;
25063 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25064 var ddaysText = this.disabledDaysText;
25065 var format = this.format;
25067 var setCellClass = function(cal, cell){
25069 var t = d.getTime();
25070 cell.firstChild.dateValue = t;
25072 cell.className += " x-date-today";
25073 cell.title = cal.todayText;
25076 cell.className += " x-date-selected";
25077 setTimeout(function(){
25078 try{cell.firstChild.focus();}catch(e){}
25083 cell.className = " x-date-disabled";
25084 cell.title = cal.minText;
25088 cell.className = " x-date-disabled";
25089 cell.title = cal.maxText;
25093 if(ddays.indexOf(d.getDay()) != -1){
25094 cell.title = ddaysText;
25095 cell.className = " x-date-disabled";
25098 if(ddMatch && format){
25099 var fvalue = d.dateFormat(format);
25100 if(ddMatch.test(fvalue)){
25101 cell.title = ddText.replace("%0", fvalue);
25102 cell.className = " x-date-disabled";
25108 for(; i < startingPos; i++) {
25109 textEls[i].innerHTML = (++prevStart);
25110 d.setDate(d.getDate()+1);
25111 cells[i].className = "x-date-prevday";
25112 setCellClass(this, cells[i]);
25114 for(; i < days; i++){
25115 intDay = i - startingPos + 1;
25116 textEls[i].innerHTML = (intDay);
25117 d.setDate(d.getDate()+1);
25118 cells[i].className = "x-date-active";
25119 setCellClass(this, cells[i]);
25122 for(; i < 42; i++) {
25123 textEls[i].innerHTML = (++extraDays);
25124 d.setDate(d.getDate()+1);
25125 cells[i].className = "x-date-nextday";
25126 setCellClass(this, cells[i]);
25129 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25131 if(!this.internalRender){
25132 var main = this.el.dom.firstChild;
25133 var w = main.offsetWidth;
25134 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25135 Roo.fly(main).setWidth(w);
25136 this.internalRender = true;
25137 // opera does not respect the auto grow header center column
25138 // then, after it gets a width opera refuses to recalculate
25139 // without a second pass
25140 if(Roo.isOpera && !this.secondPass){
25141 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25142 this.secondPass = true;
25143 this.update.defer(10, this, [date]);
25149 * Ext JS Library 1.1.1
25150 * Copyright(c) 2006-2007, Ext JS, LLC.
25152 * Originally Released Under LGPL - original licence link has changed is not relivant.
25155 * <script type="text/javascript">
25158 * @class Roo.TabPanel
25159 * @extends Roo.util.Observable
25160 * A lightweight tab container.
25164 // basic tabs 1, built from existing content
25165 var tabs = new Roo.TabPanel("tabs1");
25166 tabs.addTab("script", "View Script");
25167 tabs.addTab("markup", "View Markup");
25168 tabs.activate("script");
25170 // more advanced tabs, built from javascript
25171 var jtabs = new Roo.TabPanel("jtabs");
25172 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25174 // set up the UpdateManager
25175 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25176 var updater = tab2.getUpdateManager();
25177 updater.setDefaultUrl("ajax1.htm");
25178 tab2.on('activate', updater.refresh, updater, true);
25180 // Use setUrl for Ajax loading
25181 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25182 tab3.setUrl("ajax2.htm", null, true);
25185 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25188 jtabs.activate("jtabs-1");
25191 * Create a new TabPanel.
25192 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25193 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25195 Roo.TabPanel = function(container, config){
25197 * The container element for this TabPanel.
25198 * @type Roo.Element
25200 this.el = Roo.get(container, true);
25202 if(typeof config == "boolean"){
25203 this.tabPosition = config ? "bottom" : "top";
25205 Roo.apply(this, config);
25208 if(this.tabPosition == "bottom"){
25209 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25210 this.el.addClass("x-tabs-bottom");
25212 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25213 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25214 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25216 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25218 if(this.tabPosition != "bottom"){
25219 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
25220 * @type Roo.Element
25222 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25223 this.el.addClass("x-tabs-top");
25227 this.bodyEl.setStyle("position", "relative");
25229 this.active = null;
25230 this.activateDelegate = this.activate.createDelegate(this);
25235 * Fires when the active tab changes
25236 * @param {Roo.TabPanel} this
25237 * @param {Roo.TabPanelItem} activePanel The new active tab
25241 * @event beforetabchange
25242 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25243 * @param {Roo.TabPanel} this
25244 * @param {Object} e Set cancel to true on this object to cancel the tab change
25245 * @param {Roo.TabPanelItem} tab The tab being changed to
25247 "beforetabchange" : true
25250 Roo.EventManager.onWindowResize(this.onResize, this);
25251 this.cpad = this.el.getPadding("lr");
25252 this.hiddenCount = 0;
25255 // toolbar on the tabbar support...
25256 if (this.toolbar) {
25257 var tcfg = this.toolbar;
25258 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
25259 this.toolbar = new Roo.Toolbar(tcfg);
25260 if (Roo.isSafari) {
25261 var tbl = tcfg.container.child('table', true);
25262 tbl.setAttribute('width', '100%');
25269 Roo.TabPanel.superclass.constructor.call(this);
25272 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25274 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25276 tabPosition : "top",
25278 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25280 currentTabWidth : 0,
25282 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25286 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25290 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25292 preferredTabWidth : 175,
25294 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25296 resizeTabs : false,
25298 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25300 monitorResize : true,
25302 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
25307 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25308 * @param {String} id The id of the div to use <b>or create</b>
25309 * @param {String} text The text for the tab
25310 * @param {String} content (optional) Content to put in the TabPanelItem body
25311 * @param {Boolean} closable (optional) True to create a close icon on the tab
25312 * @return {Roo.TabPanelItem} The created TabPanelItem
25314 addTab : function(id, text, content, closable){
25315 var item = new Roo.TabPanelItem(this, id, text, closable);
25316 this.addTabItem(item);
25318 item.setContent(content);
25324 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25325 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25326 * @return {Roo.TabPanelItem}
25328 getTab : function(id){
25329 return this.items[id];
25333 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25334 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25336 hideTab : function(id){
25337 var t = this.items[id];
25340 this.hiddenCount++;
25341 this.autoSizeTabs();
25346 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25347 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25349 unhideTab : function(id){
25350 var t = this.items[id];
25352 t.setHidden(false);
25353 this.hiddenCount--;
25354 this.autoSizeTabs();
25359 * Adds an existing {@link Roo.TabPanelItem}.
25360 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25362 addTabItem : function(item){
25363 this.items[item.id] = item;
25364 this.items.push(item);
25365 if(this.resizeTabs){
25366 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25367 this.autoSizeTabs();
25374 * Removes a {@link Roo.TabPanelItem}.
25375 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25377 removeTab : function(id){
25378 var items = this.items;
25379 var tab = items[id];
25380 if(!tab) { return; }
25381 var index = items.indexOf(tab);
25382 if(this.active == tab && items.length > 1){
25383 var newTab = this.getNextAvailable(index);
25388 this.stripEl.dom.removeChild(tab.pnode.dom);
25389 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25390 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25392 items.splice(index, 1);
25393 delete this.items[tab.id];
25394 tab.fireEvent("close", tab);
25395 tab.purgeListeners();
25396 this.autoSizeTabs();
25399 getNextAvailable : function(start){
25400 var items = this.items;
25402 // look for a next tab that will slide over to
25403 // replace the one being removed
25404 while(index < items.length){
25405 var item = items[++index];
25406 if(item && !item.isHidden()){
25410 // if one isn't found select the previous tab (on the left)
25413 var item = items[--index];
25414 if(item && !item.isHidden()){
25422 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25423 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25425 disableTab : function(id){
25426 var tab = this.items[id];
25427 if(tab && this.active != tab){
25433 * Enables a {@link Roo.TabPanelItem} that is disabled.
25434 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25436 enableTab : function(id){
25437 var tab = this.items[id];
25442 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25443 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25444 * @return {Roo.TabPanelItem} The TabPanelItem.
25446 activate : function(id){
25447 var tab = this.items[id];
25451 if(tab == this.active || tab.disabled){
25455 this.fireEvent("beforetabchange", this, e, tab);
25456 if(e.cancel !== true && !tab.disabled){
25458 this.active.hide();
25460 this.active = this.items[id];
25461 this.active.show();
25462 this.fireEvent("tabchange", this, this.active);
25468 * Gets the active {@link Roo.TabPanelItem}.
25469 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25471 getActiveTab : function(){
25472 return this.active;
25476 * Updates the tab body element to fit the height of the container element
25477 * for overflow scrolling
25478 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25480 syncHeight : function(targetHeight){
25481 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25482 var bm = this.bodyEl.getMargins();
25483 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25484 this.bodyEl.setHeight(newHeight);
25488 onResize : function(){
25489 if(this.monitorResize){
25490 this.autoSizeTabs();
25495 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25497 beginUpdate : function(){
25498 this.updating = true;
25502 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25504 endUpdate : function(){
25505 this.updating = false;
25506 this.autoSizeTabs();
25510 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25512 autoSizeTabs : function(){
25513 var count = this.items.length;
25514 var vcount = count - this.hiddenCount;
25515 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25516 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25517 var availWidth = Math.floor(w / vcount);
25518 var b = this.stripBody;
25519 if(b.getWidth() > w){
25520 var tabs = this.items;
25521 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25522 if(availWidth < this.minTabWidth){
25523 /*if(!this.sleft){ // incomplete scrolling code
25524 this.createScrollButtons();
25527 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25530 if(this.currentTabWidth < this.preferredTabWidth){
25531 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25537 * Returns the number of tabs in this TabPanel.
25540 getCount : function(){
25541 return this.items.length;
25545 * Resizes all the tabs to the passed width
25546 * @param {Number} The new width
25548 setTabWidth : function(width){
25549 this.currentTabWidth = width;
25550 for(var i = 0, len = this.items.length; i < len; i++) {
25551 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25556 * Destroys this TabPanel
25557 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25559 destroy : function(removeEl){
25560 Roo.EventManager.removeResizeListener(this.onResize, this);
25561 for(var i = 0, len = this.items.length; i < len; i++){
25562 this.items[i].purgeListeners();
25564 if(removeEl === true){
25565 this.el.update("");
25572 * @class Roo.TabPanelItem
25573 * @extends Roo.util.Observable
25574 * Represents an individual item (tab plus body) in a TabPanel.
25575 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25576 * @param {String} id The id of this TabPanelItem
25577 * @param {String} text The text for the tab of this TabPanelItem
25578 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25580 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25582 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25583 * @type Roo.TabPanel
25585 this.tabPanel = tabPanel;
25587 * The id for this TabPanelItem
25592 this.disabled = false;
25596 this.loaded = false;
25597 this.closable = closable;
25600 * The body element for this TabPanelItem.
25601 * @type Roo.Element
25603 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25604 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25605 this.bodyEl.setStyle("display", "block");
25606 this.bodyEl.setStyle("zoom", "1");
25609 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25611 this.el = Roo.get(els.el, true);
25612 this.inner = Roo.get(els.inner, true);
25613 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25614 this.pnode = Roo.get(els.el.parentNode, true);
25615 this.el.on("mousedown", this.onTabMouseDown, this);
25616 this.el.on("click", this.onTabClick, this);
25619 var c = Roo.get(els.close, true);
25620 c.dom.title = this.closeText;
25621 c.addClassOnOver("close-over");
25622 c.on("click", this.closeClick, this);
25628 * Fires when this tab becomes the active tab.
25629 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25630 * @param {Roo.TabPanelItem} this
25634 * @event beforeclose
25635 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25636 * @param {Roo.TabPanelItem} this
25637 * @param {Object} e Set cancel to true on this object to cancel the close.
25639 "beforeclose": true,
25642 * Fires when this tab is closed.
25643 * @param {Roo.TabPanelItem} this
25647 * @event deactivate
25648 * Fires when this tab is no longer the active tab.
25649 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25650 * @param {Roo.TabPanelItem} this
25652 "deactivate" : true
25654 this.hidden = false;
25656 Roo.TabPanelItem.superclass.constructor.call(this);
25659 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25660 purgeListeners : function(){
25661 Roo.util.Observable.prototype.purgeListeners.call(this);
25662 this.el.removeAllListeners();
25665 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25668 this.pnode.addClass("on");
25671 this.tabPanel.stripWrap.repaint();
25673 this.fireEvent("activate", this.tabPanel, this);
25677 * Returns true if this tab is the active tab.
25678 * @return {Boolean}
25680 isActive : function(){
25681 return this.tabPanel.getActiveTab() == this;
25685 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25688 this.pnode.removeClass("on");
25690 this.fireEvent("deactivate", this.tabPanel, this);
25693 hideAction : function(){
25694 this.bodyEl.hide();
25695 this.bodyEl.setStyle("position", "absolute");
25696 this.bodyEl.setLeft("-20000px");
25697 this.bodyEl.setTop("-20000px");
25700 showAction : function(){
25701 this.bodyEl.setStyle("position", "relative");
25702 this.bodyEl.setTop("");
25703 this.bodyEl.setLeft("");
25704 this.bodyEl.show();
25708 * Set the tooltip for the tab.
25709 * @param {String} tooltip The tab's tooltip
25711 setTooltip : function(text){
25712 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25713 this.textEl.dom.qtip = text;
25714 this.textEl.dom.removeAttribute('title');
25716 this.textEl.dom.title = text;
25720 onTabClick : function(e){
25721 e.preventDefault();
25722 this.tabPanel.activate(this.id);
25725 onTabMouseDown : function(e){
25726 e.preventDefault();
25727 this.tabPanel.activate(this.id);
25730 getWidth : function(){
25731 return this.inner.getWidth();
25734 setWidth : function(width){
25735 var iwidth = width - this.pnode.getPadding("lr");
25736 this.inner.setWidth(iwidth);
25737 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25738 this.pnode.setWidth(width);
25742 * Show or hide the tab
25743 * @param {Boolean} hidden True to hide or false to show.
25745 setHidden : function(hidden){
25746 this.hidden = hidden;
25747 this.pnode.setStyle("display", hidden ? "none" : "");
25751 * Returns true if this tab is "hidden"
25752 * @return {Boolean}
25754 isHidden : function(){
25755 return this.hidden;
25759 * Returns the text for this tab
25762 getText : function(){
25766 autoSize : function(){
25767 //this.el.beginMeasure();
25768 this.textEl.setWidth(1);
25769 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25770 //this.el.endMeasure();
25774 * Sets the text for the tab (Note: this also sets the tooltip text)
25775 * @param {String} text The tab's text and tooltip
25777 setText : function(text){
25779 this.textEl.update(text);
25780 this.setTooltip(text);
25781 if(!this.tabPanel.resizeTabs){
25786 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25788 activate : function(){
25789 this.tabPanel.activate(this.id);
25793 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25795 disable : function(){
25796 if(this.tabPanel.active != this){
25797 this.disabled = true;
25798 this.pnode.addClass("disabled");
25803 * Enables this TabPanelItem if it was previously disabled.
25805 enable : function(){
25806 this.disabled = false;
25807 this.pnode.removeClass("disabled");
25811 * Sets the content for this TabPanelItem.
25812 * @param {String} content The content
25813 * @param {Boolean} loadScripts true to look for and load scripts
25815 setContent : function(content, loadScripts){
25816 this.bodyEl.update(content, loadScripts);
25820 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25821 * @return {Roo.UpdateManager} The UpdateManager
25823 getUpdateManager : function(){
25824 return this.bodyEl.getUpdateManager();
25828 * Set a URL to be used to load the content for this TabPanelItem.
25829 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25830 * @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)
25831 * @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)
25832 * @return {Roo.UpdateManager} The UpdateManager
25834 setUrl : function(url, params, loadOnce){
25835 if(this.refreshDelegate){
25836 this.un('activate', this.refreshDelegate);
25838 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25839 this.on("activate", this.refreshDelegate);
25840 return this.bodyEl.getUpdateManager();
25844 _handleRefresh : function(url, params, loadOnce){
25845 if(!loadOnce || !this.loaded){
25846 var updater = this.bodyEl.getUpdateManager();
25847 updater.update(url, params, this._setLoaded.createDelegate(this));
25852 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25853 * Will fail silently if the setUrl method has not been called.
25854 * This does not activate the panel, just updates its content.
25856 refresh : function(){
25857 if(this.refreshDelegate){
25858 this.loaded = false;
25859 this.refreshDelegate();
25864 _setLoaded : function(){
25865 this.loaded = true;
25869 closeClick : function(e){
25872 this.fireEvent("beforeclose", this, o);
25873 if(o.cancel !== true){
25874 this.tabPanel.removeTab(this.id);
25878 * The text displayed in the tooltip for the close icon.
25881 closeText : "Close this tab"
25885 Roo.TabPanel.prototype.createStrip = function(container){
25886 var strip = document.createElement("div");
25887 strip.className = "x-tabs-wrap";
25888 container.appendChild(strip);
25892 Roo.TabPanel.prototype.createStripList = function(strip){
25893 // div wrapper for retard IE
25894 // returns the "tr" element.
25895 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
25896 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
25897 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
25898 return strip.firstChild.firstChild.firstChild.firstChild;
25901 Roo.TabPanel.prototype.createBody = function(container){
25902 var body = document.createElement("div");
25903 Roo.id(body, "tab-body");
25904 Roo.fly(body).addClass("x-tabs-body");
25905 container.appendChild(body);
25909 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25910 var body = Roo.getDom(id);
25912 body = document.createElement("div");
25915 Roo.fly(body).addClass("x-tabs-item-body");
25916 bodyEl.insertBefore(body, bodyEl.firstChild);
25920 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25921 var td = document.createElement("td");
25922 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
25923 //stripEl.appendChild(td);
25925 td.className = "x-tabs-closable";
25926 if(!this.closeTpl){
25927 this.closeTpl = new Roo.Template(
25928 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25929 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25930 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25933 var el = this.closeTpl.overwrite(td, {"text": text});
25934 var close = el.getElementsByTagName("div")[0];
25935 var inner = el.getElementsByTagName("em")[0];
25936 return {"el": el, "close": close, "inner": inner};
25939 this.tabTpl = new Roo.Template(
25940 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25941 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25944 var el = this.tabTpl.overwrite(td, {"text": text});
25945 var inner = el.getElementsByTagName("em")[0];
25946 return {"el": el, "inner": inner};
25950 * Ext JS Library 1.1.1
25951 * Copyright(c) 2006-2007, Ext JS, LLC.
25953 * Originally Released Under LGPL - original licence link has changed is not relivant.
25956 * <script type="text/javascript">
25960 * @class Roo.Button
25961 * @extends Roo.util.Observable
25962 * Simple Button class
25963 * @cfg {String} text The button text
25964 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25965 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25966 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25967 * @cfg {Object} scope The scope of the handler
25968 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25969 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25970 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25971 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25972 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25973 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25974 applies if enableToggle = true)
25975 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25976 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25977 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25979 * Create a new button
25980 * @param {Object} config The config object
25982 Roo.Button = function(renderTo, config)
25986 renderTo = config.renderTo || false;
25989 Roo.apply(this, config);
25993 * Fires when this button is clicked
25994 * @param {Button} this
25995 * @param {EventObject} e The click event
26000 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26001 * @param {Button} this
26002 * @param {Boolean} pressed
26007 * Fires when the mouse hovers over the button
26008 * @param {Button} this
26009 * @param {Event} e The event object
26011 'mouseover' : true,
26014 * Fires when the mouse exits the button
26015 * @param {Button} this
26016 * @param {Event} e The event object
26021 * Fires when the button is rendered
26022 * @param {Button} this
26027 this.menu = Roo.menu.MenuMgr.get(this.menu);
26029 // register listeners first!! - so render can be captured..
26030 Roo.util.Observable.call(this);
26032 this.render(renderTo);
26038 Roo.extend(Roo.Button, Roo.util.Observable, {
26044 * Read-only. True if this button is hidden
26049 * Read-only. True if this button is disabled
26054 * Read-only. True if this button is pressed (only if enableToggle = true)
26060 * @cfg {Number} tabIndex
26061 * The DOM tabIndex for this button (defaults to undefined)
26063 tabIndex : undefined,
26066 * @cfg {Boolean} enableToggle
26067 * True to enable pressed/not pressed toggling (defaults to false)
26069 enableToggle: false,
26071 * @cfg {Mixed} menu
26072 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26076 * @cfg {String} menuAlign
26077 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26079 menuAlign : "tl-bl?",
26082 * @cfg {String} iconCls
26083 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26085 iconCls : undefined,
26087 * @cfg {String} type
26088 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26093 menuClassTarget: 'tr',
26096 * @cfg {String} clickEvent
26097 * The type of event to map to the button's event handler (defaults to 'click')
26099 clickEvent : 'click',
26102 * @cfg {Boolean} handleMouseEvents
26103 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26105 handleMouseEvents : true,
26108 * @cfg {String} tooltipType
26109 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26111 tooltipType : 'qtip',
26114 * @cfg {String} cls
26115 * A CSS class to apply to the button's main element.
26119 * @cfg {Roo.Template} template (Optional)
26120 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26121 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26122 * require code modifications if required elements (e.g. a button) aren't present.
26126 render : function(renderTo){
26128 if(this.hideParent){
26129 this.parentEl = Roo.get(renderTo);
26131 if(!this.dhconfig){
26132 if(!this.template){
26133 if(!Roo.Button.buttonTemplate){
26134 // hideous table template
26135 Roo.Button.buttonTemplate = new Roo.Template(
26136 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26137 '<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>',
26138 "</tr></tbody></table>");
26140 this.template = Roo.Button.buttonTemplate;
26142 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26143 var btnEl = btn.child("button:first");
26144 btnEl.on('focus', this.onFocus, this);
26145 btnEl.on('blur', this.onBlur, this);
26147 btn.addClass(this.cls);
26150 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26153 btnEl.addClass(this.iconCls);
26155 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26158 if(this.tabIndex !== undefined){
26159 btnEl.dom.tabIndex = this.tabIndex;
26162 if(typeof this.tooltip == 'object'){
26163 Roo.QuickTips.tips(Roo.apply({
26167 btnEl.dom[this.tooltipType] = this.tooltip;
26171 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26175 this.el.dom.id = this.el.id = this.id;
26178 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26179 this.menu.on("show", this.onMenuShow, this);
26180 this.menu.on("hide", this.onMenuHide, this);
26182 btn.addClass("x-btn");
26183 if(Roo.isIE && !Roo.isIE7){
26184 this.autoWidth.defer(1, this);
26188 if(this.handleMouseEvents){
26189 btn.on("mouseover", this.onMouseOver, this);
26190 btn.on("mouseout", this.onMouseOut, this);
26191 btn.on("mousedown", this.onMouseDown, this);
26193 btn.on(this.clickEvent, this.onClick, this);
26194 //btn.on("mouseup", this.onMouseUp, this);
26201 Roo.ButtonToggleMgr.register(this);
26203 this.el.addClass("x-btn-pressed");
26206 var repeater = new Roo.util.ClickRepeater(btn,
26207 typeof this.repeat == "object" ? this.repeat : {}
26209 repeater.on("click", this.onClick, this);
26212 this.fireEvent('render', this);
26216 * Returns the button's underlying element
26217 * @return {Roo.Element} The element
26219 getEl : function(){
26224 * Destroys this Button and removes any listeners.
26226 destroy : function(){
26227 Roo.ButtonToggleMgr.unregister(this);
26228 this.el.removeAllListeners();
26229 this.purgeListeners();
26234 autoWidth : function(){
26236 this.el.setWidth("auto");
26237 if(Roo.isIE7 && Roo.isStrict){
26238 var ib = this.el.child('button');
26239 if(ib && ib.getWidth() > 20){
26241 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26246 this.el.beginMeasure();
26248 if(this.el.getWidth() < this.minWidth){
26249 this.el.setWidth(this.minWidth);
26252 this.el.endMeasure();
26259 * Assigns this button's click handler
26260 * @param {Function} handler The function to call when the button is clicked
26261 * @param {Object} scope (optional) Scope for the function passed in
26263 setHandler : function(handler, scope){
26264 this.handler = handler;
26265 this.scope = scope;
26269 * Sets this button's text
26270 * @param {String} text The button text
26272 setText : function(text){
26275 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26281 * Gets the text for this button
26282 * @return {String} The button text
26284 getText : function(){
26292 this.hidden = false;
26294 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26302 this.hidden = true;
26304 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26309 * Convenience function for boolean show/hide
26310 * @param {Boolean} visible True to show, false to hide
26312 setVisible: function(visible){
26321 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26322 * @param {Boolean} state (optional) Force a particular state
26324 toggle : function(state){
26325 state = state === undefined ? !this.pressed : state;
26326 if(state != this.pressed){
26328 this.el.addClass("x-btn-pressed");
26329 this.pressed = true;
26330 this.fireEvent("toggle", this, true);
26332 this.el.removeClass("x-btn-pressed");
26333 this.pressed = false;
26334 this.fireEvent("toggle", this, false);
26336 if(this.toggleHandler){
26337 this.toggleHandler.call(this.scope || this, this, state);
26345 focus : function(){
26346 this.el.child('button:first').focus();
26350 * Disable this button
26352 disable : function(){
26354 this.el.addClass("x-btn-disabled");
26356 this.disabled = true;
26360 * Enable this button
26362 enable : function(){
26364 this.el.removeClass("x-btn-disabled");
26366 this.disabled = false;
26370 * Convenience function for boolean enable/disable
26371 * @param {Boolean} enabled True to enable, false to disable
26373 setDisabled : function(v){
26374 this[v !== true ? "enable" : "disable"]();
26378 onClick : function(e){
26380 e.preventDefault();
26385 if(!this.disabled){
26386 if(this.enableToggle){
26389 if(this.menu && !this.menu.isVisible()){
26390 this.menu.show(this.el, this.menuAlign);
26392 this.fireEvent("click", this, e);
26394 this.el.removeClass("x-btn-over");
26395 this.handler.call(this.scope || this, this, e);
26400 onMouseOver : function(e){
26401 if(!this.disabled){
26402 this.el.addClass("x-btn-over");
26403 this.fireEvent('mouseover', this, e);
26407 onMouseOut : function(e){
26408 if(!e.within(this.el, true)){
26409 this.el.removeClass("x-btn-over");
26410 this.fireEvent('mouseout', this, e);
26414 onFocus : function(e){
26415 if(!this.disabled){
26416 this.el.addClass("x-btn-focus");
26420 onBlur : function(e){
26421 this.el.removeClass("x-btn-focus");
26424 onMouseDown : function(e){
26425 if(!this.disabled && e.button == 0){
26426 this.el.addClass("x-btn-click");
26427 Roo.get(document).on('mouseup', this.onMouseUp, this);
26431 onMouseUp : function(e){
26433 this.el.removeClass("x-btn-click");
26434 Roo.get(document).un('mouseup', this.onMouseUp, this);
26438 onMenuShow : function(e){
26439 this.el.addClass("x-btn-menu-active");
26442 onMenuHide : function(e){
26443 this.el.removeClass("x-btn-menu-active");
26447 // Private utility class used by Button
26448 Roo.ButtonToggleMgr = function(){
26451 function toggleGroup(btn, state){
26453 var g = groups[btn.toggleGroup];
26454 for(var i = 0, l = g.length; i < l; i++){
26456 g[i].toggle(false);
26463 register : function(btn){
26464 if(!btn.toggleGroup){
26467 var g = groups[btn.toggleGroup];
26469 g = groups[btn.toggleGroup] = [];
26472 btn.on("toggle", toggleGroup);
26475 unregister : function(btn){
26476 if(!btn.toggleGroup){
26479 var g = groups[btn.toggleGroup];
26482 btn.un("toggle", toggleGroup);
26488 * Ext JS Library 1.1.1
26489 * Copyright(c) 2006-2007, Ext JS, LLC.
26491 * Originally Released Under LGPL - original licence link has changed is not relivant.
26494 * <script type="text/javascript">
26498 * @class Roo.SplitButton
26499 * @extends Roo.Button
26500 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26501 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26502 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26503 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26504 * @cfg {String} arrowTooltip The title attribute of the arrow
26506 * Create a new menu button
26507 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26508 * @param {Object} config The config object
26510 Roo.SplitButton = function(renderTo, config){
26511 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26513 * @event arrowclick
26514 * Fires when this button's arrow is clicked
26515 * @param {SplitButton} this
26516 * @param {EventObject} e The click event
26518 this.addEvents({"arrowclick":true});
26521 Roo.extend(Roo.SplitButton, Roo.Button, {
26522 render : function(renderTo){
26523 // this is one sweet looking template!
26524 var tpl = new Roo.Template(
26525 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26526 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26527 '<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>',
26528 "</tbody></table></td><td>",
26529 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26530 '<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>',
26531 "</tbody></table></td></tr></table>"
26533 var btn = tpl.append(renderTo, [this.text, this.type], true);
26534 var btnEl = btn.child("button");
26536 btn.addClass(this.cls);
26539 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26542 btnEl.addClass(this.iconCls);
26544 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26548 if(this.handleMouseEvents){
26549 btn.on("mouseover", this.onMouseOver, this);
26550 btn.on("mouseout", this.onMouseOut, this);
26551 btn.on("mousedown", this.onMouseDown, this);
26552 btn.on("mouseup", this.onMouseUp, this);
26554 btn.on(this.clickEvent, this.onClick, this);
26556 if(typeof this.tooltip == 'object'){
26557 Roo.QuickTips.tips(Roo.apply({
26561 btnEl.dom[this.tooltipType] = this.tooltip;
26564 if(this.arrowTooltip){
26565 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26574 this.el.addClass("x-btn-pressed");
26576 if(Roo.isIE && !Roo.isIE7){
26577 this.autoWidth.defer(1, this);
26582 this.menu.on("show", this.onMenuShow, this);
26583 this.menu.on("hide", this.onMenuHide, this);
26585 this.fireEvent('render', this);
26589 autoWidth : function(){
26591 var tbl = this.el.child("table:first");
26592 var tbl2 = this.el.child("table:last");
26593 this.el.setWidth("auto");
26594 tbl.setWidth("auto");
26595 if(Roo.isIE7 && Roo.isStrict){
26596 var ib = this.el.child('button:first');
26597 if(ib && ib.getWidth() > 20){
26599 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26604 this.el.beginMeasure();
26606 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26607 tbl.setWidth(this.minWidth-tbl2.getWidth());
26610 this.el.endMeasure();
26613 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26617 * Sets this button's click handler
26618 * @param {Function} handler The function to call when the button is clicked
26619 * @param {Object} scope (optional) Scope for the function passed above
26621 setHandler : function(handler, scope){
26622 this.handler = handler;
26623 this.scope = scope;
26627 * Sets this button's arrow click handler
26628 * @param {Function} handler The function to call when the arrow is clicked
26629 * @param {Object} scope (optional) Scope for the function passed above
26631 setArrowHandler : function(handler, scope){
26632 this.arrowHandler = handler;
26633 this.scope = scope;
26639 focus : function(){
26641 this.el.child("button:first").focus();
26646 onClick : function(e){
26647 e.preventDefault();
26648 if(!this.disabled){
26649 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26650 if(this.menu && !this.menu.isVisible()){
26651 this.menu.show(this.el, this.menuAlign);
26653 this.fireEvent("arrowclick", this, e);
26654 if(this.arrowHandler){
26655 this.arrowHandler.call(this.scope || this, this, e);
26658 this.fireEvent("click", this, e);
26660 this.handler.call(this.scope || this, this, e);
26666 onMouseDown : function(e){
26667 if(!this.disabled){
26668 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26672 onMouseUp : function(e){
26673 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26678 // backwards compat
26679 Roo.MenuButton = Roo.SplitButton;/*
26681 * Ext JS Library 1.1.1
26682 * Copyright(c) 2006-2007, Ext JS, LLC.
26684 * Originally Released Under LGPL - original licence link has changed is not relivant.
26687 * <script type="text/javascript">
26691 * @class Roo.Toolbar
26692 * Basic Toolbar class.
26694 * Creates a new Toolbar
26695 * @param {Object} config The config object
26697 Roo.Toolbar = function(container, buttons, config)
26699 /// old consturctor format still supported..
26700 if(container instanceof Array){ // omit the container for later rendering
26701 buttons = container;
26705 if (typeof(container) == 'object' && container.xtype) {
26706 config = container;
26707 container = config.container;
26708 buttons = config.buttons; // not really - use items!!
26711 if (config && config.items) {
26712 xitems = config.items;
26713 delete config.items;
26715 Roo.apply(this, config);
26716 this.buttons = buttons;
26719 this.render(container);
26721 Roo.each(xitems, function(b) {
26727 Roo.Toolbar.prototype = {
26729 * @cfg {Roo.data.Store} items
26730 * array of button configs or elements to add
26734 * @cfg {String/HTMLElement/Element} container
26735 * The id or element that will contain the toolbar
26738 render : function(ct){
26739 this.el = Roo.get(ct);
26741 this.el.addClass(this.cls);
26743 // using a table allows for vertical alignment
26744 // 100% width is needed by Safari...
26745 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26746 this.tr = this.el.child("tr", true);
26748 this.items = new Roo.util.MixedCollection(false, function(o){
26749 return o.id || ("item" + (++autoId));
26752 this.add.apply(this, this.buttons);
26753 delete this.buttons;
26758 * Adds element(s) to the toolbar -- this function takes a variable number of
26759 * arguments of mixed type and adds them to the toolbar.
26760 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26762 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26763 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26764 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26765 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26766 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26767 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26768 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26769 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26770 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26772 * @param {Mixed} arg2
26773 * @param {Mixed} etc.
26776 var a = arguments, l = a.length;
26777 for(var i = 0; i < l; i++){
26782 _add : function(el) {
26785 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26788 if (el.applyTo){ // some kind of form field
26789 return this.addField(el);
26791 if (el.render){ // some kind of Toolbar.Item
26792 return this.addItem(el);
26794 if (typeof el == "string"){ // string
26795 if(el == "separator" || el == "-"){
26796 return this.addSeparator();
26799 return this.addSpacer();
26802 return this.addFill();
26804 return this.addText(el);
26807 if(el.tagName){ // element
26808 return this.addElement(el);
26810 if(typeof el == "object"){ // must be button config?
26811 return this.addButton(el);
26813 // and now what?!?!
26819 * Add an Xtype element
26820 * @param {Object} xtype Xtype Object
26821 * @return {Object} created Object
26823 addxtype : function(e){
26824 return this.add(e);
26828 * Returns the Element for this toolbar.
26829 * @return {Roo.Element}
26831 getEl : function(){
26837 * @return {Roo.Toolbar.Item} The separator item
26839 addSeparator : function(){
26840 return this.addItem(new Roo.Toolbar.Separator());
26844 * Adds a spacer element
26845 * @return {Roo.Toolbar.Spacer} The spacer item
26847 addSpacer : function(){
26848 return this.addItem(new Roo.Toolbar.Spacer());
26852 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26853 * @return {Roo.Toolbar.Fill} The fill item
26855 addFill : function(){
26856 return this.addItem(new Roo.Toolbar.Fill());
26860 * Adds any standard HTML element to the toolbar
26861 * @param {String/HTMLElement/Element} el The element or id of the element to add
26862 * @return {Roo.Toolbar.Item} The element's item
26864 addElement : function(el){
26865 return this.addItem(new Roo.Toolbar.Item(el));
26868 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26869 * @type Roo.util.MixedCollection
26874 * Adds any Toolbar.Item or subclass
26875 * @param {Roo.Toolbar.Item} item
26876 * @return {Roo.Toolbar.Item} The item
26878 addItem : function(item){
26879 var td = this.nextBlock();
26881 this.items.add(item);
26886 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26887 * @param {Object/Array} config A button config or array of configs
26888 * @return {Roo.Toolbar.Button/Array}
26890 addButton : function(config){
26891 if(config instanceof Array){
26893 for(var i = 0, len = config.length; i < len; i++) {
26894 buttons.push(this.addButton(config[i]));
26899 if(!(config instanceof Roo.Toolbar.Button)){
26901 new Roo.Toolbar.SplitButton(config) :
26902 new Roo.Toolbar.Button(config);
26904 var td = this.nextBlock();
26911 * Adds text to the toolbar
26912 * @param {String} text The text to add
26913 * @return {Roo.Toolbar.Item} The element's item
26915 addText : function(text){
26916 return this.addItem(new Roo.Toolbar.TextItem(text));
26920 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26921 * @param {Number} index The index where the item is to be inserted
26922 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26923 * @return {Roo.Toolbar.Button/Item}
26925 insertButton : function(index, item){
26926 if(item instanceof Array){
26928 for(var i = 0, len = item.length; i < len; i++) {
26929 buttons.push(this.insertButton(index + i, item[i]));
26933 if (!(item instanceof Roo.Toolbar.Button)){
26934 item = new Roo.Toolbar.Button(item);
26936 var td = document.createElement("td");
26937 this.tr.insertBefore(td, this.tr.childNodes[index]);
26939 this.items.insert(index, item);
26944 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26945 * @param {Object} config
26946 * @return {Roo.Toolbar.Item} The element's item
26948 addDom : function(config, returnEl){
26949 var td = this.nextBlock();
26950 Roo.DomHelper.overwrite(td, config);
26951 var ti = new Roo.Toolbar.Item(td.firstChild);
26953 this.items.add(ti);
26958 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26959 * @type Roo.util.MixedCollection
26964 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26965 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26966 * @param {Roo.form.Field} field
26967 * @return {Roo.ToolbarItem}
26971 addField : function(field) {
26972 if (!this.fields) {
26974 this.fields = new Roo.util.MixedCollection(false, function(o){
26975 return o.id || ("item" + (++autoId));
26980 var td = this.nextBlock();
26982 var ti = new Roo.Toolbar.Item(td.firstChild);
26984 this.items.add(ti);
26985 this.fields.add(field);
26996 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26997 this.el.child('div').hide();
27005 this.el.child('div').show();
27009 nextBlock : function(){
27010 var td = document.createElement("td");
27011 this.tr.appendChild(td);
27016 destroy : function(){
27017 if(this.items){ // rendered?
27018 Roo.destroy.apply(Roo, this.items.items);
27020 if(this.fields){ // rendered?
27021 Roo.destroy.apply(Roo, this.fields.items);
27023 Roo.Element.uncache(this.el, this.tr);
27028 * @class Roo.Toolbar.Item
27029 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27031 * Creates a new Item
27032 * @param {HTMLElement} el
27034 Roo.Toolbar.Item = function(el){
27035 this.el = Roo.getDom(el);
27036 this.id = Roo.id(this.el);
27037 this.hidden = false;
27040 Roo.Toolbar.Item.prototype = {
27043 * Get this item's HTML Element
27044 * @return {HTMLElement}
27046 getEl : function(){
27051 render : function(td){
27053 td.appendChild(this.el);
27057 * Removes and destroys this item.
27059 destroy : function(){
27060 this.td.parentNode.removeChild(this.td);
27067 this.hidden = false;
27068 this.td.style.display = "";
27075 this.hidden = true;
27076 this.td.style.display = "none";
27080 * Convenience function for boolean show/hide.
27081 * @param {Boolean} visible true to show/false to hide
27083 setVisible: function(visible){
27092 * Try to focus this item.
27094 focus : function(){
27095 Roo.fly(this.el).focus();
27099 * Disables this item.
27101 disable : function(){
27102 Roo.fly(this.td).addClass("x-item-disabled");
27103 this.disabled = true;
27104 this.el.disabled = true;
27108 * Enables this item.
27110 enable : function(){
27111 Roo.fly(this.td).removeClass("x-item-disabled");
27112 this.disabled = false;
27113 this.el.disabled = false;
27119 * @class Roo.Toolbar.Separator
27120 * @extends Roo.Toolbar.Item
27121 * A simple toolbar separator class
27123 * Creates a new Separator
27125 Roo.Toolbar.Separator = function(){
27126 var s = document.createElement("span");
27127 s.className = "ytb-sep";
27128 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27130 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27131 enable:Roo.emptyFn,
27132 disable:Roo.emptyFn,
27137 * @class Roo.Toolbar.Spacer
27138 * @extends Roo.Toolbar.Item
27139 * A simple element that adds extra horizontal space to a toolbar.
27141 * Creates a new Spacer
27143 Roo.Toolbar.Spacer = function(){
27144 var s = document.createElement("div");
27145 s.className = "ytb-spacer";
27146 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27148 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27149 enable:Roo.emptyFn,
27150 disable:Roo.emptyFn,
27155 * @class Roo.Toolbar.Fill
27156 * @extends Roo.Toolbar.Spacer
27157 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27159 * Creates a new Spacer
27161 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27163 render : function(td){
27164 td.style.width = '100%';
27165 Roo.Toolbar.Fill.superclass.render.call(this, td);
27170 * @class Roo.Toolbar.TextItem
27171 * @extends Roo.Toolbar.Item
27172 * A simple class that renders text directly into a toolbar.
27174 * Creates a new TextItem
27175 * @param {String} text
27177 Roo.Toolbar.TextItem = function(text){
27178 if (typeof(text) == 'object') {
27181 var s = document.createElement("span");
27182 s.className = "ytb-text";
27183 s.innerHTML = text;
27184 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27186 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27187 enable:Roo.emptyFn,
27188 disable:Roo.emptyFn,
27193 * @class Roo.Toolbar.Button
27194 * @extends Roo.Button
27195 * A button that renders into a toolbar.
27197 * Creates a new Button
27198 * @param {Object} config A standard {@link Roo.Button} config object
27200 Roo.Toolbar.Button = function(config){
27201 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27203 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27204 render : function(td){
27206 Roo.Toolbar.Button.superclass.render.call(this, td);
27210 * Removes and destroys this button
27212 destroy : function(){
27213 Roo.Toolbar.Button.superclass.destroy.call(this);
27214 this.td.parentNode.removeChild(this.td);
27218 * Shows this button
27221 this.hidden = false;
27222 this.td.style.display = "";
27226 * Hides this button
27229 this.hidden = true;
27230 this.td.style.display = "none";
27234 * Disables this item
27236 disable : function(){
27237 Roo.fly(this.td).addClass("x-item-disabled");
27238 this.disabled = true;
27242 * Enables this item
27244 enable : function(){
27245 Roo.fly(this.td).removeClass("x-item-disabled");
27246 this.disabled = false;
27249 // backwards compat
27250 Roo.ToolbarButton = Roo.Toolbar.Button;
27253 * @class Roo.Toolbar.SplitButton
27254 * @extends Roo.SplitButton
27255 * A menu button that renders into a toolbar.
27257 * Creates a new SplitButton
27258 * @param {Object} config A standard {@link Roo.SplitButton} config object
27260 Roo.Toolbar.SplitButton = function(config){
27261 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27263 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27264 render : function(td){
27266 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27270 * Removes and destroys this button
27272 destroy : function(){
27273 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27274 this.td.parentNode.removeChild(this.td);
27278 * Shows this button
27281 this.hidden = false;
27282 this.td.style.display = "";
27286 * Hides this button
27289 this.hidden = true;
27290 this.td.style.display = "none";
27294 // backwards compat
27295 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27297 * Ext JS Library 1.1.1
27298 * Copyright(c) 2006-2007, Ext JS, LLC.
27300 * Originally Released Under LGPL - original licence link has changed is not relivant.
27303 * <script type="text/javascript">
27307 * @class Roo.PagingToolbar
27308 * @extends Roo.Toolbar
27309 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27311 * Create a new PagingToolbar
27312 * @param {Object} config The config object
27314 Roo.PagingToolbar = function(el, ds, config)
27316 // old args format still supported... - xtype is prefered..
27317 if (typeof(el) == 'object' && el.xtype) {
27318 // created from xtype...
27320 ds = el.dataSource;
27321 el = config.container;
27324 if (config.items) {
27325 items = config.items;
27329 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27332 this.renderButtons(this.el);
27335 // supprot items array.
27337 Roo.each(items, function(e) {
27338 this.add(Roo.factory(e));
27343 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27345 * @cfg {Roo.data.Store} dataSource
27346 * The underlying data store providing the paged data
27349 * @cfg {String/HTMLElement/Element} container
27350 * container The id or element that will contain the toolbar
27353 * @cfg {Boolean} displayInfo
27354 * True to display the displayMsg (defaults to false)
27357 * @cfg {Number} pageSize
27358 * The number of records to display per page (defaults to 20)
27362 * @cfg {String} displayMsg
27363 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27365 displayMsg : 'Displaying {0} - {1} of {2}',
27367 * @cfg {String} emptyMsg
27368 * The message to display when no records are found (defaults to "No data to display")
27370 emptyMsg : 'No data to display',
27372 * Customizable piece of the default paging text (defaults to "Page")
27375 beforePageText : "Page",
27377 * Customizable piece of the default paging text (defaults to "of %0")
27380 afterPageText : "of {0}",
27382 * Customizable piece of the default paging text (defaults to "First Page")
27385 firstText : "First Page",
27387 * Customizable piece of the default paging text (defaults to "Previous Page")
27390 prevText : "Previous Page",
27392 * Customizable piece of the default paging text (defaults to "Next Page")
27395 nextText : "Next Page",
27397 * Customizable piece of the default paging text (defaults to "Last Page")
27400 lastText : "Last Page",
27402 * Customizable piece of the default paging text (defaults to "Refresh")
27405 refreshText : "Refresh",
27408 renderButtons : function(el){
27409 Roo.PagingToolbar.superclass.render.call(this, el);
27410 this.first = this.addButton({
27411 tooltip: this.firstText,
27412 cls: "x-btn-icon x-grid-page-first",
27414 handler: this.onClick.createDelegate(this, ["first"])
27416 this.prev = this.addButton({
27417 tooltip: this.prevText,
27418 cls: "x-btn-icon x-grid-page-prev",
27420 handler: this.onClick.createDelegate(this, ["prev"])
27422 //this.addSeparator();
27423 this.add(this.beforePageText);
27424 this.field = Roo.get(this.addDom({
27429 cls: "x-grid-page-number"
27431 this.field.on("keydown", this.onPagingKeydown, this);
27432 this.field.on("focus", function(){this.dom.select();});
27433 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27434 this.field.setHeight(18);
27435 //this.addSeparator();
27436 this.next = this.addButton({
27437 tooltip: this.nextText,
27438 cls: "x-btn-icon x-grid-page-next",
27440 handler: this.onClick.createDelegate(this, ["next"])
27442 this.last = this.addButton({
27443 tooltip: this.lastText,
27444 cls: "x-btn-icon x-grid-page-last",
27446 handler: this.onClick.createDelegate(this, ["last"])
27448 //this.addSeparator();
27449 this.loading = this.addButton({
27450 tooltip: this.refreshText,
27451 cls: "x-btn-icon x-grid-loading",
27452 handler: this.onClick.createDelegate(this, ["refresh"])
27455 if(this.displayInfo){
27456 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27461 updateInfo : function(){
27462 if(this.displayEl){
27463 var count = this.ds.getCount();
27464 var msg = count == 0 ?
27468 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27470 this.displayEl.update(msg);
27475 onLoad : function(ds, r, o){
27476 this.cursor = o.params ? o.params.start : 0;
27477 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27479 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27480 this.field.dom.value = ap;
27481 this.first.setDisabled(ap == 1);
27482 this.prev.setDisabled(ap == 1);
27483 this.next.setDisabled(ap == ps);
27484 this.last.setDisabled(ap == ps);
27485 this.loading.enable();
27490 getPageData : function(){
27491 var total = this.ds.getTotalCount();
27494 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27495 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27500 onLoadError : function(){
27501 this.loading.enable();
27505 onPagingKeydown : function(e){
27506 var k = e.getKey();
27507 var d = this.getPageData();
27509 var v = this.field.dom.value, pageNum;
27510 if(!v || isNaN(pageNum = parseInt(v, 10))){
27511 this.field.dom.value = d.activePage;
27514 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27515 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27518 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))
27520 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27521 this.field.dom.value = pageNum;
27522 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27525 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27527 var v = this.field.dom.value, pageNum;
27528 var increment = (e.shiftKey) ? 10 : 1;
27529 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27531 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27532 this.field.dom.value = d.activePage;
27535 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27537 this.field.dom.value = parseInt(v, 10) + increment;
27538 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27539 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27546 beforeLoad : function(){
27548 this.loading.disable();
27553 onClick : function(which){
27557 ds.load({params:{start: 0, limit: this.pageSize}});
27560 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27563 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27566 var total = ds.getTotalCount();
27567 var extra = total % this.pageSize;
27568 var lastStart = extra ? (total - extra) : total-this.pageSize;
27569 ds.load({params:{start: lastStart, limit: this.pageSize}});
27572 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27578 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27579 * @param {Roo.data.Store} store The data store to unbind
27581 unbind : function(ds){
27582 ds.un("beforeload", this.beforeLoad, this);
27583 ds.un("load", this.onLoad, this);
27584 ds.un("loadexception", this.onLoadError, this);
27585 ds.un("remove", this.updateInfo, this);
27586 ds.un("add", this.updateInfo, this);
27587 this.ds = undefined;
27591 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27592 * @param {Roo.data.Store} store The data store to bind
27594 bind : function(ds){
27595 ds.on("beforeload", this.beforeLoad, this);
27596 ds.on("load", this.onLoad, this);
27597 ds.on("loadexception", this.onLoadError, this);
27598 ds.on("remove", this.updateInfo, this);
27599 ds.on("add", this.updateInfo, this);
27604 * Ext JS Library 1.1.1
27605 * Copyright(c) 2006-2007, Ext JS, LLC.
27607 * Originally Released Under LGPL - original licence link has changed is not relivant.
27610 * <script type="text/javascript">
27614 * @class Roo.Resizable
27615 * @extends Roo.util.Observable
27616 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27617 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27618 * 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
27619 * the element will be wrapped for you automatically.</p>
27620 * <p>Here is the list of valid resize handles:</p>
27623 ------ -------------------
27632 'hd' horizontal drag
27635 * <p>Here's an example showing the creation of a typical Resizable:</p>
27637 var resizer = new Roo.Resizable("element-id", {
27645 resizer.on("resize", myHandler);
27647 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27648 * resizer.east.setDisplayed(false);</p>
27649 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27650 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27651 * resize operation's new size (defaults to [0, 0])
27652 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27653 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27654 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27655 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27656 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27657 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27658 * @cfg {Number} width The width of the element in pixels (defaults to null)
27659 * @cfg {Number} height The height of the element in pixels (defaults to null)
27660 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27661 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27662 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27663 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27664 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27665 * in favor of the handles config option (defaults to false)
27666 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27667 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27668 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27669 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27670 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27671 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27672 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27673 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27674 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27675 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27676 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27678 * Create a new resizable component
27679 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27680 * @param {Object} config configuration options
27682 Roo.Resizable = function(el, config)
27684 this.el = Roo.get(el);
27686 if(config && config.wrap){
27687 config.resizeChild = this.el;
27688 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27689 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27690 this.el.setStyle("overflow", "hidden");
27691 this.el.setPositioning(config.resizeChild.getPositioning());
27692 config.resizeChild.clearPositioning();
27693 if(!config.width || !config.height){
27694 var csize = config.resizeChild.getSize();
27695 this.el.setSize(csize.width, csize.height);
27697 if(config.pinned && !config.adjustments){
27698 config.adjustments = "auto";
27702 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27703 this.proxy.unselectable();
27704 this.proxy.enableDisplayMode('block');
27706 Roo.apply(this, config);
27709 this.disableTrackOver = true;
27710 this.el.addClass("x-resizable-pinned");
27712 // if the element isn't positioned, make it relative
27713 var position = this.el.getStyle("position");
27714 if(position != "absolute" && position != "fixed"){
27715 this.el.setStyle("position", "relative");
27717 if(!this.handles){ // no handles passed, must be legacy style
27718 this.handles = 's,e,se';
27719 if(this.multiDirectional){
27720 this.handles += ',n,w';
27723 if(this.handles == "all"){
27724 this.handles = "n s e w ne nw se sw";
27726 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27727 var ps = Roo.Resizable.positions;
27728 for(var i = 0, len = hs.length; i < len; i++){
27729 if(hs[i] && ps[hs[i]]){
27730 var pos = ps[hs[i]];
27731 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27735 this.corner = this.southeast;
27737 // updateBox = the box can move..
27738 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27739 this.updateBox = true;
27742 this.activeHandle = null;
27744 if(this.resizeChild){
27745 if(typeof this.resizeChild == "boolean"){
27746 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27748 this.resizeChild = Roo.get(this.resizeChild, true);
27752 if(this.adjustments == "auto"){
27753 var rc = this.resizeChild;
27754 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27755 if(rc && (hw || hn)){
27756 rc.position("relative");
27757 rc.setLeft(hw ? hw.el.getWidth() : 0);
27758 rc.setTop(hn ? hn.el.getHeight() : 0);
27760 this.adjustments = [
27761 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27762 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27766 if(this.draggable){
27767 this.dd = this.dynamic ?
27768 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27769 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27775 * @event beforeresize
27776 * Fired before resize is allowed. Set enabled to false to cancel resize.
27777 * @param {Roo.Resizable} this
27778 * @param {Roo.EventObject} e The mousedown event
27780 "beforeresize" : true,
27783 * Fired after a resize.
27784 * @param {Roo.Resizable} this
27785 * @param {Number} width The new width
27786 * @param {Number} height The new height
27787 * @param {Roo.EventObject} e The mouseup event
27792 if(this.width !== null && this.height !== null){
27793 this.resizeTo(this.width, this.height);
27795 this.updateChildSize();
27798 this.el.dom.style.zoom = 1;
27800 Roo.Resizable.superclass.constructor.call(this);
27803 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27804 resizeChild : false,
27805 adjustments : [0, 0],
27815 multiDirectional : false,
27816 disableTrackOver : false,
27817 easing : 'easeOutStrong',
27818 widthIncrement : 0,
27819 heightIncrement : 0,
27823 preserveRatio : false,
27824 transparent: false,
27830 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27832 constrainTo: undefined,
27834 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27836 resizeRegion: undefined,
27840 * Perform a manual resize
27841 * @param {Number} width
27842 * @param {Number} height
27844 resizeTo : function(width, height){
27845 this.el.setSize(width, height);
27846 this.updateChildSize();
27847 this.fireEvent("resize", this, width, height, null);
27851 startSizing : function(e, handle){
27852 this.fireEvent("beforeresize", this, e);
27853 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27856 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27857 this.overlay.unselectable();
27858 this.overlay.enableDisplayMode("block");
27859 this.overlay.on("mousemove", this.onMouseMove, this);
27860 this.overlay.on("mouseup", this.onMouseUp, this);
27862 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27864 this.resizing = true;
27865 this.startBox = this.el.getBox();
27866 this.startPoint = e.getXY();
27867 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27868 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27870 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27871 this.overlay.show();
27873 if(this.constrainTo) {
27874 var ct = Roo.get(this.constrainTo);
27875 this.resizeRegion = ct.getRegion().adjust(
27876 ct.getFrameWidth('t'),
27877 ct.getFrameWidth('l'),
27878 -ct.getFrameWidth('b'),
27879 -ct.getFrameWidth('r')
27883 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27885 this.proxy.setBox(this.startBox);
27887 this.proxy.setStyle('visibility', 'visible');
27893 onMouseDown : function(handle, e){
27896 this.activeHandle = handle;
27897 this.startSizing(e, handle);
27902 onMouseUp : function(e){
27903 var size = this.resizeElement();
27904 this.resizing = false;
27906 this.overlay.hide();
27908 this.fireEvent("resize", this, size.width, size.height, e);
27912 updateChildSize : function(){
27913 if(this.resizeChild){
27915 var child = this.resizeChild;
27916 var adj = this.adjustments;
27917 if(el.dom.offsetWidth){
27918 var b = el.getSize(true);
27919 child.setSize(b.width+adj[0], b.height+adj[1]);
27921 // Second call here for IE
27922 // The first call enables instant resizing and
27923 // the second call corrects scroll bars if they
27926 setTimeout(function(){
27927 if(el.dom.offsetWidth){
27928 var b = el.getSize(true);
27929 child.setSize(b.width+adj[0], b.height+adj[1]);
27937 snap : function(value, inc, min){
27938 if(!inc || !value) return value;
27939 var newValue = value;
27940 var m = value % inc;
27943 newValue = value + (inc-m);
27945 newValue = value - m;
27948 return Math.max(min, newValue);
27952 resizeElement : function(){
27953 var box = this.proxy.getBox();
27954 if(this.updateBox){
27955 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27957 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27959 this.updateChildSize();
27967 constrain : function(v, diff, m, mx){
27970 }else if(v - diff > mx){
27977 onMouseMove : function(e){
27979 try{// try catch so if something goes wrong the user doesn't get hung
27981 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27985 //var curXY = this.startPoint;
27986 var curSize = this.curSize || this.startBox;
27987 var x = this.startBox.x, y = this.startBox.y;
27988 var ox = x, oy = y;
27989 var w = curSize.width, h = curSize.height;
27990 var ow = w, oh = h;
27991 var mw = this.minWidth, mh = this.minHeight;
27992 var mxw = this.maxWidth, mxh = this.maxHeight;
27993 var wi = this.widthIncrement;
27994 var hi = this.heightIncrement;
27996 var eventXY = e.getXY();
27997 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27998 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28000 var pos = this.activeHandle.position;
28005 w = Math.min(Math.max(mw, w), mxw);
28010 h = Math.min(Math.max(mh, h), mxh);
28015 w = Math.min(Math.max(mw, w), mxw);
28016 h = Math.min(Math.max(mh, h), mxh);
28019 diffY = this.constrain(h, diffY, mh, mxh);
28026 var adiffX = Math.abs(diffX);
28027 var sub = (adiffX % wi); // how much
28028 if (sub > (wi/2)) { // far enough to snap
28029 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28031 // remove difference..
28032 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28036 x = Math.max(this.minX, x);
28039 diffX = this.constrain(w, diffX, mw, mxw);
28045 w = Math.min(Math.max(mw, w), mxw);
28046 diffY = this.constrain(h, diffY, mh, mxh);
28051 diffX = this.constrain(w, diffX, mw, mxw);
28052 diffY = this.constrain(h, diffY, mh, mxh);
28059 diffX = this.constrain(w, diffX, mw, mxw);
28061 h = Math.min(Math.max(mh, h), mxh);
28067 var sw = this.snap(w, wi, mw);
28068 var sh = this.snap(h, hi, mh);
28069 if(sw != w || sh != h){
28092 if(this.preserveRatio){
28097 h = Math.min(Math.max(mh, h), mxh);
28102 w = Math.min(Math.max(mw, w), mxw);
28107 w = Math.min(Math.max(mw, w), mxw);
28113 w = Math.min(Math.max(mw, w), mxw);
28119 h = Math.min(Math.max(mh, h), mxh);
28127 h = Math.min(Math.max(mh, h), mxh);
28137 h = Math.min(Math.max(mh, h), mxh);
28145 if (pos == 'hdrag') {
28148 this.proxy.setBounds(x, y, w, h);
28150 this.resizeElement();
28157 handleOver : function(){
28159 this.el.addClass("x-resizable-over");
28164 handleOut : function(){
28165 if(!this.resizing){
28166 this.el.removeClass("x-resizable-over");
28171 * Returns the element this component is bound to.
28172 * @return {Roo.Element}
28174 getEl : function(){
28179 * Returns the resizeChild element (or null).
28180 * @return {Roo.Element}
28182 getResizeChild : function(){
28183 return this.resizeChild;
28187 * Destroys this resizable. If the element was wrapped and
28188 * removeEl is not true then the element remains.
28189 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28191 destroy : function(removeEl){
28192 this.proxy.remove();
28194 this.overlay.removeAllListeners();
28195 this.overlay.remove();
28197 var ps = Roo.Resizable.positions;
28199 if(typeof ps[k] != "function" && this[ps[k]]){
28200 var h = this[ps[k]];
28201 h.el.removeAllListeners();
28206 this.el.update("");
28213 // hash to map config positions to true positions
28214 Roo.Resizable.positions = {
28215 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28220 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28222 // only initialize the template if resizable is used
28223 var tpl = Roo.DomHelper.createTemplate(
28224 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28227 Roo.Resizable.Handle.prototype.tpl = tpl;
28229 this.position = pos;
28231 // show north drag fro topdra
28232 var handlepos = pos == 'hdrag' ? 'north' : pos;
28234 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28235 if (pos == 'hdrag') {
28236 this.el.setStyle('cursor', 'pointer');
28238 this.el.unselectable();
28240 this.el.setOpacity(0);
28242 this.el.on("mousedown", this.onMouseDown, this);
28243 if(!disableTrackOver){
28244 this.el.on("mouseover", this.onMouseOver, this);
28245 this.el.on("mouseout", this.onMouseOut, this);
28250 Roo.Resizable.Handle.prototype = {
28251 afterResize : function(rz){
28255 onMouseDown : function(e){
28256 this.rz.onMouseDown(this, e);
28259 onMouseOver : function(e){
28260 this.rz.handleOver(this, e);
28263 onMouseOut : function(e){
28264 this.rz.handleOut(this, e);
28268 * Ext JS Library 1.1.1
28269 * Copyright(c) 2006-2007, Ext JS, LLC.
28271 * Originally Released Under LGPL - original licence link has changed is not relivant.
28274 * <script type="text/javascript">
28278 * @class Roo.Editor
28279 * @extends Roo.Component
28280 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28282 * Create a new Editor
28283 * @param {Roo.form.Field} field The Field object (or descendant)
28284 * @param {Object} config The config object
28286 Roo.Editor = function(field, config){
28287 Roo.Editor.superclass.constructor.call(this, config);
28288 this.field = field;
28291 * @event beforestartedit
28292 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28293 * false from the handler of this event.
28294 * @param {Editor} this
28295 * @param {Roo.Element} boundEl The underlying element bound to this editor
28296 * @param {Mixed} value The field value being set
28298 "beforestartedit" : true,
28301 * Fires when this editor is displayed
28302 * @param {Roo.Element} boundEl The underlying element bound to this editor
28303 * @param {Mixed} value The starting field value
28305 "startedit" : true,
28307 * @event beforecomplete
28308 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28309 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28310 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28311 * event will not fire since no edit actually occurred.
28312 * @param {Editor} this
28313 * @param {Mixed} value The current field value
28314 * @param {Mixed} startValue The original field value
28316 "beforecomplete" : true,
28319 * Fires after editing is complete and any changed value has been written to the underlying field.
28320 * @param {Editor} this
28321 * @param {Mixed} value The current field value
28322 * @param {Mixed} startValue The original field value
28326 * @event specialkey
28327 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28328 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28329 * @param {Roo.form.Field} this
28330 * @param {Roo.EventObject} e The event object
28332 "specialkey" : true
28336 Roo.extend(Roo.Editor, Roo.Component, {
28338 * @cfg {Boolean/String} autosize
28339 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28340 * or "height" to adopt the height only (defaults to false)
28343 * @cfg {Boolean} revertInvalid
28344 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28345 * validation fails (defaults to true)
28348 * @cfg {Boolean} ignoreNoChange
28349 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28350 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28351 * will never be ignored.
28354 * @cfg {Boolean} hideEl
28355 * False to keep the bound element visible while the editor is displayed (defaults to true)
28358 * @cfg {Mixed} value
28359 * The data value of the underlying field (defaults to "")
28363 * @cfg {String} alignment
28364 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28368 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28369 * for bottom-right shadow (defaults to "frame")
28373 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28377 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28379 completeOnEnter : false,
28381 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28383 cancelOnEsc : false,
28385 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28390 onRender : function(ct, position){
28391 this.el = new Roo.Layer({
28392 shadow: this.shadow,
28398 constrain: this.constrain
28400 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28401 if(this.field.msgTarget != 'title'){
28402 this.field.msgTarget = 'qtip';
28404 this.field.render(this.el);
28406 this.field.el.dom.setAttribute('autocomplete', 'off');
28408 this.field.on("specialkey", this.onSpecialKey, this);
28409 if(this.swallowKeys){
28410 this.field.el.swallowEvent(['keydown','keypress']);
28413 this.field.on("blur", this.onBlur, this);
28414 if(this.field.grow){
28415 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28419 onSpecialKey : function(field, e)
28421 //Roo.log('editor onSpecialKey');
28422 if(this.completeOnEnter && e.getKey() == e.ENTER){
28424 this.completeEdit();
28427 // do not fire special key otherwise it might hide close the editor...
28428 if(e.getKey() == e.ENTER){
28431 if(this.cancelOnEsc && e.getKey() == e.ESC){
28435 this.fireEvent('specialkey', field, e);
28440 * Starts the editing process and shows the editor.
28441 * @param {String/HTMLElement/Element} el The element to edit
28442 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28443 * to the innerHTML of el.
28445 startEdit : function(el, value){
28447 this.completeEdit();
28449 this.boundEl = Roo.get(el);
28450 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28451 if(!this.rendered){
28452 this.render(this.parentEl || document.body);
28454 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28457 this.startValue = v;
28458 this.field.setValue(v);
28460 var sz = this.boundEl.getSize();
28461 switch(this.autoSize){
28463 this.setSize(sz.width, "");
28466 this.setSize("", sz.height);
28469 this.setSize(sz.width, sz.height);
28472 this.el.alignTo(this.boundEl, this.alignment);
28473 this.editing = true;
28475 Roo.QuickTips.disable();
28481 * Sets the height and width of this editor.
28482 * @param {Number} width The new width
28483 * @param {Number} height The new height
28485 setSize : function(w, h){
28486 this.field.setSize(w, h);
28493 * Realigns the editor to the bound field based on the current alignment config value.
28495 realign : function(){
28496 this.el.alignTo(this.boundEl, this.alignment);
28500 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28501 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28503 completeEdit : function(remainVisible){
28507 var v = this.getValue();
28508 if(this.revertInvalid !== false && !this.field.isValid()){
28509 v = this.startValue;
28510 this.cancelEdit(true);
28512 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28513 this.editing = false;
28517 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28518 this.editing = false;
28519 if(this.updateEl && this.boundEl){
28520 this.boundEl.update(v);
28522 if(remainVisible !== true){
28525 this.fireEvent("complete", this, v, this.startValue);
28530 onShow : function(){
28532 if(this.hideEl !== false){
28533 this.boundEl.hide();
28536 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28537 this.fixIEFocus = true;
28538 this.deferredFocus.defer(50, this);
28540 this.field.focus();
28542 this.fireEvent("startedit", this.boundEl, this.startValue);
28545 deferredFocus : function(){
28547 this.field.focus();
28552 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28553 * reverted to the original starting value.
28554 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28555 * cancel (defaults to false)
28557 cancelEdit : function(remainVisible){
28559 this.setValue(this.startValue);
28560 if(remainVisible !== true){
28567 onBlur : function(){
28568 if(this.allowBlur !== true && this.editing){
28569 this.completeEdit();
28574 onHide : function(){
28576 this.completeEdit();
28580 if(this.field.collapse){
28581 this.field.collapse();
28584 if(this.hideEl !== false){
28585 this.boundEl.show();
28588 Roo.QuickTips.enable();
28593 * Sets the data value of the editor
28594 * @param {Mixed} value Any valid value supported by the underlying field
28596 setValue : function(v){
28597 this.field.setValue(v);
28601 * Gets the data value of the editor
28602 * @return {Mixed} The data value
28604 getValue : function(){
28605 return this.field.getValue();
28609 * Ext JS Library 1.1.1
28610 * Copyright(c) 2006-2007, Ext JS, LLC.
28612 * Originally Released Under LGPL - original licence link has changed is not relivant.
28615 * <script type="text/javascript">
28619 * @class Roo.BasicDialog
28620 * @extends Roo.util.Observable
28621 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28623 var dlg = new Roo.BasicDialog("my-dlg", {
28632 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28633 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28634 dlg.addButton('Cancel', dlg.hide, dlg);
28637 <b>A Dialog should always be a direct child of the body element.</b>
28638 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28639 * @cfg {String} title Default text to display in the title bar (defaults to null)
28640 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28641 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28642 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28643 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28644 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28645 * (defaults to null with no animation)
28646 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28647 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28648 * property for valid values (defaults to 'all')
28649 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28650 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28651 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28652 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28653 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28654 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28655 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28656 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28657 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28658 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28659 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28660 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28661 * draggable = true (defaults to false)
28662 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28663 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28664 * shadow (defaults to false)
28665 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28666 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28667 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28668 * @cfg {Array} buttons Array of buttons
28669 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28671 * Create a new BasicDialog.
28672 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28673 * @param {Object} config Configuration options
28675 Roo.BasicDialog = function(el, config){
28676 this.el = Roo.get(el);
28677 var dh = Roo.DomHelper;
28678 if(!this.el && config && config.autoCreate){
28679 if(typeof config.autoCreate == "object"){
28680 if(!config.autoCreate.id){
28681 config.autoCreate.id = el;
28683 this.el = dh.append(document.body,
28684 config.autoCreate, true);
28686 this.el = dh.append(document.body,
28687 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28691 el.setDisplayed(true);
28692 el.hide = this.hideAction;
28694 el.addClass("x-dlg");
28696 Roo.apply(this, config);
28698 this.proxy = el.createProxy("x-dlg-proxy");
28699 this.proxy.hide = this.hideAction;
28700 this.proxy.setOpacity(.5);
28704 el.setWidth(config.width);
28707 el.setHeight(config.height);
28709 this.size = el.getSize();
28710 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28711 this.xy = [config.x,config.y];
28713 this.xy = el.getCenterXY(true);
28715 /** The header element @type Roo.Element */
28716 this.header = el.child("> .x-dlg-hd");
28717 /** The body element @type Roo.Element */
28718 this.body = el.child("> .x-dlg-bd");
28719 /** The footer element @type Roo.Element */
28720 this.footer = el.child("> .x-dlg-ft");
28723 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28726 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28729 this.header.unselectable();
28731 this.header.update(this.title);
28733 // this element allows the dialog to be focused for keyboard event
28734 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28735 this.focusEl.swallowEvent("click", true);
28737 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28739 // wrap the body and footer for special rendering
28740 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28742 this.bwrap.dom.appendChild(this.footer.dom);
28745 this.bg = this.el.createChild({
28746 tag: "div", cls:"x-dlg-bg",
28747 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28749 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28752 if(this.autoScroll !== false && !this.autoTabs){
28753 this.body.setStyle("overflow", "auto");
28756 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28758 if(this.closable !== false){
28759 this.el.addClass("x-dlg-closable");
28760 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28761 this.close.on("click", this.closeClick, this);
28762 this.close.addClassOnOver("x-dlg-close-over");
28764 if(this.collapsible !== false){
28765 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28766 this.collapseBtn.on("click", this.collapseClick, this);
28767 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28768 this.header.on("dblclick", this.collapseClick, this);
28770 if(this.resizable !== false){
28771 this.el.addClass("x-dlg-resizable");
28772 this.resizer = new Roo.Resizable(el, {
28773 minWidth: this.minWidth || 80,
28774 minHeight:this.minHeight || 80,
28775 handles: this.resizeHandles || "all",
28778 this.resizer.on("beforeresize", this.beforeResize, this);
28779 this.resizer.on("resize", this.onResize, this);
28781 if(this.draggable !== false){
28782 el.addClass("x-dlg-draggable");
28783 if (!this.proxyDrag) {
28784 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28787 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28789 dd.setHandleElId(this.header.id);
28790 dd.endDrag = this.endMove.createDelegate(this);
28791 dd.startDrag = this.startMove.createDelegate(this);
28792 dd.onDrag = this.onDrag.createDelegate(this);
28797 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28798 this.mask.enableDisplayMode("block");
28800 this.el.addClass("x-dlg-modal");
28803 this.shadow = new Roo.Shadow({
28804 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28805 offset : this.shadowOffset
28808 this.shadowOffset = 0;
28810 if(Roo.useShims && this.shim !== false){
28811 this.shim = this.el.createShim();
28812 this.shim.hide = this.hideAction;
28820 if (this.buttons) {
28821 var bts= this.buttons;
28823 Roo.each(bts, function(b) {
28832 * Fires when a key is pressed
28833 * @param {Roo.BasicDialog} this
28834 * @param {Roo.EventObject} e
28839 * Fires when this dialog is moved by the user.
28840 * @param {Roo.BasicDialog} this
28841 * @param {Number} x The new page X
28842 * @param {Number} y The new page Y
28847 * Fires when this dialog is resized by the user.
28848 * @param {Roo.BasicDialog} this
28849 * @param {Number} width The new width
28850 * @param {Number} height The new height
28854 * @event beforehide
28855 * Fires before this dialog is hidden.
28856 * @param {Roo.BasicDialog} this
28858 "beforehide" : true,
28861 * Fires when this dialog is hidden.
28862 * @param {Roo.BasicDialog} this
28866 * @event beforeshow
28867 * Fires before this dialog is shown.
28868 * @param {Roo.BasicDialog} this
28870 "beforeshow" : true,
28873 * Fires when this dialog is shown.
28874 * @param {Roo.BasicDialog} this
28878 el.on("keydown", this.onKeyDown, this);
28879 el.on("mousedown", this.toFront, this);
28880 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28882 Roo.DialogManager.register(this);
28883 Roo.BasicDialog.superclass.constructor.call(this);
28886 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28887 shadowOffset: Roo.isIE ? 6 : 5,
28890 minButtonWidth: 75,
28891 defaultButton: null,
28892 buttonAlign: "right",
28897 * Sets the dialog title text
28898 * @param {String} text The title text to display
28899 * @return {Roo.BasicDialog} this
28901 setTitle : function(text){
28902 this.header.update(text);
28907 closeClick : function(){
28912 collapseClick : function(){
28913 this[this.collapsed ? "expand" : "collapse"]();
28917 * Collapses the dialog to its minimized state (only the title bar is visible).
28918 * Equivalent to the user clicking the collapse dialog button.
28920 collapse : function(){
28921 if(!this.collapsed){
28922 this.collapsed = true;
28923 this.el.addClass("x-dlg-collapsed");
28924 this.restoreHeight = this.el.getHeight();
28925 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28930 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28931 * clicking the expand dialog button.
28933 expand : function(){
28934 if(this.collapsed){
28935 this.collapsed = false;
28936 this.el.removeClass("x-dlg-collapsed");
28937 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28942 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28943 * @return {Roo.TabPanel} The tabs component
28945 initTabs : function(){
28946 var tabs = this.getTabs();
28947 while(tabs.getTab(0)){
28950 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28952 tabs.addTab(Roo.id(dom), dom.title);
28960 beforeResize : function(){
28961 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28965 onResize : function(){
28966 this.refreshSize();
28967 this.syncBodyHeight();
28968 this.adjustAssets();
28970 this.fireEvent("resize", this, this.size.width, this.size.height);
28974 onKeyDown : function(e){
28975 if(this.isVisible()){
28976 this.fireEvent("keydown", this, e);
28981 * Resizes the dialog.
28982 * @param {Number} width
28983 * @param {Number} height
28984 * @return {Roo.BasicDialog} this
28986 resizeTo : function(width, height){
28987 this.el.setSize(width, height);
28988 this.size = {width: width, height: height};
28989 this.syncBodyHeight();
28990 if(this.fixedcenter){
28993 if(this.isVisible()){
28994 this.constrainXY();
28995 this.adjustAssets();
28997 this.fireEvent("resize", this, width, height);
29003 * Resizes the dialog to fit the specified content size.
29004 * @param {Number} width
29005 * @param {Number} height
29006 * @return {Roo.BasicDialog} this
29008 setContentSize : function(w, h){
29009 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29010 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29011 //if(!this.el.isBorderBox()){
29012 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29013 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29016 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29017 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29019 this.resizeTo(w, h);
29024 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29025 * executed in response to a particular key being pressed while the dialog is active.
29026 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29027 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29028 * @param {Function} fn The function to call
29029 * @param {Object} scope (optional) The scope of the function
29030 * @return {Roo.BasicDialog} this
29032 addKeyListener : function(key, fn, scope){
29033 var keyCode, shift, ctrl, alt;
29034 if(typeof key == "object" && !(key instanceof Array)){
29035 keyCode = key["key"];
29036 shift = key["shift"];
29037 ctrl = key["ctrl"];
29042 var handler = function(dlg, e){
29043 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29044 var k = e.getKey();
29045 if(keyCode instanceof Array){
29046 for(var i = 0, len = keyCode.length; i < len; i++){
29047 if(keyCode[i] == k){
29048 fn.call(scope || window, dlg, k, e);
29054 fn.call(scope || window, dlg, k, e);
29059 this.on("keydown", handler);
29064 * Returns the TabPanel component (creates it if it doesn't exist).
29065 * Note: If you wish to simply check for the existence of tabs without creating them,
29066 * check for a null 'tabs' property.
29067 * @return {Roo.TabPanel} The tabs component
29069 getTabs : function(){
29071 this.el.addClass("x-dlg-auto-tabs");
29072 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29073 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29079 * Adds a button to the footer section of the dialog.
29080 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29081 * object or a valid Roo.DomHelper element config
29082 * @param {Function} handler The function called when the button is clicked
29083 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29084 * @return {Roo.Button} The new button
29086 addButton : function(config, handler, scope){
29087 var dh = Roo.DomHelper;
29089 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29091 if(!this.btnContainer){
29092 var tb = this.footer.createChild({
29094 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29095 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29097 this.btnContainer = tb.firstChild.firstChild.firstChild;
29102 minWidth: this.minButtonWidth,
29105 if(typeof config == "string"){
29106 bconfig.text = config;
29109 bconfig.dhconfig = config;
29111 Roo.apply(bconfig, config);
29115 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29116 bconfig.position = Math.max(0, bconfig.position);
29117 fc = this.btnContainer.childNodes[bconfig.position];
29120 var btn = new Roo.Button(
29122 this.btnContainer.insertBefore(document.createElement("td"),fc)
29123 : this.btnContainer.appendChild(document.createElement("td")),
29124 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29127 this.syncBodyHeight();
29130 * Array of all the buttons that have been added to this dialog via addButton
29135 this.buttons.push(btn);
29140 * Sets the default button to be focused when the dialog is displayed.
29141 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29142 * @return {Roo.BasicDialog} this
29144 setDefaultButton : function(btn){
29145 this.defaultButton = btn;
29150 getHeaderFooterHeight : function(safe){
29153 height += this.header.getHeight();
29156 var fm = this.footer.getMargins();
29157 height += (this.footer.getHeight()+fm.top+fm.bottom);
29159 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29160 height += this.centerBg.getPadding("tb");
29165 syncBodyHeight : function(){
29166 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29167 var height = this.size.height - this.getHeaderFooterHeight(false);
29168 bd.setHeight(height-bd.getMargins("tb"));
29169 var hh = this.header.getHeight();
29170 var h = this.size.height-hh;
29172 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29173 bw.setHeight(h-cb.getPadding("tb"));
29174 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29175 bd.setWidth(bw.getWidth(true));
29177 this.tabs.syncHeight();
29179 this.tabs.el.repaint();
29185 * Restores the previous state of the dialog if Roo.state is configured.
29186 * @return {Roo.BasicDialog} this
29188 restoreState : function(){
29189 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29190 if(box && box.width){
29191 this.xy = [box.x, box.y];
29192 this.resizeTo(box.width, box.height);
29198 beforeShow : function(){
29200 if(this.fixedcenter){
29201 this.xy = this.el.getCenterXY(true);
29204 Roo.get(document.body).addClass("x-body-masked");
29205 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29208 this.constrainXY();
29212 animShow : function(){
29213 var b = Roo.get(this.animateTarget).getBox();
29214 this.proxy.setSize(b.width, b.height);
29215 this.proxy.setLocation(b.x, b.y);
29217 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29218 true, .35, this.showEl.createDelegate(this));
29222 * Shows the dialog.
29223 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29224 * @return {Roo.BasicDialog} this
29226 show : function(animateTarget){
29227 if (this.fireEvent("beforeshow", this) === false){
29230 if(this.syncHeightBeforeShow){
29231 this.syncBodyHeight();
29232 }else if(this.firstShow){
29233 this.firstShow = false;
29234 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29236 this.animateTarget = animateTarget || this.animateTarget;
29237 if(!this.el.isVisible()){
29239 if(this.animateTarget && Roo.get(this.animateTarget)){
29249 showEl : function(){
29251 this.el.setXY(this.xy);
29253 this.adjustAssets(true);
29256 // IE peekaboo bug - fix found by Dave Fenwick
29260 this.fireEvent("show", this);
29264 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29265 * dialog itself will receive focus.
29267 focus : function(){
29268 if(this.defaultButton){
29269 this.defaultButton.focus();
29271 this.focusEl.focus();
29276 constrainXY : function(){
29277 if(this.constraintoviewport !== false){
29278 if(!this.viewSize){
29279 if(this.container){
29280 var s = this.container.getSize();
29281 this.viewSize = [s.width, s.height];
29283 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29286 var s = Roo.get(this.container||document).getScroll();
29288 var x = this.xy[0], y = this.xy[1];
29289 var w = this.size.width, h = this.size.height;
29290 var vw = this.viewSize[0], vh = this.viewSize[1];
29291 // only move it if it needs it
29293 // first validate right/bottom
29294 if(x + w > vw+s.left){
29298 if(y + h > vh+s.top){
29302 // then make sure top/left isn't negative
29314 if(this.isVisible()){
29315 this.el.setLocation(x, y);
29316 this.adjustAssets();
29323 onDrag : function(){
29324 if(!this.proxyDrag){
29325 this.xy = this.el.getXY();
29326 this.adjustAssets();
29331 adjustAssets : function(doShow){
29332 var x = this.xy[0], y = this.xy[1];
29333 var w = this.size.width, h = this.size.height;
29334 if(doShow === true){
29336 this.shadow.show(this.el);
29342 if(this.shadow && this.shadow.isVisible()){
29343 this.shadow.show(this.el);
29345 if(this.shim && this.shim.isVisible()){
29346 this.shim.setBounds(x, y, w, h);
29351 adjustViewport : function(w, h){
29353 w = Roo.lib.Dom.getViewWidth();
29354 h = Roo.lib.Dom.getViewHeight();
29357 this.viewSize = [w, h];
29358 if(this.modal && this.mask.isVisible()){
29359 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29360 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29362 if(this.isVisible()){
29363 this.constrainXY();
29368 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29369 * shadow, proxy, mask, etc.) Also removes all event listeners.
29370 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29372 destroy : function(removeEl){
29373 if(this.isVisible()){
29374 this.animateTarget = null;
29377 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29379 this.tabs.destroy(removeEl);
29392 for(var i = 0, len = this.buttons.length; i < len; i++){
29393 this.buttons[i].destroy();
29396 this.el.removeAllListeners();
29397 if(removeEl === true){
29398 this.el.update("");
29401 Roo.DialogManager.unregister(this);
29405 startMove : function(){
29406 if(this.proxyDrag){
29409 if(this.constraintoviewport !== false){
29410 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29415 endMove : function(){
29416 if(!this.proxyDrag){
29417 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29419 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29422 this.refreshSize();
29423 this.adjustAssets();
29425 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29429 * Brings this dialog to the front of any other visible dialogs
29430 * @return {Roo.BasicDialog} this
29432 toFront : function(){
29433 Roo.DialogManager.bringToFront(this);
29438 * Sends this dialog to the back (under) of any other visible dialogs
29439 * @return {Roo.BasicDialog} this
29441 toBack : function(){
29442 Roo.DialogManager.sendToBack(this);
29447 * Centers this dialog in the viewport
29448 * @return {Roo.BasicDialog} this
29450 center : function(){
29451 var xy = this.el.getCenterXY(true);
29452 this.moveTo(xy[0], xy[1]);
29457 * Moves the dialog's top-left corner to the specified point
29458 * @param {Number} x
29459 * @param {Number} y
29460 * @return {Roo.BasicDialog} this
29462 moveTo : function(x, y){
29464 if(this.isVisible()){
29465 this.el.setXY(this.xy);
29466 this.adjustAssets();
29472 * Aligns the dialog to the specified element
29473 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29474 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29475 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29476 * @return {Roo.BasicDialog} this
29478 alignTo : function(element, position, offsets){
29479 this.xy = this.el.getAlignToXY(element, position, offsets);
29480 if(this.isVisible()){
29481 this.el.setXY(this.xy);
29482 this.adjustAssets();
29488 * Anchors an element to another element and realigns it when the window is resized.
29489 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29490 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29491 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29492 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29493 * is a number, it is used as the buffer delay (defaults to 50ms).
29494 * @return {Roo.BasicDialog} this
29496 anchorTo : function(el, alignment, offsets, monitorScroll){
29497 var action = function(){
29498 this.alignTo(el, alignment, offsets);
29500 Roo.EventManager.onWindowResize(action, this);
29501 var tm = typeof monitorScroll;
29502 if(tm != 'undefined'){
29503 Roo.EventManager.on(window, 'scroll', action, this,
29504 {buffer: tm == 'number' ? monitorScroll : 50});
29511 * Returns true if the dialog is visible
29512 * @return {Boolean}
29514 isVisible : function(){
29515 return this.el.isVisible();
29519 animHide : function(callback){
29520 var b = Roo.get(this.animateTarget).getBox();
29522 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29524 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29525 this.hideEl.createDelegate(this, [callback]));
29529 * Hides the dialog.
29530 * @param {Function} callback (optional) Function to call when the dialog is hidden
29531 * @return {Roo.BasicDialog} this
29533 hide : function(callback){
29534 if (this.fireEvent("beforehide", this) === false){
29538 this.shadow.hide();
29543 // sometimes animateTarget seems to get set.. causing problems...
29544 // this just double checks..
29545 if(this.animateTarget && Roo.get(this.animateTarget)) {
29546 this.animHide(callback);
29549 this.hideEl(callback);
29555 hideEl : function(callback){
29559 Roo.get(document.body).removeClass("x-body-masked");
29561 this.fireEvent("hide", this);
29562 if(typeof callback == "function"){
29568 hideAction : function(){
29569 this.setLeft("-10000px");
29570 this.setTop("-10000px");
29571 this.setStyle("visibility", "hidden");
29575 refreshSize : function(){
29576 this.size = this.el.getSize();
29577 this.xy = this.el.getXY();
29578 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29582 // z-index is managed by the DialogManager and may be overwritten at any time
29583 setZIndex : function(index){
29585 this.mask.setStyle("z-index", index);
29588 this.shim.setStyle("z-index", ++index);
29591 this.shadow.setZIndex(++index);
29593 this.el.setStyle("z-index", ++index);
29595 this.proxy.setStyle("z-index", ++index);
29598 this.resizer.proxy.setStyle("z-index", ++index);
29601 this.lastZIndex = index;
29605 * Returns the element for this dialog
29606 * @return {Roo.Element} The underlying dialog Element
29608 getEl : function(){
29614 * @class Roo.DialogManager
29615 * Provides global access to BasicDialogs that have been created and
29616 * support for z-indexing (layering) multiple open dialogs.
29618 Roo.DialogManager = function(){
29620 var accessList = [];
29624 var sortDialogs = function(d1, d2){
29625 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29629 var orderDialogs = function(){
29630 accessList.sort(sortDialogs);
29631 var seed = Roo.DialogManager.zseed;
29632 for(var i = 0, len = accessList.length; i < len; i++){
29633 var dlg = accessList[i];
29635 dlg.setZIndex(seed + (i*10));
29642 * The starting z-index for BasicDialogs (defaults to 9000)
29643 * @type Number The z-index value
29648 register : function(dlg){
29649 list[dlg.id] = dlg;
29650 accessList.push(dlg);
29654 unregister : function(dlg){
29655 delete list[dlg.id];
29658 if(!accessList.indexOf){
29659 for( i = 0, len = accessList.length; i < len; i++){
29660 if(accessList[i] == dlg){
29661 accessList.splice(i, 1);
29666 i = accessList.indexOf(dlg);
29668 accessList.splice(i, 1);
29674 * Gets a registered dialog by id
29675 * @param {String/Object} id The id of the dialog or a dialog
29676 * @return {Roo.BasicDialog} this
29678 get : function(id){
29679 return typeof id == "object" ? id : list[id];
29683 * Brings the specified dialog to the front
29684 * @param {String/Object} dlg The id of the dialog or a dialog
29685 * @return {Roo.BasicDialog} this
29687 bringToFront : function(dlg){
29688 dlg = this.get(dlg);
29691 dlg._lastAccess = new Date().getTime();
29698 * Sends the specified dialog to the back
29699 * @param {String/Object} dlg The id of the dialog or a dialog
29700 * @return {Roo.BasicDialog} this
29702 sendToBack : function(dlg){
29703 dlg = this.get(dlg);
29704 dlg._lastAccess = -(new Date().getTime());
29710 * Hides all dialogs
29712 hideAll : function(){
29713 for(var id in list){
29714 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29723 * @class Roo.LayoutDialog
29724 * @extends Roo.BasicDialog
29725 * Dialog which provides adjustments for working with a layout in a Dialog.
29726 * Add your necessary layout config options to the dialog's config.<br>
29727 * Example usage (including a nested layout):
29730 dialog = new Roo.LayoutDialog("download-dlg", {
29739 // layout config merges with the dialog config
29741 tabPosition: "top",
29742 alwaysShowTabs: true
29745 dialog.addKeyListener(27, dialog.hide, dialog);
29746 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29747 dialog.addButton("Build It!", this.getDownload, this);
29749 // we can even add nested layouts
29750 var innerLayout = new Roo.BorderLayout("dl-inner", {
29760 innerLayout.beginUpdate();
29761 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29762 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29763 innerLayout.endUpdate(true);
29765 var layout = dialog.getLayout();
29766 layout.beginUpdate();
29767 layout.add("center", new Roo.ContentPanel("standard-panel",
29768 {title: "Download the Source", fitToFrame:true}));
29769 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29770 {title: "Build your own roo.js"}));
29771 layout.getRegion("center").showPanel(sp);
29772 layout.endUpdate();
29776 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29777 * @param {Object} config configuration options
29779 Roo.LayoutDialog = function(el, cfg){
29782 if (typeof(cfg) == 'undefined') {
29783 config = Roo.apply({}, el);
29784 // not sure why we use documentElement here.. - it should always be body.
29785 // IE7 borks horribly if we use documentElement.
29786 // webkit also does not like documentElement - it creates a body element...
29787 el = Roo.get( document.body || document.documentElement ).createChild();
29788 //config.autoCreate = true;
29792 config.autoTabs = false;
29793 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29794 this.body.setStyle({overflow:"hidden", position:"relative"});
29795 this.layout = new Roo.BorderLayout(this.body.dom, config);
29796 this.layout.monitorWindowResize = false;
29797 this.el.addClass("x-dlg-auto-layout");
29798 // fix case when center region overwrites center function
29799 this.center = Roo.BasicDialog.prototype.center;
29800 this.on("show", this.layout.layout, this.layout, true);
29801 if (config.items) {
29802 var xitems = config.items;
29803 delete config.items;
29804 Roo.each(xitems, this.addxtype, this);
29809 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29811 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29814 endUpdate : function(){
29815 this.layout.endUpdate();
29819 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29822 beginUpdate : function(){
29823 this.layout.beginUpdate();
29827 * Get the BorderLayout for this dialog
29828 * @return {Roo.BorderLayout}
29830 getLayout : function(){
29831 return this.layout;
29834 showEl : function(){
29835 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29837 this.layout.layout();
29842 // Use the syncHeightBeforeShow config option to control this automatically
29843 syncBodyHeight : function(){
29844 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29845 if(this.layout){this.layout.layout();}
29849 * Add an xtype element (actually adds to the layout.)
29850 * @return {Object} xdata xtype object data.
29853 addxtype : function(c) {
29854 return this.layout.addxtype(c);
29858 * Ext JS Library 1.1.1
29859 * Copyright(c) 2006-2007, Ext JS, LLC.
29861 * Originally Released Under LGPL - original licence link has changed is not relivant.
29864 * <script type="text/javascript">
29868 * @class Roo.MessageBox
29869 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29873 Roo.Msg.alert('Status', 'Changes saved successfully.');
29875 // Prompt for user data:
29876 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29878 // process text value...
29882 // Show a dialog using config options:
29884 title:'Save Changes?',
29885 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29886 buttons: Roo.Msg.YESNOCANCEL,
29893 Roo.MessageBox = function(){
29894 var dlg, opt, mask, waitTimer;
29895 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29896 var buttons, activeTextEl, bwidth;
29899 var handleButton = function(button){
29901 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29905 var handleHide = function(){
29906 if(opt && opt.cls){
29907 dlg.el.removeClass(opt.cls);
29910 Roo.TaskMgr.stop(waitTimer);
29916 var updateButtons = function(b){
29919 buttons["ok"].hide();
29920 buttons["cancel"].hide();
29921 buttons["yes"].hide();
29922 buttons["no"].hide();
29923 dlg.footer.dom.style.display = 'none';
29926 dlg.footer.dom.style.display = '';
29927 for(var k in buttons){
29928 if(typeof buttons[k] != "function"){
29931 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29932 width += buttons[k].el.getWidth()+15;
29942 var handleEsc = function(d, k, e){
29943 if(opt && opt.closable !== false){
29953 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29954 * @return {Roo.BasicDialog} The BasicDialog element
29956 getDialog : function(){
29958 dlg = new Roo.BasicDialog("x-msg-box", {
29963 constraintoviewport:false,
29965 collapsible : false,
29968 width:400, height:100,
29969 buttonAlign:"center",
29970 closeClick : function(){
29971 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29972 handleButton("no");
29974 handleButton("cancel");
29978 dlg.on("hide", handleHide);
29980 dlg.addKeyListener(27, handleEsc);
29982 var bt = this.buttonText;
29983 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29984 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29985 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29986 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29987 bodyEl = dlg.body.createChild({
29989 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>'
29991 msgEl = bodyEl.dom.firstChild;
29992 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29993 textboxEl.enableDisplayMode();
29994 textboxEl.addKeyListener([10,13], function(){
29995 if(dlg.isVisible() && opt && opt.buttons){
29996 if(opt.buttons.ok){
29997 handleButton("ok");
29998 }else if(opt.buttons.yes){
29999 handleButton("yes");
30003 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
30004 textareaEl.enableDisplayMode();
30005 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
30006 progressEl.enableDisplayMode();
30007 var pf = progressEl.dom.firstChild;
30009 pp = Roo.get(pf.firstChild);
30010 pp.setHeight(pf.offsetHeight);
30018 * Updates the message box body text
30019 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30020 * the XHTML-compliant non-breaking space character '&#160;')
30021 * @return {Roo.MessageBox} This message box
30023 updateText : function(text){
30024 if(!dlg.isVisible() && !opt.width){
30025 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30027 msgEl.innerHTML = text || ' ';
30028 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
30029 Math.max(opt.minWidth || this.minWidth, bwidth));
30031 activeTextEl.setWidth(w);
30033 if(dlg.isVisible()){
30034 dlg.fixedcenter = false;
30036 dlg.setContentSize(w, bodyEl.getHeight());
30037 if(dlg.isVisible()){
30038 dlg.fixedcenter = true;
30044 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30045 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30046 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30047 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30048 * @return {Roo.MessageBox} This message box
30050 updateProgress : function(value, text){
30052 this.updateText(text);
30054 if (pp) { // weird bug on my firefox - for some reason this is not defined
30055 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30061 * Returns true if the message box is currently displayed
30062 * @return {Boolean} True if the message box is visible, else false
30064 isVisible : function(){
30065 return dlg && dlg.isVisible();
30069 * Hides the message box if it is displayed
30072 if(this.isVisible()){
30078 * Displays a new message box, or reinitializes an existing message box, based on the config options
30079 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30080 * The following config object properties are supported:
30082 Property Type Description
30083 ---------- --------------- ------------------------------------------------------------------------------------
30084 animEl String/Element An id or Element from which the message box should animate as it opens and
30085 closes (defaults to undefined)
30086 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30087 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30088 closable Boolean False to hide the top-right close button (defaults to true). Note that
30089 progress and wait dialogs will ignore this property and always hide the
30090 close button as they can only be closed programmatically.
30091 cls String A custom CSS class to apply to the message box element
30092 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30093 displayed (defaults to 75)
30094 fn Function A callback function to execute after closing the dialog. The arguments to the
30095 function will be btn (the name of the button that was clicked, if applicable,
30096 e.g. "ok"), and text (the value of the active text field, if applicable).
30097 Progress and wait dialogs will ignore this option since they do not respond to
30098 user actions and can only be closed programmatically, so any required function
30099 should be called by the same code after it closes the dialog.
30100 icon String A CSS class that provides a background image to be used as an icon for
30101 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30102 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30103 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30104 modal Boolean False to allow user interaction with the page while the message box is
30105 displayed (defaults to true)
30106 msg String A string that will replace the existing message box body text (defaults
30107 to the XHTML-compliant non-breaking space character ' ')
30108 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30109 progress Boolean True to display a progress bar (defaults to false)
30110 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30111 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30112 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30113 title String The title text
30114 value String The string value to set into the active textbox element if displayed
30115 wait Boolean True to display a progress bar (defaults to false)
30116 width Number The width of the dialog in pixels
30123 msg: 'Please enter your address:',
30125 buttons: Roo.MessageBox.OKCANCEL,
30128 animEl: 'addAddressBtn'
30131 * @param {Object} config Configuration options
30132 * @return {Roo.MessageBox} This message box
30134 show : function(options){
30135 if(this.isVisible()){
30138 var d = this.getDialog();
30140 d.setTitle(opt.title || " ");
30141 d.close.setDisplayed(opt.closable !== false);
30142 activeTextEl = textboxEl;
30143 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30148 textareaEl.setHeight(typeof opt.multiline == "number" ?
30149 opt.multiline : this.defaultTextHeight);
30150 activeTextEl = textareaEl;
30159 progressEl.setDisplayed(opt.progress === true);
30160 this.updateProgress(0);
30161 activeTextEl.dom.value = opt.value || "";
30163 dlg.setDefaultButton(activeTextEl);
30165 var bs = opt.buttons;
30168 db = buttons["ok"];
30169 }else if(bs && bs.yes){
30170 db = buttons["yes"];
30172 dlg.setDefaultButton(db);
30174 bwidth = updateButtons(opt.buttons);
30175 this.updateText(opt.msg);
30177 d.el.addClass(opt.cls);
30179 d.proxyDrag = opt.proxyDrag === true;
30180 d.modal = opt.modal !== false;
30181 d.mask = opt.modal !== false ? mask : false;
30182 if(!d.isVisible()){
30183 // force it to the end of the z-index stack so it gets a cursor in FF
30184 document.body.appendChild(dlg.el.dom);
30185 d.animateTarget = null;
30186 d.show(options.animEl);
30192 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30193 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30194 * and closing the message box when the process is complete.
30195 * @param {String} title The title bar text
30196 * @param {String} msg The message box body text
30197 * @return {Roo.MessageBox} This message box
30199 progress : function(title, msg){
30206 minWidth: this.minProgressWidth,
30213 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30214 * If a callback function is passed it will be called after the user clicks the button, and the
30215 * id of the button that was clicked will be passed as the only parameter to the callback
30216 * (could also be the top-right close button).
30217 * @param {String} title The title bar text
30218 * @param {String} msg The message box body text
30219 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30220 * @param {Object} scope (optional) The scope of the callback function
30221 * @return {Roo.MessageBox} This message box
30223 alert : function(title, msg, fn, scope){
30236 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30237 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30238 * You are responsible for closing the message box when the process is complete.
30239 * @param {String} msg The message box body text
30240 * @param {String} title (optional) The title bar text
30241 * @return {Roo.MessageBox} This message box
30243 wait : function(msg, title){
30254 waitTimer = Roo.TaskMgr.start({
30256 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30264 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30265 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30266 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30267 * @param {String} title The title bar text
30268 * @param {String} msg The message box body text
30269 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30270 * @param {Object} scope (optional) The scope of the callback function
30271 * @return {Roo.MessageBox} This message box
30273 confirm : function(title, msg, fn, scope){
30277 buttons: this.YESNO,
30286 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30287 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30288 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30289 * (could also be the top-right close button) and the text that was entered will be passed as the two
30290 * parameters to the callback.
30291 * @param {String} title The title bar text
30292 * @param {String} msg The message box body text
30293 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30294 * @param {Object} scope (optional) The scope of the callback function
30295 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30296 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30297 * @return {Roo.MessageBox} This message box
30299 prompt : function(title, msg, fn, scope, multiline){
30303 buttons: this.OKCANCEL,
30308 multiline: multiline,
30315 * Button config that displays a single OK button
30320 * Button config that displays Yes and No buttons
30323 YESNO : {yes:true, no:true},
30325 * Button config that displays OK and Cancel buttons
30328 OKCANCEL : {ok:true, cancel:true},
30330 * Button config that displays Yes, No and Cancel buttons
30333 YESNOCANCEL : {yes:true, no:true, cancel:true},
30336 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30339 defaultTextHeight : 75,
30341 * The maximum width in pixels of the message box (defaults to 600)
30346 * The minimum width in pixels of the message box (defaults to 100)
30351 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30352 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30355 minProgressWidth : 250,
30357 * An object containing the default button text strings that can be overriden for localized language support.
30358 * Supported properties are: ok, cancel, yes and no.
30359 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30372 * Shorthand for {@link Roo.MessageBox}
30374 Roo.Msg = Roo.MessageBox;/*
30376 * Ext JS Library 1.1.1
30377 * Copyright(c) 2006-2007, Ext JS, LLC.
30379 * Originally Released Under LGPL - original licence link has changed is not relivant.
30382 * <script type="text/javascript">
30385 * @class Roo.QuickTips
30386 * Provides attractive and customizable tooltips for any element.
30389 Roo.QuickTips = function(){
30390 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30391 var ce, bd, xy, dd;
30392 var visible = false, disabled = true, inited = false;
30393 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30395 var onOver = function(e){
30399 var t = e.getTarget();
30400 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30403 if(ce && t == ce.el){
30404 clearTimeout(hideProc);
30407 if(t && tagEls[t.id]){
30408 tagEls[t.id].el = t;
30409 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30412 var ttp, et = Roo.fly(t);
30413 var ns = cfg.namespace;
30414 if(tm.interceptTitles && t.title){
30417 t.removeAttribute("title");
30418 e.preventDefault();
30420 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30423 showProc = show.defer(tm.showDelay, tm, [{
30426 width: et.getAttributeNS(ns, cfg.width),
30427 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30428 title: et.getAttributeNS(ns, cfg.title),
30429 cls: et.getAttributeNS(ns, cfg.cls)
30434 var onOut = function(e){
30435 clearTimeout(showProc);
30436 var t = e.getTarget();
30437 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30438 hideProc = setTimeout(hide, tm.hideDelay);
30442 var onMove = function(e){
30448 if(tm.trackMouse && ce){
30453 var onDown = function(e){
30454 clearTimeout(showProc);
30455 clearTimeout(hideProc);
30457 if(tm.hideOnClick){
30460 tm.enable.defer(100, tm);
30465 var getPad = function(){
30466 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30469 var show = function(o){
30473 clearTimeout(dismissProc);
30475 if(removeCls){ // in case manually hidden
30476 el.removeClass(removeCls);
30480 el.addClass(ce.cls);
30481 removeCls = ce.cls;
30484 tipTitle.update(ce.title);
30487 tipTitle.update('');
30490 el.dom.style.width = tm.maxWidth+'px';
30491 //tipBody.dom.style.width = '';
30492 tipBodyText.update(o.text);
30493 var p = getPad(), w = ce.width;
30495 var td = tipBodyText.dom;
30496 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30497 if(aw > tm.maxWidth){
30499 }else if(aw < tm.minWidth){
30505 //tipBody.setWidth(w);
30506 el.setWidth(parseInt(w, 10) + p);
30507 if(ce.autoHide === false){
30508 close.setDisplayed(true);
30513 close.setDisplayed(false);
30519 el.avoidY = xy[1]-18;
30524 el.setStyle("visibility", "visible");
30525 el.fadeIn({callback: afterShow});
30531 var afterShow = function(){
30535 if(tm.autoDismiss && ce.autoHide !== false){
30536 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30541 var hide = function(noanim){
30542 clearTimeout(dismissProc);
30543 clearTimeout(hideProc);
30545 if(el.isVisible()){
30547 if(noanim !== true && tm.animate){
30548 el.fadeOut({callback: afterHide});
30555 var afterHide = function(){
30558 el.removeClass(removeCls);
30565 * @cfg {Number} minWidth
30566 * The minimum width of the quick tip (defaults to 40)
30570 * @cfg {Number} maxWidth
30571 * The maximum width of the quick tip (defaults to 300)
30575 * @cfg {Boolean} interceptTitles
30576 * True to automatically use the element's DOM title value if available (defaults to false)
30578 interceptTitles : false,
30580 * @cfg {Boolean} trackMouse
30581 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30583 trackMouse : false,
30585 * @cfg {Boolean} hideOnClick
30586 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30588 hideOnClick : true,
30590 * @cfg {Number} showDelay
30591 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30595 * @cfg {Number} hideDelay
30596 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30600 * @cfg {Boolean} autoHide
30601 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30602 * Used in conjunction with hideDelay.
30607 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30608 * (defaults to true). Used in conjunction with autoDismissDelay.
30610 autoDismiss : true,
30613 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30615 autoDismissDelay : 5000,
30617 * @cfg {Boolean} animate
30618 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30623 * @cfg {String} title
30624 * Title text to display (defaults to ''). This can be any valid HTML markup.
30628 * @cfg {String} text
30629 * Body text to display (defaults to ''). This can be any valid HTML markup.
30633 * @cfg {String} cls
30634 * A CSS class to apply to the base quick tip element (defaults to '').
30638 * @cfg {Number} width
30639 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30640 * minWidth or maxWidth.
30645 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30646 * or display QuickTips in a page.
30649 tm = Roo.QuickTips;
30650 cfg = tm.tagConfig;
30652 if(!Roo.isReady){ // allow calling of init() before onReady
30653 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30656 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30657 el.fxDefaults = {stopFx: true};
30658 // maximum custom styling
30659 //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>');
30660 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>');
30661 tipTitle = el.child('h3');
30662 tipTitle.enableDisplayMode("block");
30663 tipBody = el.child('div.x-tip-bd');
30664 tipBodyText = el.child('div.x-tip-bd-inner');
30665 //bdLeft = el.child('div.x-tip-bd-left');
30666 //bdRight = el.child('div.x-tip-bd-right');
30667 close = el.child('div.x-tip-close');
30668 close.enableDisplayMode("block");
30669 close.on("click", hide);
30670 var d = Roo.get(document);
30671 d.on("mousedown", onDown);
30672 d.on("mouseover", onOver);
30673 d.on("mouseout", onOut);
30674 d.on("mousemove", onMove);
30675 esc = d.addKeyListener(27, hide);
30678 dd = el.initDD("default", null, {
30679 onDrag : function(){
30683 dd.setHandleElId(tipTitle.id);
30692 * Configures a new quick tip instance and assigns it to a target element. The following config options
30695 Property Type Description
30696 ---------- --------------------- ------------------------------------------------------------------------
30697 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30699 * @param {Object} config The config object
30701 register : function(config){
30702 var cs = config instanceof Array ? config : arguments;
30703 for(var i = 0, len = cs.length; i < len; i++) {
30705 var target = c.target;
30707 if(target instanceof Array){
30708 for(var j = 0, jlen = target.length; j < jlen; j++){
30709 tagEls[target[j]] = c;
30712 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30719 * Removes this quick tip from its element and destroys it.
30720 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30722 unregister : function(el){
30723 delete tagEls[Roo.id(el)];
30727 * Enable this quick tip.
30729 enable : function(){
30730 if(inited && disabled){
30732 if(locks.length < 1){
30739 * Disable this quick tip.
30741 disable : function(){
30743 clearTimeout(showProc);
30744 clearTimeout(hideProc);
30745 clearTimeout(dismissProc);
30753 * Returns true if the quick tip is enabled, else false.
30755 isEnabled : function(){
30762 attribute : "qtip",
30772 // backwards compat
30773 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30775 * Ext JS Library 1.1.1
30776 * Copyright(c) 2006-2007, Ext JS, LLC.
30778 * Originally Released Under LGPL - original licence link has changed is not relivant.
30781 * <script type="text/javascript">
30786 * @class Roo.tree.TreePanel
30787 * @extends Roo.data.Tree
30789 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30790 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30791 * @cfg {Boolean} enableDD true to enable drag and drop
30792 * @cfg {Boolean} enableDrag true to enable just drag
30793 * @cfg {Boolean} enableDrop true to enable just drop
30794 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30795 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30796 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30797 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30798 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30799 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30800 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30801 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30802 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30803 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30804 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30805 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30806 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30807 * @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>
30808 * @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>
30811 * @param {String/HTMLElement/Element} el The container element
30812 * @param {Object} config
30814 Roo.tree.TreePanel = function(el, config){
30816 var loader = false;
30818 root = config.root;
30819 delete config.root;
30821 if (config.loader) {
30822 loader = config.loader;
30823 delete config.loader;
30826 Roo.apply(this, config);
30827 Roo.tree.TreePanel.superclass.constructor.call(this);
30828 this.el = Roo.get(el);
30829 this.el.addClass('x-tree');
30830 //console.log(root);
30832 this.setRootNode( Roo.factory(root, Roo.tree));
30835 this.loader = Roo.factory(loader, Roo.tree);
30838 * Read-only. The id of the container element becomes this TreePanel's id.
30840 this.id = this.el.id;
30843 * @event beforeload
30844 * Fires before a node is loaded, return false to cancel
30845 * @param {Node} node The node being loaded
30847 "beforeload" : true,
30850 * Fires when a node is loaded
30851 * @param {Node} node The node that was loaded
30855 * @event textchange
30856 * Fires when the text for a node is changed
30857 * @param {Node} node The node
30858 * @param {String} text The new text
30859 * @param {String} oldText The old text
30861 "textchange" : true,
30863 * @event beforeexpand
30864 * Fires before a node is expanded, return false to cancel.
30865 * @param {Node} node The node
30866 * @param {Boolean} deep
30867 * @param {Boolean} anim
30869 "beforeexpand" : true,
30871 * @event beforecollapse
30872 * Fires before a node is collapsed, return false to cancel.
30873 * @param {Node} node The node
30874 * @param {Boolean} deep
30875 * @param {Boolean} anim
30877 "beforecollapse" : true,
30880 * Fires when a node is expanded
30881 * @param {Node} node The node
30885 * @event disabledchange
30886 * Fires when the disabled status of a node changes
30887 * @param {Node} node The node
30888 * @param {Boolean} disabled
30890 "disabledchange" : true,
30893 * Fires when a node is collapsed
30894 * @param {Node} node The node
30898 * @event beforeclick
30899 * Fires before click processing on a node. Return false to cancel the default action.
30900 * @param {Node} node The node
30901 * @param {Roo.EventObject} e The event object
30903 "beforeclick":true,
30905 * @event checkchange
30906 * Fires when a node with a checkbox's checked property changes
30907 * @param {Node} this This node
30908 * @param {Boolean} checked
30910 "checkchange":true,
30913 * Fires when a node is clicked
30914 * @param {Node} node The node
30915 * @param {Roo.EventObject} e The event object
30920 * Fires when a node is double clicked
30921 * @param {Node} node The node
30922 * @param {Roo.EventObject} e The event object
30926 * @event contextmenu
30927 * Fires when a node is right clicked
30928 * @param {Node} node The node
30929 * @param {Roo.EventObject} e The event object
30931 "contextmenu":true,
30933 * @event beforechildrenrendered
30934 * Fires right before the child nodes for a node are rendered
30935 * @param {Node} node The node
30937 "beforechildrenrendered":true,
30940 * Fires when a node starts being dragged
30941 * @param {Roo.tree.TreePanel} this
30942 * @param {Roo.tree.TreeNode} node
30943 * @param {event} e The raw browser event
30945 "startdrag" : true,
30948 * Fires when a drag operation is complete
30949 * @param {Roo.tree.TreePanel} this
30950 * @param {Roo.tree.TreeNode} node
30951 * @param {event} e The raw browser event
30956 * Fires when a dragged node is dropped on a valid DD target
30957 * @param {Roo.tree.TreePanel} this
30958 * @param {Roo.tree.TreeNode} node
30959 * @param {DD} dd The dd it was dropped on
30960 * @param {event} e The raw browser event
30964 * @event beforenodedrop
30965 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30966 * passed to handlers has the following properties:<br />
30967 * <ul style="padding:5px;padding-left:16px;">
30968 * <li>tree - The TreePanel</li>
30969 * <li>target - The node being targeted for the drop</li>
30970 * <li>data - The drag data from the drag source</li>
30971 * <li>point - The point of the drop - append, above or below</li>
30972 * <li>source - The drag source</li>
30973 * <li>rawEvent - Raw mouse event</li>
30974 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30975 * to be inserted by setting them on this object.</li>
30976 * <li>cancel - Set this to true to cancel the drop.</li>
30978 * @param {Object} dropEvent
30980 "beforenodedrop" : true,
30983 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30984 * passed to handlers has the following properties:<br />
30985 * <ul style="padding:5px;padding-left:16px;">
30986 * <li>tree - The TreePanel</li>
30987 * <li>target - The node being targeted for the drop</li>
30988 * <li>data - The drag data from the drag source</li>
30989 * <li>point - The point of the drop - append, above or below</li>
30990 * <li>source - The drag source</li>
30991 * <li>rawEvent - Raw mouse event</li>
30992 * <li>dropNode - Dropped node(s).</li>
30994 * @param {Object} dropEvent
30998 * @event nodedragover
30999 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31000 * passed to handlers has the following properties:<br />
31001 * <ul style="padding:5px;padding-left:16px;">
31002 * <li>tree - The TreePanel</li>
31003 * <li>target - The node being targeted for the drop</li>
31004 * <li>data - The drag data from the drag source</li>
31005 * <li>point - The point of the drop - append, above or below</li>
31006 * <li>source - The drag source</li>
31007 * <li>rawEvent - Raw mouse event</li>
31008 * <li>dropNode - Drop node(s) provided by the source.</li>
31009 * <li>cancel - Set this to true to signal drop not allowed.</li>
31011 * @param {Object} dragOverEvent
31013 "nodedragover" : true
31016 if(this.singleExpand){
31017 this.on("beforeexpand", this.restrictExpand, this);
31020 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31021 rootVisible : true,
31022 animate: Roo.enableFx,
31025 hlDrop : Roo.enableFx,
31029 rendererTip: false,
31031 restrictExpand : function(node){
31032 var p = node.parentNode;
31034 if(p.expandedChild && p.expandedChild.parentNode == p){
31035 p.expandedChild.collapse();
31037 p.expandedChild = node;
31041 // private override
31042 setRootNode : function(node){
31043 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31044 if(!this.rootVisible){
31045 node.ui = new Roo.tree.RootTreeNodeUI(node);
31051 * Returns the container element for this TreePanel
31053 getEl : function(){
31058 * Returns the default TreeLoader for this TreePanel
31060 getLoader : function(){
31061 return this.loader;
31067 expandAll : function(){
31068 this.root.expand(true);
31072 * Collapse all nodes
31074 collapseAll : function(){
31075 this.root.collapse(true);
31079 * Returns the selection model used by this TreePanel
31081 getSelectionModel : function(){
31082 if(!this.selModel){
31083 this.selModel = new Roo.tree.DefaultSelectionModel();
31085 return this.selModel;
31089 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31090 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31091 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31094 getChecked : function(a, startNode){
31095 startNode = startNode || this.root;
31097 var f = function(){
31098 if(this.attributes.checked){
31099 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31102 startNode.cascade(f);
31107 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31108 * @param {String} path
31109 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31110 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31111 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31113 expandPath : function(path, attr, callback){
31114 attr = attr || "id";
31115 var keys = path.split(this.pathSeparator);
31116 var curNode = this.root;
31117 if(curNode.attributes[attr] != keys[1]){ // invalid root
31119 callback(false, null);
31124 var f = function(){
31125 if(++index == keys.length){
31127 callback(true, curNode);
31131 var c = curNode.findChild(attr, keys[index]);
31134 callback(false, curNode);
31139 c.expand(false, false, f);
31141 curNode.expand(false, false, f);
31145 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31146 * @param {String} path
31147 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31148 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31149 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31151 selectPath : function(path, attr, callback){
31152 attr = attr || "id";
31153 var keys = path.split(this.pathSeparator);
31154 var v = keys.pop();
31155 if(keys.length > 0){
31156 var f = function(success, node){
31157 if(success && node){
31158 var n = node.findChild(attr, v);
31164 }else if(callback){
31165 callback(false, n);
31169 callback(false, n);
31173 this.expandPath(keys.join(this.pathSeparator), attr, f);
31175 this.root.select();
31177 callback(true, this.root);
31182 getTreeEl : function(){
31187 * Trigger rendering of this TreePanel
31189 render : function(){
31190 if (this.innerCt) {
31191 return this; // stop it rendering more than once!!
31194 this.innerCt = this.el.createChild({tag:"ul",
31195 cls:"x-tree-root-ct " +
31196 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31198 if(this.containerScroll){
31199 Roo.dd.ScrollManager.register(this.el);
31201 if((this.enableDD || this.enableDrop) && !this.dropZone){
31203 * The dropZone used by this tree if drop is enabled
31204 * @type Roo.tree.TreeDropZone
31206 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31207 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31210 if((this.enableDD || this.enableDrag) && !this.dragZone){
31212 * The dragZone used by this tree if drag is enabled
31213 * @type Roo.tree.TreeDragZone
31215 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31216 ddGroup: this.ddGroup || "TreeDD",
31217 scroll: this.ddScroll
31220 this.getSelectionModel().init(this);
31222 console.log("ROOT not set in tree");
31225 this.root.render();
31226 if(!this.rootVisible){
31227 this.root.renderChildren();
31233 * Ext JS Library 1.1.1
31234 * Copyright(c) 2006-2007, Ext JS, LLC.
31236 * Originally Released Under LGPL - original licence link has changed is not relivant.
31239 * <script type="text/javascript">
31244 * @class Roo.tree.DefaultSelectionModel
31245 * @extends Roo.util.Observable
31246 * The default single selection for a TreePanel.
31248 Roo.tree.DefaultSelectionModel = function(){
31249 this.selNode = null;
31253 * @event selectionchange
31254 * Fires when the selected node changes
31255 * @param {DefaultSelectionModel} this
31256 * @param {TreeNode} node the new selection
31258 "selectionchange" : true,
31261 * @event beforeselect
31262 * Fires before the selected node changes, return false to cancel the change
31263 * @param {DefaultSelectionModel} this
31264 * @param {TreeNode} node the new selection
31265 * @param {TreeNode} node the old selection
31267 "beforeselect" : true
31271 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31272 init : function(tree){
31274 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31275 tree.on("click", this.onNodeClick, this);
31278 onNodeClick : function(node, e){
31279 if (e.ctrlKey && this.selNode == node) {
31280 this.unselect(node);
31288 * @param {TreeNode} node The node to select
31289 * @return {TreeNode} The selected node
31291 select : function(node){
31292 var last = this.selNode;
31293 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31295 last.ui.onSelectedChange(false);
31297 this.selNode = node;
31298 node.ui.onSelectedChange(true);
31299 this.fireEvent("selectionchange", this, node, last);
31306 * @param {TreeNode} node The node to unselect
31308 unselect : function(node){
31309 if(this.selNode == node){
31310 this.clearSelections();
31315 * Clear all selections
31317 clearSelections : function(){
31318 var n = this.selNode;
31320 n.ui.onSelectedChange(false);
31321 this.selNode = null;
31322 this.fireEvent("selectionchange", this, null);
31328 * Get the selected node
31329 * @return {TreeNode} The selected node
31331 getSelectedNode : function(){
31332 return this.selNode;
31336 * Returns true if the node is selected
31337 * @param {TreeNode} node The node to check
31338 * @return {Boolean}
31340 isSelected : function(node){
31341 return this.selNode == node;
31345 * Selects the node above the selected node in the tree, intelligently walking the nodes
31346 * @return TreeNode The new selection
31348 selectPrevious : function(){
31349 var s = this.selNode || this.lastSelNode;
31353 var ps = s.previousSibling;
31355 if(!ps.isExpanded() || ps.childNodes.length < 1){
31356 return this.select(ps);
31358 var lc = ps.lastChild;
31359 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31362 return this.select(lc);
31364 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31365 return this.select(s.parentNode);
31371 * Selects the node above the selected node in the tree, intelligently walking the nodes
31372 * @return TreeNode The new selection
31374 selectNext : function(){
31375 var s = this.selNode || this.lastSelNode;
31379 if(s.firstChild && s.isExpanded()){
31380 return this.select(s.firstChild);
31381 }else if(s.nextSibling){
31382 return this.select(s.nextSibling);
31383 }else if(s.parentNode){
31385 s.parentNode.bubble(function(){
31386 if(this.nextSibling){
31387 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31396 onKeyDown : function(e){
31397 var s = this.selNode || this.lastSelNode;
31398 // undesirable, but required
31403 var k = e.getKey();
31411 this.selectPrevious();
31414 e.preventDefault();
31415 if(s.hasChildNodes()){
31416 if(!s.isExpanded()){
31418 }else if(s.firstChild){
31419 this.select(s.firstChild, e);
31424 e.preventDefault();
31425 if(s.hasChildNodes() && s.isExpanded()){
31427 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31428 this.select(s.parentNode, e);
31436 * @class Roo.tree.MultiSelectionModel
31437 * @extends Roo.util.Observable
31438 * Multi selection for a TreePanel.
31440 Roo.tree.MultiSelectionModel = function(){
31441 this.selNodes = [];
31445 * @event selectionchange
31446 * Fires when the selected nodes change
31447 * @param {MultiSelectionModel} this
31448 * @param {Array} nodes Array of the selected nodes
31450 "selectionchange" : true
31454 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31455 init : function(tree){
31457 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31458 tree.on("click", this.onNodeClick, this);
31461 onNodeClick : function(node, e){
31462 this.select(node, e, e.ctrlKey);
31467 * @param {TreeNode} node The node to select
31468 * @param {EventObject} e (optional) An event associated with the selection
31469 * @param {Boolean} keepExisting True to retain existing selections
31470 * @return {TreeNode} The selected node
31472 select : function(node, e, keepExisting){
31473 if(keepExisting !== true){
31474 this.clearSelections(true);
31476 if(this.isSelected(node)){
31477 this.lastSelNode = node;
31480 this.selNodes.push(node);
31481 this.selMap[node.id] = node;
31482 this.lastSelNode = node;
31483 node.ui.onSelectedChange(true);
31484 this.fireEvent("selectionchange", this, this.selNodes);
31490 * @param {TreeNode} node The node to unselect
31492 unselect : function(node){
31493 if(this.selMap[node.id]){
31494 node.ui.onSelectedChange(false);
31495 var sn = this.selNodes;
31498 index = sn.indexOf(node);
31500 for(var i = 0, len = sn.length; i < len; i++){
31508 this.selNodes.splice(index, 1);
31510 delete this.selMap[node.id];
31511 this.fireEvent("selectionchange", this, this.selNodes);
31516 * Clear all selections
31518 clearSelections : function(suppressEvent){
31519 var sn = this.selNodes;
31521 for(var i = 0, len = sn.length; i < len; i++){
31522 sn[i].ui.onSelectedChange(false);
31524 this.selNodes = [];
31526 if(suppressEvent !== true){
31527 this.fireEvent("selectionchange", this, this.selNodes);
31533 * Returns true if the node is selected
31534 * @param {TreeNode} node The node to check
31535 * @return {Boolean}
31537 isSelected : function(node){
31538 return this.selMap[node.id] ? true : false;
31542 * Returns an array of the selected nodes
31545 getSelectedNodes : function(){
31546 return this.selNodes;
31549 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31551 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31553 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31556 * Ext JS Library 1.1.1
31557 * Copyright(c) 2006-2007, Ext JS, LLC.
31559 * Originally Released Under LGPL - original licence link has changed is not relivant.
31562 * <script type="text/javascript">
31566 * @class Roo.tree.TreeNode
31567 * @extends Roo.data.Node
31568 * @cfg {String} text The text for this node
31569 * @cfg {Boolean} expanded true to start the node expanded
31570 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31571 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31572 * @cfg {Boolean} disabled true to start the node disabled
31573 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31574 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31575 * @cfg {String} cls A css class to be added to the node
31576 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31577 * @cfg {String} href URL of the link used for the node (defaults to #)
31578 * @cfg {String} hrefTarget target frame for the link
31579 * @cfg {String} qtip An Ext QuickTip for the node
31580 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31581 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31582 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31583 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31584 * (defaults to undefined with no checkbox rendered)
31586 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31588 Roo.tree.TreeNode = function(attributes){
31589 attributes = attributes || {};
31590 if(typeof attributes == "string"){
31591 attributes = {text: attributes};
31593 this.childrenRendered = false;
31594 this.rendered = false;
31595 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31596 this.expanded = attributes.expanded === true;
31597 this.isTarget = attributes.isTarget !== false;
31598 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31599 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31602 * Read-only. The text for this node. To change it use setText().
31605 this.text = attributes.text;
31607 * True if this node is disabled.
31610 this.disabled = attributes.disabled === true;
31614 * @event textchange
31615 * Fires when the text for this node is changed
31616 * @param {Node} this This node
31617 * @param {String} text The new text
31618 * @param {String} oldText The old text
31620 "textchange" : true,
31622 * @event beforeexpand
31623 * Fires before this node is expanded, return false to cancel.
31624 * @param {Node} this This node
31625 * @param {Boolean} deep
31626 * @param {Boolean} anim
31628 "beforeexpand" : true,
31630 * @event beforecollapse
31631 * Fires before this node is collapsed, return false to cancel.
31632 * @param {Node} this This node
31633 * @param {Boolean} deep
31634 * @param {Boolean} anim
31636 "beforecollapse" : true,
31639 * Fires when this node is expanded
31640 * @param {Node} this This node
31644 * @event disabledchange
31645 * Fires when the disabled status of this node changes
31646 * @param {Node} this This node
31647 * @param {Boolean} disabled
31649 "disabledchange" : true,
31652 * Fires when this node is collapsed
31653 * @param {Node} this This node
31657 * @event beforeclick
31658 * Fires before click processing. Return false to cancel the default action.
31659 * @param {Node} this This node
31660 * @param {Roo.EventObject} e The event object
31662 "beforeclick":true,
31664 * @event checkchange
31665 * Fires when a node with a checkbox's checked property changes
31666 * @param {Node} this This node
31667 * @param {Boolean} checked
31669 "checkchange":true,
31672 * Fires when this node is clicked
31673 * @param {Node} this This node
31674 * @param {Roo.EventObject} e The event object
31679 * Fires when this node is double clicked
31680 * @param {Node} this This node
31681 * @param {Roo.EventObject} e The event object
31685 * @event contextmenu
31686 * Fires when this node is right clicked
31687 * @param {Node} this This node
31688 * @param {Roo.EventObject} e The event object
31690 "contextmenu":true,
31692 * @event beforechildrenrendered
31693 * Fires right before the child nodes for this node are rendered
31694 * @param {Node} this This node
31696 "beforechildrenrendered":true
31699 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31702 * Read-only. The UI for this node
31705 this.ui = new uiClass(this);
31707 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31708 preventHScroll: true,
31710 * Returns true if this node is expanded
31711 * @return {Boolean}
31713 isExpanded : function(){
31714 return this.expanded;
31718 * Returns the UI object for this node
31719 * @return {TreeNodeUI}
31721 getUI : function(){
31725 // private override
31726 setFirstChild : function(node){
31727 var of = this.firstChild;
31728 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31729 if(this.childrenRendered && of && node != of){
31730 of.renderIndent(true, true);
31733 this.renderIndent(true, true);
31737 // private override
31738 setLastChild : function(node){
31739 var ol = this.lastChild;
31740 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31741 if(this.childrenRendered && ol && node != ol){
31742 ol.renderIndent(true, true);
31745 this.renderIndent(true, true);
31749 // these methods are overridden to provide lazy rendering support
31750 // private override
31751 appendChild : function(){
31752 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31753 if(node && this.childrenRendered){
31756 this.ui.updateExpandIcon();
31760 // private override
31761 removeChild : function(node){
31762 this.ownerTree.getSelectionModel().unselect(node);
31763 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31764 // if it's been rendered remove dom node
31765 if(this.childrenRendered){
31768 if(this.childNodes.length < 1){
31769 this.collapse(false, false);
31771 this.ui.updateExpandIcon();
31773 if(!this.firstChild) {
31774 this.childrenRendered = false;
31779 // private override
31780 insertBefore : function(node, refNode){
31781 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31782 if(newNode && refNode && this.childrenRendered){
31785 this.ui.updateExpandIcon();
31790 * Sets the text for this node
31791 * @param {String} text
31793 setText : function(text){
31794 var oldText = this.text;
31796 this.attributes.text = text;
31797 if(this.rendered){ // event without subscribing
31798 this.ui.onTextChange(this, text, oldText);
31800 this.fireEvent("textchange", this, text, oldText);
31804 * Triggers selection of this node
31806 select : function(){
31807 this.getOwnerTree().getSelectionModel().select(this);
31811 * Triggers deselection of this node
31813 unselect : function(){
31814 this.getOwnerTree().getSelectionModel().unselect(this);
31818 * Returns true if this node is selected
31819 * @return {Boolean}
31821 isSelected : function(){
31822 return this.getOwnerTree().getSelectionModel().isSelected(this);
31826 * Expand this node.
31827 * @param {Boolean} deep (optional) True to expand all children as well
31828 * @param {Boolean} anim (optional) false to cancel the default animation
31829 * @param {Function} callback (optional) A callback to be called when
31830 * expanding this node completes (does not wait for deep expand to complete).
31831 * Called with 1 parameter, this node.
31833 expand : function(deep, anim, callback){
31834 if(!this.expanded){
31835 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31838 if(!this.childrenRendered){
31839 this.renderChildren();
31841 this.expanded = true;
31842 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31843 this.ui.animExpand(function(){
31844 this.fireEvent("expand", this);
31845 if(typeof callback == "function"){
31849 this.expandChildNodes(true);
31851 }.createDelegate(this));
31855 this.fireEvent("expand", this);
31856 if(typeof callback == "function"){
31861 if(typeof callback == "function"){
31866 this.expandChildNodes(true);
31870 isHiddenRoot : function(){
31871 return this.isRoot && !this.getOwnerTree().rootVisible;
31875 * Collapse this node.
31876 * @param {Boolean} deep (optional) True to collapse all children as well
31877 * @param {Boolean} anim (optional) false to cancel the default animation
31879 collapse : function(deep, anim){
31880 if(this.expanded && !this.isHiddenRoot()){
31881 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31884 this.expanded = false;
31885 if((this.getOwnerTree().animate && anim !== false) || anim){
31886 this.ui.animCollapse(function(){
31887 this.fireEvent("collapse", this);
31889 this.collapseChildNodes(true);
31891 }.createDelegate(this));
31894 this.ui.collapse();
31895 this.fireEvent("collapse", this);
31899 var cs = this.childNodes;
31900 for(var i = 0, len = cs.length; i < len; i++) {
31901 cs[i].collapse(true, false);
31907 delayedExpand : function(delay){
31908 if(!this.expandProcId){
31909 this.expandProcId = this.expand.defer(delay, this);
31914 cancelExpand : function(){
31915 if(this.expandProcId){
31916 clearTimeout(this.expandProcId);
31918 this.expandProcId = false;
31922 * Toggles expanded/collapsed state of the node
31924 toggle : function(){
31933 * Ensures all parent nodes are expanded
31935 ensureVisible : function(callback){
31936 var tree = this.getOwnerTree();
31937 tree.expandPath(this.parentNode.getPath(), false, function(){
31938 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31939 Roo.callback(callback);
31940 }.createDelegate(this));
31944 * Expand all child nodes
31945 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31947 expandChildNodes : function(deep){
31948 var cs = this.childNodes;
31949 for(var i = 0, len = cs.length; i < len; i++) {
31950 cs[i].expand(deep);
31955 * Collapse all child nodes
31956 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31958 collapseChildNodes : function(deep){
31959 var cs = this.childNodes;
31960 for(var i = 0, len = cs.length; i < len; i++) {
31961 cs[i].collapse(deep);
31966 * Disables this node
31968 disable : function(){
31969 this.disabled = true;
31971 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31972 this.ui.onDisableChange(this, true);
31974 this.fireEvent("disabledchange", this, true);
31978 * Enables this node
31980 enable : function(){
31981 this.disabled = false;
31982 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31983 this.ui.onDisableChange(this, false);
31985 this.fireEvent("disabledchange", this, false);
31989 renderChildren : function(suppressEvent){
31990 if(suppressEvent !== false){
31991 this.fireEvent("beforechildrenrendered", this);
31993 var cs = this.childNodes;
31994 for(var i = 0, len = cs.length; i < len; i++){
31995 cs[i].render(true);
31997 this.childrenRendered = true;
32001 sort : function(fn, scope){
32002 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32003 if(this.childrenRendered){
32004 var cs = this.childNodes;
32005 for(var i = 0, len = cs.length; i < len; i++){
32006 cs[i].render(true);
32012 render : function(bulkRender){
32013 this.ui.render(bulkRender);
32014 if(!this.rendered){
32015 this.rendered = true;
32017 this.expanded = false;
32018 this.expand(false, false);
32024 renderIndent : function(deep, refresh){
32026 this.ui.childIndent = null;
32028 this.ui.renderIndent();
32029 if(deep === true && this.childrenRendered){
32030 var cs = this.childNodes;
32031 for(var i = 0, len = cs.length; i < len; i++){
32032 cs[i].renderIndent(true, refresh);
32038 * Ext JS Library 1.1.1
32039 * Copyright(c) 2006-2007, Ext JS, LLC.
32041 * Originally Released Under LGPL - original licence link has changed is not relivant.
32044 * <script type="text/javascript">
32048 * @class Roo.tree.AsyncTreeNode
32049 * @extends Roo.tree.TreeNode
32050 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32052 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32054 Roo.tree.AsyncTreeNode = function(config){
32055 this.loaded = false;
32056 this.loading = false;
32057 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32059 * @event beforeload
32060 * Fires before this node is loaded, return false to cancel
32061 * @param {Node} this This node
32063 this.addEvents({'beforeload':true, 'load': true});
32066 * Fires when this node is loaded
32067 * @param {Node} this This node
32070 * The loader used by this node (defaults to using the tree's defined loader)
32075 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32076 expand : function(deep, anim, callback){
32077 if(this.loading){ // if an async load is already running, waiting til it's done
32079 var f = function(){
32080 if(!this.loading){ // done loading
32081 clearInterval(timer);
32082 this.expand(deep, anim, callback);
32084 }.createDelegate(this);
32085 timer = setInterval(f, 200);
32089 if(this.fireEvent("beforeload", this) === false){
32092 this.loading = true;
32093 this.ui.beforeLoad(this);
32094 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32096 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32100 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32104 * Returns true if this node is currently loading
32105 * @return {Boolean}
32107 isLoading : function(){
32108 return this.loading;
32111 loadComplete : function(deep, anim, callback){
32112 this.loading = false;
32113 this.loaded = true;
32114 this.ui.afterLoad(this);
32115 this.fireEvent("load", this);
32116 this.expand(deep, anim, callback);
32120 * Returns true if this node has been loaded
32121 * @return {Boolean}
32123 isLoaded : function(){
32124 return this.loaded;
32127 hasChildNodes : function(){
32128 if(!this.isLeaf() && !this.loaded){
32131 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32136 * Trigger a reload for this node
32137 * @param {Function} callback
32139 reload : function(callback){
32140 this.collapse(false, false);
32141 while(this.firstChild){
32142 this.removeChild(this.firstChild);
32144 this.childrenRendered = false;
32145 this.loaded = false;
32146 if(this.isHiddenRoot()){
32147 this.expanded = false;
32149 this.expand(false, false, callback);
32153 * Ext JS Library 1.1.1
32154 * Copyright(c) 2006-2007, Ext JS, LLC.
32156 * Originally Released Under LGPL - original licence link has changed is not relivant.
32159 * <script type="text/javascript">
32163 * @class Roo.tree.TreeNodeUI
32165 * @param {Object} node The node to render
32166 * The TreeNode UI implementation is separate from the
32167 * tree implementation. Unless you are customizing the tree UI,
32168 * you should never have to use this directly.
32170 Roo.tree.TreeNodeUI = function(node){
32172 this.rendered = false;
32173 this.animating = false;
32174 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32177 Roo.tree.TreeNodeUI.prototype = {
32178 removeChild : function(node){
32180 this.ctNode.removeChild(node.ui.getEl());
32184 beforeLoad : function(){
32185 this.addClass("x-tree-node-loading");
32188 afterLoad : function(){
32189 this.removeClass("x-tree-node-loading");
32192 onTextChange : function(node, text, oldText){
32194 this.textNode.innerHTML = text;
32198 onDisableChange : function(node, state){
32199 this.disabled = state;
32201 this.addClass("x-tree-node-disabled");
32203 this.removeClass("x-tree-node-disabled");
32207 onSelectedChange : function(state){
32210 this.addClass("x-tree-selected");
32213 this.removeClass("x-tree-selected");
32217 onMove : function(tree, node, oldParent, newParent, index, refNode){
32218 this.childIndent = null;
32220 var targetNode = newParent.ui.getContainer();
32221 if(!targetNode){//target not rendered
32222 this.holder = document.createElement("div");
32223 this.holder.appendChild(this.wrap);
32226 var insertBefore = refNode ? refNode.ui.getEl() : null;
32228 targetNode.insertBefore(this.wrap, insertBefore);
32230 targetNode.appendChild(this.wrap);
32232 this.node.renderIndent(true);
32236 addClass : function(cls){
32238 Roo.fly(this.elNode).addClass(cls);
32242 removeClass : function(cls){
32244 Roo.fly(this.elNode).removeClass(cls);
32248 remove : function(){
32250 this.holder = document.createElement("div");
32251 this.holder.appendChild(this.wrap);
32255 fireEvent : function(){
32256 return this.node.fireEvent.apply(this.node, arguments);
32259 initEvents : function(){
32260 this.node.on("move", this.onMove, this);
32261 var E = Roo.EventManager;
32262 var a = this.anchor;
32264 var el = Roo.fly(a, '_treeui');
32266 if(Roo.isOpera){ // opera render bug ignores the CSS
32267 el.setStyle("text-decoration", "none");
32270 el.on("click", this.onClick, this);
32271 el.on("dblclick", this.onDblClick, this);
32274 Roo.EventManager.on(this.checkbox,
32275 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32278 el.on("contextmenu", this.onContextMenu, this);
32280 var icon = Roo.fly(this.iconNode);
32281 icon.on("click", this.onClick, this);
32282 icon.on("dblclick", this.onDblClick, this);
32283 icon.on("contextmenu", this.onContextMenu, this);
32284 E.on(this.ecNode, "click", this.ecClick, this, true);
32286 if(this.node.disabled){
32287 this.addClass("x-tree-node-disabled");
32289 if(this.node.hidden){
32290 this.addClass("x-tree-node-disabled");
32292 var ot = this.node.getOwnerTree();
32293 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32294 if(dd && (!this.node.isRoot || ot.rootVisible)){
32295 Roo.dd.Registry.register(this.elNode, {
32297 handles: this.getDDHandles(),
32303 getDDHandles : function(){
32304 return [this.iconNode, this.textNode];
32309 this.wrap.style.display = "none";
32315 this.wrap.style.display = "";
32319 onContextMenu : function(e){
32320 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32321 e.preventDefault();
32323 this.fireEvent("contextmenu", this.node, e);
32327 onClick : function(e){
32332 if(this.fireEvent("beforeclick", this.node, e) !== false){
32333 if(!this.disabled && this.node.attributes.href){
32334 this.fireEvent("click", this.node, e);
32337 e.preventDefault();
32342 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32343 this.node.toggle();
32346 this.fireEvent("click", this.node, e);
32352 onDblClick : function(e){
32353 e.preventDefault();
32358 this.toggleCheck();
32360 if(!this.animating && this.node.hasChildNodes()){
32361 this.node.toggle();
32363 this.fireEvent("dblclick", this.node, e);
32366 onCheckChange : function(){
32367 var checked = this.checkbox.checked;
32368 this.node.attributes.checked = checked;
32369 this.fireEvent('checkchange', this.node, checked);
32372 ecClick : function(e){
32373 if(!this.animating && this.node.hasChildNodes()){
32374 this.node.toggle();
32378 startDrop : function(){
32379 this.dropping = true;
32382 // delayed drop so the click event doesn't get fired on a drop
32383 endDrop : function(){
32384 setTimeout(function(){
32385 this.dropping = false;
32386 }.createDelegate(this), 50);
32389 expand : function(){
32390 this.updateExpandIcon();
32391 this.ctNode.style.display = "";
32394 focus : function(){
32395 if(!this.node.preventHScroll){
32396 try{this.anchor.focus();
32398 }else if(!Roo.isIE){
32400 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32401 var l = noscroll.scrollLeft;
32402 this.anchor.focus();
32403 noscroll.scrollLeft = l;
32408 toggleCheck : function(value){
32409 var cb = this.checkbox;
32411 cb.checked = (value === undefined ? !cb.checked : value);
32417 this.anchor.blur();
32421 animExpand : function(callback){
32422 var ct = Roo.get(this.ctNode);
32424 if(!this.node.hasChildNodes()){
32425 this.updateExpandIcon();
32426 this.ctNode.style.display = "";
32427 Roo.callback(callback);
32430 this.animating = true;
32431 this.updateExpandIcon();
32434 callback : function(){
32435 this.animating = false;
32436 Roo.callback(callback);
32439 duration: this.node.ownerTree.duration || .25
32443 highlight : function(){
32444 var tree = this.node.getOwnerTree();
32445 Roo.fly(this.wrap).highlight(
32446 tree.hlColor || "C3DAF9",
32447 {endColor: tree.hlBaseColor}
32451 collapse : function(){
32452 this.updateExpandIcon();
32453 this.ctNode.style.display = "none";
32456 animCollapse : function(callback){
32457 var ct = Roo.get(this.ctNode);
32458 ct.enableDisplayMode('block');
32461 this.animating = true;
32462 this.updateExpandIcon();
32465 callback : function(){
32466 this.animating = false;
32467 Roo.callback(callback);
32470 duration: this.node.ownerTree.duration || .25
32474 getContainer : function(){
32475 return this.ctNode;
32478 getEl : function(){
32482 appendDDGhost : function(ghostNode){
32483 ghostNode.appendChild(this.elNode.cloneNode(true));
32486 getDDRepairXY : function(){
32487 return Roo.lib.Dom.getXY(this.iconNode);
32490 onRender : function(){
32494 render : function(bulkRender){
32495 var n = this.node, a = n.attributes;
32496 var targetNode = n.parentNode ?
32497 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32499 if(!this.rendered){
32500 this.rendered = true;
32502 this.renderElements(n, a, targetNode, bulkRender);
32505 if(this.textNode.setAttributeNS){
32506 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32508 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32511 this.textNode.setAttribute("ext:qtip", a.qtip);
32513 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32516 }else if(a.qtipCfg){
32517 a.qtipCfg.target = Roo.id(this.textNode);
32518 Roo.QuickTips.register(a.qtipCfg);
32521 if(!this.node.expanded){
32522 this.updateExpandIcon();
32525 if(bulkRender === true) {
32526 targetNode.appendChild(this.wrap);
32531 renderElements : function(n, a, targetNode, bulkRender){
32532 // add some indent caching, this helps performance when rendering a large tree
32533 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32534 var t = n.getOwnerTree();
32535 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32536 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32537 var cb = typeof a.checked == 'boolean';
32538 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32539 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32540 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32541 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32542 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32543 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32544 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32545 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32546 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32547 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32550 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32551 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32552 n.nextSibling.ui.getEl(), buf.join(""));
32554 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32557 this.elNode = this.wrap.childNodes[0];
32558 this.ctNode = this.wrap.childNodes[1];
32559 var cs = this.elNode.childNodes;
32560 this.indentNode = cs[0];
32561 this.ecNode = cs[1];
32562 this.iconNode = cs[2];
32565 this.checkbox = cs[3];
32568 this.anchor = cs[index];
32569 this.textNode = cs[index].firstChild;
32572 getAnchor : function(){
32573 return this.anchor;
32576 getTextEl : function(){
32577 return this.textNode;
32580 getIconEl : function(){
32581 return this.iconNode;
32584 isChecked : function(){
32585 return this.checkbox ? this.checkbox.checked : false;
32588 updateExpandIcon : function(){
32590 var n = this.node, c1, c2;
32591 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32592 var hasChild = n.hasChildNodes();
32596 c1 = "x-tree-node-collapsed";
32597 c2 = "x-tree-node-expanded";
32600 c1 = "x-tree-node-expanded";
32601 c2 = "x-tree-node-collapsed";
32604 this.removeClass("x-tree-node-leaf");
32605 this.wasLeaf = false;
32607 if(this.c1 != c1 || this.c2 != c2){
32608 Roo.fly(this.elNode).replaceClass(c1, c2);
32609 this.c1 = c1; this.c2 = c2;
32613 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32616 this.wasLeaf = true;
32619 var ecc = "x-tree-ec-icon "+cls;
32620 if(this.ecc != ecc){
32621 this.ecNode.className = ecc;
32627 getChildIndent : function(){
32628 if(!this.childIndent){
32632 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32634 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32636 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32641 this.childIndent = buf.join("");
32643 return this.childIndent;
32646 renderIndent : function(){
32649 var p = this.node.parentNode;
32651 indent = p.ui.getChildIndent();
32653 if(this.indentMarkup != indent){ // don't rerender if not required
32654 this.indentNode.innerHTML = indent;
32655 this.indentMarkup = indent;
32657 this.updateExpandIcon();
32662 Roo.tree.RootTreeNodeUI = function(){
32663 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32665 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32666 render : function(){
32667 if(!this.rendered){
32668 var targetNode = this.node.ownerTree.innerCt.dom;
32669 this.node.expanded = true;
32670 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32671 this.wrap = this.ctNode = targetNode.firstChild;
32674 collapse : function(){
32676 expand : function(){
32680 * Ext JS Library 1.1.1
32681 * Copyright(c) 2006-2007, Ext JS, LLC.
32683 * Originally Released Under LGPL - original licence link has changed is not relivant.
32686 * <script type="text/javascript">
32689 * @class Roo.tree.TreeLoader
32690 * @extends Roo.util.Observable
32691 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32692 * nodes from a specified URL. The response must be a javascript Array definition
32693 * who's elements are node definition objects. eg:
32695 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32696 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32699 * A server request is sent, and child nodes are loaded only when a node is expanded.
32700 * The loading node's id is passed to the server under the parameter name "node" to
32701 * enable the server to produce the correct child nodes.
32703 * To pass extra parameters, an event handler may be attached to the "beforeload"
32704 * event, and the parameters specified in the TreeLoader's baseParams property:
32706 myTreeLoader.on("beforeload", function(treeLoader, node) {
32707 this.baseParams.category = node.attributes.category;
32710 * This would pass an HTTP parameter called "category" to the server containing
32711 * the value of the Node's "category" attribute.
32713 * Creates a new Treeloader.
32714 * @param {Object} config A config object containing config properties.
32716 Roo.tree.TreeLoader = function(config){
32717 this.baseParams = {};
32718 this.requestMethod = "POST";
32719 Roo.apply(this, config);
32724 * @event beforeload
32725 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32726 * @param {Object} This TreeLoader object.
32727 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32728 * @param {Object} callback The callback function specified in the {@link #load} call.
32733 * Fires when the node has been successfuly loaded.
32734 * @param {Object} This TreeLoader object.
32735 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32736 * @param {Object} response The response object containing the data from the server.
32740 * @event loadexception
32741 * Fires if the network request failed.
32742 * @param {Object} This TreeLoader object.
32743 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32744 * @param {Object} response The response object containing the data from the server.
32746 loadexception : true,
32749 * Fires before a node is created, enabling you to return custom Node types
32750 * @param {Object} This TreeLoader object.
32751 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32756 Roo.tree.TreeLoader.superclass.constructor.call(this);
32759 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32761 * @cfg {String} dataUrl The URL from which to request a Json string which
32762 * specifies an array of node definition object representing the child nodes
32766 * @cfg {Object} baseParams (optional) An object containing properties which
32767 * specify HTTP parameters to be passed to each request for child nodes.
32770 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32771 * created by this loader. If the attributes sent by the server have an attribute in this object,
32772 * they take priority.
32775 * @cfg {Object} uiProviders (optional) An object containing properties which
32777 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32778 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32779 * <i>uiProvider</i> attribute of a returned child node is a string rather
32780 * than a reference to a TreeNodeUI implementation, this that string value
32781 * is used as a property name in the uiProviders object. You can define the provider named
32782 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32787 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32788 * child nodes before loading.
32790 clearOnLoad : true,
32793 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32794 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32795 * Grid query { data : [ .....] }
32800 * @cfg {String} queryParam (optional)
32801 * Name of the query as it will be passed on the querystring (defaults to 'node')
32802 * eg. the request will be ?node=[id]
32809 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32810 * This is called automatically when a node is expanded, but may be used to reload
32811 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32812 * @param {Roo.tree.TreeNode} node
32813 * @param {Function} callback
32815 load : function(node, callback){
32816 if(this.clearOnLoad){
32817 while(node.firstChild){
32818 node.removeChild(node.firstChild);
32821 if(node.attributes.children){ // preloaded json children
32822 var cs = node.attributes.children;
32823 for(var i = 0, len = cs.length; i < len; i++){
32824 node.appendChild(this.createNode(cs[i]));
32826 if(typeof callback == "function"){
32829 }else if(this.dataUrl){
32830 this.requestData(node, callback);
32834 getParams: function(node){
32835 var buf = [], bp = this.baseParams;
32836 for(var key in bp){
32837 if(typeof bp[key] != "function"){
32838 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32841 var n = this.queryParam === false ? 'node' : this.queryParam;
32842 buf.push(n + "=", encodeURIComponent(node.id));
32843 return buf.join("");
32846 requestData : function(node, callback){
32847 if(this.fireEvent("beforeload", this, node, callback) !== false){
32848 this.transId = Roo.Ajax.request({
32849 method:this.requestMethod,
32850 url: this.dataUrl||this.url,
32851 success: this.handleResponse,
32852 failure: this.handleFailure,
32854 argument: {callback: callback, node: node},
32855 params: this.getParams(node)
32858 // if the load is cancelled, make sure we notify
32859 // the node that we are done
32860 if(typeof callback == "function"){
32866 isLoading : function(){
32867 return this.transId ? true : false;
32870 abort : function(){
32871 if(this.isLoading()){
32872 Roo.Ajax.abort(this.transId);
32877 createNode : function(attr){
32878 // apply baseAttrs, nice idea Corey!
32879 if(this.baseAttrs){
32880 Roo.applyIf(attr, this.baseAttrs);
32882 if(this.applyLoader !== false){
32883 attr.loader = this;
32885 // uiProvider = depreciated..
32887 if(typeof(attr.uiProvider) == 'string'){
32888 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32889 /** eval:var:attr */ eval(attr.uiProvider);
32891 if(typeof(this.uiProviders['default']) != 'undefined') {
32892 attr.uiProvider = this.uiProviders['default'];
32895 this.fireEvent('create', this, attr);
32897 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32899 new Roo.tree.TreeNode(attr) :
32900 new Roo.tree.AsyncTreeNode(attr));
32903 processResponse : function(response, node, callback){
32904 var json = response.responseText;
32907 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32908 if (this.root !== false) {
32912 for(var i = 0, len = o.length; i < len; i++){
32913 var n = this.createNode(o[i]);
32915 node.appendChild(n);
32918 if(typeof callback == "function"){
32919 callback(this, node);
32922 this.handleFailure(response);
32926 handleResponse : function(response){
32927 this.transId = false;
32928 var a = response.argument;
32929 this.processResponse(response, a.node, a.callback);
32930 this.fireEvent("load", this, a.node, response);
32933 handleFailure : function(response){
32934 this.transId = false;
32935 var a = response.argument;
32936 this.fireEvent("loadexception", this, a.node, response);
32937 if(typeof a.callback == "function"){
32938 a.callback(this, a.node);
32943 * Ext JS Library 1.1.1
32944 * Copyright(c) 2006-2007, Ext JS, LLC.
32946 * Originally Released Under LGPL - original licence link has changed is not relivant.
32949 * <script type="text/javascript">
32953 * @class Roo.tree.TreeFilter
32954 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32955 * @param {TreePanel} tree
32956 * @param {Object} config (optional)
32958 Roo.tree.TreeFilter = function(tree, config){
32960 this.filtered = {};
32961 Roo.apply(this, config);
32964 Roo.tree.TreeFilter.prototype = {
32971 * Filter the data by a specific attribute.
32972 * @param {String/RegExp} value Either string that the attribute value
32973 * should start with or a RegExp to test against the attribute
32974 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32975 * @param {TreeNode} startNode (optional) The node to start the filter at.
32977 filter : function(value, attr, startNode){
32978 attr = attr || "text";
32980 if(typeof value == "string"){
32981 var vlen = value.length;
32982 // auto clear empty filter
32983 if(vlen == 0 && this.clearBlank){
32987 value = value.toLowerCase();
32989 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32991 }else if(value.exec){ // regex?
32993 return value.test(n.attributes[attr]);
32996 throw 'Illegal filter type, must be string or regex';
32998 this.filterBy(f, null, startNode);
33002 * Filter by a function. The passed function will be called with each
33003 * node in the tree (or from the startNode). If the function returns true, the node is kept
33004 * otherwise it is filtered. If a node is filtered, its children are also filtered.
33005 * @param {Function} fn The filter function
33006 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33008 filterBy : function(fn, scope, startNode){
33009 startNode = startNode || this.tree.root;
33010 if(this.autoClear){
33013 var af = this.filtered, rv = this.reverse;
33014 var f = function(n){
33015 if(n == startNode){
33021 var m = fn.call(scope || n, n);
33029 startNode.cascade(f);
33032 if(typeof id != "function"){
33034 if(n && n.parentNode){
33035 n.parentNode.removeChild(n);
33043 * Clears the current filter. Note: with the "remove" option
33044 * set a filter cannot be cleared.
33046 clear : function(){
33048 var af = this.filtered;
33050 if(typeof id != "function"){
33057 this.filtered = {};
33062 * Ext JS Library 1.1.1
33063 * Copyright(c) 2006-2007, Ext JS, LLC.
33065 * Originally Released Under LGPL - original licence link has changed is not relivant.
33068 * <script type="text/javascript">
33073 * @class Roo.tree.TreeSorter
33074 * Provides sorting of nodes in a TreePanel
33076 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33077 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33078 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33079 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33080 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33081 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33083 * @param {TreePanel} tree
33084 * @param {Object} config
33086 Roo.tree.TreeSorter = function(tree, config){
33087 Roo.apply(this, config);
33088 tree.on("beforechildrenrendered", this.doSort, this);
33089 tree.on("append", this.updateSort, this);
33090 tree.on("insert", this.updateSort, this);
33092 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33093 var p = this.property || "text";
33094 var sortType = this.sortType;
33095 var fs = this.folderSort;
33096 var cs = this.caseSensitive === true;
33097 var leafAttr = this.leafAttr || 'leaf';
33099 this.sortFn = function(n1, n2){
33101 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33104 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33108 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33109 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33111 return dsc ? +1 : -1;
33113 return dsc ? -1 : +1;
33120 Roo.tree.TreeSorter.prototype = {
33121 doSort : function(node){
33122 node.sort(this.sortFn);
33125 compareNodes : function(n1, n2){
33126 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33129 updateSort : function(tree, node){
33130 if(node.childrenRendered){
33131 this.doSort.defer(1, this, [node]);
33136 * Ext JS Library 1.1.1
33137 * Copyright(c) 2006-2007, Ext JS, LLC.
33139 * Originally Released Under LGPL - original licence link has changed is not relivant.
33142 * <script type="text/javascript">
33145 if(Roo.dd.DropZone){
33147 Roo.tree.TreeDropZone = function(tree, config){
33148 this.allowParentInsert = false;
33149 this.allowContainerDrop = false;
33150 this.appendOnly = false;
33151 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33153 this.lastInsertClass = "x-tree-no-status";
33154 this.dragOverData = {};
33157 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33158 ddGroup : "TreeDD",
33160 expandDelay : 1000,
33162 expandNode : function(node){
33163 if(node.hasChildNodes() && !node.isExpanded()){
33164 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33168 queueExpand : function(node){
33169 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33172 cancelExpand : function(){
33173 if(this.expandProcId){
33174 clearTimeout(this.expandProcId);
33175 this.expandProcId = false;
33179 isValidDropPoint : function(n, pt, dd, e, data){
33180 if(!n || !data){ return false; }
33181 var targetNode = n.node;
33182 var dropNode = data.node;
33183 // default drop rules
33184 if(!(targetNode && targetNode.isTarget && pt)){
33187 if(pt == "append" && targetNode.allowChildren === false){
33190 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33193 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33196 // reuse the object
33197 var overEvent = this.dragOverData;
33198 overEvent.tree = this.tree;
33199 overEvent.target = targetNode;
33200 overEvent.data = data;
33201 overEvent.point = pt;
33202 overEvent.source = dd;
33203 overEvent.rawEvent = e;
33204 overEvent.dropNode = dropNode;
33205 overEvent.cancel = false;
33206 var result = this.tree.fireEvent("nodedragover", overEvent);
33207 return overEvent.cancel === false && result !== false;
33210 getDropPoint : function(e, n, dd){
33213 return tn.allowChildren !== false ? "append" : false; // always append for root
33215 var dragEl = n.ddel;
33216 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33217 var y = Roo.lib.Event.getPageY(e);
33218 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33220 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33221 var noAppend = tn.allowChildren === false;
33222 if(this.appendOnly || tn.parentNode.allowChildren === false){
33223 return noAppend ? false : "append";
33225 var noBelow = false;
33226 if(!this.allowParentInsert){
33227 noBelow = tn.hasChildNodes() && tn.isExpanded();
33229 var q = (b - t) / (noAppend ? 2 : 3);
33230 if(y >= t && y < (t + q)){
33232 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33239 onNodeEnter : function(n, dd, e, data){
33240 this.cancelExpand();
33243 onNodeOver : function(n, dd, e, data){
33244 var pt = this.getDropPoint(e, n, dd);
33247 // auto node expand check
33248 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33249 this.queueExpand(node);
33250 }else if(pt != "append"){
33251 this.cancelExpand();
33254 // set the insert point style on the target node
33255 var returnCls = this.dropNotAllowed;
33256 if(this.isValidDropPoint(n, pt, dd, e, data)){
33261 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33262 cls = "x-tree-drag-insert-above";
33263 }else if(pt == "below"){
33264 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33265 cls = "x-tree-drag-insert-below";
33267 returnCls = "x-tree-drop-ok-append";
33268 cls = "x-tree-drag-append";
33270 if(this.lastInsertClass != cls){
33271 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33272 this.lastInsertClass = cls;
33279 onNodeOut : function(n, dd, e, data){
33280 this.cancelExpand();
33281 this.removeDropIndicators(n);
33284 onNodeDrop : function(n, dd, e, data){
33285 var point = this.getDropPoint(e, n, dd);
33286 var targetNode = n.node;
33287 targetNode.ui.startDrop();
33288 if(!this.isValidDropPoint(n, point, dd, e, data)){
33289 targetNode.ui.endDrop();
33292 // first try to find the drop node
33293 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33296 target: targetNode,
33301 dropNode: dropNode,
33304 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33305 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33306 targetNode.ui.endDrop();
33309 // allow target changing
33310 targetNode = dropEvent.target;
33311 if(point == "append" && !targetNode.isExpanded()){
33312 targetNode.expand(false, null, function(){
33313 this.completeDrop(dropEvent);
33314 }.createDelegate(this));
33316 this.completeDrop(dropEvent);
33321 completeDrop : function(de){
33322 var ns = de.dropNode, p = de.point, t = de.target;
33323 if(!(ns instanceof Array)){
33327 for(var i = 0, len = ns.length; i < len; i++){
33330 t.parentNode.insertBefore(n, t);
33331 }else if(p == "below"){
33332 t.parentNode.insertBefore(n, t.nextSibling);
33338 if(this.tree.hlDrop){
33342 this.tree.fireEvent("nodedrop", de);
33345 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33346 if(this.tree.hlDrop){
33347 dropNode.ui.focus();
33348 dropNode.ui.highlight();
33350 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33353 getTree : function(){
33357 removeDropIndicators : function(n){
33360 Roo.fly(el).removeClass([
33361 "x-tree-drag-insert-above",
33362 "x-tree-drag-insert-below",
33363 "x-tree-drag-append"]);
33364 this.lastInsertClass = "_noclass";
33368 beforeDragDrop : function(target, e, id){
33369 this.cancelExpand();
33373 afterRepair : function(data){
33374 if(data && Roo.enableFx){
33375 data.node.ui.highlight();
33384 * Ext JS Library 1.1.1
33385 * Copyright(c) 2006-2007, Ext JS, LLC.
33387 * Originally Released Under LGPL - original licence link has changed is not relivant.
33390 * <script type="text/javascript">
33394 if(Roo.dd.DragZone){
33395 Roo.tree.TreeDragZone = function(tree, config){
33396 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33400 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33401 ddGroup : "TreeDD",
33403 onBeforeDrag : function(data, e){
33405 return n && n.draggable && !n.disabled;
33408 onInitDrag : function(e){
33409 var data = this.dragData;
33410 this.tree.getSelectionModel().select(data.node);
33411 this.proxy.update("");
33412 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33413 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33416 getRepairXY : function(e, data){
33417 return data.node.ui.getDDRepairXY();
33420 onEndDrag : function(data, e){
33421 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33424 onValidDrop : function(dd, e, id){
33425 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33429 beforeInvalidDrop : function(e, id){
33430 // this scrolls the original position back into view
33431 var sm = this.tree.getSelectionModel();
33432 sm.clearSelections();
33433 sm.select(this.dragData.node);
33438 * Ext JS Library 1.1.1
33439 * Copyright(c) 2006-2007, Ext JS, LLC.
33441 * Originally Released Under LGPL - original licence link has changed is not relivant.
33444 * <script type="text/javascript">
33447 * @class Roo.tree.TreeEditor
33448 * @extends Roo.Editor
33449 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33450 * as the editor field.
33452 * @param {TreePanel} tree
33453 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33455 Roo.tree.TreeEditor = function(tree, config){
33456 config = config || {};
33457 var field = config.events ? config : new Roo.form.TextField(config);
33458 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33462 tree.on('beforeclick', this.beforeNodeClick, this);
33463 tree.getTreeEl().on('mousedown', this.hide, this);
33464 this.on('complete', this.updateNode, this);
33465 this.on('beforestartedit', this.fitToTree, this);
33466 this.on('startedit', this.bindScroll, this, {delay:10});
33467 this.on('specialkey', this.onSpecialKey, this);
33470 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33472 * @cfg {String} alignment
33473 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33479 * @cfg {Boolean} hideEl
33480 * True to hide the bound element while the editor is displayed (defaults to false)
33484 * @cfg {String} cls
33485 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33487 cls: "x-small-editor x-tree-editor",
33489 * @cfg {Boolean} shim
33490 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33496 * @cfg {Number} maxWidth
33497 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33498 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33499 * scroll and client offsets into account prior to each edit.
33506 fitToTree : function(ed, el){
33507 var td = this.tree.getTreeEl().dom, nd = el.dom;
33508 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33509 td.scrollLeft = nd.offsetLeft;
33513 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33514 this.setSize(w, '');
33518 triggerEdit : function(node){
33519 this.completeEdit();
33520 this.editNode = node;
33521 this.startEdit(node.ui.textNode, node.text);
33525 bindScroll : function(){
33526 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33530 beforeNodeClick : function(node, e){
33531 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33532 this.lastClick = new Date();
33533 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33535 this.triggerEdit(node);
33541 updateNode : function(ed, value){
33542 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33543 this.editNode.setText(value);
33547 onHide : function(){
33548 Roo.tree.TreeEditor.superclass.onHide.call(this);
33550 this.editNode.ui.focus();
33555 onSpecialKey : function(field, e){
33556 var k = e.getKey();
33560 }else if(k == e.ENTER && !e.hasModifier()){
33562 this.completeEdit();
33565 });//<Script type="text/javascript">
33568 * Ext JS Library 1.1.1
33569 * Copyright(c) 2006-2007, Ext JS, LLC.
33571 * Originally Released Under LGPL - original licence link has changed is not relivant.
33574 * <script type="text/javascript">
33578 * Not documented??? - probably should be...
33581 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33582 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33584 renderElements : function(n, a, targetNode, bulkRender){
33585 //consel.log("renderElements?");
33586 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33588 var t = n.getOwnerTree();
33589 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33591 var cols = t.columns;
33592 var bw = t.borderWidth;
33594 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33595 var cb = typeof a.checked == "boolean";
33596 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33597 var colcls = 'x-t-' + tid + '-c0';
33599 '<li class="x-tree-node">',
33602 '<div class="x-tree-node-el ', a.cls,'">',
33604 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33607 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33608 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33609 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33610 (a.icon ? ' x-tree-node-inline-icon' : ''),
33611 (a.iconCls ? ' '+a.iconCls : ''),
33612 '" unselectable="on" />',
33613 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33614 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33616 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33617 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33618 '<span unselectable="on" qtip="' + tx + '">',
33622 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33623 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33625 for(var i = 1, len = cols.length; i < len; i++){
33627 colcls = 'x-t-' + tid + '-c' +i;
33628 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33629 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33630 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33636 '<div class="x-clear"></div></div>',
33637 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33640 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33641 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33642 n.nextSibling.ui.getEl(), buf.join(""));
33644 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33646 var el = this.wrap.firstChild;
33648 this.elNode = el.firstChild;
33649 this.ranchor = el.childNodes[1];
33650 this.ctNode = this.wrap.childNodes[1];
33651 var cs = el.firstChild.childNodes;
33652 this.indentNode = cs[0];
33653 this.ecNode = cs[1];
33654 this.iconNode = cs[2];
33657 this.checkbox = cs[3];
33660 this.anchor = cs[index];
33662 this.textNode = cs[index].firstChild;
33664 //el.on("click", this.onClick, this);
33665 //el.on("dblclick", this.onDblClick, this);
33668 // console.log(this);
33670 initEvents : function(){
33671 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33674 var a = this.ranchor;
33676 var el = Roo.get(a);
33678 if(Roo.isOpera){ // opera render bug ignores the CSS
33679 el.setStyle("text-decoration", "none");
33682 el.on("click", this.onClick, this);
33683 el.on("dblclick", this.onDblClick, this);
33684 el.on("contextmenu", this.onContextMenu, this);
33688 /*onSelectedChange : function(state){
33691 this.addClass("x-tree-selected");
33694 this.removeClass("x-tree-selected");
33697 addClass : function(cls){
33699 Roo.fly(this.elRow).addClass(cls);
33705 removeClass : function(cls){
33707 Roo.fly(this.elRow).removeClass(cls);
33713 });//<Script type="text/javascript">
33717 * Ext JS Library 1.1.1
33718 * Copyright(c) 2006-2007, Ext JS, LLC.
33720 * Originally Released Under LGPL - original licence link has changed is not relivant.
33723 * <script type="text/javascript">
33728 * @class Roo.tree.ColumnTree
33729 * @extends Roo.data.TreePanel
33730 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33731 * @cfg {int} borderWidth compined right/left border allowance
33733 * @param {String/HTMLElement/Element} el The container element
33734 * @param {Object} config
33736 Roo.tree.ColumnTree = function(el, config)
33738 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33742 * Fire this event on a container when it resizes
33743 * @param {int} w Width
33744 * @param {int} h Height
33748 this.on('resize', this.onResize, this);
33751 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33755 borderWidth: Roo.isBorderBox ? 0 : 2,
33758 render : function(){
33759 // add the header.....
33761 Roo.tree.ColumnTree.superclass.render.apply(this);
33763 this.el.addClass('x-column-tree');
33765 this.headers = this.el.createChild(
33766 {cls:'x-tree-headers'},this.innerCt.dom);
33768 var cols = this.columns, c;
33769 var totalWidth = 0;
33771 var len = cols.length;
33772 for(var i = 0; i < len; i++){
33774 totalWidth += c.width;
33775 this.headEls.push(this.headers.createChild({
33776 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33778 cls:'x-tree-hd-text',
33781 style:'width:'+(c.width-this.borderWidth)+'px;'
33784 this.headers.createChild({cls:'x-clear'});
33785 // prevent floats from wrapping when clipped
33786 this.headers.setWidth(totalWidth);
33787 //this.innerCt.setWidth(totalWidth);
33788 this.innerCt.setStyle({ overflow: 'auto' });
33789 this.onResize(this.width, this.height);
33793 onResize : function(w,h)
33798 this.innerCt.setWidth(this.width);
33799 this.innerCt.setHeight(this.height-20);
33802 var cols = this.columns, c;
33803 var totalWidth = 0;
33805 var len = cols.length;
33806 for(var i = 0; i < len; i++){
33808 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33809 // it's the expander..
33810 expEl = this.headEls[i];
33813 totalWidth += c.width;
33817 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33819 this.headers.setWidth(w-20);
33828 * Ext JS Library 1.1.1
33829 * Copyright(c) 2006-2007, Ext JS, LLC.
33831 * Originally Released Under LGPL - original licence link has changed is not relivant.
33834 * <script type="text/javascript">
33838 * @class Roo.menu.Menu
33839 * @extends Roo.util.Observable
33840 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33841 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33843 * Creates a new Menu
33844 * @param {Object} config Configuration options
33846 Roo.menu.Menu = function(config){
33847 Roo.apply(this, config);
33848 this.id = this.id || Roo.id();
33851 * @event beforeshow
33852 * Fires before this menu is displayed
33853 * @param {Roo.menu.Menu} this
33857 * @event beforehide
33858 * Fires before this menu is hidden
33859 * @param {Roo.menu.Menu} this
33864 * Fires after this menu is displayed
33865 * @param {Roo.menu.Menu} this
33870 * Fires after this menu is hidden
33871 * @param {Roo.menu.Menu} this
33876 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33877 * @param {Roo.menu.Menu} this
33878 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33879 * @param {Roo.EventObject} e
33884 * Fires when the mouse is hovering over this menu
33885 * @param {Roo.menu.Menu} this
33886 * @param {Roo.EventObject} e
33887 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33892 * Fires when the mouse exits this menu
33893 * @param {Roo.menu.Menu} this
33894 * @param {Roo.EventObject} e
33895 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33900 * Fires when a menu item contained in this menu is clicked
33901 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33902 * @param {Roo.EventObject} e
33906 if (this.registerMenu) {
33907 Roo.menu.MenuMgr.register(this);
33910 var mis = this.items;
33911 this.items = new Roo.util.MixedCollection();
33913 this.add.apply(this, mis);
33917 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33919 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33923 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33924 * for bottom-right shadow (defaults to "sides")
33928 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33929 * this menu (defaults to "tl-tr?")
33931 subMenuAlign : "tl-tr?",
33933 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33934 * relative to its element of origin (defaults to "tl-bl?")
33936 defaultAlign : "tl-bl?",
33938 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33940 allowOtherMenus : false,
33942 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33944 registerMenu : true,
33949 render : function(){
33953 var el = this.el = new Roo.Layer({
33955 shadow:this.shadow,
33957 parentEl: this.parentEl || document.body,
33961 this.keyNav = new Roo.menu.MenuNav(this);
33964 el.addClass("x-menu-plain");
33967 el.addClass(this.cls);
33969 // generic focus element
33970 this.focusEl = el.createChild({
33971 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33973 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33974 ul.on("click", this.onClick, this);
33975 ul.on("mouseover", this.onMouseOver, this);
33976 ul.on("mouseout", this.onMouseOut, this);
33977 this.items.each(function(item){
33978 var li = document.createElement("li");
33979 li.className = "x-menu-list-item";
33980 ul.dom.appendChild(li);
33981 item.render(li, this);
33988 autoWidth : function(){
33989 var el = this.el, ul = this.ul;
33993 var w = this.width;
33996 }else if(Roo.isIE){
33997 el.setWidth(this.minWidth);
33998 var t = el.dom.offsetWidth; // force recalc
33999 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34004 delayAutoWidth : function(){
34007 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
34009 this.awTask.delay(20);
34014 findTargetItem : function(e){
34015 var t = e.getTarget(".x-menu-list-item", this.ul, true);
34016 if(t && t.menuItemId){
34017 return this.items.get(t.menuItemId);
34022 onClick : function(e){
34024 if(t = this.findTargetItem(e)){
34026 this.fireEvent("click", this, t, e);
34031 setActiveItem : function(item, autoExpand){
34032 if(item != this.activeItem){
34033 if(this.activeItem){
34034 this.activeItem.deactivate();
34036 this.activeItem = item;
34037 item.activate(autoExpand);
34038 }else if(autoExpand){
34044 tryActivate : function(start, step){
34045 var items = this.items;
34046 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34047 var item = items.get(i);
34048 if(!item.disabled && item.canActivate){
34049 this.setActiveItem(item, false);
34057 onMouseOver : function(e){
34059 if(t = this.findTargetItem(e)){
34060 if(t.canActivate && !t.disabled){
34061 this.setActiveItem(t, true);
34064 this.fireEvent("mouseover", this, e, t);
34068 onMouseOut : function(e){
34070 if(t = this.findTargetItem(e)){
34071 if(t == this.activeItem && t.shouldDeactivate(e)){
34072 this.activeItem.deactivate();
34073 delete this.activeItem;
34076 this.fireEvent("mouseout", this, e, t);
34080 * Read-only. Returns true if the menu is currently displayed, else false.
34083 isVisible : function(){
34084 return this.el && !this.hidden;
34088 * Displays this menu relative to another element
34089 * @param {String/HTMLElement/Roo.Element} element The element to align to
34090 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34091 * the element (defaults to this.defaultAlign)
34092 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34094 show : function(el, pos, parentMenu){
34095 this.parentMenu = parentMenu;
34099 this.fireEvent("beforeshow", this);
34100 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34104 * Displays this menu at a specific xy position
34105 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34106 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34108 showAt : function(xy, parentMenu, /* private: */_e){
34109 this.parentMenu = parentMenu;
34114 this.fireEvent("beforeshow", this);
34115 xy = this.el.adjustForConstraints(xy);
34119 this.hidden = false;
34121 this.fireEvent("show", this);
34124 focus : function(){
34126 this.doFocus.defer(50, this);
34130 doFocus : function(){
34132 this.focusEl.focus();
34137 * Hides this menu and optionally all parent menus
34138 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34140 hide : function(deep){
34141 if(this.el && this.isVisible()){
34142 this.fireEvent("beforehide", this);
34143 if(this.activeItem){
34144 this.activeItem.deactivate();
34145 this.activeItem = null;
34148 this.hidden = true;
34149 this.fireEvent("hide", this);
34151 if(deep === true && this.parentMenu){
34152 this.parentMenu.hide(true);
34157 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34158 * Any of the following are valid:
34160 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34161 * <li>An HTMLElement object which will be converted to a menu item</li>
34162 * <li>A menu item config object that will be created as a new menu item</li>
34163 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34164 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34169 var menu = new Roo.menu.Menu();
34171 // Create a menu item to add by reference
34172 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34174 // Add a bunch of items at once using different methods.
34175 // Only the last item added will be returned.
34176 var item = menu.add(
34177 menuItem, // add existing item by ref
34178 'Dynamic Item', // new TextItem
34179 '-', // new separator
34180 { text: 'Config Item' } // new item by config
34183 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34184 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34187 var a = arguments, l = a.length, item;
34188 for(var i = 0; i < l; i++){
34190 if ((typeof(el) == "object") && el.xtype && el.xns) {
34191 el = Roo.factory(el, Roo.menu);
34194 if(el.render){ // some kind of Item
34195 item = this.addItem(el);
34196 }else if(typeof el == "string"){ // string
34197 if(el == "separator" || el == "-"){
34198 item = this.addSeparator();
34200 item = this.addText(el);
34202 }else if(el.tagName || el.el){ // element
34203 item = this.addElement(el);
34204 }else if(typeof el == "object"){ // must be menu item config?
34205 item = this.addMenuItem(el);
34212 * Returns this menu's underlying {@link Roo.Element} object
34213 * @return {Roo.Element} The element
34215 getEl : function(){
34223 * Adds a separator bar to the menu
34224 * @return {Roo.menu.Item} The menu item that was added
34226 addSeparator : function(){
34227 return this.addItem(new Roo.menu.Separator());
34231 * Adds an {@link Roo.Element} object to the menu
34232 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34233 * @return {Roo.menu.Item} The menu item that was added
34235 addElement : function(el){
34236 return this.addItem(new Roo.menu.BaseItem(el));
34240 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34241 * @param {Roo.menu.Item} item The menu item to add
34242 * @return {Roo.menu.Item} The menu item that was added
34244 addItem : function(item){
34245 this.items.add(item);
34247 var li = document.createElement("li");
34248 li.className = "x-menu-list-item";
34249 this.ul.dom.appendChild(li);
34250 item.render(li, this);
34251 this.delayAutoWidth();
34257 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34258 * @param {Object} config A MenuItem config object
34259 * @return {Roo.menu.Item} The menu item that was added
34261 addMenuItem : function(config){
34262 if(!(config instanceof Roo.menu.Item)){
34263 if(typeof config.checked == "boolean"){ // must be check menu item config?
34264 config = new Roo.menu.CheckItem(config);
34266 config = new Roo.menu.Item(config);
34269 return this.addItem(config);
34273 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34274 * @param {String} text The text to display in the menu item
34275 * @return {Roo.menu.Item} The menu item that was added
34277 addText : function(text){
34278 return this.addItem(new Roo.menu.TextItem({ text : text }));
34282 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34283 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34284 * @param {Roo.menu.Item} item The menu item to add
34285 * @return {Roo.menu.Item} The menu item that was added
34287 insert : function(index, item){
34288 this.items.insert(index, item);
34290 var li = document.createElement("li");
34291 li.className = "x-menu-list-item";
34292 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34293 item.render(li, this);
34294 this.delayAutoWidth();
34300 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34301 * @param {Roo.menu.Item} item The menu item to remove
34303 remove : function(item){
34304 this.items.removeKey(item.id);
34309 * Removes and destroys all items in the menu
34311 removeAll : function(){
34313 while(f = this.items.first()){
34319 // MenuNav is a private utility class used internally by the Menu
34320 Roo.menu.MenuNav = function(menu){
34321 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34322 this.scope = this.menu = menu;
34325 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34326 doRelay : function(e, h){
34327 var k = e.getKey();
34328 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34329 this.menu.tryActivate(0, 1);
34332 return h.call(this.scope || this, e, this.menu);
34335 up : function(e, m){
34336 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34337 m.tryActivate(m.items.length-1, -1);
34341 down : function(e, m){
34342 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34343 m.tryActivate(0, 1);
34347 right : function(e, m){
34349 m.activeItem.expandMenu(true);
34353 left : function(e, m){
34355 if(m.parentMenu && m.parentMenu.activeItem){
34356 m.parentMenu.activeItem.activate();
34360 enter : function(e, m){
34362 e.stopPropagation();
34363 m.activeItem.onClick(e);
34364 m.fireEvent("click", this, m.activeItem);
34370 * Ext JS Library 1.1.1
34371 * Copyright(c) 2006-2007, Ext JS, LLC.
34373 * Originally Released Under LGPL - original licence link has changed is not relivant.
34376 * <script type="text/javascript">
34380 * @class Roo.menu.MenuMgr
34381 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34384 Roo.menu.MenuMgr = function(){
34385 var menus, active, groups = {}, attached = false, lastShow = new Date();
34387 // private - called when first menu is created
34390 active = new Roo.util.MixedCollection();
34391 Roo.get(document).addKeyListener(27, function(){
34392 if(active.length > 0){
34399 function hideAll(){
34400 if(active && active.length > 0){
34401 var c = active.clone();
34402 c.each(function(m){
34409 function onHide(m){
34411 if(active.length < 1){
34412 Roo.get(document).un("mousedown", onMouseDown);
34418 function onShow(m){
34419 var last = active.last();
34420 lastShow = new Date();
34423 Roo.get(document).on("mousedown", onMouseDown);
34427 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34428 m.parentMenu.activeChild = m;
34429 }else if(last && last.isVisible()){
34430 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34435 function onBeforeHide(m){
34437 m.activeChild.hide();
34439 if(m.autoHideTimer){
34440 clearTimeout(m.autoHideTimer);
34441 delete m.autoHideTimer;
34446 function onBeforeShow(m){
34447 var pm = m.parentMenu;
34448 if(!pm && !m.allowOtherMenus){
34450 }else if(pm && pm.activeChild && active != m){
34451 pm.activeChild.hide();
34456 function onMouseDown(e){
34457 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34463 function onBeforeCheck(mi, state){
34465 var g = groups[mi.group];
34466 for(var i = 0, l = g.length; i < l; i++){
34468 g[i].setChecked(false);
34477 * Hides all menus that are currently visible
34479 hideAll : function(){
34484 register : function(menu){
34488 menus[menu.id] = menu;
34489 menu.on("beforehide", onBeforeHide);
34490 menu.on("hide", onHide);
34491 menu.on("beforeshow", onBeforeShow);
34492 menu.on("show", onShow);
34493 var g = menu.group;
34494 if(g && menu.events["checkchange"]){
34498 groups[g].push(menu);
34499 menu.on("checkchange", onCheck);
34504 * Returns a {@link Roo.menu.Menu} object
34505 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34506 * be used to generate and return a new Menu instance.
34508 get : function(menu){
34509 if(typeof menu == "string"){ // menu id
34510 return menus[menu];
34511 }else if(menu.events){ // menu instance
34513 }else if(typeof menu.length == 'number'){ // array of menu items?
34514 return new Roo.menu.Menu({items:menu});
34515 }else{ // otherwise, must be a config
34516 return new Roo.menu.Menu(menu);
34521 unregister : function(menu){
34522 delete menus[menu.id];
34523 menu.un("beforehide", onBeforeHide);
34524 menu.un("hide", onHide);
34525 menu.un("beforeshow", onBeforeShow);
34526 menu.un("show", onShow);
34527 var g = menu.group;
34528 if(g && menu.events["checkchange"]){
34529 groups[g].remove(menu);
34530 menu.un("checkchange", onCheck);
34535 registerCheckable : function(menuItem){
34536 var g = menuItem.group;
34541 groups[g].push(menuItem);
34542 menuItem.on("beforecheckchange", onBeforeCheck);
34547 unregisterCheckable : function(menuItem){
34548 var g = menuItem.group;
34550 groups[g].remove(menuItem);
34551 menuItem.un("beforecheckchange", onBeforeCheck);
34557 * Ext JS Library 1.1.1
34558 * Copyright(c) 2006-2007, Ext JS, LLC.
34560 * Originally Released Under LGPL - original licence link has changed is not relivant.
34563 * <script type="text/javascript">
34568 * @class Roo.menu.BaseItem
34569 * @extends Roo.Component
34570 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34571 * management and base configuration options shared by all menu components.
34573 * Creates a new BaseItem
34574 * @param {Object} config Configuration options
34576 Roo.menu.BaseItem = function(config){
34577 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34582 * Fires when this item is clicked
34583 * @param {Roo.menu.BaseItem} this
34584 * @param {Roo.EventObject} e
34589 * Fires when this item is activated
34590 * @param {Roo.menu.BaseItem} this
34594 * @event deactivate
34595 * Fires when this item is deactivated
34596 * @param {Roo.menu.BaseItem} this
34602 this.on("click", this.handler, this.scope, true);
34606 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34608 * @cfg {Function} handler
34609 * A function that will handle the click event of this menu item (defaults to undefined)
34612 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34614 canActivate : false,
34616 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34618 activeClass : "x-menu-item-active",
34620 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34622 hideOnClick : true,
34624 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34629 ctype: "Roo.menu.BaseItem",
34632 actionMode : "container",
34635 render : function(container, parentMenu){
34636 this.parentMenu = parentMenu;
34637 Roo.menu.BaseItem.superclass.render.call(this, container);
34638 this.container.menuItemId = this.id;
34642 onRender : function(container, position){
34643 this.el = Roo.get(this.el);
34644 container.dom.appendChild(this.el.dom);
34648 onClick : function(e){
34649 if(!this.disabled && this.fireEvent("click", this, e) !== false
34650 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34651 this.handleClick(e);
34658 activate : function(){
34662 var li = this.container;
34663 li.addClass(this.activeClass);
34664 this.region = li.getRegion().adjust(2, 2, -2, -2);
34665 this.fireEvent("activate", this);
34670 deactivate : function(){
34671 this.container.removeClass(this.activeClass);
34672 this.fireEvent("deactivate", this);
34676 shouldDeactivate : function(e){
34677 return !this.region || !this.region.contains(e.getPoint());
34681 handleClick : function(e){
34682 if(this.hideOnClick){
34683 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34688 expandMenu : function(autoActivate){
34693 hideMenu : function(){
34698 * Ext JS Library 1.1.1
34699 * Copyright(c) 2006-2007, Ext JS, LLC.
34701 * Originally Released Under LGPL - original licence link has changed is not relivant.
34704 * <script type="text/javascript">
34708 * @class Roo.menu.Adapter
34709 * @extends Roo.menu.BaseItem
34710 * 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.
34711 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34713 * Creates a new Adapter
34714 * @param {Object} config Configuration options
34716 Roo.menu.Adapter = function(component, config){
34717 Roo.menu.Adapter.superclass.constructor.call(this, config);
34718 this.component = component;
34720 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34722 canActivate : true,
34725 onRender : function(container, position){
34726 this.component.render(container);
34727 this.el = this.component.getEl();
34731 activate : function(){
34735 this.component.focus();
34736 this.fireEvent("activate", this);
34741 deactivate : function(){
34742 this.fireEvent("deactivate", this);
34746 disable : function(){
34747 this.component.disable();
34748 Roo.menu.Adapter.superclass.disable.call(this);
34752 enable : function(){
34753 this.component.enable();
34754 Roo.menu.Adapter.superclass.enable.call(this);
34758 * Ext JS Library 1.1.1
34759 * Copyright(c) 2006-2007, Ext JS, LLC.
34761 * Originally Released Under LGPL - original licence link has changed is not relivant.
34764 * <script type="text/javascript">
34768 * @class Roo.menu.TextItem
34769 * @extends Roo.menu.BaseItem
34770 * Adds a static text string to a menu, usually used as either a heading or group separator.
34771 * Note: old style constructor with text is still supported.
34774 * Creates a new TextItem
34775 * @param {Object} cfg Configuration
34777 Roo.menu.TextItem = function(cfg){
34778 if (typeof(cfg) == 'string') {
34781 Roo.apply(this,cfg);
34784 Roo.menu.TextItem.superclass.constructor.call(this);
34787 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34789 * @cfg {Boolean} text Text to show on item.
34794 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34796 hideOnClick : false,
34798 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34800 itemCls : "x-menu-text",
34803 onRender : function(){
34804 var s = document.createElement("span");
34805 s.className = this.itemCls;
34806 s.innerHTML = this.text;
34808 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34812 * Ext JS Library 1.1.1
34813 * Copyright(c) 2006-2007, Ext JS, LLC.
34815 * Originally Released Under LGPL - original licence link has changed is not relivant.
34818 * <script type="text/javascript">
34822 * @class Roo.menu.Separator
34823 * @extends Roo.menu.BaseItem
34824 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34825 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34827 * @param {Object} config Configuration options
34829 Roo.menu.Separator = function(config){
34830 Roo.menu.Separator.superclass.constructor.call(this, config);
34833 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34835 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34837 itemCls : "x-menu-sep",
34839 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34841 hideOnClick : false,
34844 onRender : function(li){
34845 var s = document.createElement("span");
34846 s.className = this.itemCls;
34847 s.innerHTML = " ";
34849 li.addClass("x-menu-sep-li");
34850 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34854 * Ext JS Library 1.1.1
34855 * Copyright(c) 2006-2007, Ext JS, LLC.
34857 * Originally Released Under LGPL - original licence link has changed is not relivant.
34860 * <script type="text/javascript">
34863 * @class Roo.menu.Item
34864 * @extends Roo.menu.BaseItem
34865 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34866 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34867 * activation and click handling.
34869 * Creates a new Item
34870 * @param {Object} config Configuration options
34872 Roo.menu.Item = function(config){
34873 Roo.menu.Item.superclass.constructor.call(this, config);
34875 this.menu = Roo.menu.MenuMgr.get(this.menu);
34878 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34881 * @cfg {String} text
34882 * The text to show on the menu item.
34886 * @cfg {String} HTML to render in menu
34887 * The text to show on the menu item (HTML version).
34891 * @cfg {String} icon
34892 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34896 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34898 itemCls : "x-menu-item",
34900 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34902 canActivate : true,
34904 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34907 // doc'd in BaseItem
34911 ctype: "Roo.menu.Item",
34914 onRender : function(container, position){
34915 var el = document.createElement("a");
34916 el.hideFocus = true;
34917 el.unselectable = "on";
34918 el.href = this.href || "#";
34919 if(this.hrefTarget){
34920 el.target = this.hrefTarget;
34922 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34924 var html = this.html.length ? this.html : String.format('{0}',this.text);
34926 el.innerHTML = String.format(
34927 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
34928 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
34930 Roo.menu.Item.superclass.onRender.call(this, container, position);
34934 * Sets the text to display in this menu item
34935 * @param {String} text The text to display
34936 * @param {Boolean} isHTML true to indicate text is pure html.
34938 setText : function(text, isHTML){
34946 var html = this.html.length ? this.html : String.format('{0}',this.text);
34948 this.el.update(String.format(
34949 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
34950 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34951 this.parentMenu.autoWidth();
34956 handleClick : function(e){
34957 if(!this.href){ // if no link defined, stop the event automatically
34960 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34964 activate : function(autoExpand){
34965 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34975 shouldDeactivate : function(e){
34976 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34977 if(this.menu && this.menu.isVisible()){
34978 return !this.menu.getEl().getRegion().contains(e.getPoint());
34986 deactivate : function(){
34987 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34992 expandMenu : function(autoActivate){
34993 if(!this.disabled && this.menu){
34994 clearTimeout(this.hideTimer);
34995 delete this.hideTimer;
34996 if(!this.menu.isVisible() && !this.showTimer){
34997 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34998 }else if (this.menu.isVisible() && autoActivate){
34999 this.menu.tryActivate(0, 1);
35005 deferExpand : function(autoActivate){
35006 delete this.showTimer;
35007 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35009 this.menu.tryActivate(0, 1);
35014 hideMenu : function(){
35015 clearTimeout(this.showTimer);
35016 delete this.showTimer;
35017 if(!this.hideTimer && this.menu && this.menu.isVisible()){
35018 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35023 deferHide : function(){
35024 delete this.hideTimer;
35029 * Ext JS Library 1.1.1
35030 * Copyright(c) 2006-2007, Ext JS, LLC.
35032 * Originally Released Under LGPL - original licence link has changed is not relivant.
35035 * <script type="text/javascript">
35039 * @class Roo.menu.CheckItem
35040 * @extends Roo.menu.Item
35041 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35043 * Creates a new CheckItem
35044 * @param {Object} config Configuration options
35046 Roo.menu.CheckItem = function(config){
35047 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35050 * @event beforecheckchange
35051 * Fires before the checked value is set, providing an opportunity to cancel if needed
35052 * @param {Roo.menu.CheckItem} this
35053 * @param {Boolean} checked The new checked value that will be set
35055 "beforecheckchange" : true,
35057 * @event checkchange
35058 * Fires after the checked value has been set
35059 * @param {Roo.menu.CheckItem} this
35060 * @param {Boolean} checked The checked value that was set
35062 "checkchange" : true
35064 if(this.checkHandler){
35065 this.on('checkchange', this.checkHandler, this.scope);
35068 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35070 * @cfg {String} group
35071 * All check items with the same group name will automatically be grouped into a single-select
35072 * radio button group (defaults to '')
35075 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35077 itemCls : "x-menu-item x-menu-check-item",
35079 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35081 groupClass : "x-menu-group-item",
35084 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35085 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35086 * initialized with checked = true will be rendered as checked.
35091 ctype: "Roo.menu.CheckItem",
35094 onRender : function(c){
35095 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35097 this.el.addClass(this.groupClass);
35099 Roo.menu.MenuMgr.registerCheckable(this);
35101 this.checked = false;
35102 this.setChecked(true, true);
35107 destroy : function(){
35109 Roo.menu.MenuMgr.unregisterCheckable(this);
35111 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35115 * Set the checked state of this item
35116 * @param {Boolean} checked The new checked value
35117 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35119 setChecked : function(state, suppressEvent){
35120 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35121 if(this.container){
35122 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35124 this.checked = state;
35125 if(suppressEvent !== true){
35126 this.fireEvent("checkchange", this, state);
35132 handleClick : function(e){
35133 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35134 this.setChecked(!this.checked);
35136 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35140 * Ext JS Library 1.1.1
35141 * Copyright(c) 2006-2007, Ext JS, LLC.
35143 * Originally Released Under LGPL - original licence link has changed is not relivant.
35146 * <script type="text/javascript">
35150 * @class Roo.menu.DateItem
35151 * @extends Roo.menu.Adapter
35152 * A menu item that wraps the {@link Roo.DatPicker} component.
35154 * Creates a new DateItem
35155 * @param {Object} config Configuration options
35157 Roo.menu.DateItem = function(config){
35158 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35159 /** The Roo.DatePicker object @type Roo.DatePicker */
35160 this.picker = this.component;
35161 this.addEvents({select: true});
35163 this.picker.on("render", function(picker){
35164 picker.getEl().swallowEvent("click");
35165 picker.container.addClass("x-menu-date-item");
35168 this.picker.on("select", this.onSelect, this);
35171 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35173 onSelect : function(picker, date){
35174 this.fireEvent("select", this, date, picker);
35175 Roo.menu.DateItem.superclass.handleClick.call(this);
35179 * Ext JS Library 1.1.1
35180 * Copyright(c) 2006-2007, Ext JS, LLC.
35182 * Originally Released Under LGPL - original licence link has changed is not relivant.
35185 * <script type="text/javascript">
35189 * @class Roo.menu.ColorItem
35190 * @extends Roo.menu.Adapter
35191 * A menu item that wraps the {@link Roo.ColorPalette} component.
35193 * Creates a new ColorItem
35194 * @param {Object} config Configuration options
35196 Roo.menu.ColorItem = function(config){
35197 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35198 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35199 this.palette = this.component;
35200 this.relayEvents(this.palette, ["select"]);
35201 if(this.selectHandler){
35202 this.on('select', this.selectHandler, this.scope);
35205 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35207 * Ext JS Library 1.1.1
35208 * Copyright(c) 2006-2007, Ext JS, LLC.
35210 * Originally Released Under LGPL - original licence link has changed is not relivant.
35213 * <script type="text/javascript">
35218 * @class Roo.menu.DateMenu
35219 * @extends Roo.menu.Menu
35220 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35222 * Creates a new DateMenu
35223 * @param {Object} config Configuration options
35225 Roo.menu.DateMenu = function(config){
35226 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35228 var di = new Roo.menu.DateItem(config);
35231 * The {@link Roo.DatePicker} instance for this DateMenu
35234 this.picker = di.picker;
35237 * @param {DatePicker} picker
35238 * @param {Date} date
35240 this.relayEvents(di, ["select"]);
35242 this.on('beforeshow', function(){
35244 this.picker.hideMonthPicker(true);
35248 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35252 * Ext JS Library 1.1.1
35253 * Copyright(c) 2006-2007, Ext JS, LLC.
35255 * Originally Released Under LGPL - original licence link has changed is not relivant.
35258 * <script type="text/javascript">
35263 * @class Roo.menu.ColorMenu
35264 * @extends Roo.menu.Menu
35265 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35267 * Creates a new ColorMenu
35268 * @param {Object} config Configuration options
35270 Roo.menu.ColorMenu = function(config){
35271 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35273 var ci = new Roo.menu.ColorItem(config);
35276 * The {@link Roo.ColorPalette} instance for this ColorMenu
35277 * @type ColorPalette
35279 this.palette = ci.palette;
35282 * @param {ColorPalette} palette
35283 * @param {String} color
35285 this.relayEvents(ci, ["select"]);
35287 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35289 * Ext JS Library 1.1.1
35290 * Copyright(c) 2006-2007, Ext JS, LLC.
35292 * Originally Released Under LGPL - original licence link has changed is not relivant.
35295 * <script type="text/javascript">
35299 * @class Roo.form.Field
35300 * @extends Roo.BoxComponent
35301 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35303 * Creates a new Field
35304 * @param {Object} config Configuration options
35306 Roo.form.Field = function(config){
35307 Roo.form.Field.superclass.constructor.call(this, config);
35310 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35312 * @cfg {String} fieldLabel Label to use when rendering a form.
35315 * @cfg {String} qtip Mouse over tip
35319 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35321 invalidClass : "x-form-invalid",
35323 * @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")
35325 invalidText : "The value in this field is invalid",
35327 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35329 focusClass : "x-form-focus",
35331 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35332 automatic validation (defaults to "keyup").
35334 validationEvent : "keyup",
35336 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35338 validateOnBlur : true,
35340 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35342 validationDelay : 250,
35344 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35345 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35347 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35349 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35351 fieldClass : "x-form-field",
35353 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35356 ----------- ----------------------------------------------------------------------
35357 qtip Display a quick tip when the user hovers over the field
35358 title Display a default browser title attribute popup
35359 under Add a block div beneath the field containing the error text
35360 side Add an error icon to the right of the field with a popup on hover
35361 [element id] Add the error text directly to the innerHTML of the specified element
35364 msgTarget : 'qtip',
35366 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35371 * @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.
35376 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35381 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35383 inputType : undefined,
35386 * @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).
35388 tabIndex : undefined,
35391 isFormField : true,
35396 * @property {Roo.Element} fieldEl
35397 * Element Containing the rendered Field (with label etc.)
35400 * @cfg {Mixed} value A value to initialize this field with.
35405 * @cfg {String} name The field's HTML name attribute.
35408 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35412 initComponent : function(){
35413 Roo.form.Field.superclass.initComponent.call(this);
35417 * Fires when this field receives input focus.
35418 * @param {Roo.form.Field} this
35423 * Fires when this field loses input focus.
35424 * @param {Roo.form.Field} this
35428 * @event specialkey
35429 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35430 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35431 * @param {Roo.form.Field} this
35432 * @param {Roo.EventObject} e The event object
35437 * Fires just before the field blurs if the field value has changed.
35438 * @param {Roo.form.Field} this
35439 * @param {Mixed} newValue The new value
35440 * @param {Mixed} oldValue The original value
35445 * Fires after the field has been marked as invalid.
35446 * @param {Roo.form.Field} this
35447 * @param {String} msg The validation message
35452 * Fires after the field has been validated with no errors.
35453 * @param {Roo.form.Field} this
35458 * Fires after the key up
35459 * @param {Roo.form.Field} this
35460 * @param {Roo.EventObject} e The event Object
35467 * Returns the name attribute of the field if available
35468 * @return {String} name The field name
35470 getName: function(){
35471 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35475 onRender : function(ct, position){
35476 Roo.form.Field.superclass.onRender.call(this, ct, position);
35478 var cfg = this.getAutoCreate();
35480 cfg.name = this.name || this.id;
35482 if(this.inputType){
35483 cfg.type = this.inputType;
35485 this.el = ct.createChild(cfg, position);
35487 var type = this.el.dom.type;
35489 if(type == 'password'){
35492 this.el.addClass('x-form-'+type);
35495 this.el.dom.readOnly = true;
35497 if(this.tabIndex !== undefined){
35498 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35501 this.el.addClass([this.fieldClass, this.cls]);
35506 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35507 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35508 * @return {Roo.form.Field} this
35510 applyTo : function(target){
35511 this.allowDomMove = false;
35512 this.el = Roo.get(target);
35513 this.render(this.el.dom.parentNode);
35518 initValue : function(){
35519 if(this.value !== undefined){
35520 this.setValue(this.value);
35521 }else if(this.el.dom.value.length > 0){
35522 this.setValue(this.el.dom.value);
35527 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35529 isDirty : function() {
35530 if(this.disabled) {
35533 return String(this.getValue()) !== String(this.originalValue);
35537 afterRender : function(){
35538 Roo.form.Field.superclass.afterRender.call(this);
35543 fireKey : function(e){
35544 //Roo.log('field ' + e.getKey());
35545 if(e.isNavKeyPress()){
35546 this.fireEvent("specialkey", this, e);
35551 * Resets the current field value to the originally loaded value and clears any validation messages
35553 reset : function(){
35554 this.setValue(this.originalValue);
35555 this.clearInvalid();
35559 initEvents : function(){
35560 // safari killled keypress - so keydown is now used..
35561 this.el.on("keydown" , this.fireKey, this);
35562 this.el.on("focus", this.onFocus, this);
35563 this.el.on("blur", this.onBlur, this);
35564 this.el.relayEvent('keyup', this);
35566 // reference to original value for reset
35567 this.originalValue = this.getValue();
35571 onFocus : function(){
35572 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35573 this.el.addClass(this.focusClass);
35575 if(!this.hasFocus){
35576 this.hasFocus = true;
35577 this.startValue = this.getValue();
35578 this.fireEvent("focus", this);
35582 beforeBlur : Roo.emptyFn,
35585 onBlur : function(){
35587 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35588 this.el.removeClass(this.focusClass);
35590 this.hasFocus = false;
35591 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35594 var v = this.getValue();
35595 if(String(v) !== String(this.startValue)){
35596 this.fireEvent('change', this, v, this.startValue);
35598 this.fireEvent("blur", this);
35602 * Returns whether or not the field value is currently valid
35603 * @param {Boolean} preventMark True to disable marking the field invalid
35604 * @return {Boolean} True if the value is valid, else false
35606 isValid : function(preventMark){
35610 var restore = this.preventMark;
35611 this.preventMark = preventMark === true;
35612 var v = this.validateValue(this.processValue(this.getRawValue()));
35613 this.preventMark = restore;
35618 * Validates the field value
35619 * @return {Boolean} True if the value is valid, else false
35621 validate : function(){
35622 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35623 this.clearInvalid();
35629 processValue : function(value){
35634 // Subclasses should provide the validation implementation by overriding this
35635 validateValue : function(value){
35640 * Mark this field as invalid
35641 * @param {String} msg The validation message
35643 markInvalid : function(msg){
35644 if(!this.rendered || this.preventMark){ // not rendered
35647 this.el.addClass(this.invalidClass);
35648 msg = msg || this.invalidText;
35649 switch(this.msgTarget){
35651 this.el.dom.qtip = msg;
35652 this.el.dom.qclass = 'x-form-invalid-tip';
35653 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35654 Roo.QuickTips.enable();
35658 this.el.dom.title = msg;
35662 var elp = this.el.findParent('.x-form-element', 5, true);
35663 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35664 this.errorEl.setWidth(elp.getWidth(true)-20);
35666 this.errorEl.update(msg);
35667 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35670 if(!this.errorIcon){
35671 var elp = this.el.findParent('.x-form-element', 5, true);
35672 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35674 this.alignErrorIcon();
35675 this.errorIcon.dom.qtip = msg;
35676 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35677 this.errorIcon.show();
35678 this.on('resize', this.alignErrorIcon, this);
35681 var t = Roo.getDom(this.msgTarget);
35683 t.style.display = this.msgDisplay;
35686 this.fireEvent('invalid', this, msg);
35690 alignErrorIcon : function(){
35691 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35695 * Clear any invalid styles/messages for this field
35697 clearInvalid : function(){
35698 if(!this.rendered || this.preventMark){ // not rendered
35701 this.el.removeClass(this.invalidClass);
35702 switch(this.msgTarget){
35704 this.el.dom.qtip = '';
35707 this.el.dom.title = '';
35711 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35715 if(this.errorIcon){
35716 this.errorIcon.dom.qtip = '';
35717 this.errorIcon.hide();
35718 this.un('resize', this.alignErrorIcon, this);
35722 var t = Roo.getDom(this.msgTarget);
35724 t.style.display = 'none';
35727 this.fireEvent('valid', this);
35731 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35732 * @return {Mixed} value The field value
35734 getRawValue : function(){
35735 var v = this.el.getValue();
35736 if(v === this.emptyText){
35743 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35744 * @return {Mixed} value The field value
35746 getValue : function(){
35747 var v = this.el.getValue();
35748 if(v === this.emptyText || v === undefined){
35755 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35756 * @param {Mixed} value The value to set
35758 setRawValue : function(v){
35759 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35763 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35764 * @param {Mixed} value The value to set
35766 setValue : function(v){
35769 this.el.dom.value = (v === null || v === undefined ? '' : v);
35774 adjustSize : function(w, h){
35775 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35776 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35780 adjustWidth : function(tag, w){
35781 tag = tag.toLowerCase();
35782 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35783 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35784 if(tag == 'input'){
35787 if(tag = 'textarea'){
35790 }else if(Roo.isOpera){
35791 if(tag == 'input'){
35794 if(tag = 'textarea'){
35804 // anything other than normal should be considered experimental
35805 Roo.form.Field.msgFx = {
35807 show: function(msgEl, f){
35808 msgEl.setDisplayed('block');
35811 hide : function(msgEl, f){
35812 msgEl.setDisplayed(false).update('');
35817 show: function(msgEl, f){
35818 msgEl.slideIn('t', {stopFx:true});
35821 hide : function(msgEl, f){
35822 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35827 show: function(msgEl, f){
35828 msgEl.fixDisplay();
35829 msgEl.alignTo(f.el, 'tl-tr');
35830 msgEl.slideIn('l', {stopFx:true});
35833 hide : function(msgEl, f){
35834 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35839 * Ext JS Library 1.1.1
35840 * Copyright(c) 2006-2007, Ext JS, LLC.
35842 * Originally Released Under LGPL - original licence link has changed is not relivant.
35845 * <script type="text/javascript">
35850 * @class Roo.form.TextField
35851 * @extends Roo.form.Field
35852 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35853 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35855 * Creates a new TextField
35856 * @param {Object} config Configuration options
35858 Roo.form.TextField = function(config){
35859 Roo.form.TextField.superclass.constructor.call(this, config);
35863 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35864 * according to the default logic, but this event provides a hook for the developer to apply additional
35865 * logic at runtime to resize the field if needed.
35866 * @param {Roo.form.Field} this This text field
35867 * @param {Number} width The new field width
35873 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35875 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35879 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35883 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35887 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35891 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35895 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35897 disableKeyFilter : false,
35899 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35903 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35907 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35909 maxLength : Number.MAX_VALUE,
35911 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35913 minLengthText : "The minimum length for this field is {0}",
35915 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35917 maxLengthText : "The maximum length for this field is {0}",
35919 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35921 selectOnFocus : false,
35923 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35925 blankText : "This field is required",
35927 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35928 * If available, this function will be called only after the basic validators all return true, and will be passed the
35929 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35933 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35934 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35935 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35939 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35943 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35947 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35948 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35950 emptyClass : 'x-form-empty-field',
35953 initEvents : function(){
35954 Roo.form.TextField.superclass.initEvents.call(this);
35955 if(this.validationEvent == 'keyup'){
35956 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35957 this.el.on('keyup', this.filterValidation, this);
35959 else if(this.validationEvent !== false){
35960 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35962 if(this.selectOnFocus || this.emptyText){
35963 this.on("focus", this.preFocus, this);
35964 if(this.emptyText){
35965 this.on('blur', this.postBlur, this);
35966 this.applyEmptyText();
35969 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35970 this.el.on("keypress", this.filterKeys, this);
35973 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35974 this.el.on("click", this.autoSize, this);
35978 processValue : function(value){
35979 if(this.stripCharsRe){
35980 var newValue = value.replace(this.stripCharsRe, '');
35981 if(newValue !== value){
35982 this.setRawValue(newValue);
35989 filterValidation : function(e){
35990 if(!e.isNavKeyPress()){
35991 this.validationTask.delay(this.validationDelay);
35996 onKeyUp : function(e){
35997 if(!e.isNavKeyPress()){
36003 * Resets the current field value to the originally-loaded value and clears any validation messages.
36004 * Also adds emptyText and emptyClass if the original value was blank.
36006 reset : function(){
36007 Roo.form.TextField.superclass.reset.call(this);
36008 this.applyEmptyText();
36011 applyEmptyText : function(){
36012 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
36013 this.setRawValue(this.emptyText);
36014 this.el.addClass(this.emptyClass);
36019 preFocus : function(){
36020 if(this.emptyText){
36021 if(this.el.dom.value == this.emptyText){
36022 this.setRawValue('');
36024 this.el.removeClass(this.emptyClass);
36026 if(this.selectOnFocus){
36027 this.el.dom.select();
36032 postBlur : function(){
36033 this.applyEmptyText();
36037 filterKeys : function(e){
36038 var k = e.getKey();
36039 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36042 var c = e.getCharCode(), cc = String.fromCharCode(c);
36043 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36046 if(!this.maskRe.test(cc)){
36051 setValue : function(v){
36052 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
36053 this.el.removeClass(this.emptyClass);
36055 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36056 this.applyEmptyText();
36061 * Validates a value according to the field's validation rules and marks the field as invalid
36062 * if the validation fails
36063 * @param {Mixed} value The value to validate
36064 * @return {Boolean} True if the value is valid, else false
36066 validateValue : function(value){
36067 if(value.length < 1 || value === this.emptyText){ // if it's blank
36068 if(this.allowBlank){
36069 this.clearInvalid();
36072 this.markInvalid(this.blankText);
36076 if(value.length < this.minLength){
36077 this.markInvalid(String.format(this.minLengthText, this.minLength));
36080 if(value.length > this.maxLength){
36081 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36085 var vt = Roo.form.VTypes;
36086 if(!vt[this.vtype](value, this)){
36087 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36091 if(typeof this.validator == "function"){
36092 var msg = this.validator(value);
36094 this.markInvalid(msg);
36098 if(this.regex && !this.regex.test(value)){
36099 this.markInvalid(this.regexText);
36106 * Selects text in this field
36107 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36108 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36110 selectText : function(start, end){
36111 var v = this.getRawValue();
36113 start = start === undefined ? 0 : start;
36114 end = end === undefined ? v.length : end;
36115 var d = this.el.dom;
36116 if(d.setSelectionRange){
36117 d.setSelectionRange(start, end);
36118 }else if(d.createTextRange){
36119 var range = d.createTextRange();
36120 range.moveStart("character", start);
36121 range.moveEnd("character", v.length-end);
36128 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36129 * This only takes effect if grow = true, and fires the autosize event.
36131 autoSize : function(){
36132 if(!this.grow || !this.rendered){
36136 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36139 var v = el.dom.value;
36140 var d = document.createElement('div');
36141 d.appendChild(document.createTextNode(v));
36145 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36146 this.el.setWidth(w);
36147 this.fireEvent("autosize", this, w);
36151 * Ext JS Library 1.1.1
36152 * Copyright(c) 2006-2007, Ext JS, LLC.
36154 * Originally Released Under LGPL - original licence link has changed is not relivant.
36157 * <script type="text/javascript">
36161 * @class Roo.form.Hidden
36162 * @extends Roo.form.TextField
36163 * Simple Hidden element used on forms
36165 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36168 * Creates a new Hidden form element.
36169 * @param {Object} config Configuration options
36174 // easy hidden field...
36175 Roo.form.Hidden = function(config){
36176 Roo.form.Hidden.superclass.constructor.call(this, config);
36179 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36181 inputType: 'hidden',
36184 labelSeparator: '',
36186 itemCls : 'x-form-item-display-none'
36194 * Ext JS Library 1.1.1
36195 * Copyright(c) 2006-2007, Ext JS, LLC.
36197 * Originally Released Under LGPL - original licence link has changed is not relivant.
36200 * <script type="text/javascript">
36204 * @class Roo.form.TriggerField
36205 * @extends Roo.form.TextField
36206 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36207 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36208 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36209 * for which you can provide a custom implementation. For example:
36211 var trigger = new Roo.form.TriggerField();
36212 trigger.onTriggerClick = myTriggerFn;
36213 trigger.applyTo('my-field');
36216 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36217 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36218 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36219 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36221 * Create a new TriggerField.
36222 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36223 * to the base TextField)
36225 Roo.form.TriggerField = function(config){
36226 this.mimicing = false;
36227 Roo.form.TriggerField.superclass.constructor.call(this, config);
36230 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36232 * @cfg {String} triggerClass A CSS class to apply to the trigger
36235 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36236 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36238 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36240 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36244 /** @cfg {Boolean} grow @hide */
36245 /** @cfg {Number} growMin @hide */
36246 /** @cfg {Number} growMax @hide */
36252 autoSize: Roo.emptyFn,
36256 deferHeight : true,
36259 actionMode : 'wrap',
36261 onResize : function(w, h){
36262 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36263 if(typeof w == 'number'){
36264 var x = w - this.trigger.getWidth();
36265 this.el.setWidth(this.adjustWidth('input', x));
36266 this.trigger.setStyle('left', x+'px');
36271 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36274 getResizeEl : function(){
36279 getPositionEl : function(){
36284 alignErrorIcon : function(){
36285 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36289 onRender : function(ct, position){
36290 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36291 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36292 this.trigger = this.wrap.createChild(this.triggerConfig ||
36293 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36294 if(this.hideTrigger){
36295 this.trigger.setDisplayed(false);
36297 this.initTrigger();
36299 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36304 initTrigger : function(){
36305 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36306 this.trigger.addClassOnOver('x-form-trigger-over');
36307 this.trigger.addClassOnClick('x-form-trigger-click');
36311 onDestroy : function(){
36313 this.trigger.removeAllListeners();
36314 this.trigger.remove();
36317 this.wrap.remove();
36319 Roo.form.TriggerField.superclass.onDestroy.call(this);
36323 onFocus : function(){
36324 Roo.form.TriggerField.superclass.onFocus.call(this);
36325 if(!this.mimicing){
36326 this.wrap.addClass('x-trigger-wrap-focus');
36327 this.mimicing = true;
36328 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36329 if(this.monitorTab){
36330 this.el.on("keydown", this.checkTab, this);
36336 checkTab : function(e){
36337 if(e.getKey() == e.TAB){
36338 this.triggerBlur();
36343 onBlur : function(){
36348 mimicBlur : function(e, t){
36349 if(!this.wrap.contains(t) && this.validateBlur()){
36350 this.triggerBlur();
36355 triggerBlur : function(){
36356 this.mimicing = false;
36357 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36358 if(this.monitorTab){
36359 this.el.un("keydown", this.checkTab, this);
36361 this.wrap.removeClass('x-trigger-wrap-focus');
36362 Roo.form.TriggerField.superclass.onBlur.call(this);
36366 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36367 validateBlur : function(e, t){
36372 onDisable : function(){
36373 Roo.form.TriggerField.superclass.onDisable.call(this);
36375 this.wrap.addClass('x-item-disabled');
36380 onEnable : function(){
36381 Roo.form.TriggerField.superclass.onEnable.call(this);
36383 this.wrap.removeClass('x-item-disabled');
36388 onShow : function(){
36389 var ae = this.getActionEl();
36392 ae.dom.style.display = '';
36393 ae.dom.style.visibility = 'visible';
36399 onHide : function(){
36400 var ae = this.getActionEl();
36401 ae.dom.style.display = 'none';
36405 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36406 * by an implementing function.
36408 * @param {EventObject} e
36410 onTriggerClick : Roo.emptyFn
36413 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36414 // to be extended by an implementing class. For an example of implementing this class, see the custom
36415 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36416 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36417 initComponent : function(){
36418 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36420 this.triggerConfig = {
36421 tag:'span', cls:'x-form-twin-triggers', cn:[
36422 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36423 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36427 getTrigger : function(index){
36428 return this.triggers[index];
36431 initTrigger : function(){
36432 var ts = this.trigger.select('.x-form-trigger', true);
36433 this.wrap.setStyle('overflow', 'hidden');
36434 var triggerField = this;
36435 ts.each(function(t, all, index){
36436 t.hide = function(){
36437 var w = triggerField.wrap.getWidth();
36438 this.dom.style.display = 'none';
36439 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36441 t.show = function(){
36442 var w = triggerField.wrap.getWidth();
36443 this.dom.style.display = '';
36444 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36446 var triggerIndex = 'Trigger'+(index+1);
36448 if(this['hide'+triggerIndex]){
36449 t.dom.style.display = 'none';
36451 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36452 t.addClassOnOver('x-form-trigger-over');
36453 t.addClassOnClick('x-form-trigger-click');
36455 this.triggers = ts.elements;
36458 onTrigger1Click : Roo.emptyFn,
36459 onTrigger2Click : Roo.emptyFn
36462 * Ext JS Library 1.1.1
36463 * Copyright(c) 2006-2007, Ext JS, LLC.
36465 * Originally Released Under LGPL - original licence link has changed is not relivant.
36468 * <script type="text/javascript">
36472 * @class Roo.form.TextArea
36473 * @extends Roo.form.TextField
36474 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36475 * support for auto-sizing.
36477 * Creates a new TextArea
36478 * @param {Object} config Configuration options
36480 Roo.form.TextArea = function(config){
36481 Roo.form.TextArea.superclass.constructor.call(this, config);
36482 // these are provided exchanges for backwards compat
36483 // minHeight/maxHeight were replaced by growMin/growMax to be
36484 // compatible with TextField growing config values
36485 if(this.minHeight !== undefined){
36486 this.growMin = this.minHeight;
36488 if(this.maxHeight !== undefined){
36489 this.growMax = this.maxHeight;
36493 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36495 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36499 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36503 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36504 * in the field (equivalent to setting overflow: hidden, defaults to false)
36506 preventScrollbars: false,
36508 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36509 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36513 onRender : function(ct, position){
36515 this.defaultAutoCreate = {
36517 style:"width:300px;height:60px;",
36518 autocomplete: "off"
36521 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36523 this.textSizeEl = Roo.DomHelper.append(document.body, {
36524 tag: "pre", cls: "x-form-grow-sizer"
36526 if(this.preventScrollbars){
36527 this.el.setStyle("overflow", "hidden");
36529 this.el.setHeight(this.growMin);
36533 onDestroy : function(){
36534 if(this.textSizeEl){
36535 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36537 Roo.form.TextArea.superclass.onDestroy.call(this);
36541 onKeyUp : function(e){
36542 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36548 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36549 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36551 autoSize : function(){
36552 if(!this.grow || !this.textSizeEl){
36556 var v = el.dom.value;
36557 var ts = this.textSizeEl;
36560 ts.appendChild(document.createTextNode(v));
36563 Roo.fly(ts).setWidth(this.el.getWidth());
36565 v = "  ";
36568 v = v.replace(/\n/g, '<p> </p>');
36570 v += " \n ";
36573 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36574 if(h != this.lastHeight){
36575 this.lastHeight = h;
36576 this.el.setHeight(h);
36577 this.fireEvent("autosize", this, h);
36582 * Ext JS Library 1.1.1
36583 * Copyright(c) 2006-2007, Ext JS, LLC.
36585 * Originally Released Under LGPL - original licence link has changed is not relivant.
36588 * <script type="text/javascript">
36593 * @class Roo.form.NumberField
36594 * @extends Roo.form.TextField
36595 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36597 * Creates a new NumberField
36598 * @param {Object} config Configuration options
36600 Roo.form.NumberField = function(config){
36601 Roo.form.NumberField.superclass.constructor.call(this, config);
36604 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36606 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36608 fieldClass: "x-form-field x-form-num-field",
36610 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36612 allowDecimals : true,
36614 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36616 decimalSeparator : ".",
36618 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36620 decimalPrecision : 2,
36622 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36624 allowNegative : true,
36626 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36628 minValue : Number.NEGATIVE_INFINITY,
36630 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36632 maxValue : Number.MAX_VALUE,
36634 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36636 minText : "The minimum value for this field is {0}",
36638 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36640 maxText : "The maximum value for this field is {0}",
36642 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36643 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36645 nanText : "{0} is not a valid number",
36648 initEvents : function(){
36649 Roo.form.NumberField.superclass.initEvents.call(this);
36650 var allowed = "0123456789";
36651 if(this.allowDecimals){
36652 allowed += this.decimalSeparator;
36654 if(this.allowNegative){
36657 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36658 var keyPress = function(e){
36659 var k = e.getKey();
36660 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36663 var c = e.getCharCode();
36664 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36668 this.el.on("keypress", keyPress, this);
36672 validateValue : function(value){
36673 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36676 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36679 var num = this.parseValue(value);
36681 this.markInvalid(String.format(this.nanText, value));
36684 if(num < this.minValue){
36685 this.markInvalid(String.format(this.minText, this.minValue));
36688 if(num > this.maxValue){
36689 this.markInvalid(String.format(this.maxText, this.maxValue));
36695 getValue : function(){
36696 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36700 parseValue : function(value){
36701 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36702 return isNaN(value) ? '' : value;
36706 fixPrecision : function(value){
36707 var nan = isNaN(value);
36708 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36709 return nan ? '' : value;
36711 return parseFloat(value).toFixed(this.decimalPrecision);
36714 setValue : function(v){
36715 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36719 decimalPrecisionFcn : function(v){
36720 return Math.floor(v);
36723 beforeBlur : function(){
36724 var v = this.parseValue(this.getRawValue());
36726 this.setValue(this.fixPrecision(v));
36731 * Ext JS Library 1.1.1
36732 * Copyright(c) 2006-2007, Ext JS, LLC.
36734 * Originally Released Under LGPL - original licence link has changed is not relivant.
36737 * <script type="text/javascript">
36741 * @class Roo.form.DateField
36742 * @extends Roo.form.TriggerField
36743 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36745 * Create a new DateField
36746 * @param {Object} config
36748 Roo.form.DateField = function(config){
36749 Roo.form.DateField.superclass.constructor.call(this, config);
36755 * Fires when a date is selected
36756 * @param {Roo.form.DateField} combo This combo box
36757 * @param {Date} date The date selected
36764 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36765 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36766 this.ddMatch = null;
36767 if(this.disabledDates){
36768 var dd = this.disabledDates;
36770 for(var i = 0; i < dd.length; i++){
36772 if(i != dd.length-1) re += "|";
36774 this.ddMatch = new RegExp(re + ")");
36778 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36780 * @cfg {String} format
36781 * The default date format string which can be overriden for localization support. The format must be
36782 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36786 * @cfg {String} altFormats
36787 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36788 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36790 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36792 * @cfg {Array} disabledDays
36793 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36795 disabledDays : null,
36797 * @cfg {String} disabledDaysText
36798 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36800 disabledDaysText : "Disabled",
36802 * @cfg {Array} disabledDates
36803 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36804 * expression so they are very powerful. Some examples:
36806 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36807 * <li>["03/08", "09/16"] would disable those days for every year</li>
36808 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36809 * <li>["03/../2006"] would disable every day in March 2006</li>
36810 * <li>["^03"] would disable every day in every March</li>
36812 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36813 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36815 disabledDates : null,
36817 * @cfg {String} disabledDatesText
36818 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36820 disabledDatesText : "Disabled",
36822 * @cfg {Date/String} minValue
36823 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36824 * valid format (defaults to null).
36828 * @cfg {Date/String} maxValue
36829 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36830 * valid format (defaults to null).
36834 * @cfg {String} minText
36835 * The error text to display when the date in the cell is before minValue (defaults to
36836 * 'The date in this field must be after {minValue}').
36838 minText : "The date in this field must be equal to or after {0}",
36840 * @cfg {String} maxText
36841 * The error text to display when the date in the cell is after maxValue (defaults to
36842 * 'The date in this field must be before {maxValue}').
36844 maxText : "The date in this field must be equal to or before {0}",
36846 * @cfg {String} invalidText
36847 * The error text to display when the date in the field is invalid (defaults to
36848 * '{value} is not a valid date - it must be in the format {format}').
36850 invalidText : "{0} is not a valid date - it must be in the format {1}",
36852 * @cfg {String} triggerClass
36853 * An additional CSS class used to style the trigger button. The trigger will always get the
36854 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36855 * which displays a calendar icon).
36857 triggerClass : 'x-form-date-trigger',
36861 * @cfg {bool} useIso
36862 * if enabled, then the date field will use a hidden field to store the
36863 * real value as iso formated date. default (false)
36867 * @cfg {String/Object} autoCreate
36868 * A DomHelper element spec, or true for a default element spec (defaults to
36869 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36872 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36875 hiddenField: false,
36877 onRender : function(ct, position)
36879 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36881 this.el.dom.removeAttribute('name');
36882 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36884 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36885 // prevent input submission
36886 this.hiddenName = this.name;
36893 validateValue : function(value)
36895 value = this.formatDate(value);
36896 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36899 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36902 var svalue = value;
36903 value = this.parseDate(value);
36905 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36908 var time = value.getTime();
36909 if(this.minValue && time < this.minValue.getTime()){
36910 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36913 if(this.maxValue && time > this.maxValue.getTime()){
36914 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36917 if(this.disabledDays){
36918 var day = value.getDay();
36919 for(var i = 0; i < this.disabledDays.length; i++) {
36920 if(day === this.disabledDays[i]){
36921 this.markInvalid(this.disabledDaysText);
36926 var fvalue = this.formatDate(value);
36927 if(this.ddMatch && this.ddMatch.test(fvalue)){
36928 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36935 // Provides logic to override the default TriggerField.validateBlur which just returns true
36936 validateBlur : function(){
36937 return !this.menu || !this.menu.isVisible();
36941 * Returns the current date value of the date field.
36942 * @return {Date} The date value
36944 getValue : function(){
36946 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36950 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36951 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36952 * (the default format used is "m/d/y").
36955 //All of these calls set the same date value (May 4, 2006)
36957 //Pass a date object:
36958 var dt = new Date('5/4/06');
36959 dateField.setValue(dt);
36961 //Pass a date string (default format):
36962 dateField.setValue('5/4/06');
36964 //Pass a date string (custom format):
36965 dateField.format = 'Y-m-d';
36966 dateField.setValue('2006-5-4');
36968 * @param {String/Date} date The date or valid date string
36970 setValue : function(date){
36971 if (this.hiddenField) {
36972 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36974 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36978 parseDate : function(value){
36979 if(!value || value instanceof Date){
36982 var v = Date.parseDate(value, this.format);
36983 if(!v && this.altFormats){
36984 if(!this.altFormatsArray){
36985 this.altFormatsArray = this.altFormats.split("|");
36987 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36988 v = Date.parseDate(value, this.altFormatsArray[i]);
36995 formatDate : function(date, fmt){
36996 return (!date || !(date instanceof Date)) ?
36997 date : date.dateFormat(fmt || this.format);
37002 select: function(m, d){
37004 this.fireEvent('select', this, d);
37006 show : function(){ // retain focus styling
37010 this.focus.defer(10, this);
37011 var ml = this.menuListeners;
37012 this.menu.un("select", ml.select, this);
37013 this.menu.un("show", ml.show, this);
37014 this.menu.un("hide", ml.hide, this);
37019 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37020 onTriggerClick : function(){
37024 if(this.menu == null){
37025 this.menu = new Roo.menu.DateMenu();
37027 Roo.apply(this.menu.picker, {
37028 showClear: this.allowBlank,
37029 minDate : this.minValue,
37030 maxDate : this.maxValue,
37031 disabledDatesRE : this.ddMatch,
37032 disabledDatesText : this.disabledDatesText,
37033 disabledDays : this.disabledDays,
37034 disabledDaysText : this.disabledDaysText,
37035 format : this.format,
37036 minText : String.format(this.minText, this.formatDate(this.minValue)),
37037 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37039 this.menu.on(Roo.apply({}, this.menuListeners, {
37042 this.menu.picker.setValue(this.getValue() || new Date());
37043 this.menu.show(this.el, "tl-bl?");
37046 beforeBlur : function(){
37047 var v = this.parseDate(this.getRawValue());
37053 /** @cfg {Boolean} grow @hide */
37054 /** @cfg {Number} growMin @hide */
37055 /** @cfg {Number} growMax @hide */
37062 * Ext JS Library 1.1.1
37063 * Copyright(c) 2006-2007, Ext JS, LLC.
37065 * Originally Released Under LGPL - original licence link has changed is not relivant.
37068 * <script type="text/javascript">
37073 * @class Roo.form.ComboBox
37074 * @extends Roo.form.TriggerField
37075 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
37077 * Create a new ComboBox.
37078 * @param {Object} config Configuration options
37080 Roo.form.ComboBox = function(config){
37081 Roo.form.ComboBox.superclass.constructor.call(this, config);
37085 * Fires when the dropdown list is expanded
37086 * @param {Roo.form.ComboBox} combo This combo box
37091 * Fires when the dropdown list is collapsed
37092 * @param {Roo.form.ComboBox} combo This combo box
37096 * @event beforeselect
37097 * Fires before a list item is selected. Return false to cancel the selection.
37098 * @param {Roo.form.ComboBox} combo This combo box
37099 * @param {Roo.data.Record} record The data record returned from the underlying store
37100 * @param {Number} index The index of the selected item in the dropdown list
37102 'beforeselect' : true,
37105 * Fires when a list item is selected
37106 * @param {Roo.form.ComboBox} combo This combo box
37107 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37108 * @param {Number} index The index of the selected item in the dropdown list
37112 * @event beforequery
37113 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37114 * The event object passed has these properties:
37115 * @param {Roo.form.ComboBox} combo This combo box
37116 * @param {String} query The query
37117 * @param {Boolean} forceAll true to force "all" query
37118 * @param {Boolean} cancel true to cancel the query
37119 * @param {Object} e The query event object
37121 'beforequery': true,
37124 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37125 * @param {Roo.form.ComboBox} combo This combo box
37130 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37131 * @param {Roo.form.ComboBox} combo This combo box
37132 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37138 if(this.transform){
37139 this.allowDomMove = false;
37140 var s = Roo.getDom(this.transform);
37141 if(!this.hiddenName){
37142 this.hiddenName = s.name;
37145 this.mode = 'local';
37146 var d = [], opts = s.options;
37147 for(var i = 0, len = opts.length;i < len; i++){
37149 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37151 this.value = value;
37153 d.push([value, o.text]);
37155 this.store = new Roo.data.SimpleStore({
37157 fields: ['value', 'text'],
37160 this.valueField = 'value';
37161 this.displayField = 'text';
37163 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37164 if(!this.lazyRender){
37165 this.target = true;
37166 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37167 s.parentNode.removeChild(s); // remove it
37168 this.render(this.el.parentNode);
37170 s.parentNode.removeChild(s); // remove it
37175 this.store = Roo.factory(this.store, Roo.data);
37178 this.selectedIndex = -1;
37179 if(this.mode == 'local'){
37180 if(config.queryDelay === undefined){
37181 this.queryDelay = 10;
37183 if(config.minChars === undefined){
37189 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37191 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37194 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37195 * rendering into an Roo.Editor, defaults to false)
37198 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37199 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37202 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37205 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37206 * the dropdown list (defaults to undefined, with no header element)
37210 * @cfg {String/Roo.Template} tpl The template to use to render the output
37214 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37216 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37218 listWidth: undefined,
37220 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37221 * mode = 'remote' or 'text' if mode = 'local')
37223 displayField: undefined,
37225 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37226 * mode = 'remote' or 'value' if mode = 'local').
37227 * Note: use of a valueField requires the user make a selection
37228 * in order for a value to be mapped.
37230 valueField: undefined,
37232 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37233 * field's data value (defaults to the underlying DOM element's name)
37235 hiddenName: undefined,
37237 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37241 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37243 selectedClass: 'x-combo-selected',
37245 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37246 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37247 * which displays a downward arrow icon).
37249 triggerClass : 'x-form-arrow-trigger',
37251 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37255 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37256 * anchor positions (defaults to 'tl-bl')
37258 listAlign: 'tl-bl?',
37260 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37264 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37265 * query specified by the allQuery config option (defaults to 'query')
37267 triggerAction: 'query',
37269 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37270 * (defaults to 4, does not apply if editable = false)
37274 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37275 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37279 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37280 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37284 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37285 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37289 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37290 * when editable = true (defaults to false)
37292 selectOnFocus:false,
37294 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37296 queryParam: 'query',
37298 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37299 * when mode = 'remote' (defaults to 'Loading...')
37301 loadingText: 'Loading...',
37303 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37307 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37311 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37312 * traditional select (defaults to true)
37316 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37320 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37324 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37325 * listWidth has a higher value)
37329 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37330 * allow the user to set arbitrary text into the field (defaults to false)
37332 forceSelection:false,
37334 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37335 * if typeAhead = true (defaults to 250)
37337 typeAheadDelay : 250,
37339 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37340 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37342 valueNotFoundText : undefined,
37344 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37346 blockFocus : false,
37349 * @cfg {Boolean} disableClear Disable showing of clear button.
37351 disableClear : false,
37353 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37355 alwaysQuery : false,
37363 onRender : function(ct, position){
37364 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37365 if(this.hiddenName){
37366 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37368 this.hiddenField.value =
37369 this.hiddenValue !== undefined ? this.hiddenValue :
37370 this.value !== undefined ? this.value : '';
37372 // prevent input submission
37373 this.el.dom.removeAttribute('name');
37376 this.el.dom.setAttribute('autocomplete', 'off');
37379 var cls = 'x-combo-list';
37381 this.list = new Roo.Layer({
37382 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37385 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37386 this.list.setWidth(lw);
37387 this.list.swallowEvent('mousewheel');
37388 this.assetHeight = 0;
37391 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37392 this.assetHeight += this.header.getHeight();
37395 this.innerList = this.list.createChild({cls:cls+'-inner'});
37396 this.innerList.on('mouseover', this.onViewOver, this);
37397 this.innerList.on('mousemove', this.onViewMove, this);
37398 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37400 if(this.allowBlank && !this.pageSize && !this.disableClear){
37401 this.footer = this.list.createChild({cls:cls+'-ft'});
37402 this.pageTb = new Roo.Toolbar(this.footer);
37406 this.footer = this.list.createChild({cls:cls+'-ft'});
37407 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37408 {pageSize: this.pageSize});
37412 if (this.pageTb && this.allowBlank && !this.disableClear) {
37414 this.pageTb.add(new Roo.Toolbar.Fill(), {
37415 cls: 'x-btn-icon x-btn-clear',
37417 handler: function()
37420 _this.clearValue();
37421 _this.onSelect(false, -1);
37426 this.assetHeight += this.footer.getHeight();
37431 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37434 this.view = new Roo.View(this.innerList, this.tpl, {
37435 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37438 this.view.on('click', this.onViewClick, this);
37440 this.store.on('beforeload', this.onBeforeLoad, this);
37441 this.store.on('load', this.onLoad, this);
37442 this.store.on('loadexception', this.collapse, this);
37444 if(this.resizable){
37445 this.resizer = new Roo.Resizable(this.list, {
37446 pinned:true, handles:'se'
37448 this.resizer.on('resize', function(r, w, h){
37449 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37450 this.listWidth = w;
37451 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37452 this.restrictHeight();
37454 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37456 if(!this.editable){
37457 this.editable = true;
37458 this.setEditable(false);
37462 if (typeof(this.events.add.listeners) != 'undefined') {
37464 this.addicon = this.wrap.createChild(
37465 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37467 this.addicon.on('click', function(e) {
37468 this.fireEvent('add', this);
37471 if (typeof(this.events.edit.listeners) != 'undefined') {
37473 this.editicon = this.wrap.createChild(
37474 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37475 if (this.addicon) {
37476 this.editicon.setStyle('margin-left', '40px');
37478 this.editicon.on('click', function(e) {
37480 // we fire even if inothing is selected..
37481 this.fireEvent('edit', this, this.lastData );
37491 initEvents : function(){
37492 Roo.form.ComboBox.superclass.initEvents.call(this);
37494 this.keyNav = new Roo.KeyNav(this.el, {
37495 "up" : function(e){
37496 this.inKeyMode = true;
37500 "down" : function(e){
37501 if(!this.isExpanded()){
37502 this.onTriggerClick();
37504 this.inKeyMode = true;
37509 "enter" : function(e){
37510 this.onViewClick();
37514 "esc" : function(e){
37518 "tab" : function(e){
37519 this.onViewClick(false);
37525 doRelay : function(foo, bar, hname){
37526 if(hname == 'down' || this.scope.isExpanded()){
37527 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37534 this.queryDelay = Math.max(this.queryDelay || 10,
37535 this.mode == 'local' ? 10 : 250);
37536 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37537 if(this.typeAhead){
37538 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37540 if(this.editable !== false){
37541 this.el.on("keyup", this.onKeyUp, this);
37543 if(this.forceSelection){
37544 this.on('blur', this.doForce, this);
37548 onDestroy : function(){
37550 this.view.setStore(null);
37551 this.view.el.removeAllListeners();
37552 this.view.el.remove();
37553 this.view.purgeListeners();
37556 this.list.destroy();
37559 this.store.un('beforeload', this.onBeforeLoad, this);
37560 this.store.un('load', this.onLoad, this);
37561 this.store.un('loadexception', this.collapse, this);
37563 Roo.form.ComboBox.superclass.onDestroy.call(this);
37567 fireKey : function(e){
37568 if(e.isNavKeyPress() && !this.list.isVisible()){
37569 this.fireEvent("specialkey", this, e);
37574 onResize: function(w, h){
37575 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37577 if(typeof w != 'number'){
37578 // we do not handle it!?!?
37581 var tw = this.trigger.getWidth();
37582 tw += this.addicon ? this.addicon.getWidth() : 0;
37583 tw += this.editicon ? this.editicon.getWidth() : 0;
37585 this.el.setWidth( this.adjustWidth('input', x));
37587 this.trigger.setStyle('left', x+'px');
37589 if(this.list && this.listWidth === undefined){
37590 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37591 this.list.setWidth(lw);
37592 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37600 * Allow or prevent the user from directly editing the field text. If false is passed,
37601 * the user will only be able to select from the items defined in the dropdown list. This method
37602 * is the runtime equivalent of setting the 'editable' config option at config time.
37603 * @param {Boolean} value True to allow the user to directly edit the field text
37605 setEditable : function(value){
37606 if(value == this.editable){
37609 this.editable = value;
37611 this.el.dom.setAttribute('readOnly', true);
37612 this.el.on('mousedown', this.onTriggerClick, this);
37613 this.el.addClass('x-combo-noedit');
37615 this.el.dom.setAttribute('readOnly', false);
37616 this.el.un('mousedown', this.onTriggerClick, this);
37617 this.el.removeClass('x-combo-noedit');
37622 onBeforeLoad : function(){
37623 if(!this.hasFocus){
37626 this.innerList.update(this.loadingText ?
37627 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37628 this.restrictHeight();
37629 this.selectedIndex = -1;
37633 onLoad : function(){
37634 if(!this.hasFocus){
37637 if(this.store.getCount() > 0){
37639 this.restrictHeight();
37640 if(this.lastQuery == this.allQuery){
37642 this.el.dom.select();
37644 if(!this.selectByValue(this.value, true)){
37645 this.select(0, true);
37649 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37650 this.taTask.delay(this.typeAheadDelay);
37654 this.onEmptyResults();
37660 onTypeAhead : function(){
37661 if(this.store.getCount() > 0){
37662 var r = this.store.getAt(0);
37663 var newValue = r.data[this.displayField];
37664 var len = newValue.length;
37665 var selStart = this.getRawValue().length;
37666 if(selStart != len){
37667 this.setRawValue(newValue);
37668 this.selectText(selStart, newValue.length);
37674 onSelect : function(record, index){
37675 if(this.fireEvent('beforeselect', this, record, index) !== false){
37676 this.setFromData(index > -1 ? record.data : false);
37678 this.fireEvent('select', this, record, index);
37683 * Returns the currently selected field value or empty string if no value is set.
37684 * @return {String} value The selected value
37686 getValue : function(){
37687 if(this.valueField){
37688 return typeof this.value != 'undefined' ? this.value : '';
37690 return Roo.form.ComboBox.superclass.getValue.call(this);
37695 * Clears any text/value currently set in the field
37697 clearValue : function(){
37698 if(this.hiddenField){
37699 this.hiddenField.value = '';
37702 this.setRawValue('');
37703 this.lastSelectionText = '';
37704 this.applyEmptyText();
37708 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37709 * will be displayed in the field. If the value does not match the data value of an existing item,
37710 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37711 * Otherwise the field will be blank (although the value will still be set).
37712 * @param {String} value The value to match
37714 setValue : function(v){
37716 if(this.valueField){
37717 var r = this.findRecord(this.valueField, v);
37719 text = r.data[this.displayField];
37720 }else if(this.valueNotFoundText !== undefined){
37721 text = this.valueNotFoundText;
37724 this.lastSelectionText = text;
37725 if(this.hiddenField){
37726 this.hiddenField.value = v;
37728 Roo.form.ComboBox.superclass.setValue.call(this, text);
37732 * @property {Object} the last set data for the element
37737 * Sets the value of the field based on a object which is related to the record format for the store.
37738 * @param {Object} value the value to set as. or false on reset?
37740 setFromData : function(o){
37741 var dv = ''; // display value
37742 var vv = ''; // value value..
37744 if (this.displayField) {
37745 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37747 // this is an error condition!!!
37748 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
37751 if(this.valueField){
37752 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37754 if(this.hiddenField){
37755 this.hiddenField.value = vv;
37757 this.lastSelectionText = dv;
37758 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37762 // no hidden field.. - we store the value in 'value', but still display
37763 // display field!!!!
37764 this.lastSelectionText = dv;
37765 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37771 reset : function(){
37772 // overridden so that last data is reset..
37773 this.setValue(this.originalValue);
37774 this.clearInvalid();
37775 this.lastData = false;
37778 findRecord : function(prop, value){
37780 if(this.store.getCount() > 0){
37781 this.store.each(function(r){
37782 if(r.data[prop] == value){
37792 onViewMove : function(e, t){
37793 this.inKeyMode = false;
37797 onViewOver : function(e, t){
37798 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37801 var item = this.view.findItemFromChild(t);
37803 var index = this.view.indexOf(item);
37804 this.select(index, false);
37809 onViewClick : function(doFocus){
37810 var index = this.view.getSelectedIndexes()[0];
37811 var r = this.store.getAt(index);
37813 this.onSelect(r, index);
37815 if(doFocus !== false && !this.blockFocus){
37821 restrictHeight : function(){
37822 this.innerList.dom.style.height = '';
37823 var inner = this.innerList.dom;
37824 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37825 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37826 this.list.beginUpdate();
37827 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37828 this.list.alignTo(this.el, this.listAlign);
37829 this.list.endUpdate();
37833 onEmptyResults : function(){
37838 * Returns true if the dropdown list is expanded, else false.
37840 isExpanded : function(){
37841 return this.list.isVisible();
37845 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37846 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37847 * @param {String} value The data value of the item to select
37848 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37849 * selected item if it is not currently in view (defaults to true)
37850 * @return {Boolean} True if the value matched an item in the list, else false
37852 selectByValue : function(v, scrollIntoView){
37853 if(v !== undefined && v !== null){
37854 var r = this.findRecord(this.valueField || this.displayField, v);
37856 this.select(this.store.indexOf(r), scrollIntoView);
37864 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37865 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37866 * @param {Number} index The zero-based index of the list item to select
37867 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37868 * selected item if it is not currently in view (defaults to true)
37870 select : function(index, scrollIntoView){
37871 this.selectedIndex = index;
37872 this.view.select(index);
37873 if(scrollIntoView !== false){
37874 var el = this.view.getNode(index);
37876 this.innerList.scrollChildIntoView(el, false);
37882 selectNext : function(){
37883 var ct = this.store.getCount();
37885 if(this.selectedIndex == -1){
37887 }else if(this.selectedIndex < ct-1){
37888 this.select(this.selectedIndex+1);
37894 selectPrev : function(){
37895 var ct = this.store.getCount();
37897 if(this.selectedIndex == -1){
37899 }else if(this.selectedIndex != 0){
37900 this.select(this.selectedIndex-1);
37906 onKeyUp : function(e){
37907 if(this.editable !== false && !e.isSpecialKey()){
37908 this.lastKey = e.getKey();
37909 this.dqTask.delay(this.queryDelay);
37914 validateBlur : function(){
37915 return !this.list || !this.list.isVisible();
37919 initQuery : function(){
37920 this.doQuery(this.getRawValue());
37924 doForce : function(){
37925 if(this.el.dom.value.length > 0){
37926 this.el.dom.value =
37927 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37928 this.applyEmptyText();
37933 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37934 * query allowing the query action to be canceled if needed.
37935 * @param {String} query The SQL query to execute
37936 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37937 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37938 * saved in the current store (defaults to false)
37940 doQuery : function(q, forceAll){
37941 if(q === undefined || q === null){
37946 forceAll: forceAll,
37950 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37954 forceAll = qe.forceAll;
37955 if(forceAll === true || (q.length >= this.minChars)){
37956 if(this.lastQuery != q || this.alwaysQuery){
37957 this.lastQuery = q;
37958 if(this.mode == 'local'){
37959 this.selectedIndex = -1;
37961 this.store.clearFilter();
37963 this.store.filter(this.displayField, q);
37967 this.store.baseParams[this.queryParam] = q;
37969 params: this.getParams(q)
37974 this.selectedIndex = -1;
37981 getParams : function(q){
37983 //p[this.queryParam] = q;
37986 p.limit = this.pageSize;
37992 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37994 collapse : function(){
37995 if(!this.isExpanded()){
37999 Roo.get(document).un('mousedown', this.collapseIf, this);
38000 Roo.get(document).un('mousewheel', this.collapseIf, this);
38001 if (!this.editable) {
38002 Roo.get(document).un('keydown', this.listKeyPress, this);
38004 this.fireEvent('collapse', this);
38008 collapseIf : function(e){
38009 if(!e.within(this.wrap) && !e.within(this.list)){
38015 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
38017 expand : function(){
38018 if(this.isExpanded() || !this.hasFocus){
38021 this.list.alignTo(this.el, this.listAlign);
38023 Roo.get(document).on('mousedown', this.collapseIf, this);
38024 Roo.get(document).on('mousewheel', this.collapseIf, this);
38025 if (!this.editable) {
38026 Roo.get(document).on('keydown', this.listKeyPress, this);
38029 this.fireEvent('expand', this);
38033 // Implements the default empty TriggerField.onTriggerClick function
38034 onTriggerClick : function(){
38038 if(this.isExpanded()){
38040 if (!this.blockFocus) {
38045 this.hasFocus = true;
38046 if(this.triggerAction == 'all') {
38047 this.doQuery(this.allQuery, true);
38049 this.doQuery(this.getRawValue());
38051 if (!this.blockFocus) {
38056 listKeyPress : function(e)
38058 //Roo.log('listkeypress');
38059 // scroll to first matching element based on key pres..
38060 if (e.isSpecialKey()) {
38063 var k = String.fromCharCode(e.getKey()).toUpperCase();
38066 var csel = this.view.getSelectedNodes();
38067 var cselitem = false;
38069 var ix = this.view.indexOf(csel[0]);
38070 cselitem = this.store.getAt(ix);
38071 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
38077 this.store.each(function(v) {
38079 // start at existing selection.
38080 if (cselitem.id == v.id) {
38086 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
38087 match = this.store.indexOf(v);
38092 if (match === false) {
38093 return true; // no more action?
38096 this.view.select(match);
38097 var sn = Roo.get(this.view.getSelectedNodes()[0])
38098 sn.scrollIntoView(sn.dom.parentNode, false);
38102 * @cfg {Boolean} grow
38106 * @cfg {Number} growMin
38110 * @cfg {Number} growMax
38119 * Ext JS Library 1.1.1
38120 * Copyright(c) 2006-2007, Ext JS, LLC.
38122 * Originally Released Under LGPL - original licence link has changed is not relivant.
38125 * <script type="text/javascript">
38128 * @class Roo.form.Checkbox
38129 * @extends Roo.form.Field
38130 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
38132 * Creates a new Checkbox
38133 * @param {Object} config Configuration options
38135 Roo.form.Checkbox = function(config){
38136 Roo.form.Checkbox.superclass.constructor.call(this, config);
38140 * Fires when the checkbox is checked or unchecked.
38141 * @param {Roo.form.Checkbox} this This checkbox
38142 * @param {Boolean} checked The new checked value
38148 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38150 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38152 focusClass : undefined,
38154 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38156 fieldClass: "x-form-field",
38158 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38162 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38163 * {tag: "input", type: "checkbox", autocomplete: "off"})
38165 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38167 * @cfg {String} boxLabel The text that appears beside the checkbox
38171 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38175 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38177 valueOff: '0', // value when not checked..
38179 actionMode : 'viewEl',
38182 itemCls : 'x-menu-check-item x-form-item',
38183 groupClass : 'x-menu-group-item',
38184 inputType : 'hidden',
38187 inSetChecked: false, // check that we are not calling self...
38189 inputElement: false, // real input element?
38190 basedOn: false, // ????
38192 isFormField: true, // not sure where this is needed!!!!
38194 onResize : function(){
38195 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38196 if(!this.boxLabel){
38197 this.el.alignTo(this.wrap, 'c-c');
38201 initEvents : function(){
38202 Roo.form.Checkbox.superclass.initEvents.call(this);
38203 this.el.on("click", this.onClick, this);
38204 this.el.on("change", this.onClick, this);
38208 getResizeEl : function(){
38212 getPositionEl : function(){
38217 onRender : function(ct, position){
38218 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38220 if(this.inputValue !== undefined){
38221 this.el.dom.value = this.inputValue;
38224 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38225 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38226 var viewEl = this.wrap.createChild({
38227 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38228 this.viewEl = viewEl;
38229 this.wrap.on('click', this.onClick, this);
38231 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38232 this.el.on('propertychange', this.setFromHidden, this); //ie
38237 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38238 // viewEl.on('click', this.onClick, this);
38240 //if(this.checked){
38241 this.setChecked(this.checked);
38243 //this.checked = this.el.dom;
38249 initValue : Roo.emptyFn,
38252 * Returns the checked state of the checkbox.
38253 * @return {Boolean} True if checked, else false
38255 getValue : function(){
38257 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38259 return this.valueOff;
38264 onClick : function(){
38265 this.setChecked(!this.checked);
38267 //if(this.el.dom.checked != this.checked){
38268 // this.setValue(this.el.dom.checked);
38273 * Sets the checked state of the checkbox.
38274 * On is always based on a string comparison between inputValue and the param.
38275 * @param {Boolean/String} value - the value to set
38276 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38278 setValue : function(v,suppressEvent){
38281 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38282 //if(this.el && this.el.dom){
38283 // this.el.dom.checked = this.checked;
38284 // this.el.dom.defaultChecked = this.checked;
38286 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38287 //this.fireEvent("check", this, this.checked);
38290 setChecked : function(state,suppressEvent)
38292 if (this.inSetChecked) {
38293 this.checked = state;
38299 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38301 this.checked = state;
38302 if(suppressEvent !== true){
38303 this.fireEvent('check', this, state);
38305 this.inSetChecked = true;
38306 this.el.dom.value = state ? this.inputValue : this.valueOff;
38307 this.inSetChecked = false;
38310 // handle setting of hidden value by some other method!!?!?
38311 setFromHidden: function()
38316 //console.log("SET FROM HIDDEN");
38317 //alert('setFrom hidden');
38318 this.setValue(this.el.dom.value);
38321 onDestroy : function()
38324 Roo.get(this.viewEl).remove();
38327 Roo.form.Checkbox.superclass.onDestroy.call(this);
38332 * Ext JS Library 1.1.1
38333 * Copyright(c) 2006-2007, Ext JS, LLC.
38335 * Originally Released Under LGPL - original licence link has changed is not relivant.
38338 * <script type="text/javascript">
38342 * @class Roo.form.Radio
38343 * @extends Roo.form.Checkbox
38344 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38345 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38347 * Creates a new Radio
38348 * @param {Object} config Configuration options
38350 Roo.form.Radio = function(){
38351 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38353 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38354 inputType: 'radio',
38357 * If this radio is part of a group, it will return the selected value
38360 getGroupValue : function(){
38361 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38363 });//<script type="text/javascript">
38366 * Ext JS Library 1.1.1
38367 * Copyright(c) 2006-2007, Ext JS, LLC.
38368 * licensing@extjs.com
38370 * http://www.extjs.com/license
38376 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38377 * - IE ? - no idea how much works there.
38385 * @class Ext.form.HtmlEditor
38386 * @extends Ext.form.Field
38387 * Provides a lightweight HTML Editor component.
38388 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38390 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38391 * supported by this editor.</b><br/><br/>
38392 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38393 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38395 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38397 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38401 * @cfg {String} createLinkText The default text for the create link prompt
38403 createLinkText : 'Please enter the URL for the link:',
38405 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38407 defaultLinkValue : 'http:/'+'/',
38413 // private properties
38414 validationEvent : false,
38416 initialized : false,
38418 sourceEditMode : false,
38419 onFocus : Roo.emptyFn,
38421 hideMode:'offsets',
38422 defaultAutoCreate : {
38424 style:"width:500px;height:300px;",
38425 autocomplete: "off"
38429 initComponent : function(){
38432 * @event initialize
38433 * Fires when the editor is fully initialized (including the iframe)
38434 * @param {HtmlEditor} this
38439 * Fires when the editor is first receives the focus. Any insertion must wait
38440 * until after this event.
38441 * @param {HtmlEditor} this
38445 * @event beforesync
38446 * Fires before the textarea is updated with content from the editor iframe. Return false
38447 * to cancel the sync.
38448 * @param {HtmlEditor} this
38449 * @param {String} html
38453 * @event beforepush
38454 * Fires before the iframe editor is updated with content from the textarea. Return false
38455 * to cancel the push.
38456 * @param {HtmlEditor} this
38457 * @param {String} html
38462 * Fires when the textarea is updated with content from the editor iframe.
38463 * @param {HtmlEditor} this
38464 * @param {String} html
38469 * Fires when the iframe editor is updated with content from the textarea.
38470 * @param {HtmlEditor} this
38471 * @param {String} html
38475 * @event editmodechange
38476 * Fires when the editor switches edit modes
38477 * @param {HtmlEditor} this
38478 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38480 editmodechange: true,
38482 * @event editorevent
38483 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38484 * @param {HtmlEditor} this
38491 * Protected method that will not generally be called directly. It
38492 * is called when the editor creates its toolbar. Override this method if you need to
38493 * add custom toolbar buttons.
38494 * @param {HtmlEditor} editor
38496 createToolbar : function(editor){
38497 if (!editor.toolbars || !editor.toolbars.length) {
38498 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38501 for (var i =0 ; i < editor.toolbars.length;i++) {
38502 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38503 editor.toolbars[i].init(editor);
38510 * Protected method that will not generally be called directly. It
38511 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38512 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38514 getDocMarkup : function(){
38515 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
38519 onRender : function(ct, position){
38520 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38521 this.el.dom.style.border = '0 none';
38522 this.el.dom.setAttribute('tabIndex', -1);
38523 this.el.addClass('x-hidden');
38524 if(Roo.isIE){ // fix IE 1px bogus margin
38525 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38527 this.wrap = this.el.wrap({
38528 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38531 this.frameId = Roo.id();
38532 this.createToolbar(this);
38539 var iframe = this.wrap.createChild({
38542 name: this.frameId,
38543 frameBorder : 'no',
38544 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38547 // console.log(iframe);
38548 //this.wrap.dom.appendChild(iframe);
38550 this.iframe = iframe.dom;
38552 this.assignDocWin();
38554 this.doc.designMode = 'on';
38557 this.doc.write(this.getDocMarkup());
38561 var task = { // must defer to wait for browser to be ready
38563 //console.log("run task?" + this.doc.readyState);
38564 this.assignDocWin();
38565 if(this.doc.body || this.doc.readyState == 'complete'){
38567 this.doc.designMode="on";
38571 Roo.TaskMgr.stop(task);
38572 this.initEditor.defer(10, this);
38579 Roo.TaskMgr.start(task);
38582 this.setSize(this.el.getSize());
38587 onResize : function(w, h){
38588 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38589 if(this.el && this.iframe){
38590 if(typeof w == 'number'){
38591 var aw = w - this.wrap.getFrameWidth('lr');
38592 this.el.setWidth(this.adjustWidth('textarea', aw));
38593 this.iframe.style.width = aw + 'px';
38595 if(typeof h == 'number'){
38597 for (var i =0; i < this.toolbars.length;i++) {
38598 // fixme - ask toolbars for heights?
38599 tbh += this.toolbars[i].tb.el.getHeight();
38605 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38606 this.el.setHeight(this.adjustWidth('textarea', ah));
38607 this.iframe.style.height = ah + 'px';
38609 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38616 * Toggles the editor between standard and source edit mode.
38617 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38619 toggleSourceEdit : function(sourceEditMode){
38621 this.sourceEditMode = sourceEditMode === true;
38623 if(this.sourceEditMode){
38626 this.iframe.className = 'x-hidden';
38627 this.el.removeClass('x-hidden');
38628 this.el.dom.removeAttribute('tabIndex');
38633 this.iframe.className = '';
38634 this.el.addClass('x-hidden');
38635 this.el.dom.setAttribute('tabIndex', -1);
38638 this.setSize(this.wrap.getSize());
38639 this.fireEvent('editmodechange', this, this.sourceEditMode);
38642 // private used internally
38643 createLink : function(){
38644 var url = prompt(this.createLinkText, this.defaultLinkValue);
38645 if(url && url != 'http:/'+'/'){
38646 this.relayCmd('createlink', url);
38650 // private (for BoxComponent)
38651 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38653 // private (for BoxComponent)
38654 getResizeEl : function(){
38658 // private (for BoxComponent)
38659 getPositionEl : function(){
38664 initEvents : function(){
38665 this.originalValue = this.getValue();
38669 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38672 markInvalid : Roo.emptyFn,
38674 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38677 clearInvalid : Roo.emptyFn,
38679 setValue : function(v){
38680 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38685 * Protected method that will not generally be called directly. If you need/want
38686 * custom HTML cleanup, this is the method you should override.
38687 * @param {String} html The HTML to be cleaned
38688 * return {String} The cleaned HTML
38690 cleanHtml : function(html){
38691 html = String(html);
38692 if(html.length > 5){
38693 if(Roo.isSafari){ // strip safari nonsense
38694 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38697 if(html == ' '){
38704 * Protected method that will not generally be called directly. Syncs the contents
38705 * of the editor iframe with the textarea.
38707 syncValue : function(){
38708 if(this.initialized){
38709 var bd = (this.doc.body || this.doc.documentElement);
38710 this.cleanUpPaste();
38711 var html = bd.innerHTML;
38713 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38714 var m = bs.match(/text-align:(.*?);/i);
38716 html = '<div style="'+m[0]+'">' + html + '</div>';
38719 html = this.cleanHtml(html);
38720 if(this.fireEvent('beforesync', this, html) !== false){
38721 this.el.dom.value = html;
38722 this.fireEvent('sync', this, html);
38728 * Protected method that will not generally be called directly. Pushes the value of the textarea
38729 * into the iframe editor.
38731 pushValue : function(){
38732 if(this.initialized){
38733 var v = this.el.dom.value;
38738 if(this.fireEvent('beforepush', this, v) !== false){
38739 var d = (this.doc.body || this.doc.documentElement);
38741 this.cleanUpPaste();
38742 this.el.dom.value = d.innerHTML;
38743 this.fireEvent('push', this, v);
38749 deferFocus : function(){
38750 this.focus.defer(10, this);
38754 focus : function(){
38755 if(this.win && !this.sourceEditMode){
38762 assignDocWin: function()
38764 var iframe = this.iframe;
38767 this.doc = iframe.contentWindow.document;
38768 this.win = iframe.contentWindow;
38770 if (!Roo.get(this.frameId)) {
38773 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38774 this.win = Roo.get(this.frameId).dom.contentWindow;
38779 initEditor : function(){
38780 //console.log("INIT EDITOR");
38781 this.assignDocWin();
38785 this.doc.designMode="on";
38787 this.doc.write(this.getDocMarkup());
38790 var dbody = (this.doc.body || this.doc.documentElement);
38791 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38792 // this copies styles from the containing element into thsi one..
38793 // not sure why we need all of this..
38794 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38795 ss['background-attachment'] = 'fixed'; // w3c
38796 dbody.bgProperties = 'fixed'; // ie
38797 Roo.DomHelper.applyStyles(dbody, ss);
38798 Roo.EventManager.on(this.doc, {
38799 'mousedown': this.onEditorEvent,
38800 'dblclick': this.onEditorEvent,
38801 'click': this.onEditorEvent,
38802 'keyup': this.onEditorEvent,
38807 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
38809 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38810 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38812 this.initialized = true;
38814 this.fireEvent('initialize', this);
38819 onDestroy : function(){
38825 for (var i =0; i < this.toolbars.length;i++) {
38826 // fixme - ask toolbars for heights?
38827 this.toolbars[i].onDestroy();
38830 this.wrap.dom.innerHTML = '';
38831 this.wrap.remove();
38836 onFirstFocus : function(){
38838 this.assignDocWin();
38841 this.activated = true;
38842 for (var i =0; i < this.toolbars.length;i++) {
38843 this.toolbars[i].onFirstFocus();
38846 if(Roo.isGecko){ // prevent silly gecko errors
38848 var s = this.win.getSelection();
38849 if(!s.focusNode || s.focusNode.nodeType != 3){
38850 var r = s.getRangeAt(0);
38851 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38856 this.execCmd('useCSS', true);
38857 this.execCmd('styleWithCSS', false);
38860 this.fireEvent('activate', this);
38864 adjustFont: function(btn){
38865 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38866 //if(Roo.isSafari){ // safari
38869 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38870 if(Roo.isSafari){ // safari
38871 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38872 v = (v < 10) ? 10 : v;
38873 v = (v > 48) ? 48 : v;
38874 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38879 v = Math.max(1, v+adjust);
38881 this.execCmd('FontSize', v );
38884 onEditorEvent : function(e){
38885 this.fireEvent('editorevent', this, e);
38886 // this.updateToolbar();
38890 insertTag : function(tg)
38892 // could be a bit smarter... -> wrap the current selected tRoo..
38894 this.execCmd("formatblock", tg);
38898 insertText : function(txt)
38902 range = this.createRange();
38903 range.deleteContents();
38904 //alert(Sender.getAttribute('label'));
38906 range.insertNode(this.doc.createTextNode(txt));
38910 relayBtnCmd : function(btn){
38911 this.relayCmd(btn.cmd);
38915 * Executes a Midas editor command on the editor document and performs necessary focus and
38916 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38917 * @param {String} cmd The Midas command
38918 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38920 relayCmd : function(cmd, value){
38922 this.execCmd(cmd, value);
38923 this.fireEvent('editorevent', this);
38924 //this.updateToolbar();
38929 * Executes a Midas editor command directly on the editor document.
38930 * For visual commands, you should use {@link #relayCmd} instead.
38931 * <b>This should only be called after the editor is initialized.</b>
38932 * @param {String} cmd The Midas command
38933 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38935 execCmd : function(cmd, value){
38936 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38942 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38944 * @param {String} text
38946 insertAtCursor : function(text){
38947 if(!this.activated){
38952 var r = this.doc.selection.createRange();
38959 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
38961 this.execCmd('InsertHTML', text);
38966 mozKeyPress : function(e){
38968 var c = e.getCharCode(), cmd;
38971 c = String.fromCharCode(c).toLowerCase();
38982 this.cleanUpPaste.defer(100, this);
38990 e.preventDefault();
38998 fixKeys : function(){ // load time branching for fastest keydown performance
39000 return function(e){
39001 var k = e.getKey(), r;
39004 r = this.doc.selection.createRange();
39007 r.pasteHTML('    ');
39014 r = this.doc.selection.createRange();
39016 var target = r.parentElement();
39017 if(!target || target.tagName.toLowerCase() != 'li'){
39019 r.pasteHTML('<br />');
39025 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39026 this.cleanUpPaste.defer(100, this);
39032 }else if(Roo.isOpera){
39033 return function(e){
39034 var k = e.getKey();
39038 this.execCmd('InsertHTML','    ');
39041 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39042 this.cleanUpPaste.defer(100, this);
39047 }else if(Roo.isSafari){
39048 return function(e){
39049 var k = e.getKey();
39053 this.execCmd('InsertText','\t');
39057 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39058 this.cleanUpPaste.defer(100, this);
39066 getAllAncestors: function()
39068 var p = this.getSelectedNode();
39071 a.push(p); // push blank onto stack..
39072 p = this.getParentElement();
39076 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
39080 a.push(this.doc.body);
39084 lastSelNode : false,
39087 getSelection : function()
39089 this.assignDocWin();
39090 return Roo.isIE ? this.doc.selection : this.win.getSelection();
39093 getSelectedNode: function()
39095 // this may only work on Gecko!!!
39097 // should we cache this!!!!
39102 var range = this.createRange(this.getSelection());
39105 var parent = range.parentElement();
39107 var testRange = range.duplicate();
39108 testRange.moveToElementText(parent);
39109 if (testRange.inRange(range)) {
39112 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
39115 parent = parent.parentElement;
39121 var ar = range.endContainer.childNodes;
39123 ar = range.commonAncestorContainer.childNodes;
39124 //alert(ar.length);
39127 var other_nodes = [];
39128 var has_other_nodes = false;
39129 for (var i=0;i<ar.length;i++) {
39130 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
39133 // fullly contained node.
39135 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
39140 // probably selected..
39141 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
39142 other_nodes.push(ar[i]);
39145 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39150 has_other_nodes = true;
39152 if (!nodes.length && other_nodes.length) {
39153 nodes= other_nodes;
39155 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39161 createRange: function(sel)
39163 // this has strange effects when using with
39164 // top toolbar - not sure if it's a great idea.
39165 //this.editor.contentWindow.focus();
39166 if (typeof sel != "undefined") {
39168 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39170 return this.doc.createRange();
39173 return this.doc.createRange();
39176 getParentElement: function()
39179 this.assignDocWin();
39180 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39182 var range = this.createRange(sel);
39185 var p = range.commonAncestorContainer;
39186 while (p.nodeType == 3) { // text node
39198 // BC Hacks - cause I cant work out what i was trying to do..
39199 rangeIntersectsNode : function(range, node)
39201 var nodeRange = node.ownerDocument.createRange();
39203 nodeRange.selectNode(node);
39206 nodeRange.selectNodeContents(node);
39209 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
39210 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
39212 rangeCompareNode : function(range, node) {
39213 var nodeRange = node.ownerDocument.createRange();
39215 nodeRange.selectNode(node);
39217 nodeRange.selectNodeContents(node);
39219 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
39220 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
39222 if (nodeIsBefore && !nodeIsAfter)
39224 if (!nodeIsBefore && nodeIsAfter)
39226 if (nodeIsBefore && nodeIsAfter)
39232 // private? - in a new class?
39233 cleanUpPaste : function()
39235 // cleans up the whole document..
39236 // console.log('cleanuppaste');
39237 this.cleanUpChildren(this.doc.body);
39241 cleanUpChildren : function (n)
39243 if (!n.childNodes.length) {
39246 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39247 this.cleanUpChild(n.childNodes[i]);
39254 cleanUpChild : function (node)
39256 //console.log(node);
39257 if (node.nodeName == "#text") {
39258 // clean up silly Windows -- stuff?
39261 if (node.nodeName == "#comment") {
39262 node.parentNode.removeChild(node);
39263 // clean up silly Windows -- stuff?
39267 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39269 node.parentNode.removeChild(node);
39273 if (!node.attributes || !node.attributes.length) {
39274 this.cleanUpChildren(node);
39278 function cleanAttr(n,v)
39281 if (v.match(/^\./) || v.match(/^\//)) {
39284 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39287 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39288 node.removeAttribute(n);
39292 function cleanStyle(n,v)
39294 if (v.match(/expression/)) { //XSS?? should we even bother..
39295 node.removeAttribute(n);
39300 var parts = v.split(/;/);
39301 Roo.each(parts, function(p) {
39302 p = p.replace(/\s+/g,'');
39306 var l = p.split(':').shift().replace(/\s+/g,'');
39308 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39309 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39310 node.removeAttribute(n);
39319 for (var i = node.attributes.length-1; i > -1 ; i--) {
39320 var a = node.attributes[i];
39322 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39323 node.removeAttribute(a.name);
39326 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39327 cleanAttr(a.name,a.value); // fixme..
39330 if (a.name == 'style') {
39331 cleanStyle(a.name,a.value);
39333 /// clean up MS crap..
39334 if (a.name == 'class') {
39335 if (a.value.match(/^Mso/)) {
39336 node.className = '';
39346 this.cleanUpChildren(node);
39352 // hide stuff that is not compatible
39366 * @event specialkey
39370 * @cfg {String} fieldClass @hide
39373 * @cfg {String} focusClass @hide
39376 * @cfg {String} autoCreate @hide
39379 * @cfg {String} inputType @hide
39382 * @cfg {String} invalidClass @hide
39385 * @cfg {String} invalidText @hide
39388 * @cfg {String} msgFx @hide
39391 * @cfg {String} validateOnBlur @hide
39395 Roo.form.HtmlEditor.white = [
39396 'area', 'br', 'img', 'input', 'hr', 'wbr',
39398 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39399 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39400 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39401 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39402 'table', 'ul', 'xmp',
39404 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39407 'dir', 'menu', 'ol', 'ul', 'dl',
39413 Roo.form.HtmlEditor.black = [
39414 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39416 'base', 'basefont', 'bgsound', 'blink', 'body',
39417 'frame', 'frameset', 'head', 'html', 'ilayer',
39418 'iframe', 'layer', 'link', 'meta', 'object',
39419 'script', 'style' ,'title', 'xml' // clean later..
39421 Roo.form.HtmlEditor.clean = [
39422 'script', 'style', 'title', 'xml'
39427 Roo.form.HtmlEditor.ablack = [
39431 Roo.form.HtmlEditor.aclean = [
39432 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39436 Roo.form.HtmlEditor.pwhite= [
39437 'http', 'https', 'mailto'
39440 Roo.form.HtmlEditor.cwhite= [
39445 // <script type="text/javascript">
39448 * Ext JS Library 1.1.1
39449 * Copyright(c) 2006-2007, Ext JS, LLC.
39455 * @class Roo.form.HtmlEditorToolbar1
39460 new Roo.form.HtmlEditor({
39463 new Roo.form.HtmlEditorToolbar1({
39464 disable : { fonts: 1 , format: 1, ..., ... , ...],
39470 * @cfg {Object} disable List of elements to disable..
39471 * @cfg {Array} btns List of additional buttons.
39475 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39478 Roo.form.HtmlEditor.ToolbarStandard = function(config)
39481 Roo.apply(this, config);
39482 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39483 // dont call parent... till later.
39486 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
39494 * @cfg {Object} disable List of toolbar elements to disable
39499 * @cfg {Array} fontFamilies An array of available font families
39517 // "á" , ?? a acute?
39522 "°" // , // degrees
39524 // "é" , // e ecute
39525 // "ú" , // u ecute?
39528 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
39529 "input:submit", "input:button", "select", "textarea", "label" ],
39532 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
39534 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39537 * @cfg {String} defaultFont default font to use.
39539 defaultFont: 'tahoma',
39541 fontSelect : false,
39544 formatCombo : false,
39546 init : function(editor)
39548 this.editor = editor;
39551 var fid = editor.frameId;
39553 function btn(id, toggle, handler){
39554 var xid = fid + '-'+ id ;
39558 cls : 'x-btn-icon x-edit-'+id,
39559 enableToggle:toggle !== false,
39560 scope: editor, // was editor...
39561 handler:handler||editor.relayBtnCmd,
39562 clickEvent:'mousedown',
39563 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39570 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
39572 // stop form submits
39573 tb.el.on('click', function(e){
39574 e.preventDefault(); // what does this do?
39577 if(!this.disable.font && !Roo.isSafari){
39578 /* why no safari for fonts
39579 editor.fontSelect = tb.el.createChild({
39582 cls:'x-font-select',
39583 html: editor.createFontOptions()
39585 editor.fontSelect.on('change', function(){
39586 var font = editor.fontSelect.dom.value;
39587 editor.relayCmd('fontname', font);
39588 editor.deferFocus();
39591 editor.fontSelect.dom,
39596 if(!this.disable.formats){
39597 this.formatCombo = new Roo.form.ComboBox({
39598 store: new Roo.data.SimpleStore({
39601 data : this.formats // from states.js
39604 //autoCreate : {tag: "div", size: "20"},
39605 displayField:'tag',
39609 triggerAction: 'all',
39610 emptyText:'Add tag',
39611 selectOnFocus:true,
39614 'select': function(c, r, i) {
39615 editor.insertTag(r.get('tag'));
39621 tb.addField(this.formatCombo);
39625 if(!this.disable.format){
39632 if(!this.disable.fontSize){
39637 btn('increasefontsize', false, editor.adjustFont),
39638 btn('decreasefontsize', false, editor.adjustFont)
39643 if(this.disable.colors){
39646 id:editor.frameId +'-forecolor',
39647 cls:'x-btn-icon x-edit-forecolor',
39648 clickEvent:'mousedown',
39649 tooltip: this.buttonTips['forecolor'] || undefined,
39651 menu : new Roo.menu.ColorMenu({
39652 allowReselect: true,
39653 focus: Roo.emptyFn,
39656 selectHandler: function(cp, color){
39657 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
39658 editor.deferFocus();
39661 clickEvent:'mousedown'
39664 id:editor.frameId +'backcolor',
39665 cls:'x-btn-icon x-edit-backcolor',
39666 clickEvent:'mousedown',
39667 tooltip: this.buttonTips['backcolor'] || undefined,
39669 menu : new Roo.menu.ColorMenu({
39670 focus: Roo.emptyFn,
39673 allowReselect: true,
39674 selectHandler: function(cp, color){
39676 editor.execCmd('useCSS', false);
39677 editor.execCmd('hilitecolor', color);
39678 editor.execCmd('useCSS', true);
39679 editor.deferFocus();
39681 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
39682 Roo.isSafari || Roo.isIE ? '#'+color : color);
39683 editor.deferFocus();
39687 clickEvent:'mousedown'
39692 // now add all the items...
39695 if(!this.disable.alignments){
39698 btn('justifyleft'),
39699 btn('justifycenter'),
39700 btn('justifyright')
39704 //if(!Roo.isSafari){
39705 if(!this.disable.links){
39708 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
39712 if(!this.disable.lists){
39715 btn('insertorderedlist'),
39716 btn('insertunorderedlist')
39719 if(!this.disable.sourceEdit){
39722 btn('sourceedit', true, function(btn){
39723 this.toggleSourceEdit(btn.pressed);
39730 // special menu.. - needs to be tidied up..
39731 if (!this.disable.special) {
39734 cls: 'x-edit-none',
39739 for (var i =0; i < this.specialChars.length; i++) {
39740 smenu.menu.items.push({
39742 html: this.specialChars[i],
39743 handler: function(a,b) {
39744 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
39757 for(var i =0; i< this.btns.length;i++) {
39758 var b = this.btns[i];
39759 b.cls = 'x-edit-none';
39768 // disable everything...
39770 this.tb.items.each(function(item){
39771 if(item.id != editor.frameId+ '-sourceedit'){
39775 this.rendered = true;
39777 // the all the btns;
39778 editor.on('editorevent', this.updateToolbar, this);
39779 // other toolbars need to implement this..
39780 //editor.on('editmodechange', this.updateToolbar, this);
39786 * Protected method that will not generally be called directly. It triggers
39787 * a toolbar update by reading the markup state of the current selection in the editor.
39789 updateToolbar: function(){
39791 if(!this.editor.activated){
39792 this.editor.onFirstFocus();
39796 var btns = this.tb.items.map,
39797 doc = this.editor.doc,
39798 frameId = this.editor.frameId;
39800 if(!this.disable.font && !Roo.isSafari){
39802 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39803 if(name != this.fontSelect.dom.value){
39804 this.fontSelect.dom.value = name;
39808 if(!this.disable.format){
39809 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39810 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39811 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39813 if(!this.disable.alignments){
39814 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39815 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39816 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39818 if(!Roo.isSafari && !this.disable.lists){
39819 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39820 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39823 var ans = this.editor.getAllAncestors();
39824 if (this.formatCombo) {
39827 var store = this.formatCombo.store;
39828 this.formatCombo.setValue("");
39829 for (var i =0; i < ans.length;i++) {
39830 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
39832 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39840 // hides menus... - so this cant be on a menu...
39841 Roo.menu.MenuMgr.hideAll();
39843 //this.editorsyncValue();
39847 createFontOptions : function(){
39848 var buf = [], fs = this.fontFamilies, ff, lc;
39849 for(var i = 0, len = fs.length; i< len; i++){
39851 lc = ff.toLowerCase();
39853 '<option value="',lc,'" style="font-family:',ff,';"',
39854 (this.defaultFont == lc ? ' selected="true">' : '>'),
39859 return buf.join('');
39862 toggleSourceEdit : function(sourceEditMode){
39863 if(sourceEditMode === undefined){
39864 sourceEditMode = !this.sourceEditMode;
39866 this.sourceEditMode = sourceEditMode === true;
39867 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39868 // just toggle the button?
39869 if(btn.pressed !== this.editor.sourceEditMode){
39870 btn.toggle(this.editor.sourceEditMode);
39874 if(this.sourceEditMode){
39875 this.tb.items.each(function(item){
39876 if(item.cmd != 'sourceedit'){
39882 if(this.initialized){
39883 this.tb.items.each(function(item){
39889 // tell the editor that it's been pressed..
39890 this.editor.toggleSourceEdit(sourceEditMode);
39894 * Object collection of toolbar tooltips for the buttons in the editor. The key
39895 * is the command id associated with that button and the value is a valid QuickTips object.
39900 title: 'Bold (Ctrl+B)',
39901 text: 'Make the selected text bold.',
39902 cls: 'x-html-editor-tip'
39905 title: 'Italic (Ctrl+I)',
39906 text: 'Make the selected text italic.',
39907 cls: 'x-html-editor-tip'
39915 title: 'Bold (Ctrl+B)',
39916 text: 'Make the selected text bold.',
39917 cls: 'x-html-editor-tip'
39920 title: 'Italic (Ctrl+I)',
39921 text: 'Make the selected text italic.',
39922 cls: 'x-html-editor-tip'
39925 title: 'Underline (Ctrl+U)',
39926 text: 'Underline the selected text.',
39927 cls: 'x-html-editor-tip'
39929 increasefontsize : {
39930 title: 'Grow Text',
39931 text: 'Increase the font size.',
39932 cls: 'x-html-editor-tip'
39934 decreasefontsize : {
39935 title: 'Shrink Text',
39936 text: 'Decrease the font size.',
39937 cls: 'x-html-editor-tip'
39940 title: 'Text Highlight Color',
39941 text: 'Change the background color of the selected text.',
39942 cls: 'x-html-editor-tip'
39945 title: 'Font Color',
39946 text: 'Change the color of the selected text.',
39947 cls: 'x-html-editor-tip'
39950 title: 'Align Text Left',
39951 text: 'Align text to the left.',
39952 cls: 'x-html-editor-tip'
39955 title: 'Center Text',
39956 text: 'Center text in the editor.',
39957 cls: 'x-html-editor-tip'
39960 title: 'Align Text Right',
39961 text: 'Align text to the right.',
39962 cls: 'x-html-editor-tip'
39964 insertunorderedlist : {
39965 title: 'Bullet List',
39966 text: 'Start a bulleted list.',
39967 cls: 'x-html-editor-tip'
39969 insertorderedlist : {
39970 title: 'Numbered List',
39971 text: 'Start a numbered list.',
39972 cls: 'x-html-editor-tip'
39975 title: 'Hyperlink',
39976 text: 'Make the selected text a hyperlink.',
39977 cls: 'x-html-editor-tip'
39980 title: 'Source Edit',
39981 text: 'Switch to source editing mode.',
39982 cls: 'x-html-editor-tip'
39986 onDestroy : function(){
39989 this.tb.items.each(function(item){
39991 item.menu.removeAll();
39993 item.menu.el.destroy();
40001 onFirstFocus: function() {
40002 this.tb.items.each(function(item){
40011 // <script type="text/javascript">
40014 * Ext JS Library 1.1.1
40015 * Copyright(c) 2006-2007, Ext JS, LLC.
40022 * @class Roo.form.HtmlEditor.ToolbarContext
40027 new Roo.form.HtmlEditor({
40030 new Roo.form.HtmlEditor.ToolbarStandard(),
40031 new Roo.form.HtmlEditor.ToolbarContext()
40036 * @config : {Object} disable List of elements to disable.. (not done yet.)
40041 Roo.form.HtmlEditor.ToolbarContext = function(config)
40044 Roo.apply(this, config);
40045 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
40046 // dont call parent... till later.
40048 Roo.form.HtmlEditor.ToolbarContext.types = {
40060 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
40122 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
40127 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40191 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40199 * @cfg {Object} disable List of toolbar elements to disable
40208 init : function(editor)
40210 this.editor = editor;
40213 var fid = editor.frameId;
40215 function btn(id, toggle, handler){
40216 var xid = fid + '-'+ id ;
40220 cls : 'x-btn-icon x-edit-'+id,
40221 enableToggle:toggle !== false,
40222 scope: editor, // was editor...
40223 handler:handler||editor.relayBtnCmd,
40224 clickEvent:'mousedown',
40225 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40229 // create a new element.
40230 var wdiv = editor.wrap.createChild({
40232 }, editor.wrap.dom.firstChild.nextSibling, true);
40234 // can we do this more than once??
40236 // stop form submits
40239 // disable everything...
40240 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40241 this.toolbars = {};
40243 for (var i in ty) {
40245 this.toolbars[i] = this.buildToolbar(ty[i],i);
40247 this.tb = this.toolbars.BODY;
40251 this.rendered = true;
40253 // the all the btns;
40254 editor.on('editorevent', this.updateToolbar, this);
40255 // other toolbars need to implement this..
40256 //editor.on('editmodechange', this.updateToolbar, this);
40262 * Protected method that will not generally be called directly. It triggers
40263 * a toolbar update by reading the markup state of the current selection in the editor.
40265 updateToolbar: function(){
40267 if(!this.editor.activated){
40268 this.editor.onFirstFocus();
40273 var ans = this.editor.getAllAncestors();
40276 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40277 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40278 sel = sel ? sel : this.editor.doc.body;
40279 sel = sel.tagName.length ? sel : this.editor.doc.body;
40280 var tn = sel.tagName.toUpperCase();
40281 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40282 tn = sel.tagName.toUpperCase();
40283 if (this.tb.name == tn) {
40284 return; // no change
40287 ///console.log("show: " + tn);
40288 this.tb = this.toolbars[tn];
40290 this.tb.fields.each(function(e) {
40291 e.setValue(sel.getAttribute(e.name));
40293 this.tb.selectedNode = sel;
40296 Roo.menu.MenuMgr.hideAll();
40298 //this.editorsyncValue();
40303 onDestroy : function(){
40306 this.tb.items.each(function(item){
40308 item.menu.removeAll();
40310 item.menu.el.destroy();
40318 onFirstFocus: function() {
40319 // need to do this for all the toolbars..
40320 this.tb.items.each(function(item){
40324 buildToolbar: function(tlist, nm)
40326 var editor = this.editor;
40327 // create a new element.
40328 var wdiv = editor.wrap.createChild({
40330 }, editor.wrap.dom.firstChild.nextSibling, true);
40333 var tb = new Roo.Toolbar(wdiv);
40334 tb.add(nm+ ": ");
40335 for (var i in tlist) {
40336 var item = tlist[i];
40337 tb.add(item.title + ": ");
40342 tb.addField( new Roo.form.ComboBox({
40343 store: new Roo.data.SimpleStore({
40346 data : item.opts // from states.js
40349 displayField:'val',
40353 triggerAction: 'all',
40354 emptyText:'Select',
40355 selectOnFocus:true,
40356 width: item.width ? item.width : 130,
40358 'select': function(c, r, i) {
40359 tb.selectedNode.setAttribute(c.name, r.get('val'));
40370 tb.addField( new Roo.form.TextField({
40373 //allowBlank:false,
40378 tb.addField( new Roo.form.TextField({
40384 'change' : function(f, nv, ov) {
40385 tb.selectedNode.setAttribute(f.name, nv);
40391 tb.el.on('click', function(e){
40392 e.preventDefault(); // what does this do?
40394 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40397 // dont need to disable them... as they will get hidden
40414 * Ext JS Library 1.1.1
40415 * Copyright(c) 2006-2007, Ext JS, LLC.
40417 * Originally Released Under LGPL - original licence link has changed is not relivant.
40420 * <script type="text/javascript">
40424 * @class Roo.form.BasicForm
40425 * @extends Roo.util.Observable
40426 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
40428 * @param {String/HTMLElement/Roo.Element} el The form element or its id
40429 * @param {Object} config Configuration options
40431 Roo.form.BasicForm = function(el, config){
40432 this.allItems = [];
40433 this.childForms = [];
40434 Roo.apply(this, config);
40436 * The Roo.form.Field items in this form.
40437 * @type MixedCollection
40441 this.items = new Roo.util.MixedCollection(false, function(o){
40442 return o.id || (o.id = Roo.id());
40446 * @event beforeaction
40447 * Fires before any action is performed. Return false to cancel the action.
40448 * @param {Form} this
40449 * @param {Action} action The action to be performed
40451 beforeaction: true,
40453 * @event actionfailed
40454 * Fires when an action fails.
40455 * @param {Form} this
40456 * @param {Action} action The action that failed
40458 actionfailed : true,
40460 * @event actioncomplete
40461 * Fires when an action is completed.
40462 * @param {Form} this
40463 * @param {Action} action The action that completed
40465 actioncomplete : true
40470 Roo.form.BasicForm.superclass.constructor.call(this);
40473 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
40475 * @cfg {String} method
40476 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
40479 * @cfg {DataReader} reader
40480 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
40481 * This is optional as there is built-in support for processing JSON.
40484 * @cfg {DataReader} errorReader
40485 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
40486 * This is completely optional as there is built-in support for processing JSON.
40489 * @cfg {String} url
40490 * The URL to use for form actions if one isn't supplied in the action options.
40493 * @cfg {Boolean} fileUpload
40494 * Set to true if this form is a file upload.
40498 * @cfg {Object} baseParams
40499 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
40504 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
40509 activeAction : null,
40512 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
40513 * or setValues() data instead of when the form was first created.
40515 trackResetOnLoad : false,
40519 * childForms - used for multi-tab forms
40522 childForms : false,
40525 * allItems - full list of fields.
40531 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
40532 * element by passing it or its id or mask the form itself by passing in true.
40535 waitMsgTarget : false,
40538 initEl : function(el){
40539 this.el = Roo.get(el);
40540 this.id = this.el.id || Roo.id();
40541 this.el.on('submit', this.onSubmit, this);
40542 this.el.addClass('x-form');
40546 onSubmit : function(e){
40551 * Returns true if client-side validation on the form is successful.
40554 isValid : function(){
40556 this.items.each(function(f){
40565 * Returns true if any fields in this form have changed since their original load.
40568 isDirty : function(){
40570 this.items.each(function(f){
40580 * Performs a predefined action (submit or load) or custom actions you define on this form.
40581 * @param {String} actionName The name of the action type
40582 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
40583 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
40584 * accept other config options):
40586 Property Type Description
40587 ---------------- --------------- ----------------------------------------------------------------------------------
40588 url String The url for the action (defaults to the form's url)
40589 method String The form method to use (defaults to the form's method, or POST if not defined)
40590 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
40591 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
40592 validate the form on the client (defaults to false)
40594 * @return {BasicForm} this
40596 doAction : function(action, options){
40597 if(typeof action == 'string'){
40598 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
40600 if(this.fireEvent('beforeaction', this, action) !== false){
40601 this.beforeAction(action);
40602 action.run.defer(100, action);
40608 * Shortcut to do a submit action.
40609 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40610 * @return {BasicForm} this
40612 submit : function(options){
40613 this.doAction('submit', options);
40618 * Shortcut to do a load action.
40619 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40620 * @return {BasicForm} this
40622 load : function(options){
40623 this.doAction('load', options);
40628 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
40629 * @param {Record} record The record to edit
40630 * @return {BasicForm} this
40632 updateRecord : function(record){
40633 record.beginEdit();
40634 var fs = record.fields;
40635 fs.each(function(f){
40636 var field = this.findField(f.name);
40638 record.set(f.name, field.getValue());
40646 * Loads an Roo.data.Record into this form.
40647 * @param {Record} record The record to load
40648 * @return {BasicForm} this
40650 loadRecord : function(record){
40651 this.setValues(record.data);
40656 beforeAction : function(action){
40657 var o = action.options;
40660 if(this.waitMsgTarget === true){
40661 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
40662 }else if(this.waitMsgTarget){
40663 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
40664 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
40666 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
40672 afterAction : function(action, success){
40673 this.activeAction = null;
40674 var o = action.options;
40676 if(this.waitMsgTarget === true){
40678 }else if(this.waitMsgTarget){
40679 this.waitMsgTarget.unmask();
40681 Roo.MessageBox.updateProgress(1);
40682 Roo.MessageBox.hide();
40689 Roo.callback(o.success, o.scope, [this, action]);
40690 this.fireEvent('actioncomplete', this, action);
40693 Roo.callback(o.failure, o.scope, [this, action]);
40694 // show an error message if no failed handler is set..
40695 if (!this.hasListener('actionfailed')) {
40696 Roo.MessageBox.alert("Error", "Saving Failed, please check your entries");
40699 this.fireEvent('actionfailed', this, action);
40705 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
40706 * @param {String} id The value to search for
40709 findField : function(id){
40710 var field = this.items.get(id);
40712 this.items.each(function(f){
40713 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
40719 return field || null;
40723 * Add a secondary form to this one,
40724 * Used to provide tabbed forms. One form is primary, with hidden values
40725 * which mirror the elements from the other forms.
40727 * @param {Roo.form.Form} form to add.
40730 addForm : function(form)
40733 if (this.childForms.indexOf(form) > -1) {
40737 this.childForms.push(form);
40739 Roo.each(form.allItems, function (fe) {
40741 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
40742 if (this.findField(n)) { // already added..
40745 var add = new Roo.form.Hidden({
40748 add.render(this.el);
40755 * Mark fields in this form invalid in bulk.
40756 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
40757 * @return {BasicForm} this
40759 markInvalid : function(errors){
40760 if(errors instanceof Array){
40761 for(var i = 0, len = errors.length; i < len; i++){
40762 var fieldError = errors[i];
40763 var f = this.findField(fieldError.id);
40765 f.markInvalid(fieldError.msg);
40771 if(typeof errors[id] != 'function' && (field = this.findField(id))){
40772 field.markInvalid(errors[id]);
40776 Roo.each(this.childForms || [], function (f) {
40777 f.markInvalid(errors);
40784 * Set values for fields in this form in bulk.
40785 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
40786 * @return {BasicForm} this
40788 setValues : function(values){
40789 if(values instanceof Array){ // array of objects
40790 for(var i = 0, len = values.length; i < len; i++){
40792 var f = this.findField(v.id);
40794 f.setValue(v.value);
40795 if(this.trackResetOnLoad){
40796 f.originalValue = f.getValue();
40800 }else{ // object hash
40803 if(typeof values[id] != 'function' && (field = this.findField(id))){
40805 if (field.setFromData &&
40806 field.valueField &&
40807 field.displayField &&
40808 // combos' with local stores can
40809 // be queried via setValue()
40810 // to set their value..
40811 (field.store && !field.store.isLocal)
40815 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40816 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40817 field.setFromData(sd);
40820 field.setValue(values[id]);
40824 if(this.trackResetOnLoad){
40825 field.originalValue = field.getValue();
40831 Roo.each(this.childForms || [], function (f) {
40832 f.setValues(values);
40839 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40840 * they are returned as an array.
40841 * @param {Boolean} asString
40844 getValues : function(asString){
40845 if (this.childForms) {
40846 // copy values from the child forms
40847 Roo.each(this.childForms, function (f) {
40848 this.setValues(f.getValues());
40854 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40855 if(asString === true){
40858 return Roo.urlDecode(fs);
40862 * Returns the fields in this form as an object with key/value pairs.
40863 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
40866 getFieldValues : function()
40868 if (this.childForms) {
40869 // copy values from the child forms
40870 Roo.each(this.childForms, function (f) {
40871 this.setValues(f.getValues());
40876 this.items.each(function(f){
40877 if (!f.getName()) {
40880 var v = f.getValue();
40881 if ((typeof(v) == 'object') && f.getRawValue) {
40882 v = f.getRawValue() ; // dates..
40884 ret[f.getName()] = v;
40891 * Clears all invalid messages in this form.
40892 * @return {BasicForm} this
40894 clearInvalid : function(){
40895 this.items.each(function(f){
40899 Roo.each(this.childForms || [], function (f) {
40908 * Resets this form.
40909 * @return {BasicForm} this
40911 reset : function(){
40912 this.items.each(function(f){
40916 Roo.each(this.childForms || [], function (f) {
40925 * Add Roo.form components to this form.
40926 * @param {Field} field1
40927 * @param {Field} field2 (optional)
40928 * @param {Field} etc (optional)
40929 * @return {BasicForm} this
40932 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40938 * Removes a field from the items collection (does NOT remove its markup).
40939 * @param {Field} field
40940 * @return {BasicForm} this
40942 remove : function(field){
40943 this.items.remove(field);
40948 * Looks at the fields in this form, checks them for an id attribute,
40949 * and calls applyTo on the existing dom element with that id.
40950 * @return {BasicForm} this
40952 render : function(){
40953 this.items.each(function(f){
40954 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40962 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40963 * @param {Object} values
40964 * @return {BasicForm} this
40966 applyToFields : function(o){
40967 this.items.each(function(f){
40974 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40975 * @param {Object} values
40976 * @return {BasicForm} this
40978 applyIfToFields : function(o){
40979 this.items.each(function(f){
40987 Roo.BasicForm = Roo.form.BasicForm;/*
40989 * Ext JS Library 1.1.1
40990 * Copyright(c) 2006-2007, Ext JS, LLC.
40992 * Originally Released Under LGPL - original licence link has changed is not relivant.
40995 * <script type="text/javascript">
40999 * @class Roo.form.Form
41000 * @extends Roo.form.BasicForm
41001 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
41003 * @param {Object} config Configuration options
41005 Roo.form.Form = function(config){
41007 if (config.items) {
41008 xitems = config.items;
41009 delete config.items;
41013 Roo.form.Form.superclass.constructor.call(this, null, config);
41014 this.url = this.url || this.action;
41016 this.root = new Roo.form.Layout(Roo.applyIf({
41020 this.active = this.root;
41022 * Array of all the buttons that have been added to this form via {@link addButton}
41026 this.allItems = [];
41029 * @event clientvalidation
41030 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
41031 * @param {Form} this
41032 * @param {Boolean} valid true if the form has passed client-side validation
41034 clientvalidation: true,
41037 * Fires when the form is rendered
41038 * @param {Roo.form.Form} form
41043 if (this.progressUrl) {
41044 // push a hidden field onto the list of fields..
41048 name : 'UPLOAD_IDENTIFIER'
41053 Roo.each(xitems, this.addxtype, this);
41059 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
41061 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
41064 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
41067 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
41069 buttonAlign:'center',
41072 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
41077 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
41078 * This property cascades to child containers if not set.
41083 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
41084 * fires a looping event with that state. This is required to bind buttons to the valid
41085 * state using the config value formBind:true on the button.
41087 monitorValid : false,
41090 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
41095 * @cfg {String} progressUrl - Url to return progress data
41098 progressUrl : false,
41101 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
41102 * fields are added and the column is closed. If no fields are passed the column remains open
41103 * until end() is called.
41104 * @param {Object} config The config to pass to the column
41105 * @param {Field} field1 (optional)
41106 * @param {Field} field2 (optional)
41107 * @param {Field} etc (optional)
41108 * @return Column The column container object
41110 column : function(c){
41111 var col = new Roo.form.Column(c);
41113 if(arguments.length > 1){ // duplicate code required because of Opera
41114 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41121 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
41122 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
41123 * until end() is called.
41124 * @param {Object} config The config to pass to the fieldset
41125 * @param {Field} field1 (optional)
41126 * @param {Field} field2 (optional)
41127 * @param {Field} etc (optional)
41128 * @return FieldSet The fieldset container object
41130 fieldset : function(c){
41131 var fs = new Roo.form.FieldSet(c);
41133 if(arguments.length > 1){ // duplicate code required because of Opera
41134 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41141 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
41142 * fields are added and the container is closed. If no fields are passed the container remains open
41143 * until end() is called.
41144 * @param {Object} config The config to pass to the Layout
41145 * @param {Field} field1 (optional)
41146 * @param {Field} field2 (optional)
41147 * @param {Field} etc (optional)
41148 * @return Layout The container object
41150 container : function(c){
41151 var l = new Roo.form.Layout(c);
41153 if(arguments.length > 1){ // duplicate code required because of Opera
41154 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41161 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41162 * @param {Object} container A Roo.form.Layout or subclass of Layout
41163 * @return {Form} this
41165 start : function(c){
41166 // cascade label info
41167 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
41168 this.active.stack.push(c);
41169 c.ownerCt = this.active;
41175 * Closes the current open container
41176 * @return {Form} this
41179 if(this.active == this.root){
41182 this.active = this.active.ownerCt;
41187 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
41188 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
41189 * as the label of the field.
41190 * @param {Field} field1
41191 * @param {Field} field2 (optional)
41192 * @param {Field} etc. (optional)
41193 * @return {Form} this
41196 this.active.stack.push.apply(this.active.stack, arguments);
41197 this.allItems.push.apply(this.allItems,arguments);
41199 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
41200 if(a[i].isFormField){
41205 Roo.form.Form.superclass.add.apply(this, r);
41215 * Find any element that has been added to a form, using it's ID or name
41216 * This can include framesets, columns etc. along with regular fields..
41217 * @param {String} id - id or name to find.
41219 * @return {Element} e - or false if nothing found.
41221 findbyId : function(id)
41227 Roo.each(this.allItems, function(f){
41228 if (f.id == id || f.name == id ){
41239 * Render this form into the passed container. This should only be called once!
41240 * @param {String/HTMLElement/Element} container The element this component should be rendered into
41241 * @return {Form} this
41243 render : function(ct)
41249 var o = this.autoCreate || {
41251 method : this.method || 'POST',
41252 id : this.id || Roo.id()
41254 this.initEl(ct.createChild(o));
41256 this.root.render(this.el);
41260 this.items.each(function(f){
41261 f.render('x-form-el-'+f.id);
41264 if(this.buttons.length > 0){
41265 // tables are required to maintain order and for correct IE layout
41266 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
41267 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
41268 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
41270 var tr = tb.getElementsByTagName('tr')[0];
41271 for(var i = 0, len = this.buttons.length; i < len; i++) {
41272 var b = this.buttons[i];
41273 var td = document.createElement('td');
41274 td.className = 'x-form-btn-td';
41275 b.render(tr.appendChild(td));
41278 if(this.monitorValid){ // initialize after render
41279 this.startMonitoring();
41281 this.fireEvent('rendered', this);
41286 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
41287 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
41288 * object or a valid Roo.DomHelper element config
41289 * @param {Function} handler The function called when the button is clicked
41290 * @param {Object} scope (optional) The scope of the handler function
41291 * @return {Roo.Button}
41293 addButton : function(config, handler, scope){
41297 minWidth: this.minButtonWidth,
41300 if(typeof config == "string"){
41303 Roo.apply(bc, config);
41305 var btn = new Roo.Button(null, bc);
41306 this.buttons.push(btn);
41311 * Adds a series of form elements (using the xtype property as the factory method.
41312 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41313 * @param {Object} config
41316 addxtype : function()
41318 var ar = Array.prototype.slice.call(arguments, 0);
41320 for(var i = 0; i < ar.length; i++) {
41322 continue; // skip -- if this happends something invalid got sent, we
41323 // should ignore it, as basically that interface element will not show up
41324 // and that should be pretty obvious!!
41327 if (Roo.form[ar[i].xtype]) {
41329 var fe = Roo.factory(ar[i], Roo.form);
41335 fe.store.form = this;
41340 this.allItems.push(fe);
41341 if (fe.items && fe.addxtype) {
41342 fe.addxtype.apply(fe, fe.items);
41352 // console.log('adding ' + ar[i].xtype);
41354 if (ar[i].xtype == 'Button') {
41355 //console.log('adding button');
41356 //console.log(ar[i]);
41357 this.addButton(ar[i]);
41358 this.allItems.push(fe);
41362 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
41363 alert('end is not supported on xtype any more, use items');
41365 // //console.log('adding end');
41373 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
41374 * option "monitorValid"
41376 startMonitoring : function(){
41379 Roo.TaskMgr.start({
41380 run : this.bindHandler,
41381 interval : this.monitorPoll || 200,
41388 * Stops monitoring of the valid state of this form
41390 stopMonitoring : function(){
41391 this.bound = false;
41395 bindHandler : function(){
41397 return false; // stops binding
41400 this.items.each(function(f){
41401 if(!f.isValid(true)){
41406 for(var i = 0, len = this.buttons.length; i < len; i++){
41407 var btn = this.buttons[i];
41408 if(btn.formBind === true && btn.disabled === valid){
41409 btn.setDisabled(!valid);
41412 this.fireEvent('clientvalidation', this, valid);
41426 Roo.Form = Roo.form.Form;
41429 * Ext JS Library 1.1.1
41430 * Copyright(c) 2006-2007, Ext JS, LLC.
41432 * Originally Released Under LGPL - original licence link has changed is not relivant.
41435 * <script type="text/javascript">
41439 * @class Roo.form.Action
41440 * Internal Class used to handle form actions
41442 * @param {Roo.form.BasicForm} el The form element or its id
41443 * @param {Object} config Configuration options
41447 // define the action interface
41448 Roo.form.Action = function(form, options){
41450 this.options = options || {};
41453 * Client Validation Failed
41456 Roo.form.Action.CLIENT_INVALID = 'client';
41458 * Server Validation Failed
41461 Roo.form.Action.SERVER_INVALID = 'server';
41463 * Connect to Server Failed
41466 Roo.form.Action.CONNECT_FAILURE = 'connect';
41468 * Reading Data from Server Failed
41471 Roo.form.Action.LOAD_FAILURE = 'load';
41473 Roo.form.Action.prototype = {
41475 failureType : undefined,
41476 response : undefined,
41477 result : undefined,
41479 // interface method
41480 run : function(options){
41484 // interface method
41485 success : function(response){
41489 // interface method
41490 handleResponse : function(response){
41494 // default connection failure
41495 failure : function(response){
41497 this.response = response;
41498 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41499 this.form.afterAction(this, false);
41502 processResponse : function(response){
41503 this.response = response;
41504 if(!response.responseText){
41507 this.result = this.handleResponse(response);
41508 return this.result;
41511 // utility functions used internally
41512 getUrl : function(appendParams){
41513 var url = this.options.url || this.form.url || this.form.el.dom.action;
41515 var p = this.getParams();
41517 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
41523 getMethod : function(){
41524 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
41527 getParams : function(){
41528 var bp = this.form.baseParams;
41529 var p = this.options.params;
41531 if(typeof p == "object"){
41532 p = Roo.urlEncode(Roo.applyIf(p, bp));
41533 }else if(typeof p == 'string' && bp){
41534 p += '&' + Roo.urlEncode(bp);
41537 p = Roo.urlEncode(bp);
41542 createCallback : function(){
41544 success: this.success,
41545 failure: this.failure,
41547 timeout: (this.form.timeout*1000),
41548 upload: this.form.fileUpload ? this.success : undefined
41553 Roo.form.Action.Submit = function(form, options){
41554 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
41557 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
41560 haveProgress : false,
41561 uploadComplete : false,
41563 // uploadProgress indicator.
41564 uploadProgress : function()
41566 if (!this.form.progressUrl) {
41570 if (!this.haveProgress) {
41571 Roo.MessageBox.progress("Uploading", "Uploading");
41573 if (this.uploadComplete) {
41574 Roo.MessageBox.hide();
41578 this.haveProgress = true;
41580 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
41582 var c = new Roo.data.Connection();
41584 url : this.form.progressUrl,
41589 success : function(req){
41590 //console.log(data);
41594 rdata = Roo.decode(req.responseText)
41596 Roo.log("Invalid data from server..");
41600 if (!rdata || !rdata.success) {
41604 var data = rdata.data;
41606 if (this.uploadComplete) {
41607 Roo.MessageBox.hide();
41612 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
41613 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
41616 this.uploadProgress.defer(2000,this);
41619 failure: function(data) {
41620 Roo.log('progress url failed ');
41631 // run get Values on the form, so it syncs any secondary forms.
41632 this.form.getValues();
41634 var o = this.options;
41635 var method = this.getMethod();
41636 var isPost = method == 'POST';
41637 if(o.clientValidation === false || this.form.isValid()){
41639 if (this.form.progressUrl) {
41640 this.form.findField('UPLOAD_IDENTIFIER').setValue(
41641 (new Date() * 1) + '' + Math.random());
41646 Roo.Ajax.request(Roo.apply(this.createCallback(), {
41647 form:this.form.el.dom,
41648 url:this.getUrl(!isPost),
41650 params:isPost ? this.getParams() : null,
41651 isUpload: this.form.fileUpload
41654 this.uploadProgress();
41656 }else if (o.clientValidation !== false){ // client validation failed
41657 this.failureType = Roo.form.Action.CLIENT_INVALID;
41658 this.form.afterAction(this, false);
41662 success : function(response)
41664 this.uploadComplete= true;
41665 if (this.haveProgress) {
41666 Roo.MessageBox.hide();
41670 var result = this.processResponse(response);
41671 if(result === true || result.success){
41672 this.form.afterAction(this, true);
41676 this.form.markInvalid(result.errors);
41677 this.failureType = Roo.form.Action.SERVER_INVALID;
41679 this.form.afterAction(this, false);
41681 failure : function(response)
41683 this.uploadComplete= true;
41684 if (this.haveProgress) {
41685 Roo.MessageBox.hide();
41689 this.response = response;
41690 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41691 this.form.afterAction(this, false);
41694 handleResponse : function(response){
41695 if(this.form.errorReader){
41696 var rs = this.form.errorReader.read(response);
41699 for(var i = 0, len = rs.records.length; i < len; i++) {
41700 var r = rs.records[i];
41701 errors[i] = r.data;
41704 if(errors.length < 1){
41708 success : rs.success,
41714 ret = Roo.decode(response.responseText);
41718 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
41728 Roo.form.Action.Load = function(form, options){
41729 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
41730 this.reader = this.form.reader;
41733 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
41738 Roo.Ajax.request(Roo.apply(
41739 this.createCallback(), {
41740 method:this.getMethod(),
41741 url:this.getUrl(false),
41742 params:this.getParams()
41746 success : function(response){
41748 var result = this.processResponse(response);
41749 if(result === true || !result.success || !result.data){
41750 this.failureType = Roo.form.Action.LOAD_FAILURE;
41751 this.form.afterAction(this, false);
41754 this.form.clearInvalid();
41755 this.form.setValues(result.data);
41756 this.form.afterAction(this, true);
41759 handleResponse : function(response){
41760 if(this.form.reader){
41761 var rs = this.form.reader.read(response);
41762 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
41764 success : rs.success,
41768 return Roo.decode(response.responseText);
41772 Roo.form.Action.ACTION_TYPES = {
41773 'load' : Roo.form.Action.Load,
41774 'submit' : Roo.form.Action.Submit
41777 * Ext JS Library 1.1.1
41778 * Copyright(c) 2006-2007, Ext JS, LLC.
41780 * Originally Released Under LGPL - original licence link has changed is not relivant.
41783 * <script type="text/javascript">
41787 * @class Roo.form.Layout
41788 * @extends Roo.Component
41789 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
41791 * @param {Object} config Configuration options
41793 Roo.form.Layout = function(config){
41795 if (config.items) {
41796 xitems = config.items;
41797 delete config.items;
41799 Roo.form.Layout.superclass.constructor.call(this, config);
41801 Roo.each(xitems, this.addxtype, this);
41805 Roo.extend(Roo.form.Layout, Roo.Component, {
41807 * @cfg {String/Object} autoCreate
41808 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
41811 * @cfg {String/Object/Function} style
41812 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
41813 * a function which returns such a specification.
41816 * @cfg {String} labelAlign
41817 * Valid values are "left," "top" and "right" (defaults to "left")
41820 * @cfg {Number} labelWidth
41821 * Fixed width in pixels of all field labels (defaults to undefined)
41824 * @cfg {Boolean} clear
41825 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
41829 * @cfg {String} labelSeparator
41830 * The separator to use after field labels (defaults to ':')
41832 labelSeparator : ':',
41834 * @cfg {Boolean} hideLabels
41835 * True to suppress the display of field labels in this layout (defaults to false)
41837 hideLabels : false,
41840 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
41845 onRender : function(ct, position){
41846 if(this.el){ // from markup
41847 this.el = Roo.get(this.el);
41848 }else { // generate
41849 var cfg = this.getAutoCreate();
41850 this.el = ct.createChild(cfg, position);
41853 this.el.applyStyles(this.style);
41855 if(this.labelAlign){
41856 this.el.addClass('x-form-label-'+this.labelAlign);
41858 if(this.hideLabels){
41859 this.labelStyle = "display:none";
41860 this.elementStyle = "padding-left:0;";
41862 if(typeof this.labelWidth == 'number'){
41863 this.labelStyle = "width:"+this.labelWidth+"px;";
41864 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
41866 if(this.labelAlign == 'top'){
41867 this.labelStyle = "width:auto;";
41868 this.elementStyle = "padding-left:0;";
41871 var stack = this.stack;
41872 var slen = stack.length;
41874 if(!this.fieldTpl){
41875 var t = new Roo.Template(
41876 '<div class="x-form-item {5}">',
41877 '<label for="{0}" style="{2}">{1}{4}</label>',
41878 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41880 '</div><div class="x-form-clear-left"></div>'
41882 t.disableFormats = true;
41884 Roo.form.Layout.prototype.fieldTpl = t;
41886 for(var i = 0; i < slen; i++) {
41887 if(stack[i].isFormField){
41888 this.renderField(stack[i]);
41890 this.renderComponent(stack[i]);
41895 this.el.createChild({cls:'x-form-clear'});
41900 renderField : function(f){
41901 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
41904 f.labelStyle||this.labelStyle||'', //2
41905 this.elementStyle||'', //3
41906 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
41907 f.itemCls||this.itemCls||'' //5
41908 ], true).getPrevSibling());
41912 renderComponent : function(c){
41913 c.render(c.isLayout ? this.el : this.el.createChild());
41916 * Adds a object form elements (using the xtype property as the factory method.)
41917 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
41918 * @param {Object} config
41920 addxtype : function(o)
41922 // create the lement.
41923 o.form = this.form;
41924 var fe = Roo.factory(o, Roo.form);
41925 this.form.allItems.push(fe);
41926 this.stack.push(fe);
41928 if (fe.isFormField) {
41929 this.form.items.add(fe);
41937 * @class Roo.form.Column
41938 * @extends Roo.form.Layout
41939 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
41941 * @param {Object} config Configuration options
41943 Roo.form.Column = function(config){
41944 Roo.form.Column.superclass.constructor.call(this, config);
41947 Roo.extend(Roo.form.Column, Roo.form.Layout, {
41949 * @cfg {Number/String} width
41950 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41953 * @cfg {String/Object} autoCreate
41954 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41958 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41961 onRender : function(ct, position){
41962 Roo.form.Column.superclass.onRender.call(this, ct, position);
41964 this.el.setWidth(this.width);
41971 * @class Roo.form.Row
41972 * @extends Roo.form.Layout
41973 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41975 * @param {Object} config Configuration options
41979 Roo.form.Row = function(config){
41980 Roo.form.Row.superclass.constructor.call(this, config);
41983 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41985 * @cfg {Number/String} width
41986 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41989 * @cfg {Number/String} height
41990 * The fixed height of the column in pixels or CSS value (defaults to "auto")
41992 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
41996 onRender : function(ct, position){
41997 //console.log('row render');
41999 var t = new Roo.Template(
42000 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
42001 '<label for="{0}" style="{2}">{1}{4}</label>',
42002 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
42006 t.disableFormats = true;
42008 Roo.form.Layout.prototype.rowTpl = t;
42010 this.fieldTpl = this.rowTpl;
42012 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
42013 var labelWidth = 100;
42015 if ((this.labelAlign != 'top')) {
42016 if (typeof this.labelWidth == 'number') {
42017 labelWidth = this.labelWidth
42019 this.padWidth = 20 + labelWidth;
42023 Roo.form.Column.superclass.onRender.call(this, ct, position);
42025 this.el.setWidth(this.width);
42028 this.el.setHeight(this.height);
42033 renderField : function(f){
42034 f.fieldEl = this.fieldTpl.append(this.el, [
42035 f.id, f.fieldLabel,
42036 f.labelStyle||this.labelStyle||'',
42037 this.elementStyle||'',
42038 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
42039 f.itemCls||this.itemCls||'',
42040 f.width ? f.width + this.padWidth : 160 + this.padWidth
42047 * @class Roo.form.FieldSet
42048 * @extends Roo.form.Layout
42049 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
42051 * @param {Object} config Configuration options
42053 Roo.form.FieldSet = function(config){
42054 Roo.form.FieldSet.superclass.constructor.call(this, config);
42057 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
42059 * @cfg {String} legend
42060 * The text to display as the legend for the FieldSet (defaults to '')
42063 * @cfg {String/Object} autoCreate
42064 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
42068 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
42071 onRender : function(ct, position){
42072 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
42074 this.setLegend(this.legend);
42079 setLegend : function(text){
42081 this.el.child('legend').update(text);
42086 * Ext JS Library 1.1.1
42087 * Copyright(c) 2006-2007, Ext JS, LLC.
42089 * Originally Released Under LGPL - original licence link has changed is not relivant.
42092 * <script type="text/javascript">
42095 * @class Roo.form.VTypes
42096 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
42099 Roo.form.VTypes = function(){
42100 // closure these in so they are only created once.
42101 var alpha = /^[a-zA-Z_]+$/;
42102 var alphanum = /^[a-zA-Z0-9_]+$/;
42103 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
42104 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
42106 // All these messages and functions are configurable
42109 * The function used to validate email addresses
42110 * @param {String} value The email address
42112 'email' : function(v){
42113 return email.test(v);
42116 * The error text to display when the email validation function returns false
42119 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
42121 * The keystroke filter mask to be applied on email input
42124 'emailMask' : /[a-z0-9_\.\-@]/i,
42127 * The function used to validate URLs
42128 * @param {String} value The URL
42130 'url' : function(v){
42131 return url.test(v);
42134 * The error text to display when the url validation function returns false
42137 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
42140 * The function used to validate alpha values
42141 * @param {String} value The value
42143 'alpha' : function(v){
42144 return alpha.test(v);
42147 * The error text to display when the alpha validation function returns false
42150 'alphaText' : 'This field should only contain letters and _',
42152 * The keystroke filter mask to be applied on alpha input
42155 'alphaMask' : /[a-z_]/i,
42158 * The function used to validate alphanumeric values
42159 * @param {String} value The value
42161 'alphanum' : function(v){
42162 return alphanum.test(v);
42165 * The error text to display when the alphanumeric validation function returns false
42168 'alphanumText' : 'This field should only contain letters, numbers and _',
42170 * The keystroke filter mask to be applied on alphanumeric input
42173 'alphanumMask' : /[a-z0-9_]/i
42175 }();//<script type="text/javascript">
42178 * @class Roo.form.FCKeditor
42179 * @extends Roo.form.TextArea
42180 * Wrapper around the FCKEditor http://www.fckeditor.net
42182 * Creates a new FCKeditor
42183 * @param {Object} config Configuration options
42185 Roo.form.FCKeditor = function(config){
42186 Roo.form.FCKeditor.superclass.constructor.call(this, config);
42189 * @event editorinit
42190 * Fired when the editor is initialized - you can add extra handlers here..
42191 * @param {FCKeditor} this
42192 * @param {Object} the FCK object.
42199 Roo.form.FCKeditor.editors = { };
42200 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
42202 //defaultAutoCreate : {
42203 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
42207 * @cfg {Object} fck options - see fck manual for details.
42212 * @cfg {Object} fck toolbar set (Basic or Default)
42214 toolbarSet : 'Basic',
42216 * @cfg {Object} fck BasePath
42218 basePath : '/fckeditor/',
42226 onRender : function(ct, position)
42229 this.defaultAutoCreate = {
42231 style:"width:300px;height:60px;",
42232 autocomplete: "off"
42235 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
42238 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
42239 if(this.preventScrollbars){
42240 this.el.setStyle("overflow", "hidden");
42242 this.el.setHeight(this.growMin);
42245 //console.log('onrender' + this.getId() );
42246 Roo.form.FCKeditor.editors[this.getId()] = this;
42249 this.replaceTextarea() ;
42253 getEditor : function() {
42254 return this.fckEditor;
42257 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
42258 * @param {Mixed} value The value to set
42262 setValue : function(value)
42264 //console.log('setValue: ' + value);
42266 if(typeof(value) == 'undefined') { // not sure why this is happending...
42269 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42271 //if(!this.el || !this.getEditor()) {
42272 // this.value = value;
42273 //this.setValue.defer(100,this,[value]);
42277 if(!this.getEditor()) {
42281 this.getEditor().SetData(value);
42288 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
42289 * @return {Mixed} value The field value
42291 getValue : function()
42294 if (this.frame && this.frame.dom.style.display == 'none') {
42295 return Roo.form.FCKeditor.superclass.getValue.call(this);
42298 if(!this.el || !this.getEditor()) {
42300 // this.getValue.defer(100,this);
42305 var value=this.getEditor().GetData();
42306 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42307 return Roo.form.FCKeditor.superclass.getValue.call(this);
42313 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
42314 * @return {Mixed} value The field value
42316 getRawValue : function()
42318 if (this.frame && this.frame.dom.style.display == 'none') {
42319 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42322 if(!this.el || !this.getEditor()) {
42323 //this.getRawValue.defer(100,this);
42330 var value=this.getEditor().GetData();
42331 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
42332 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42336 setSize : function(w,h) {
42340 //if (this.frame && this.frame.dom.style.display == 'none') {
42341 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42344 //if(!this.el || !this.getEditor()) {
42345 // this.setSize.defer(100,this, [w,h]);
42351 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42353 this.frame.dom.setAttribute('width', w);
42354 this.frame.dom.setAttribute('height', h);
42355 this.frame.setSize(w,h);
42359 toggleSourceEdit : function(value) {
42363 this.el.dom.style.display = value ? '' : 'none';
42364 this.frame.dom.style.display = value ? 'none' : '';
42369 focus: function(tag)
42371 if (this.frame.dom.style.display == 'none') {
42372 return Roo.form.FCKeditor.superclass.focus.call(this);
42374 if(!this.el || !this.getEditor()) {
42375 this.focus.defer(100,this, [tag]);
42382 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
42383 this.getEditor().Focus();
42385 if (!this.getEditor().Selection.GetSelection()) {
42386 this.focus.defer(100,this, [tag]);
42391 var r = this.getEditor().EditorDocument.createRange();
42392 r.setStart(tgs[0],0);
42393 r.setEnd(tgs[0],0);
42394 this.getEditor().Selection.GetSelection().removeAllRanges();
42395 this.getEditor().Selection.GetSelection().addRange(r);
42396 this.getEditor().Focus();
42403 replaceTextarea : function()
42405 if ( document.getElementById( this.getId() + '___Frame' ) )
42407 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
42409 // We must check the elements firstly using the Id and then the name.
42410 var oTextarea = document.getElementById( this.getId() );
42412 var colElementsByName = document.getElementsByName( this.getId() ) ;
42414 oTextarea.style.display = 'none' ;
42416 if ( oTextarea.tabIndex ) {
42417 this.TabIndex = oTextarea.tabIndex ;
42420 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
42421 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
42422 this.frame = Roo.get(this.getId() + '___Frame')
42425 _getConfigHtml : function()
42429 for ( var o in this.fckconfig ) {
42430 sConfig += sConfig.length > 0 ? '&' : '';
42431 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
42434 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
42438 _getIFrameHtml : function()
42440 var sFile = 'fckeditor.html' ;
42441 /* no idea what this is about..
42444 if ( (/fcksource=true/i).test( window.top.location.search ) )
42445 sFile = 'fckeditor.original.html' ;
42450 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
42451 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
42454 var html = '<iframe id="' + this.getId() +
42455 '___Frame" src="' + sLink +
42456 '" width="' + this.width +
42457 '" height="' + this.height + '"' +
42458 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
42459 ' frameborder="0" scrolling="no"></iframe>' ;
42464 _insertHtmlBefore : function( html, element )
42466 if ( element.insertAdjacentHTML ) {
42468 element.insertAdjacentHTML( 'beforeBegin', html ) ;
42470 var oRange = document.createRange() ;
42471 oRange.setStartBefore( element ) ;
42472 var oFragment = oRange.createContextualFragment( html );
42473 element.parentNode.insertBefore( oFragment, element ) ;
42486 //Roo.reg('fckeditor', Roo.form.FCKeditor);
42488 function FCKeditor_OnComplete(editorInstance){
42489 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
42490 f.fckEditor = editorInstance;
42491 //console.log("loaded");
42492 f.fireEvent('editorinit', f, editorInstance);
42512 //<script type="text/javascript">
42514 * @class Roo.form.GridField
42515 * @extends Roo.form.Field
42516 * Embed a grid (or editable grid into a form)
42519 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
42521 * xgrid.store = Roo.data.Store
42522 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
42523 * xgrid.store.reader = Roo.data.JsonReader
42527 * Creates a new GridField
42528 * @param {Object} config Configuration options
42530 Roo.form.GridField = function(config){
42531 Roo.form.GridField.superclass.constructor.call(this, config);
42535 Roo.extend(Roo.form.GridField, Roo.form.Field, {
42537 * @cfg {Number} width - used to restrict width of grid..
42541 * @cfg {Number} height - used to restrict height of grid..
42545 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
42551 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42552 * {tag: "input", type: "checkbox", autocomplete: "off"})
42554 // defaultAutoCreate : { tag: 'div' },
42555 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42557 * @cfg {String} addTitle Text to include for adding a title.
42561 onResize : function(){
42562 Roo.form.Field.superclass.onResize.apply(this, arguments);
42565 initEvents : function(){
42566 // Roo.form.Checkbox.superclass.initEvents.call(this);
42567 // has no events...
42572 getResizeEl : function(){
42576 getPositionEl : function(){
42581 onRender : function(ct, position){
42583 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
42584 var style = this.style;
42587 Roo.form.GridField.superclass.onRender.call(this, ct, position);
42588 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
42589 this.viewEl = this.wrap.createChild({ tag: 'div' });
42591 this.viewEl.applyStyles(style);
42594 this.viewEl.setWidth(this.width);
42597 this.viewEl.setHeight(this.height);
42599 //if(this.inputValue !== undefined){
42600 //this.setValue(this.value);
42603 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
42606 this.grid.render();
42607 this.grid.getDataSource().on('remove', this.refreshValue, this);
42608 this.grid.getDataSource().on('update', this.refreshValue, this);
42609 this.grid.on('afteredit', this.refreshValue, this);
42615 * Sets the value of the item.
42616 * @param {String} either an object or a string..
42618 setValue : function(v){
42620 v = v || []; // empty set..
42621 // this does not seem smart - it really only affects memoryproxy grids..
42622 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
42623 var ds = this.grid.getDataSource();
42624 // assumes a json reader..
42626 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
42627 ds.loadData( data);
42629 Roo.form.GridField.superclass.setValue.call(this, v);
42630 this.refreshValue();
42631 // should load data in the grid really....
42635 refreshValue: function() {
42637 this.grid.getDataSource().each(function(r) {
42640 this.el.dom.value = Roo.encode(val);
42648 * Ext JS Library 1.1.1
42649 * Copyright(c) 2006-2007, Ext JS, LLC.
42651 * Originally Released Under LGPL - original licence link has changed is not relivant.
42654 * <script type="text/javascript">
42657 * @class Roo.form.DisplayField
42658 * @extends Roo.form.Field
42659 * A generic Field to display non-editable data.
42661 * Creates a new Display Field item.
42662 * @param {Object} config Configuration options
42664 Roo.form.DisplayField = function(config){
42665 Roo.form.DisplayField.superclass.constructor.call(this, config);
42669 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
42670 inputType: 'hidden',
42676 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42678 focusClass : undefined,
42680 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42682 fieldClass: 'x-form-field',
42685 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
42687 valueRenderer: undefined,
42691 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42692 * {tag: "input", type: "checkbox", autocomplete: "off"})
42695 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42697 onResize : function(){
42698 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
42702 initEvents : function(){
42703 // Roo.form.Checkbox.superclass.initEvents.call(this);
42704 // has no events...
42709 getResizeEl : function(){
42713 getPositionEl : function(){
42718 onRender : function(ct, position){
42720 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
42721 //if(this.inputValue !== undefined){
42722 this.wrap = this.el.wrap();
42724 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
42726 if (this.bodyStyle) {
42727 this.viewEl.applyStyles(this.bodyStyle);
42729 //this.viewEl.setStyle('padding', '2px');
42731 this.setValue(this.value);
42736 initValue : Roo.emptyFn,
42741 onClick : function(){
42746 * Sets the checked state of the checkbox.
42747 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
42749 setValue : function(v){
42751 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
42752 // this might be called before we have a dom element..
42753 if (!this.viewEl) {
42756 this.viewEl.dom.innerHTML = html;
42757 Roo.form.DisplayField.superclass.setValue.call(this, v);
42767 * @class Roo.form.DayPicker
42768 * @extends Roo.form.Field
42769 * A Day picker show [M] [T] [W] ....
42771 * Creates a new Day Picker
42772 * @param {Object} config Configuration options
42774 Roo.form.DayPicker= function(config){
42775 Roo.form.DayPicker.superclass.constructor.call(this, config);
42779 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
42781 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42783 focusClass : undefined,
42785 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42787 fieldClass: "x-form-field",
42790 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42791 * {tag: "input", type: "checkbox", autocomplete: "off"})
42793 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42796 actionMode : 'viewEl',
42800 inputType : 'hidden',
42803 inputElement: false, // real input element?
42804 basedOn: false, // ????
42806 isFormField: true, // not sure where this is needed!!!!
42808 onResize : function(){
42809 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42810 if(!this.boxLabel){
42811 this.el.alignTo(this.wrap, 'c-c');
42815 initEvents : function(){
42816 Roo.form.Checkbox.superclass.initEvents.call(this);
42817 this.el.on("click", this.onClick, this);
42818 this.el.on("change", this.onClick, this);
42822 getResizeEl : function(){
42826 getPositionEl : function(){
42832 onRender : function(ct, position){
42833 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42835 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
42837 var r1 = '<table><tr>';
42838 var r2 = '<tr class="x-form-daypick-icons">';
42839 for (var i=0; i < 7; i++) {
42840 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
42841 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
42844 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
42845 viewEl.select('img').on('click', this.onClick, this);
42846 this.viewEl = viewEl;
42849 // this will not work on Chrome!!!
42850 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42851 this.el.on('propertychange', this.setFromHidden, this); //ie
42859 initValue : Roo.emptyFn,
42862 * Returns the checked state of the checkbox.
42863 * @return {Boolean} True if checked, else false
42865 getValue : function(){
42866 return this.el.dom.value;
42871 onClick : function(e){
42872 //this.setChecked(!this.checked);
42873 Roo.get(e.target).toggleClass('x-menu-item-checked');
42874 this.refreshValue();
42875 //if(this.el.dom.checked != this.checked){
42876 // this.setValue(this.el.dom.checked);
42881 refreshValue : function()
42884 this.viewEl.select('img',true).each(function(e,i,n) {
42885 val += e.is(".x-menu-item-checked") ? String(n) : '';
42887 this.setValue(val, true);
42891 * Sets the checked state of the checkbox.
42892 * On is always based on a string comparison between inputValue and the param.
42893 * @param {Boolean/String} value - the value to set
42894 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42896 setValue : function(v,suppressEvent){
42897 if (!this.el.dom) {
42900 var old = this.el.dom.value ;
42901 this.el.dom.value = v;
42902 if (suppressEvent) {
42906 // update display..
42907 this.viewEl.select('img',true).each(function(e,i,n) {
42909 var on = e.is(".x-menu-item-checked");
42910 var newv = v.indexOf(String(n)) > -1;
42912 e.toggleClass('x-menu-item-checked');
42918 this.fireEvent('change', this, v, old);
42923 // handle setting of hidden value by some other method!!?!?
42924 setFromHidden: function()
42929 //console.log("SET FROM HIDDEN");
42930 //alert('setFrom hidden');
42931 this.setValue(this.el.dom.value);
42934 onDestroy : function()
42937 Roo.get(this.viewEl).remove();
42940 Roo.form.DayPicker.superclass.onDestroy.call(this);
42943 });//<script type="text/javasscript">
42947 * @class Roo.DDView
42948 * A DnD enabled version of Roo.View.
42949 * @param {Element/String} container The Element in which to create the View.
42950 * @param {String} tpl The template string used to create the markup for each element of the View
42951 * @param {Object} config The configuration properties. These include all the config options of
42952 * {@link Roo.View} plus some specific to this class.<br>
42954 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
42955 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
42957 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
42958 .x-view-drag-insert-above {
42959 border-top:1px dotted #3366cc;
42961 .x-view-drag-insert-below {
42962 border-bottom:1px dotted #3366cc;
42968 Roo.DDView = function(container, tpl, config) {
42969 Roo.DDView.superclass.constructor.apply(this, arguments);
42970 this.getEl().setStyle("outline", "0px none");
42971 this.getEl().unselectable();
42972 if (this.dragGroup) {
42973 this.setDraggable(this.dragGroup.split(","));
42975 if (this.dropGroup) {
42976 this.setDroppable(this.dropGroup.split(","));
42978 if (this.deletable) {
42979 this.setDeletable();
42981 this.isDirtyFlag = false;
42987 Roo.extend(Roo.DDView, Roo.View, {
42988 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
42989 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
42990 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
42991 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
42995 reset: Roo.emptyFn,
42997 clearInvalid: Roo.form.Field.prototype.clearInvalid,
42999 validate: function() {
43003 destroy: function() {
43004 this.purgeListeners();
43005 this.getEl.removeAllListeners();
43006 this.getEl().remove();
43007 if (this.dragZone) {
43008 if (this.dragZone.destroy) {
43009 this.dragZone.destroy();
43012 if (this.dropZone) {
43013 if (this.dropZone.destroy) {
43014 this.dropZone.destroy();
43019 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
43020 getName: function() {
43024 /** Loads the View from a JSON string representing the Records to put into the Store. */
43025 setValue: function(v) {
43027 throw "DDView.setValue(). DDView must be constructed with a valid Store";
43030 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
43031 this.store.proxy = new Roo.data.MemoryProxy(data);
43035 /** @return {String} a parenthesised list of the ids of the Records in the View. */
43036 getValue: function() {
43038 this.store.each(function(rec) {
43039 result += rec.id + ',';
43041 return result.substr(0, result.length - 1) + ')';
43044 getIds: function() {
43045 var i = 0, result = new Array(this.store.getCount());
43046 this.store.each(function(rec) {
43047 result[i++] = rec.id;
43052 isDirty: function() {
43053 return this.isDirtyFlag;
43057 * Part of the Roo.dd.DropZone interface. If no target node is found, the
43058 * whole Element becomes the target, and this causes the drop gesture to append.
43060 getTargetFromEvent : function(e) {
43061 var target = e.getTarget();
43062 while ((target !== null) && (target.parentNode != this.el.dom)) {
43063 target = target.parentNode;
43066 target = this.el.dom.lastChild || this.el.dom;
43072 * Create the drag data which consists of an object which has the property "ddel" as
43073 * the drag proxy element.
43075 getDragData : function(e) {
43076 var target = this.findItemFromChild(e.getTarget());
43078 this.handleSelection(e);
43079 var selNodes = this.getSelectedNodes();
43082 copy: this.copy || (this.allowCopy && e.ctrlKey),
43086 var selectedIndices = this.getSelectedIndexes();
43087 for (var i = 0; i < selectedIndices.length; i++) {
43088 dragData.records.push(this.store.getAt(selectedIndices[i]));
43090 if (selNodes.length == 1) {
43091 dragData.ddel = target.cloneNode(true); // the div element
43093 var div = document.createElement('div'); // create the multi element drag "ghost"
43094 div.className = 'multi-proxy';
43095 for (var i = 0, len = selNodes.length; i < len; i++) {
43096 div.appendChild(selNodes[i].cloneNode(true));
43098 dragData.ddel = div;
43100 //console.log(dragData)
43101 //console.log(dragData.ddel.innerHTML)
43104 //console.log('nodragData')
43108 /** Specify to which ddGroup items in this DDView may be dragged. */
43109 setDraggable: function(ddGroup) {
43110 if (ddGroup instanceof Array) {
43111 Roo.each(ddGroup, this.setDraggable, this);
43114 if (this.dragZone) {
43115 this.dragZone.addToGroup(ddGroup);
43117 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
43118 containerScroll: true,
43122 // Draggability implies selection. DragZone's mousedown selects the element.
43123 if (!this.multiSelect) { this.singleSelect = true; }
43125 // Wire the DragZone's handlers up to methods in *this*
43126 this.dragZone.getDragData = this.getDragData.createDelegate(this);
43130 /** Specify from which ddGroup this DDView accepts drops. */
43131 setDroppable: function(ddGroup) {
43132 if (ddGroup instanceof Array) {
43133 Roo.each(ddGroup, this.setDroppable, this);
43136 if (this.dropZone) {
43137 this.dropZone.addToGroup(ddGroup);
43139 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
43140 containerScroll: true,
43144 // Wire the DropZone's handlers up to methods in *this*
43145 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
43146 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
43147 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
43148 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
43149 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
43153 /** Decide whether to drop above or below a View node. */
43154 getDropPoint : function(e, n, dd){
43155 if (n == this.el.dom) { return "above"; }
43156 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
43157 var c = t + (b - t) / 2;
43158 var y = Roo.lib.Event.getPageY(e);
43166 onNodeEnter : function(n, dd, e, data){
43170 onNodeOver : function(n, dd, e, data){
43171 var pt = this.getDropPoint(e, n, dd);
43172 // set the insert point style on the target node
43173 var dragElClass = this.dropNotAllowed;
43176 if (pt == "above"){
43177 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
43178 targetElClass = "x-view-drag-insert-above";
43180 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
43181 targetElClass = "x-view-drag-insert-below";
43183 if (this.lastInsertClass != targetElClass){
43184 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
43185 this.lastInsertClass = targetElClass;
43188 return dragElClass;
43191 onNodeOut : function(n, dd, e, data){
43192 this.removeDropIndicators(n);
43195 onNodeDrop : function(n, dd, e, data){
43196 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
43199 var pt = this.getDropPoint(e, n, dd);
43200 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
43201 if (pt == "below") { insertAt++; }
43202 for (var i = 0; i < data.records.length; i++) {
43203 var r = data.records[i];
43204 var dup = this.store.getById(r.id);
43205 if (dup && (dd != this.dragZone)) {
43206 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
43209 this.store.insert(insertAt++, r.copy());
43211 data.source.isDirtyFlag = true;
43213 this.store.insert(insertAt++, r);
43215 this.isDirtyFlag = true;
43218 this.dragZone.cachedTarget = null;
43222 removeDropIndicators : function(n){
43224 Roo.fly(n).removeClass([
43225 "x-view-drag-insert-above",
43226 "x-view-drag-insert-below"]);
43227 this.lastInsertClass = "_noclass";
43232 * Utility method. Add a delete option to the DDView's context menu.
43233 * @param {String} imageUrl The URL of the "delete" icon image.
43235 setDeletable: function(imageUrl) {
43236 if (!this.singleSelect && !this.multiSelect) {
43237 this.singleSelect = true;
43239 var c = this.getContextMenu();
43240 this.contextMenu.on("itemclick", function(item) {
43243 this.remove(this.getSelectedIndexes());
43247 this.contextMenu.add({
43254 /** Return the context menu for this DDView. */
43255 getContextMenu: function() {
43256 if (!this.contextMenu) {
43257 // Create the View's context menu
43258 this.contextMenu = new Roo.menu.Menu({
43259 id: this.id + "-contextmenu"
43261 this.el.on("contextmenu", this.showContextMenu, this);
43263 return this.contextMenu;
43266 disableContextMenu: function() {
43267 if (this.contextMenu) {
43268 this.el.un("contextmenu", this.showContextMenu, this);
43272 showContextMenu: function(e, item) {
43273 item = this.findItemFromChild(e.getTarget());
43276 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
43277 this.contextMenu.showAt(e.getXY());
43282 * Remove {@link Roo.data.Record}s at the specified indices.
43283 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
43285 remove: function(selectedIndices) {
43286 selectedIndices = [].concat(selectedIndices);
43287 for (var i = 0; i < selectedIndices.length; i++) {
43288 var rec = this.store.getAt(selectedIndices[i]);
43289 this.store.remove(rec);
43294 * Double click fires the event, but also, if this is draggable, and there is only one other
43295 * related DropZone, it transfers the selected node.
43297 onDblClick : function(e){
43298 var item = this.findItemFromChild(e.getTarget());
43300 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
43303 if (this.dragGroup) {
43304 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
43305 while (targets.indexOf(this.dropZone) > -1) {
43306 targets.remove(this.dropZone);
43308 if (targets.length == 1) {
43309 this.dragZone.cachedTarget = null;
43310 var el = Roo.get(targets[0].getEl());
43311 var box = el.getBox(true);
43312 targets[0].onNodeDrop(el.dom, {
43314 xy: [box.x, box.y + box.height - 1]
43315 }, null, this.getDragData(e));
43321 handleSelection: function(e) {
43322 this.dragZone.cachedTarget = null;
43323 var item = this.findItemFromChild(e.getTarget());
43325 this.clearSelections(true);
43328 if (item && (this.multiSelect || this.singleSelect)){
43329 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
43330 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
43331 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
43332 this.unselect(item);
43334 this.select(item, this.multiSelect && e.ctrlKey);
43335 this.lastSelection = item;
43340 onItemClick : function(item, index, e){
43341 if(this.fireEvent("beforeclick", this, index, item, e) === false){
43347 unselect : function(nodeInfo, suppressEvent){
43348 var node = this.getNode(nodeInfo);
43349 if(node && this.isSelected(node)){
43350 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
43351 Roo.fly(node).removeClass(this.selectedClass);
43352 this.selections.remove(node);
43353 if(!suppressEvent){
43354 this.fireEvent("selectionchange", this, this.selections);
43362 * Ext JS Library 1.1.1
43363 * Copyright(c) 2006-2007, Ext JS, LLC.
43365 * Originally Released Under LGPL - original licence link has changed is not relivant.
43368 * <script type="text/javascript">
43372 * @class Roo.LayoutManager
43373 * @extends Roo.util.Observable
43374 * Base class for layout managers.
43376 Roo.LayoutManager = function(container, config){
43377 Roo.LayoutManager.superclass.constructor.call(this);
43378 this.el = Roo.get(container);
43379 // ie scrollbar fix
43380 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
43381 document.body.scroll = "no";
43382 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
43383 this.el.position('relative');
43385 this.id = this.el.id;
43386 this.el.addClass("x-layout-container");
43387 /** false to disable window resize monitoring @type Boolean */
43388 this.monitorWindowResize = true;
43393 * Fires when a layout is performed.
43394 * @param {Roo.LayoutManager} this
43398 * @event regionresized
43399 * Fires when the user resizes a region.
43400 * @param {Roo.LayoutRegion} region The resized region
43401 * @param {Number} newSize The new size (width for east/west, height for north/south)
43403 "regionresized" : true,
43405 * @event regioncollapsed
43406 * Fires when a region is collapsed.
43407 * @param {Roo.LayoutRegion} region The collapsed region
43409 "regioncollapsed" : true,
43411 * @event regionexpanded
43412 * Fires when a region is expanded.
43413 * @param {Roo.LayoutRegion} region The expanded region
43415 "regionexpanded" : true
43417 this.updating = false;
43418 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
43421 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
43423 * Returns true if this layout is currently being updated
43424 * @return {Boolean}
43426 isUpdating : function(){
43427 return this.updating;
43431 * Suspend the LayoutManager from doing auto-layouts while
43432 * making multiple add or remove calls
43434 beginUpdate : function(){
43435 this.updating = true;
43439 * Restore auto-layouts and optionally disable the manager from performing a layout
43440 * @param {Boolean} noLayout true to disable a layout update
43442 endUpdate : function(noLayout){
43443 this.updating = false;
43449 layout: function(){
43453 onRegionResized : function(region, newSize){
43454 this.fireEvent("regionresized", region, newSize);
43458 onRegionCollapsed : function(region){
43459 this.fireEvent("regioncollapsed", region);
43462 onRegionExpanded : function(region){
43463 this.fireEvent("regionexpanded", region);
43467 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
43468 * performs box-model adjustments.
43469 * @return {Object} The size as an object {width: (the width), height: (the height)}
43471 getViewSize : function(){
43473 if(this.el.dom != document.body){
43474 size = this.el.getSize();
43476 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
43478 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
43479 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
43484 * Returns the Element this layout is bound to.
43485 * @return {Roo.Element}
43487 getEl : function(){
43492 * Returns the specified region.
43493 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
43494 * @return {Roo.LayoutRegion}
43496 getRegion : function(target){
43497 return this.regions[target.toLowerCase()];
43500 onWindowResize : function(){
43501 if(this.monitorWindowResize){
43507 * Ext JS Library 1.1.1
43508 * Copyright(c) 2006-2007, Ext JS, LLC.
43510 * Originally Released Under LGPL - original licence link has changed is not relivant.
43513 * <script type="text/javascript">
43516 * @class Roo.BorderLayout
43517 * @extends Roo.LayoutManager
43518 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
43519 * please see: <br><br>
43520 * <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>
43521 * <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>
43524 var layout = new Roo.BorderLayout(document.body, {
43558 preferredTabWidth: 150
43563 var CP = Roo.ContentPanel;
43565 layout.beginUpdate();
43566 layout.add("north", new CP("north", "North"));
43567 layout.add("south", new CP("south", {title: "South", closable: true}));
43568 layout.add("west", new CP("west", {title: "West"}));
43569 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
43570 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
43571 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
43572 layout.getRegion("center").showPanel("center1");
43573 layout.endUpdate();
43576 <b>The container the layout is rendered into can be either the body element or any other element.
43577 If it is not the body element, the container needs to either be an absolute positioned element,
43578 or you will need to add "position:relative" to the css of the container. You will also need to specify
43579 the container size if it is not the body element.</b>
43582 * Create a new BorderLayout
43583 * @param {String/HTMLElement/Element} container The container this layout is bound to
43584 * @param {Object} config Configuration options
43586 Roo.BorderLayout = function(container, config){
43587 config = config || {};
43588 Roo.BorderLayout.superclass.constructor.call(this, container, config);
43589 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
43590 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
43591 var target = this.factory.validRegions[i];
43592 if(config[target]){
43593 this.addRegion(target, config[target]);
43598 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
43600 * Creates and adds a new region if it doesn't already exist.
43601 * @param {String} target The target region key (north, south, east, west or center).
43602 * @param {Object} config The regions config object
43603 * @return {BorderLayoutRegion} The new region
43605 addRegion : function(target, config){
43606 if(!this.regions[target]){
43607 var r = this.factory.create(target, this, config);
43608 this.bindRegion(target, r);
43610 return this.regions[target];
43614 bindRegion : function(name, r){
43615 this.regions[name] = r;
43616 r.on("visibilitychange", this.layout, this);
43617 r.on("paneladded", this.layout, this);
43618 r.on("panelremoved", this.layout, this);
43619 r.on("invalidated", this.layout, this);
43620 r.on("resized", this.onRegionResized, this);
43621 r.on("collapsed", this.onRegionCollapsed, this);
43622 r.on("expanded", this.onRegionExpanded, this);
43626 * Performs a layout update.
43628 layout : function(){
43629 if(this.updating) return;
43630 var size = this.getViewSize();
43631 var w = size.width;
43632 var h = size.height;
43637 //var x = 0, y = 0;
43639 var rs = this.regions;
43640 var north = rs["north"];
43641 var south = rs["south"];
43642 var west = rs["west"];
43643 var east = rs["east"];
43644 var center = rs["center"];
43645 //if(this.hideOnLayout){ // not supported anymore
43646 //c.el.setStyle("display", "none");
43648 if(north && north.isVisible()){
43649 var b = north.getBox();
43650 var m = north.getMargins();
43651 b.width = w - (m.left+m.right);
43654 centerY = b.height + b.y + m.bottom;
43655 centerH -= centerY;
43656 north.updateBox(this.safeBox(b));
43658 if(south && south.isVisible()){
43659 var b = south.getBox();
43660 var m = south.getMargins();
43661 b.width = w - (m.left+m.right);
43663 var totalHeight = (b.height + m.top + m.bottom);
43664 b.y = h - totalHeight + m.top;
43665 centerH -= totalHeight;
43666 south.updateBox(this.safeBox(b));
43668 if(west && west.isVisible()){
43669 var b = west.getBox();
43670 var m = west.getMargins();
43671 b.height = centerH - (m.top+m.bottom);
43673 b.y = centerY + m.top;
43674 var totalWidth = (b.width + m.left + m.right);
43675 centerX += totalWidth;
43676 centerW -= totalWidth;
43677 west.updateBox(this.safeBox(b));
43679 if(east && east.isVisible()){
43680 var b = east.getBox();
43681 var m = east.getMargins();
43682 b.height = centerH - (m.top+m.bottom);
43683 var totalWidth = (b.width + m.left + m.right);
43684 b.x = w - totalWidth + m.left;
43685 b.y = centerY + m.top;
43686 centerW -= totalWidth;
43687 east.updateBox(this.safeBox(b));
43690 var m = center.getMargins();
43692 x: centerX + m.left,
43693 y: centerY + m.top,
43694 width: centerW - (m.left+m.right),
43695 height: centerH - (m.top+m.bottom)
43697 //if(this.hideOnLayout){
43698 //center.el.setStyle("display", "block");
43700 center.updateBox(this.safeBox(centerBox));
43703 this.fireEvent("layout", this);
43707 safeBox : function(box){
43708 box.width = Math.max(0, box.width);
43709 box.height = Math.max(0, box.height);
43714 * Adds a ContentPanel (or subclass) to this layout.
43715 * @param {String} target The target region key (north, south, east, west or center).
43716 * @param {Roo.ContentPanel} panel The panel to add
43717 * @return {Roo.ContentPanel} The added panel
43719 add : function(target, panel){
43721 target = target.toLowerCase();
43722 return this.regions[target].add(panel);
43726 * Remove a ContentPanel (or subclass) to this layout.
43727 * @param {String} target The target region key (north, south, east, west or center).
43728 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
43729 * @return {Roo.ContentPanel} The removed panel
43731 remove : function(target, panel){
43732 target = target.toLowerCase();
43733 return this.regions[target].remove(panel);
43737 * Searches all regions for a panel with the specified id
43738 * @param {String} panelId
43739 * @return {Roo.ContentPanel} The panel or null if it wasn't found
43741 findPanel : function(panelId){
43742 var rs = this.regions;
43743 for(var target in rs){
43744 if(typeof rs[target] != "function"){
43745 var p = rs[target].getPanel(panelId);
43755 * Searches all regions for a panel with the specified id and activates (shows) it.
43756 * @param {String/ContentPanel} panelId The panels id or the panel itself
43757 * @return {Roo.ContentPanel} The shown panel or null
43759 showPanel : function(panelId) {
43760 var rs = this.regions;
43761 for(var target in rs){
43762 var r = rs[target];
43763 if(typeof r != "function"){
43764 if(r.hasPanel(panelId)){
43765 return r.showPanel(panelId);
43773 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
43774 * @param {Roo.state.Provider} provider (optional) An alternate state provider
43776 restoreState : function(provider){
43778 provider = Roo.state.Manager;
43780 var sm = new Roo.LayoutStateManager();
43781 sm.init(this, provider);
43785 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
43786 * object should contain properties for each region to add ContentPanels to, and each property's value should be
43787 * a valid ContentPanel config object. Example:
43789 // Create the main layout
43790 var layout = new Roo.BorderLayout('main-ct', {
43801 // Create and add multiple ContentPanels at once via configs
43804 id: 'source-files',
43806 title:'Ext Source Files',
43819 * @param {Object} regions An object containing ContentPanel configs by region name
43821 batchAdd : function(regions){
43822 this.beginUpdate();
43823 for(var rname in regions){
43824 var lr = this.regions[rname];
43826 this.addTypedPanels(lr, regions[rname]);
43833 addTypedPanels : function(lr, ps){
43834 if(typeof ps == 'string'){
43835 lr.add(new Roo.ContentPanel(ps));
43837 else if(ps instanceof Array){
43838 for(var i =0, len = ps.length; i < len; i++){
43839 this.addTypedPanels(lr, ps[i]);
43842 else if(!ps.events){ // raw config?
43844 delete ps.el; // prevent conflict
43845 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
43847 else { // panel object assumed!
43852 * Adds a xtype elements to the layout.
43856 xtype : 'ContentPanel',
43863 xtype : 'NestedLayoutPanel',
43869 items : [ ... list of content panels or nested layout panels.. ]
43873 * @param {Object} cfg Xtype definition of item to add.
43875 addxtype : function(cfg)
43877 // basically accepts a pannel...
43878 // can accept a layout region..!?!?
43879 // console.log('BorderLayout add ' + cfg.xtype)
43881 if (!cfg.xtype.match(/Panel$/)) {
43885 var region = cfg.region;
43891 xitems = cfg.items;
43898 case 'ContentPanel': // ContentPanel (el, cfg)
43899 case 'ScrollPanel': // ContentPanel (el, cfg)
43900 if(cfg.autoCreate) {
43901 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43903 var el = this.el.createChild();
43904 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
43907 this.add(region, ret);
43911 case 'TreePanel': // our new panel!
43912 cfg.el = this.el.createChild();
43913 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43914 this.add(region, ret);
43917 case 'NestedLayoutPanel':
43918 // create a new Layout (which is a Border Layout...
43919 var el = this.el.createChild();
43920 var clayout = cfg.layout;
43922 clayout.items = clayout.items || [];
43923 // replace this exitems with the clayout ones..
43924 xitems = clayout.items;
43927 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
43928 cfg.background = false;
43930 var layout = new Roo.BorderLayout(el, clayout);
43932 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
43933 //console.log('adding nested layout panel ' + cfg.toSource());
43934 this.add(region, ret);
43940 // needs grid and region
43942 //var el = this.getRegion(region).el.createChild();
43943 var el = this.el.createChild();
43944 // create the grid first...
43946 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
43948 if (region == 'center' && this.active ) {
43949 cfg.background = false;
43951 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
43953 this.add(region, ret);
43954 if (cfg.background) {
43955 ret.on('activate', function(gp) {
43956 if (!gp.grid.rendered) {
43969 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
43971 // GridPanel (grid, cfg)
43974 this.beginUpdate();
43976 Roo.each(xitems, function(i) {
43986 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
43987 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
43988 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
43989 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
43992 var CP = Roo.ContentPanel;
43994 var layout = Roo.BorderLayout.create({
43998 panels: [new CP("north", "North")]
44007 panels: [new CP("west", {title: "West"})]
44016 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
44025 panels: [new CP("south", {title: "South", closable: true})]
44032 preferredTabWidth: 150,
44034 new CP("center1", {title: "Close Me", closable: true}),
44035 new CP("center2", {title: "Center Panel", closable: false})
44040 layout.getRegion("center").showPanel("center1");
44045 Roo.BorderLayout.create = function(config, targetEl){
44046 var layout = new Roo.BorderLayout(targetEl || document.body, config);
44047 layout.beginUpdate();
44048 var regions = Roo.BorderLayout.RegionFactory.validRegions;
44049 for(var j = 0, jlen = regions.length; j < jlen; j++){
44050 var lr = regions[j];
44051 if(layout.regions[lr] && config[lr].panels){
44052 var r = layout.regions[lr];
44053 var ps = config[lr].panels;
44054 layout.addTypedPanels(r, ps);
44057 layout.endUpdate();
44062 Roo.BorderLayout.RegionFactory = {
44064 validRegions : ["north","south","east","west","center"],
44067 create : function(target, mgr, config){
44068 target = target.toLowerCase();
44069 if(config.lightweight || config.basic){
44070 return new Roo.BasicLayoutRegion(mgr, config, target);
44074 return new Roo.NorthLayoutRegion(mgr, config);
44076 return new Roo.SouthLayoutRegion(mgr, config);
44078 return new Roo.EastLayoutRegion(mgr, config);
44080 return new Roo.WestLayoutRegion(mgr, config);
44082 return new Roo.CenterLayoutRegion(mgr, config);
44084 throw 'Layout region "'+target+'" not supported.';
44088 * Ext JS Library 1.1.1
44089 * Copyright(c) 2006-2007, Ext JS, LLC.
44091 * Originally Released Under LGPL - original licence link has changed is not relivant.
44094 * <script type="text/javascript">
44098 * @class Roo.BasicLayoutRegion
44099 * @extends Roo.util.Observable
44100 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
44101 * and does not have a titlebar, tabs or any other features. All it does is size and position
44102 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
44104 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
44106 this.position = pos;
44109 * @scope Roo.BasicLayoutRegion
44113 * @event beforeremove
44114 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
44115 * @param {Roo.LayoutRegion} this
44116 * @param {Roo.ContentPanel} panel The panel
44117 * @param {Object} e The cancel event object
44119 "beforeremove" : true,
44121 * @event invalidated
44122 * Fires when the layout for this region is changed.
44123 * @param {Roo.LayoutRegion} this
44125 "invalidated" : true,
44127 * @event visibilitychange
44128 * Fires when this region is shown or hidden
44129 * @param {Roo.LayoutRegion} this
44130 * @param {Boolean} visibility true or false
44132 "visibilitychange" : true,
44134 * @event paneladded
44135 * Fires when a panel is added.
44136 * @param {Roo.LayoutRegion} this
44137 * @param {Roo.ContentPanel} panel The panel
44139 "paneladded" : true,
44141 * @event panelremoved
44142 * Fires when a panel is removed.
44143 * @param {Roo.LayoutRegion} this
44144 * @param {Roo.ContentPanel} panel The panel
44146 "panelremoved" : true,
44149 * Fires when this region is collapsed.
44150 * @param {Roo.LayoutRegion} this
44152 "collapsed" : true,
44155 * Fires when this region is expanded.
44156 * @param {Roo.LayoutRegion} this
44161 * Fires when this region is slid into view.
44162 * @param {Roo.LayoutRegion} this
44164 "slideshow" : true,
44167 * Fires when this region slides out of view.
44168 * @param {Roo.LayoutRegion} this
44170 "slidehide" : true,
44172 * @event panelactivated
44173 * Fires when a panel is activated.
44174 * @param {Roo.LayoutRegion} this
44175 * @param {Roo.ContentPanel} panel The activated panel
44177 "panelactivated" : true,
44180 * Fires when the user resizes this region.
44181 * @param {Roo.LayoutRegion} this
44182 * @param {Number} newSize The new size (width for east/west, height for north/south)
44186 /** A collection of panels in this region. @type Roo.util.MixedCollection */
44187 this.panels = new Roo.util.MixedCollection();
44188 this.panels.getKey = this.getPanelId.createDelegate(this);
44190 this.activePanel = null;
44191 // ensure listeners are added...
44193 if (config.listeners || config.events) {
44194 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
44195 listeners : config.listeners || {},
44196 events : config.events || {}
44200 if(skipConfig !== true){
44201 this.applyConfig(config);
44205 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
44206 getPanelId : function(p){
44210 applyConfig : function(config){
44211 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44212 this.config = config;
44217 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
44218 * the width, for horizontal (north, south) the height.
44219 * @param {Number} newSize The new width or height
44221 resizeTo : function(newSize){
44222 var el = this.el ? this.el :
44223 (this.activePanel ? this.activePanel.getEl() : null);
44225 switch(this.position){
44228 el.setWidth(newSize);
44229 this.fireEvent("resized", this, newSize);
44233 el.setHeight(newSize);
44234 this.fireEvent("resized", this, newSize);
44240 getBox : function(){
44241 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
44244 getMargins : function(){
44245 return this.margins;
44248 updateBox : function(box){
44250 var el = this.activePanel.getEl();
44251 el.dom.style.left = box.x + "px";
44252 el.dom.style.top = box.y + "px";
44253 this.activePanel.setSize(box.width, box.height);
44257 * Returns the container element for this region.
44258 * @return {Roo.Element}
44260 getEl : function(){
44261 return this.activePanel;
44265 * Returns true if this region is currently visible.
44266 * @return {Boolean}
44268 isVisible : function(){
44269 return this.activePanel ? true : false;
44272 setActivePanel : function(panel){
44273 panel = this.getPanel(panel);
44274 if(this.activePanel && this.activePanel != panel){
44275 this.activePanel.setActiveState(false);
44276 this.activePanel.getEl().setLeftTop(-10000,-10000);
44278 this.activePanel = panel;
44279 panel.setActiveState(true);
44281 panel.setSize(this.box.width, this.box.height);
44283 this.fireEvent("panelactivated", this, panel);
44284 this.fireEvent("invalidated");
44288 * Show the specified panel.
44289 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
44290 * @return {Roo.ContentPanel} The shown panel or null
44292 showPanel : function(panel){
44293 if(panel = this.getPanel(panel)){
44294 this.setActivePanel(panel);
44300 * Get the active panel for this region.
44301 * @return {Roo.ContentPanel} The active panel or null
44303 getActivePanel : function(){
44304 return this.activePanel;
44308 * Add the passed ContentPanel(s)
44309 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44310 * @return {Roo.ContentPanel} The panel added (if only one was added)
44312 add : function(panel){
44313 if(arguments.length > 1){
44314 for(var i = 0, len = arguments.length; i < len; i++) {
44315 this.add(arguments[i]);
44319 if(this.hasPanel(panel)){
44320 this.showPanel(panel);
44323 var el = panel.getEl();
44324 if(el.dom.parentNode != this.mgr.el.dom){
44325 this.mgr.el.dom.appendChild(el.dom);
44327 if(panel.setRegion){
44328 panel.setRegion(this);
44330 this.panels.add(panel);
44331 el.setStyle("position", "absolute");
44332 if(!panel.background){
44333 this.setActivePanel(panel);
44334 if(this.config.initialSize && this.panels.getCount()==1){
44335 this.resizeTo(this.config.initialSize);
44338 this.fireEvent("paneladded", this, panel);
44343 * Returns true if the panel is in this region.
44344 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44345 * @return {Boolean}
44347 hasPanel : function(panel){
44348 if(typeof panel == "object"){ // must be panel obj
44349 panel = panel.getId();
44351 return this.getPanel(panel) ? true : false;
44355 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44356 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44357 * @param {Boolean} preservePanel Overrides the config preservePanel option
44358 * @return {Roo.ContentPanel} The panel that was removed
44360 remove : function(panel, preservePanel){
44361 panel = this.getPanel(panel);
44366 this.fireEvent("beforeremove", this, panel, e);
44367 if(e.cancel === true){
44370 var panelId = panel.getId();
44371 this.panels.removeKey(panelId);
44376 * Returns the panel specified or null if it's not in this region.
44377 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44378 * @return {Roo.ContentPanel}
44380 getPanel : function(id){
44381 if(typeof id == "object"){ // must be panel obj
44384 return this.panels.get(id);
44388 * Returns this regions position (north/south/east/west/center).
44391 getPosition: function(){
44392 return this.position;
44396 * Ext JS Library 1.1.1
44397 * Copyright(c) 2006-2007, Ext JS, LLC.
44399 * Originally Released Under LGPL - original licence link has changed is not relivant.
44402 * <script type="text/javascript">
44406 * @class Roo.LayoutRegion
44407 * @extends Roo.BasicLayoutRegion
44408 * This class represents a region in a layout manager.
44409 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
44410 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
44411 * @cfg {Boolean} floatable False to disable floating (defaults to true)
44412 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
44413 * @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})
44414 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
44415 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
44416 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
44417 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
44418 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
44419 * @cfg {String} title The title for the region (overrides panel titles)
44420 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
44421 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
44422 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
44423 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
44424 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
44425 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
44426 * the space available, similar to FireFox 1.5 tabs (defaults to false)
44427 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
44428 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
44429 * @cfg {Boolean} showPin True to show a pin button
44430 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
44431 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
44432 * @cfg {Boolean} disableTabTips True to disable tab tooltips
44433 * @cfg {Number} width For East/West panels
44434 * @cfg {Number} height For North/South panels
44435 * @cfg {Boolean} split To show the splitter
44436 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
44438 Roo.LayoutRegion = function(mgr, config, pos){
44439 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
44440 var dh = Roo.DomHelper;
44441 /** This region's container element
44442 * @type Roo.Element */
44443 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
44444 /** This region's title element
44445 * @type Roo.Element */
44447 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
44448 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
44449 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
44451 this.titleEl.enableDisplayMode();
44452 /** This region's title text element
44453 * @type HTMLElement */
44454 this.titleTextEl = this.titleEl.dom.firstChild;
44455 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
44456 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
44457 this.closeBtn.enableDisplayMode();
44458 this.closeBtn.on("click", this.closeClicked, this);
44459 this.closeBtn.hide();
44461 this.createBody(config);
44462 this.visible = true;
44463 this.collapsed = false;
44465 if(config.hideWhenEmpty){
44467 this.on("paneladded", this.validateVisibility, this);
44468 this.on("panelremoved", this.validateVisibility, this);
44470 this.applyConfig(config);
44473 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
44475 createBody : function(){
44476 /** This region's body element
44477 * @type Roo.Element */
44478 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
44481 applyConfig : function(c){
44482 if(c.collapsible && this.position != "center" && !this.collapsedEl){
44483 var dh = Roo.DomHelper;
44484 if(c.titlebar !== false){
44485 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
44486 this.collapseBtn.on("click", this.collapse, this);
44487 this.collapseBtn.enableDisplayMode();
44489 if(c.showPin === true || this.showPin){
44490 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
44491 this.stickBtn.enableDisplayMode();
44492 this.stickBtn.on("click", this.expand, this);
44493 this.stickBtn.hide();
44496 /** This region's collapsed element
44497 * @type Roo.Element */
44498 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
44499 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
44501 if(c.floatable !== false){
44502 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
44503 this.collapsedEl.on("click", this.collapseClick, this);
44506 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
44507 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
44508 id: "message", unselectable: "on", style:{"float":"left"}});
44509 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
44511 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
44512 this.expandBtn.on("click", this.expand, this);
44514 if(this.collapseBtn){
44515 this.collapseBtn.setVisible(c.collapsible == true);
44517 this.cmargins = c.cmargins || this.cmargins ||
44518 (this.position == "west" || this.position == "east" ?
44519 {top: 0, left: 2, right:2, bottom: 0} :
44520 {top: 2, left: 0, right:0, bottom: 2});
44521 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44522 this.bottomTabs = c.tabPosition != "top";
44523 this.autoScroll = c.autoScroll || false;
44524 if(this.autoScroll){
44525 this.bodyEl.setStyle("overflow", "auto");
44527 this.bodyEl.setStyle("overflow", "hidden");
44529 //if(c.titlebar !== false){
44530 if((!c.titlebar && !c.title) || c.titlebar === false){
44531 this.titleEl.hide();
44533 this.titleEl.show();
44535 this.titleTextEl.innerHTML = c.title;
44539 this.duration = c.duration || .30;
44540 this.slideDuration = c.slideDuration || .45;
44543 this.collapse(true);
44550 * Returns true if this region is currently visible.
44551 * @return {Boolean}
44553 isVisible : function(){
44554 return this.visible;
44558 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
44559 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
44561 setCollapsedTitle : function(title){
44562 title = title || " ";
44563 if(this.collapsedTitleTextEl){
44564 this.collapsedTitleTextEl.innerHTML = title;
44568 getBox : function(){
44570 if(!this.collapsed){
44571 b = this.el.getBox(false, true);
44573 b = this.collapsedEl.getBox(false, true);
44578 getMargins : function(){
44579 return this.collapsed ? this.cmargins : this.margins;
44582 highlight : function(){
44583 this.el.addClass("x-layout-panel-dragover");
44586 unhighlight : function(){
44587 this.el.removeClass("x-layout-panel-dragover");
44590 updateBox : function(box){
44592 if(!this.collapsed){
44593 this.el.dom.style.left = box.x + "px";
44594 this.el.dom.style.top = box.y + "px";
44595 this.updateBody(box.width, box.height);
44597 this.collapsedEl.dom.style.left = box.x + "px";
44598 this.collapsedEl.dom.style.top = box.y + "px";
44599 this.collapsedEl.setSize(box.width, box.height);
44602 this.tabs.autoSizeTabs();
44606 updateBody : function(w, h){
44608 this.el.setWidth(w);
44609 w -= this.el.getBorderWidth("rl");
44610 if(this.config.adjustments){
44611 w += this.config.adjustments[0];
44615 this.el.setHeight(h);
44616 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
44617 h -= this.el.getBorderWidth("tb");
44618 if(this.config.adjustments){
44619 h += this.config.adjustments[1];
44621 this.bodyEl.setHeight(h);
44623 h = this.tabs.syncHeight(h);
44626 if(this.panelSize){
44627 w = w !== null ? w : this.panelSize.width;
44628 h = h !== null ? h : this.panelSize.height;
44630 if(this.activePanel){
44631 var el = this.activePanel.getEl();
44632 w = w !== null ? w : el.getWidth();
44633 h = h !== null ? h : el.getHeight();
44634 this.panelSize = {width: w, height: h};
44635 this.activePanel.setSize(w, h);
44637 if(Roo.isIE && this.tabs){
44638 this.tabs.el.repaint();
44643 * Returns the container element for this region.
44644 * @return {Roo.Element}
44646 getEl : function(){
44651 * Hides this region.
44654 if(!this.collapsed){
44655 this.el.dom.style.left = "-2000px";
44658 this.collapsedEl.dom.style.left = "-2000px";
44659 this.collapsedEl.hide();
44661 this.visible = false;
44662 this.fireEvent("visibilitychange", this, false);
44666 * Shows this region if it was previously hidden.
44669 if(!this.collapsed){
44672 this.collapsedEl.show();
44674 this.visible = true;
44675 this.fireEvent("visibilitychange", this, true);
44678 closeClicked : function(){
44679 if(this.activePanel){
44680 this.remove(this.activePanel);
44684 collapseClick : function(e){
44686 e.stopPropagation();
44689 e.stopPropagation();
44695 * Collapses this region.
44696 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
44698 collapse : function(skipAnim){
44699 if(this.collapsed) return;
44700 this.collapsed = true;
44702 this.split.el.hide();
44704 if(this.config.animate && skipAnim !== true){
44705 this.fireEvent("invalidated", this);
44706 this.animateCollapse();
44708 this.el.setLocation(-20000,-20000);
44710 this.collapsedEl.show();
44711 this.fireEvent("collapsed", this);
44712 this.fireEvent("invalidated", this);
44716 animateCollapse : function(){
44721 * Expands this region if it was previously collapsed.
44722 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
44723 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
44725 expand : function(e, skipAnim){
44726 if(e) e.stopPropagation();
44727 if(!this.collapsed || this.el.hasActiveFx()) return;
44729 this.afterSlideIn();
44732 this.collapsed = false;
44733 if(this.config.animate && skipAnim !== true){
44734 this.animateExpand();
44738 this.split.el.show();
44740 this.collapsedEl.setLocation(-2000,-2000);
44741 this.collapsedEl.hide();
44742 this.fireEvent("invalidated", this);
44743 this.fireEvent("expanded", this);
44747 animateExpand : function(){
44751 initTabs : function()
44753 this.bodyEl.setStyle("overflow", "hidden");
44754 var ts = new Roo.TabPanel(
44757 tabPosition: this.bottomTabs ? 'bottom' : 'top',
44758 disableTooltips: this.config.disableTabTips,
44759 toolbar : this.config.toolbar
44762 if(this.config.hideTabs){
44763 ts.stripWrap.setDisplayed(false);
44766 ts.resizeTabs = this.config.resizeTabs === true;
44767 ts.minTabWidth = this.config.minTabWidth || 40;
44768 ts.maxTabWidth = this.config.maxTabWidth || 250;
44769 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
44770 ts.monitorResize = false;
44771 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44772 ts.bodyEl.addClass('x-layout-tabs-body');
44773 this.panels.each(this.initPanelAsTab, this);
44776 initPanelAsTab : function(panel){
44777 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
44778 this.config.closeOnTab && panel.isClosable());
44779 if(panel.tabTip !== undefined){
44780 ti.setTooltip(panel.tabTip);
44782 ti.on("activate", function(){
44783 this.setActivePanel(panel);
44785 if(this.config.closeOnTab){
44786 ti.on("beforeclose", function(t, e){
44788 this.remove(panel);
44794 updatePanelTitle : function(panel, title){
44795 if(this.activePanel == panel){
44796 this.updateTitle(title);
44799 var ti = this.tabs.getTab(panel.getEl().id);
44801 if(panel.tabTip !== undefined){
44802 ti.setTooltip(panel.tabTip);
44807 updateTitle : function(title){
44808 if(this.titleTextEl && !this.config.title){
44809 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
44813 setActivePanel : function(panel){
44814 panel = this.getPanel(panel);
44815 if(this.activePanel && this.activePanel != panel){
44816 this.activePanel.setActiveState(false);
44818 this.activePanel = panel;
44819 panel.setActiveState(true);
44820 if(this.panelSize){
44821 panel.setSize(this.panelSize.width, this.panelSize.height);
44824 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
44826 this.updateTitle(panel.getTitle());
44828 this.fireEvent("invalidated", this);
44830 this.fireEvent("panelactivated", this, panel);
44834 * Shows the specified panel.
44835 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
44836 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
44838 showPanel : function(panel){
44839 if(panel = this.getPanel(panel)){
44841 var tab = this.tabs.getTab(panel.getEl().id);
44842 if(tab.isHidden()){
44843 this.tabs.unhideTab(tab.id);
44847 this.setActivePanel(panel);
44854 * Get the active panel for this region.
44855 * @return {Roo.ContentPanel} The active panel or null
44857 getActivePanel : function(){
44858 return this.activePanel;
44861 validateVisibility : function(){
44862 if(this.panels.getCount() < 1){
44863 this.updateTitle(" ");
44864 this.closeBtn.hide();
44867 if(!this.isVisible()){
44874 * Adds the passed ContentPanel(s) to this region.
44875 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44876 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
44878 add : function(panel){
44879 if(arguments.length > 1){
44880 for(var i = 0, len = arguments.length; i < len; i++) {
44881 this.add(arguments[i]);
44885 if(this.hasPanel(panel)){
44886 this.showPanel(panel);
44889 panel.setRegion(this);
44890 this.panels.add(panel);
44891 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
44892 this.bodyEl.dom.appendChild(panel.getEl().dom);
44893 if(panel.background !== true){
44894 this.setActivePanel(panel);
44896 this.fireEvent("paneladded", this, panel);
44902 this.initPanelAsTab(panel);
44904 if(panel.background !== true){
44905 this.tabs.activate(panel.getEl().id);
44907 this.fireEvent("paneladded", this, panel);
44912 * Hides the tab for the specified panel.
44913 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44915 hidePanel : function(panel){
44916 if(this.tabs && (panel = this.getPanel(panel))){
44917 this.tabs.hideTab(panel.getEl().id);
44922 * Unhides the tab for a previously hidden panel.
44923 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44925 unhidePanel : function(panel){
44926 if(this.tabs && (panel = this.getPanel(panel))){
44927 this.tabs.unhideTab(panel.getEl().id);
44931 clearPanels : function(){
44932 while(this.panels.getCount() > 0){
44933 this.remove(this.panels.first());
44938 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44939 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44940 * @param {Boolean} preservePanel Overrides the config preservePanel option
44941 * @return {Roo.ContentPanel} The panel that was removed
44943 remove : function(panel, preservePanel){
44944 panel = this.getPanel(panel);
44949 this.fireEvent("beforeremove", this, panel, e);
44950 if(e.cancel === true){
44953 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
44954 var panelId = panel.getId();
44955 this.panels.removeKey(panelId);
44957 document.body.appendChild(panel.getEl().dom);
44960 this.tabs.removeTab(panel.getEl().id);
44961 }else if (!preservePanel){
44962 this.bodyEl.dom.removeChild(panel.getEl().dom);
44964 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
44965 var p = this.panels.first();
44966 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
44967 tempEl.appendChild(p.getEl().dom);
44968 this.bodyEl.update("");
44969 this.bodyEl.dom.appendChild(p.getEl().dom);
44971 this.updateTitle(p.getTitle());
44973 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44974 this.setActivePanel(p);
44976 panel.setRegion(null);
44977 if(this.activePanel == panel){
44978 this.activePanel = null;
44980 if(this.config.autoDestroy !== false && preservePanel !== true){
44981 try{panel.destroy();}catch(e){}
44983 this.fireEvent("panelremoved", this, panel);
44988 * Returns the TabPanel component used by this region
44989 * @return {Roo.TabPanel}
44991 getTabs : function(){
44995 createTool : function(parentEl, className){
44996 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
44997 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
44998 btn.addClassOnOver("x-layout-tools-button-over");
45003 * Ext JS Library 1.1.1
45004 * Copyright(c) 2006-2007, Ext JS, LLC.
45006 * Originally Released Under LGPL - original licence link has changed is not relivant.
45009 * <script type="text/javascript">
45015 * @class Roo.SplitLayoutRegion
45016 * @extends Roo.LayoutRegion
45017 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
45019 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
45020 this.cursor = cursor;
45021 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
45024 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
45025 splitTip : "Drag to resize.",
45026 collapsibleSplitTip : "Drag to resize. Double click to hide.",
45027 useSplitTips : false,
45029 applyConfig : function(config){
45030 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
45033 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
45034 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
45035 /** The SplitBar for this region
45036 * @type Roo.SplitBar */
45037 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
45038 this.split.on("moved", this.onSplitMove, this);
45039 this.split.useShim = config.useShim === true;
45040 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
45041 if(this.useSplitTips){
45042 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
45044 if(config.collapsible){
45045 this.split.el.on("dblclick", this.collapse, this);
45048 if(typeof config.minSize != "undefined"){
45049 this.split.minSize = config.minSize;
45051 if(typeof config.maxSize != "undefined"){
45052 this.split.maxSize = config.maxSize;
45054 if(config.hideWhenEmpty || config.hidden || config.collapsed){
45055 this.hideSplitter();
45060 getHMaxSize : function(){
45061 var cmax = this.config.maxSize || 10000;
45062 var center = this.mgr.getRegion("center");
45063 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
45066 getVMaxSize : function(){
45067 var cmax = this.config.maxSize || 10000;
45068 var center = this.mgr.getRegion("center");
45069 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
45072 onSplitMove : function(split, newSize){
45073 this.fireEvent("resized", this, newSize);
45077 * Returns the {@link Roo.SplitBar} for this region.
45078 * @return {Roo.SplitBar}
45080 getSplitBar : function(){
45085 this.hideSplitter();
45086 Roo.SplitLayoutRegion.superclass.hide.call(this);
45089 hideSplitter : function(){
45091 this.split.el.setLocation(-2000,-2000);
45092 this.split.el.hide();
45098 this.split.el.show();
45100 Roo.SplitLayoutRegion.superclass.show.call(this);
45103 beforeSlide: function(){
45104 if(Roo.isGecko){// firefox overflow auto bug workaround
45105 this.bodyEl.clip();
45106 if(this.tabs) this.tabs.bodyEl.clip();
45107 if(this.activePanel){
45108 this.activePanel.getEl().clip();
45110 if(this.activePanel.beforeSlide){
45111 this.activePanel.beforeSlide();
45117 afterSlide : function(){
45118 if(Roo.isGecko){// firefox overflow auto bug workaround
45119 this.bodyEl.unclip();
45120 if(this.tabs) this.tabs.bodyEl.unclip();
45121 if(this.activePanel){
45122 this.activePanel.getEl().unclip();
45123 if(this.activePanel.afterSlide){
45124 this.activePanel.afterSlide();
45130 initAutoHide : function(){
45131 if(this.autoHide !== false){
45132 if(!this.autoHideHd){
45133 var st = new Roo.util.DelayedTask(this.slideIn, this);
45134 this.autoHideHd = {
45135 "mouseout": function(e){
45136 if(!e.within(this.el, true)){
45140 "mouseover" : function(e){
45146 this.el.on(this.autoHideHd);
45150 clearAutoHide : function(){
45151 if(this.autoHide !== false){
45152 this.el.un("mouseout", this.autoHideHd.mouseout);
45153 this.el.un("mouseover", this.autoHideHd.mouseover);
45157 clearMonitor : function(){
45158 Roo.get(document).un("click", this.slideInIf, this);
45161 // these names are backwards but not changed for compat
45162 slideOut : function(){
45163 if(this.isSlid || this.el.hasActiveFx()){
45166 this.isSlid = true;
45167 if(this.collapseBtn){
45168 this.collapseBtn.hide();
45170 this.closeBtnState = this.closeBtn.getStyle('display');
45171 this.closeBtn.hide();
45173 this.stickBtn.show();
45176 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
45177 this.beforeSlide();
45178 this.el.setStyle("z-index", 10001);
45179 this.el.slideIn(this.getSlideAnchor(), {
45180 callback: function(){
45182 this.initAutoHide();
45183 Roo.get(document).on("click", this.slideInIf, this);
45184 this.fireEvent("slideshow", this);
45191 afterSlideIn : function(){
45192 this.clearAutoHide();
45193 this.isSlid = false;
45194 this.clearMonitor();
45195 this.el.setStyle("z-index", "");
45196 if(this.collapseBtn){
45197 this.collapseBtn.show();
45199 this.closeBtn.setStyle('display', this.closeBtnState);
45201 this.stickBtn.hide();
45203 this.fireEvent("slidehide", this);
45206 slideIn : function(cb){
45207 if(!this.isSlid || this.el.hasActiveFx()){
45211 this.isSlid = false;
45212 this.beforeSlide();
45213 this.el.slideOut(this.getSlideAnchor(), {
45214 callback: function(){
45215 this.el.setLeftTop(-10000, -10000);
45217 this.afterSlideIn();
45225 slideInIf : function(e){
45226 if(!e.within(this.el)){
45231 animateCollapse : function(){
45232 this.beforeSlide();
45233 this.el.setStyle("z-index", 20000);
45234 var anchor = this.getSlideAnchor();
45235 this.el.slideOut(anchor, {
45236 callback : function(){
45237 this.el.setStyle("z-index", "");
45238 this.collapsedEl.slideIn(anchor, {duration:.3});
45240 this.el.setLocation(-10000,-10000);
45242 this.fireEvent("collapsed", this);
45249 animateExpand : function(){
45250 this.beforeSlide();
45251 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
45252 this.el.setStyle("z-index", 20000);
45253 this.collapsedEl.hide({
45256 this.el.slideIn(this.getSlideAnchor(), {
45257 callback : function(){
45258 this.el.setStyle("z-index", "");
45261 this.split.el.show();
45263 this.fireEvent("invalidated", this);
45264 this.fireEvent("expanded", this);
45292 getAnchor : function(){
45293 return this.anchors[this.position];
45296 getCollapseAnchor : function(){
45297 return this.canchors[this.position];
45300 getSlideAnchor : function(){
45301 return this.sanchors[this.position];
45304 getAlignAdj : function(){
45305 var cm = this.cmargins;
45306 switch(this.position){
45322 getExpandAdj : function(){
45323 var c = this.collapsedEl, cm = this.cmargins;
45324 switch(this.position){
45326 return [-(cm.right+c.getWidth()+cm.left), 0];
45329 return [cm.right+c.getWidth()+cm.left, 0];
45332 return [0, -(cm.top+cm.bottom+c.getHeight())];
45335 return [0, cm.top+cm.bottom+c.getHeight()];
45341 * Ext JS Library 1.1.1
45342 * Copyright(c) 2006-2007, Ext JS, LLC.
45344 * Originally Released Under LGPL - original licence link has changed is not relivant.
45347 * <script type="text/javascript">
45350 * These classes are private internal classes
45352 Roo.CenterLayoutRegion = function(mgr, config){
45353 Roo.LayoutRegion.call(this, mgr, config, "center");
45354 this.visible = true;
45355 this.minWidth = config.minWidth || 20;
45356 this.minHeight = config.minHeight || 20;
45359 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
45361 // center panel can't be hidden
45365 // center panel can't be hidden
45368 getMinWidth: function(){
45369 return this.minWidth;
45372 getMinHeight: function(){
45373 return this.minHeight;
45378 Roo.NorthLayoutRegion = function(mgr, config){
45379 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
45381 this.split.placement = Roo.SplitBar.TOP;
45382 this.split.orientation = Roo.SplitBar.VERTICAL;
45383 this.split.el.addClass("x-layout-split-v");
45385 var size = config.initialSize || config.height;
45386 if(typeof size != "undefined"){
45387 this.el.setHeight(size);
45390 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
45391 orientation: Roo.SplitBar.VERTICAL,
45392 getBox : function(){
45393 if(this.collapsed){
45394 return this.collapsedEl.getBox();
45396 var box = this.el.getBox();
45398 box.height += this.split.el.getHeight();
45403 updateBox : function(box){
45404 if(this.split && !this.collapsed){
45405 box.height -= this.split.el.getHeight();
45406 this.split.el.setLeft(box.x);
45407 this.split.el.setTop(box.y+box.height);
45408 this.split.el.setWidth(box.width);
45410 if(this.collapsed){
45411 this.updateBody(box.width, null);
45413 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45417 Roo.SouthLayoutRegion = function(mgr, config){
45418 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
45420 this.split.placement = Roo.SplitBar.BOTTOM;
45421 this.split.orientation = Roo.SplitBar.VERTICAL;
45422 this.split.el.addClass("x-layout-split-v");
45424 var size = config.initialSize || config.height;
45425 if(typeof size != "undefined"){
45426 this.el.setHeight(size);
45429 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
45430 orientation: Roo.SplitBar.VERTICAL,
45431 getBox : function(){
45432 if(this.collapsed){
45433 return this.collapsedEl.getBox();
45435 var box = this.el.getBox();
45437 var sh = this.split.el.getHeight();
45444 updateBox : function(box){
45445 if(this.split && !this.collapsed){
45446 var sh = this.split.el.getHeight();
45449 this.split.el.setLeft(box.x);
45450 this.split.el.setTop(box.y-sh);
45451 this.split.el.setWidth(box.width);
45453 if(this.collapsed){
45454 this.updateBody(box.width, null);
45456 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45460 Roo.EastLayoutRegion = function(mgr, config){
45461 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
45463 this.split.placement = Roo.SplitBar.RIGHT;
45464 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45465 this.split.el.addClass("x-layout-split-h");
45467 var size = config.initialSize || config.width;
45468 if(typeof size != "undefined"){
45469 this.el.setWidth(size);
45472 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
45473 orientation: Roo.SplitBar.HORIZONTAL,
45474 getBox : function(){
45475 if(this.collapsed){
45476 return this.collapsedEl.getBox();
45478 var box = this.el.getBox();
45480 var sw = this.split.el.getWidth();
45487 updateBox : function(box){
45488 if(this.split && !this.collapsed){
45489 var sw = this.split.el.getWidth();
45491 this.split.el.setLeft(box.x);
45492 this.split.el.setTop(box.y);
45493 this.split.el.setHeight(box.height);
45496 if(this.collapsed){
45497 this.updateBody(null, box.height);
45499 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45503 Roo.WestLayoutRegion = function(mgr, config){
45504 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
45506 this.split.placement = Roo.SplitBar.LEFT;
45507 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45508 this.split.el.addClass("x-layout-split-h");
45510 var size = config.initialSize || config.width;
45511 if(typeof size != "undefined"){
45512 this.el.setWidth(size);
45515 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
45516 orientation: Roo.SplitBar.HORIZONTAL,
45517 getBox : function(){
45518 if(this.collapsed){
45519 return this.collapsedEl.getBox();
45521 var box = this.el.getBox();
45523 box.width += this.split.el.getWidth();
45528 updateBox : function(box){
45529 if(this.split && !this.collapsed){
45530 var sw = this.split.el.getWidth();
45532 this.split.el.setLeft(box.x+box.width);
45533 this.split.el.setTop(box.y);
45534 this.split.el.setHeight(box.height);
45536 if(this.collapsed){
45537 this.updateBody(null, box.height);
45539 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45544 * Ext JS Library 1.1.1
45545 * Copyright(c) 2006-2007, Ext JS, LLC.
45547 * Originally Released Under LGPL - original licence link has changed is not relivant.
45550 * <script type="text/javascript">
45555 * Private internal class for reading and applying state
45557 Roo.LayoutStateManager = function(layout){
45558 // default empty state
45567 Roo.LayoutStateManager.prototype = {
45568 init : function(layout, provider){
45569 this.provider = provider;
45570 var state = provider.get(layout.id+"-layout-state");
45572 var wasUpdating = layout.isUpdating();
45574 layout.beginUpdate();
45576 for(var key in state){
45577 if(typeof state[key] != "function"){
45578 var rstate = state[key];
45579 var r = layout.getRegion(key);
45582 r.resizeTo(rstate.size);
45584 if(rstate.collapsed == true){
45587 r.expand(null, true);
45593 layout.endUpdate();
45595 this.state = state;
45597 this.layout = layout;
45598 layout.on("regionresized", this.onRegionResized, this);
45599 layout.on("regioncollapsed", this.onRegionCollapsed, this);
45600 layout.on("regionexpanded", this.onRegionExpanded, this);
45603 storeState : function(){
45604 this.provider.set(this.layout.id+"-layout-state", this.state);
45607 onRegionResized : function(region, newSize){
45608 this.state[region.getPosition()].size = newSize;
45612 onRegionCollapsed : function(region){
45613 this.state[region.getPosition()].collapsed = true;
45617 onRegionExpanded : function(region){
45618 this.state[region.getPosition()].collapsed = false;
45623 * Ext JS Library 1.1.1
45624 * Copyright(c) 2006-2007, Ext JS, LLC.
45626 * Originally Released Under LGPL - original licence link has changed is not relivant.
45629 * <script type="text/javascript">
45632 * @class Roo.ContentPanel
45633 * @extends Roo.util.Observable
45634 * A basic ContentPanel element.
45635 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
45636 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
45637 * @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
45638 * @cfg {Boolean} closable True if the panel can be closed/removed
45639 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
45640 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
45641 * @cfg {Toolbar} toolbar A toolbar for this panel
45642 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
45643 * @cfg {String} title The title for this panel
45644 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
45645 * @cfg {String} url Calls {@link #setUrl} with this value
45646 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
45647 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
45648 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
45649 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
45652 * Create a new ContentPanel.
45653 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
45654 * @param {String/Object} config A string to set only the title or a config object
45655 * @param {String} content (optional) Set the HTML content for this panel
45656 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
45658 Roo.ContentPanel = function(el, config, content){
45662 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
45666 if (config && config.parentLayout) {
45667 el = config.parentLayout.el.createChild();
45670 if(el.autoCreate){ // xtype is available if this is called from factory
45674 this.el = Roo.get(el);
45675 if(!this.el && config && config.autoCreate){
45676 if(typeof config.autoCreate == "object"){
45677 if(!config.autoCreate.id){
45678 config.autoCreate.id = config.id||el;
45680 this.el = Roo.DomHelper.append(document.body,
45681 config.autoCreate, true);
45683 this.el = Roo.DomHelper.append(document.body,
45684 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
45687 this.closable = false;
45688 this.loaded = false;
45689 this.active = false;
45690 if(typeof config == "string"){
45691 this.title = config;
45693 Roo.apply(this, config);
45696 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
45697 this.wrapEl = this.el.wrap();
45698 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
45705 this.resizeEl = Roo.get(this.resizeEl, true);
45707 this.resizeEl = this.el;
45712 * Fires when this panel is activated.
45713 * @param {Roo.ContentPanel} this
45717 * @event deactivate
45718 * Fires when this panel is activated.
45719 * @param {Roo.ContentPanel} this
45721 "deactivate" : true,
45725 * Fires when this panel is resized if fitToFrame is true.
45726 * @param {Roo.ContentPanel} this
45727 * @param {Number} width The width after any component adjustments
45728 * @param {Number} height The height after any component adjustments
45732 if(this.autoScroll){
45733 this.resizeEl.setStyle("overflow", "auto");
45735 // fix randome scrolling
45736 this.el.on('scroll', function() {
45737 Roo.log('fix random scolling');
45738 this.scrollTo('top',0);
45741 content = content || this.content;
45743 this.setContent(content);
45745 if(config && config.url){
45746 this.setUrl(this.url, this.params, this.loadOnce);
45751 Roo.ContentPanel.superclass.constructor.call(this);
45754 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
45756 setRegion : function(region){
45757 this.region = region;
45759 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
45761 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
45766 * Returns the toolbar for this Panel if one was configured.
45767 * @return {Roo.Toolbar}
45769 getToolbar : function(){
45770 return this.toolbar;
45773 setActiveState : function(active){
45774 this.active = active;
45776 this.fireEvent("deactivate", this);
45778 this.fireEvent("activate", this);
45782 * Updates this panel's element
45783 * @param {String} content The new content
45784 * @param {Boolean} loadScripts (optional) true to look for and process scripts
45786 setContent : function(content, loadScripts){
45787 this.el.update(content, loadScripts);
45790 ignoreResize : function(w, h){
45791 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
45794 this.lastSize = {width: w, height: h};
45799 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
45800 * @return {Roo.UpdateManager} The UpdateManager
45802 getUpdateManager : function(){
45803 return this.el.getUpdateManager();
45806 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
45807 * @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:
45810 url: "your-url.php",
45811 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
45812 callback: yourFunction,
45813 scope: yourObject, //(optional scope)
45816 text: "Loading...",
45821 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
45822 * 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.
45823 * @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}
45824 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
45825 * @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.
45826 * @return {Roo.ContentPanel} this
45829 var um = this.el.getUpdateManager();
45830 um.update.apply(um, arguments);
45836 * 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.
45837 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
45838 * @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)
45839 * @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)
45840 * @return {Roo.UpdateManager} The UpdateManager
45842 setUrl : function(url, params, loadOnce){
45843 if(this.refreshDelegate){
45844 this.removeListener("activate", this.refreshDelegate);
45846 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
45847 this.on("activate", this.refreshDelegate);
45848 return this.el.getUpdateManager();
45851 _handleRefresh : function(url, params, loadOnce){
45852 if(!loadOnce || !this.loaded){
45853 var updater = this.el.getUpdateManager();
45854 updater.update(url, params, this._setLoaded.createDelegate(this));
45858 _setLoaded : function(){
45859 this.loaded = true;
45863 * Returns this panel's id
45866 getId : function(){
45871 * Returns this panel's element - used by regiosn to add.
45872 * @return {Roo.Element}
45874 getEl : function(){
45875 return this.wrapEl || this.el;
45878 adjustForComponents : function(width, height){
45879 if(this.resizeEl != this.el){
45880 width -= this.el.getFrameWidth('lr');
45881 height -= this.el.getFrameWidth('tb');
45884 var te = this.toolbar.getEl();
45885 height -= te.getHeight();
45886 te.setWidth(width);
45888 if(this.adjustments){
45889 width += this.adjustments[0];
45890 height += this.adjustments[1];
45892 return {"width": width, "height": height};
45895 setSize : function(width, height){
45896 if(this.fitToFrame && !this.ignoreResize(width, height)){
45897 if(this.fitContainer && this.resizeEl != this.el){
45898 this.el.setSize(width, height);
45900 var size = this.adjustForComponents(width, height);
45901 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
45902 this.fireEvent('resize', this, size.width, size.height);
45907 * Returns this panel's title
45910 getTitle : function(){
45915 * Set this panel's title
45916 * @param {String} title
45918 setTitle : function(title){
45919 this.title = title;
45921 this.region.updatePanelTitle(this, title);
45926 * Returns true is this panel was configured to be closable
45927 * @return {Boolean}
45929 isClosable : function(){
45930 return this.closable;
45933 beforeSlide : function(){
45935 this.resizeEl.clip();
45938 afterSlide : function(){
45940 this.resizeEl.unclip();
45944 * Force a content refresh from the URL specified in the {@link #setUrl} method.
45945 * Will fail silently if the {@link #setUrl} method has not been called.
45946 * This does not activate the panel, just updates its content.
45948 refresh : function(){
45949 if(this.refreshDelegate){
45950 this.loaded = false;
45951 this.refreshDelegate();
45956 * Destroys this panel
45958 destroy : function(){
45959 this.el.removeAllListeners();
45960 var tempEl = document.createElement("span");
45961 tempEl.appendChild(this.el.dom);
45962 tempEl.innerHTML = "";
45968 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
45978 * @param {Object} cfg Xtype definition of item to add.
45981 addxtype : function(cfg) {
45983 if (cfg.xtype.match(/^Form$/)) {
45984 var el = this.el.createChild();
45986 this.form = new Roo.form.Form(cfg);
45989 if ( this.form.allItems.length) this.form.render(el.dom);
45993 if (['View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
45995 cfg.el = this.el.appendChild(document.createElement("div"));
45997 var ret = new Roo[cfg.xtype](cfg);
45998 ret.render && ret.render(false, ''); // render blank..
46008 * @class Roo.GridPanel
46009 * @extends Roo.ContentPanel
46011 * Create a new GridPanel.
46012 * @param {Roo.grid.Grid} grid The grid for this panel
46013 * @param {String/Object} config A string to set only the panel's title, or a config object
46015 Roo.GridPanel = function(grid, config){
46018 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
46019 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
46021 this.wrapper.dom.appendChild(grid.getGridEl().dom);
46023 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
46026 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
46028 // xtype created footer. - not sure if will work as we normally have to render first..
46029 if (this.footer && !this.footer.el && this.footer.xtype) {
46031 this.footer.container = this.grid.getView().getFooterPanel(true);
46032 this.footer.dataSource = this.grid.dataSource;
46033 this.footer = Roo.factory(this.footer, Roo);
46037 grid.monitorWindowResize = false; // turn off autosizing
46038 grid.autoHeight = false;
46039 grid.autoWidth = false;
46041 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
46044 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
46045 getId : function(){
46046 return this.grid.id;
46050 * Returns the grid for this panel
46051 * @return {Roo.grid.Grid}
46053 getGrid : function(){
46057 setSize : function(width, height){
46058 if(!this.ignoreResize(width, height)){
46059 var grid = this.grid;
46060 var size = this.adjustForComponents(width, height);
46061 grid.getGridEl().setSize(size.width, size.height);
46066 beforeSlide : function(){
46067 this.grid.getView().scroller.clip();
46070 afterSlide : function(){
46071 this.grid.getView().scroller.unclip();
46074 destroy : function(){
46075 this.grid.destroy();
46077 Roo.GridPanel.superclass.destroy.call(this);
46083 * @class Roo.NestedLayoutPanel
46084 * @extends Roo.ContentPanel
46086 * Create a new NestedLayoutPanel.
46089 * @param {Roo.BorderLayout} layout The layout for this panel
46090 * @param {String/Object} config A string to set only the title or a config object
46092 Roo.NestedLayoutPanel = function(layout, config)
46094 // construct with only one argument..
46095 /* FIXME - implement nicer consturctors
46096 if (layout.layout) {
46098 layout = config.layout;
46099 delete config.layout;
46101 if (layout.xtype && !layout.getEl) {
46102 // then layout needs constructing..
46103 layout = Roo.factory(layout, Roo);
46108 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
46110 layout.monitorWindowResize = false; // turn off autosizing
46111 this.layout = layout;
46112 this.layout.getEl().addClass("x-layout-nested-layout");
46119 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
46121 setSize : function(width, height){
46122 if(!this.ignoreResize(width, height)){
46123 var size = this.adjustForComponents(width, height);
46124 var el = this.layout.getEl();
46125 el.setSize(size.width, size.height);
46126 var touch = el.dom.offsetWidth;
46127 this.layout.layout();
46128 // ie requires a double layout on the first pass
46129 if(Roo.isIE && !this.initialized){
46130 this.initialized = true;
46131 this.layout.layout();
46136 // activate all subpanels if not currently active..
46138 setActiveState : function(active){
46139 this.active = active;
46141 this.fireEvent("deactivate", this);
46145 this.fireEvent("activate", this);
46146 // not sure if this should happen before or after..
46147 if (!this.layout) {
46148 return; // should not happen..
46151 for (var r in this.layout.regions) {
46152 reg = this.layout.getRegion(r);
46153 if (reg.getActivePanel()) {
46154 //reg.showPanel(reg.getActivePanel()); // force it to activate..
46155 reg.setActivePanel(reg.getActivePanel());
46158 if (!reg.panels.length) {
46161 reg.showPanel(reg.getPanel(0));
46170 * Returns the nested BorderLayout for this panel
46171 * @return {Roo.BorderLayout}
46173 getLayout : function(){
46174 return this.layout;
46178 * Adds a xtype elements to the layout of the nested panel
46182 xtype : 'ContentPanel',
46189 xtype : 'NestedLayoutPanel',
46195 items : [ ... list of content panels or nested layout panels.. ]
46199 * @param {Object} cfg Xtype definition of item to add.
46201 addxtype : function(cfg) {
46202 return this.layout.addxtype(cfg);
46207 Roo.ScrollPanel = function(el, config, content){
46208 config = config || {};
46209 config.fitToFrame = true;
46210 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
46212 this.el.dom.style.overflow = "hidden";
46213 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
46214 this.el.removeClass("x-layout-inactive-content");
46215 this.el.on("mousewheel", this.onWheel, this);
46217 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
46218 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
46219 up.unselectable(); down.unselectable();
46220 up.on("click", this.scrollUp, this);
46221 down.on("click", this.scrollDown, this);
46222 up.addClassOnOver("x-scroller-btn-over");
46223 down.addClassOnOver("x-scroller-btn-over");
46224 up.addClassOnClick("x-scroller-btn-click");
46225 down.addClassOnClick("x-scroller-btn-click");
46226 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
46228 this.resizeEl = this.el;
46229 this.el = wrap; this.up = up; this.down = down;
46232 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
46234 wheelIncrement : 5,
46235 scrollUp : function(){
46236 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
46239 scrollDown : function(){
46240 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
46243 afterScroll : function(){
46244 var el = this.resizeEl;
46245 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
46246 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
46247 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
46250 setSize : function(){
46251 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
46252 this.afterScroll();
46255 onWheel : function(e){
46256 var d = e.getWheelDelta();
46257 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
46258 this.afterScroll();
46262 setContent : function(content, loadScripts){
46263 this.resizeEl.update(content, loadScripts);
46277 * @class Roo.TreePanel
46278 * @extends Roo.ContentPanel
46280 * Create a new TreePanel. - defaults to fit/scoll contents.
46281 * @param {String/Object} config A string to set only the panel's title, or a config object
46282 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
46284 Roo.TreePanel = function(config){
46285 var el = config.el;
46286 var tree = config.tree;
46287 delete config.tree;
46288 delete config.el; // hopefull!
46290 // wrapper for IE7 strict & safari scroll issue
46292 var treeEl = el.createChild();
46293 config.resizeEl = treeEl;
46297 Roo.TreePanel.superclass.constructor.call(this, el, config);
46300 this.tree = new Roo.tree.TreePanel(treeEl , tree);
46301 //console.log(tree);
46302 this.on('activate', function()
46304 if (this.tree.rendered) {
46307 //console.log('render tree');
46308 this.tree.render();
46311 this.on('resize', function (cp, w, h) {
46312 this.tree.innerCt.setWidth(w);
46313 this.tree.innerCt.setHeight(h);
46314 this.tree.innerCt.setStyle('overflow-y', 'auto');
46321 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
46338 * Ext JS Library 1.1.1
46339 * Copyright(c) 2006-2007, Ext JS, LLC.
46341 * Originally Released Under LGPL - original licence link has changed is not relivant.
46344 * <script type="text/javascript">
46349 * @class Roo.ReaderLayout
46350 * @extends Roo.BorderLayout
46351 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
46352 * center region containing two nested regions (a top one for a list view and one for item preview below),
46353 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
46354 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
46355 * expedites the setup of the overall layout and regions for this common application style.
46358 var reader = new Roo.ReaderLayout();
46359 var CP = Roo.ContentPanel; // shortcut for adding
46361 reader.beginUpdate();
46362 reader.add("north", new CP("north", "North"));
46363 reader.add("west", new CP("west", {title: "West"}));
46364 reader.add("east", new CP("east", {title: "East"}));
46366 reader.regions.listView.add(new CP("listView", "List"));
46367 reader.regions.preview.add(new CP("preview", "Preview"));
46368 reader.endUpdate();
46371 * Create a new ReaderLayout
46372 * @param {Object} config Configuration options
46373 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
46374 * document.body if omitted)
46376 Roo.ReaderLayout = function(config, renderTo){
46377 var c = config || {size:{}};
46378 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
46379 north: c.north !== false ? Roo.apply({
46383 }, c.north) : false,
46384 west: c.west !== false ? Roo.apply({
46392 margins:{left:5,right:0,bottom:5,top:5},
46393 cmargins:{left:5,right:5,bottom:5,top:5}
46394 }, c.west) : false,
46395 east: c.east !== false ? Roo.apply({
46403 margins:{left:0,right:5,bottom:5,top:5},
46404 cmargins:{left:5,right:5,bottom:5,top:5}
46405 }, c.east) : false,
46406 center: Roo.apply({
46407 tabPosition: 'top',
46411 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
46415 this.el.addClass('x-reader');
46417 this.beginUpdate();
46419 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
46420 south: c.preview !== false ? Roo.apply({
46427 cmargins:{top:5,left:0, right:0, bottom:0}
46428 }, c.preview) : false,
46429 center: Roo.apply({
46435 this.add('center', new Roo.NestedLayoutPanel(inner,
46436 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
46440 this.regions.preview = inner.getRegion('south');
46441 this.regions.listView = inner.getRegion('center');
46444 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
46446 * Ext JS Library 1.1.1
46447 * Copyright(c) 2006-2007, Ext JS, LLC.
46449 * Originally Released Under LGPL - original licence link has changed is not relivant.
46452 * <script type="text/javascript">
46456 * @class Roo.grid.Grid
46457 * @extends Roo.util.Observable
46458 * This class represents the primary interface of a component based grid control.
46459 * <br><br>Usage:<pre><code>
46460 var grid = new Roo.grid.Grid("my-container-id", {
46463 selModel: mySelectionModel,
46464 autoSizeColumns: true,
46465 monitorWindowResize: false,
46466 trackMouseOver: true
46471 * <b>Common Problems:</b><br/>
46472 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
46473 * element will correct this<br/>
46474 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
46475 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
46476 * are unpredictable.<br/>
46477 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
46478 * grid to calculate dimensions/offsets.<br/>
46480 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
46481 * The container MUST have some type of size defined for the grid to fill. The container will be
46482 * automatically set to position relative if it isn't already.
46483 * @param {Object} config A config object that sets properties on this grid.
46485 Roo.grid.Grid = function(container, config){
46486 // initialize the container
46487 this.container = Roo.get(container);
46488 this.container.update("");
46489 this.container.setStyle("overflow", "hidden");
46490 this.container.addClass('x-grid-container');
46492 this.id = this.container.id;
46494 Roo.apply(this, config);
46495 // check and correct shorthanded configs
46497 this.dataSource = this.ds;
46501 this.colModel = this.cm;
46505 this.selModel = this.sm;
46509 if (this.selModel) {
46510 this.selModel = Roo.factory(this.selModel, Roo.grid);
46511 this.sm = this.selModel;
46512 this.sm.xmodule = this.xmodule || false;
46514 if (typeof(this.colModel.config) == 'undefined') {
46515 this.colModel = new Roo.grid.ColumnModel(this.colModel);
46516 this.cm = this.colModel;
46517 this.cm.xmodule = this.xmodule || false;
46519 if (this.dataSource) {
46520 this.dataSource= Roo.factory(this.dataSource, Roo.data);
46521 this.ds = this.dataSource;
46522 this.ds.xmodule = this.xmodule || false;
46529 this.container.setWidth(this.width);
46533 this.container.setHeight(this.height);
46540 * The raw click event for the entire grid.
46541 * @param {Roo.EventObject} e
46546 * The raw dblclick event for the entire grid.
46547 * @param {Roo.EventObject} e
46551 * @event contextmenu
46552 * The raw contextmenu event for the entire grid.
46553 * @param {Roo.EventObject} e
46555 "contextmenu" : true,
46558 * The raw mousedown event for the entire grid.
46559 * @param {Roo.EventObject} e
46561 "mousedown" : true,
46564 * The raw mouseup event for the entire grid.
46565 * @param {Roo.EventObject} e
46570 * The raw mouseover event for the entire grid.
46571 * @param {Roo.EventObject} e
46573 "mouseover" : true,
46576 * The raw mouseout event for the entire grid.
46577 * @param {Roo.EventObject} e
46582 * The raw keypress event for the entire grid.
46583 * @param {Roo.EventObject} e
46588 * The raw keydown event for the entire grid.
46589 * @param {Roo.EventObject} e
46597 * Fires when a cell is clicked
46598 * @param {Grid} this
46599 * @param {Number} rowIndex
46600 * @param {Number} columnIndex
46601 * @param {Roo.EventObject} e
46603 "cellclick" : true,
46605 * @event celldblclick
46606 * Fires when a cell is double clicked
46607 * @param {Grid} this
46608 * @param {Number} rowIndex
46609 * @param {Number} columnIndex
46610 * @param {Roo.EventObject} e
46612 "celldblclick" : true,
46615 * Fires when a row is clicked
46616 * @param {Grid} this
46617 * @param {Number} rowIndex
46618 * @param {Roo.EventObject} e
46622 * @event rowdblclick
46623 * Fires when a row is double clicked
46624 * @param {Grid} this
46625 * @param {Number} rowIndex
46626 * @param {Roo.EventObject} e
46628 "rowdblclick" : true,
46630 * @event headerclick
46631 * Fires when a header is clicked
46632 * @param {Grid} this
46633 * @param {Number} columnIndex
46634 * @param {Roo.EventObject} e
46636 "headerclick" : true,
46638 * @event headerdblclick
46639 * Fires when a header cell is double clicked
46640 * @param {Grid} this
46641 * @param {Number} columnIndex
46642 * @param {Roo.EventObject} e
46644 "headerdblclick" : true,
46646 * @event rowcontextmenu
46647 * Fires when a row is right clicked
46648 * @param {Grid} this
46649 * @param {Number} rowIndex
46650 * @param {Roo.EventObject} e
46652 "rowcontextmenu" : true,
46654 * @event cellcontextmenu
46655 * Fires when a cell is right clicked
46656 * @param {Grid} this
46657 * @param {Number} rowIndex
46658 * @param {Number} cellIndex
46659 * @param {Roo.EventObject} e
46661 "cellcontextmenu" : true,
46663 * @event headercontextmenu
46664 * Fires when a header is right clicked
46665 * @param {Grid} this
46666 * @param {Number} columnIndex
46667 * @param {Roo.EventObject} e
46669 "headercontextmenu" : true,
46671 * @event bodyscroll
46672 * Fires when the body element is scrolled
46673 * @param {Number} scrollLeft
46674 * @param {Number} scrollTop
46676 "bodyscroll" : true,
46678 * @event columnresize
46679 * Fires when the user resizes a column
46680 * @param {Number} columnIndex
46681 * @param {Number} newSize
46683 "columnresize" : true,
46685 * @event columnmove
46686 * Fires when the user moves a column
46687 * @param {Number} oldIndex
46688 * @param {Number} newIndex
46690 "columnmove" : true,
46693 * Fires when row(s) start being dragged
46694 * @param {Grid} this
46695 * @param {Roo.GridDD} dd The drag drop object
46696 * @param {event} e The raw browser event
46698 "startdrag" : true,
46701 * Fires when a drag operation is complete
46702 * @param {Grid} this
46703 * @param {Roo.GridDD} dd The drag drop object
46704 * @param {event} e The raw browser event
46709 * Fires when dragged row(s) are dropped on a valid DD target
46710 * @param {Grid} this
46711 * @param {Roo.GridDD} dd The drag drop object
46712 * @param {String} targetId The target drag drop object
46713 * @param {event} e The raw browser event
46718 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
46719 * @param {Grid} this
46720 * @param {Roo.GridDD} dd The drag drop object
46721 * @param {String} targetId The target drag drop object
46722 * @param {event} e The raw browser event
46727 * Fires when the dragged row(s) first cross another DD target while being dragged
46728 * @param {Grid} this
46729 * @param {Roo.GridDD} dd The drag drop object
46730 * @param {String} targetId The target drag drop object
46731 * @param {event} e The raw browser event
46733 "dragenter" : true,
46736 * Fires when the dragged row(s) leave another DD target while being dragged
46737 * @param {Grid} this
46738 * @param {Roo.GridDD} dd The drag drop object
46739 * @param {String} targetId The target drag drop object
46740 * @param {event} e The raw browser event
46745 * Fires when a row is rendered, so you can change add a style to it.
46746 * @param {GridView} gridview The grid view
46747 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
46753 * Fires when the grid is rendered
46754 * @param {Grid} grid
46759 Roo.grid.Grid.superclass.constructor.call(this);
46761 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
46764 * @cfg {String} ddGroup - drag drop group.
46768 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
46770 minColumnWidth : 25,
46773 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
46774 * <b>on initial render.</b> It is more efficient to explicitly size the columns
46775 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
46777 autoSizeColumns : false,
46780 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
46782 autoSizeHeaders : true,
46785 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
46787 monitorWindowResize : true,
46790 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
46791 * rows measured to get a columns size. Default is 0 (all rows).
46793 maxRowsToMeasure : 0,
46796 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
46798 trackMouseOver : true,
46801 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
46805 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
46807 enableDragDrop : false,
46810 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
46812 enableColumnMove : true,
46815 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
46817 enableColumnHide : true,
46820 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
46822 enableRowHeightSync : false,
46825 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
46830 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
46832 autoHeight : false,
46835 * @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.
46837 autoExpandColumn : false,
46840 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
46843 autoExpandMin : 50,
46846 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
46848 autoExpandMax : 1000,
46851 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
46856 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
46860 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
46870 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
46871 * of a fixed width. Default is false.
46874 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
46877 * Called once after all setup has been completed and the grid is ready to be rendered.
46878 * @return {Roo.grid.Grid} this
46880 render : function()
46882 var c = this.container;
46883 // try to detect autoHeight/width mode
46884 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
46885 this.autoHeight = true;
46887 var view = this.getView();
46890 c.on("click", this.onClick, this);
46891 c.on("dblclick", this.onDblClick, this);
46892 c.on("contextmenu", this.onContextMenu, this);
46893 c.on("keydown", this.onKeyDown, this);
46895 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
46897 this.getSelectionModel().init(this);
46902 this.loadMask = new Roo.LoadMask(this.container,
46903 Roo.apply({store:this.dataSource}, this.loadMask));
46907 if (this.toolbar && this.toolbar.xtype) {
46908 this.toolbar.container = this.getView().getHeaderPanel(true);
46909 this.toolbar = new Roo.Toolbar(this.toolbar);
46911 if (this.footer && this.footer.xtype) {
46912 this.footer.dataSource = this.getDataSource();
46913 this.footer.container = this.getView().getFooterPanel(true);
46914 this.footer = Roo.factory(this.footer, Roo);
46916 if (this.dropTarget && this.dropTarget.xtype) {
46917 delete this.dropTarget.xtype;
46918 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
46922 this.rendered = true;
46923 this.fireEvent('render', this);
46928 * Reconfigures the grid to use a different Store and Column Model.
46929 * The View will be bound to the new objects and refreshed.
46930 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
46931 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
46933 reconfigure : function(dataSource, colModel){
46935 this.loadMask.destroy();
46936 this.loadMask = new Roo.LoadMask(this.container,
46937 Roo.apply({store:dataSource}, this.loadMask));
46939 this.view.bind(dataSource, colModel);
46940 this.dataSource = dataSource;
46941 this.colModel = colModel;
46942 this.view.refresh(true);
46946 onKeyDown : function(e){
46947 this.fireEvent("keydown", e);
46951 * Destroy this grid.
46952 * @param {Boolean} removeEl True to remove the element
46954 destroy : function(removeEl, keepListeners){
46956 this.loadMask.destroy();
46958 var c = this.container;
46959 c.removeAllListeners();
46960 this.view.destroy();
46961 this.colModel.purgeListeners();
46962 if(!keepListeners){
46963 this.purgeListeners();
46966 if(removeEl === true){
46972 processEvent : function(name, e){
46973 this.fireEvent(name, e);
46974 var t = e.getTarget();
46976 var header = v.findHeaderIndex(t);
46977 if(header !== false){
46978 this.fireEvent("header" + name, this, header, e);
46980 var row = v.findRowIndex(t);
46981 var cell = v.findCellIndex(t);
46983 this.fireEvent("row" + name, this, row, e);
46984 if(cell !== false){
46985 this.fireEvent("cell" + name, this, row, cell, e);
46992 onClick : function(e){
46993 this.processEvent("click", e);
46997 onContextMenu : function(e, t){
46998 this.processEvent("contextmenu", e);
47002 onDblClick : function(e){
47003 this.processEvent("dblclick", e);
47007 walkCells : function(row, col, step, fn, scope){
47008 var cm = this.colModel, clen = cm.getColumnCount();
47009 var ds = this.dataSource, rlen = ds.getCount(), first = true;
47021 if(fn.call(scope || this, row, col, cm) === true){
47039 if(fn.call(scope || this, row, col, cm) === true){
47051 getSelections : function(){
47052 return this.selModel.getSelections();
47056 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
47057 * but if manual update is required this method will initiate it.
47059 autoSize : function(){
47061 this.view.layout();
47062 if(this.view.adjustForScroll){
47063 this.view.adjustForScroll();
47069 * Returns the grid's underlying element.
47070 * @return {Element} The element
47072 getGridEl : function(){
47073 return this.container;
47076 // private for compatibility, overridden by editor grid
47077 stopEditing : function(){},
47080 * Returns the grid's SelectionModel.
47081 * @return {SelectionModel}
47083 getSelectionModel : function(){
47084 if(!this.selModel){
47085 this.selModel = new Roo.grid.RowSelectionModel();
47087 return this.selModel;
47091 * Returns the grid's DataSource.
47092 * @return {DataSource}
47094 getDataSource : function(){
47095 return this.dataSource;
47099 * Returns the grid's ColumnModel.
47100 * @return {ColumnModel}
47102 getColumnModel : function(){
47103 return this.colModel;
47107 * Returns the grid's GridView object.
47108 * @return {GridView}
47110 getView : function(){
47112 this.view = new Roo.grid.GridView(this.viewConfig);
47117 * Called to get grid's drag proxy text, by default returns this.ddText.
47120 getDragDropText : function(){
47121 var count = this.selModel.getCount();
47122 return String.format(this.ddText, count, count == 1 ? '' : 's');
47126 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
47127 * %0 is replaced with the number of selected rows.
47130 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
47132 * Ext JS Library 1.1.1
47133 * Copyright(c) 2006-2007, Ext JS, LLC.
47135 * Originally Released Under LGPL - original licence link has changed is not relivant.
47138 * <script type="text/javascript">
47141 Roo.grid.AbstractGridView = function(){
47145 "beforerowremoved" : true,
47146 "beforerowsinserted" : true,
47147 "beforerefresh" : true,
47148 "rowremoved" : true,
47149 "rowsinserted" : true,
47150 "rowupdated" : true,
47153 Roo.grid.AbstractGridView.superclass.constructor.call(this);
47156 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
47157 rowClass : "x-grid-row",
47158 cellClass : "x-grid-cell",
47159 tdClass : "x-grid-td",
47160 hdClass : "x-grid-hd",
47161 splitClass : "x-grid-hd-split",
47163 init: function(grid){
47165 var cid = this.grid.getGridEl().id;
47166 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
47167 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
47168 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
47169 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
47172 getColumnRenderers : function(){
47173 var renderers = [];
47174 var cm = this.grid.colModel;
47175 var colCount = cm.getColumnCount();
47176 for(var i = 0; i < colCount; i++){
47177 renderers[i] = cm.getRenderer(i);
47182 getColumnIds : function(){
47184 var cm = this.grid.colModel;
47185 var colCount = cm.getColumnCount();
47186 for(var i = 0; i < colCount; i++){
47187 ids[i] = cm.getColumnId(i);
47192 getDataIndexes : function(){
47193 if(!this.indexMap){
47194 this.indexMap = this.buildIndexMap();
47196 return this.indexMap.colToData;
47199 getColumnIndexByDataIndex : function(dataIndex){
47200 if(!this.indexMap){
47201 this.indexMap = this.buildIndexMap();
47203 return this.indexMap.dataToCol[dataIndex];
47207 * Set a css style for a column dynamically.
47208 * @param {Number} colIndex The index of the column
47209 * @param {String} name The css property name
47210 * @param {String} value The css value
47212 setCSSStyle : function(colIndex, name, value){
47213 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
47214 Roo.util.CSS.updateRule(selector, name, value);
47217 generateRules : function(cm){
47218 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
47219 Roo.util.CSS.removeStyleSheet(rulesId);
47220 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47221 var cid = cm.getColumnId(i);
47222 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
47223 this.tdSelector, cid, " {\n}\n",
47224 this.hdSelector, cid, " {\n}\n",
47225 this.splitSelector, cid, " {\n}\n");
47227 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
47231 * Ext JS Library 1.1.1
47232 * Copyright(c) 2006-2007, Ext JS, LLC.
47234 * Originally Released Under LGPL - original licence link has changed is not relivant.
47237 * <script type="text/javascript">
47241 // This is a support class used internally by the Grid components
47242 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
47244 this.view = grid.getView();
47245 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
47246 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
47248 this.setHandleElId(Roo.id(hd));
47249 this.setOuterHandleElId(Roo.id(hd2));
47251 this.scroll = false;
47253 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
47255 getDragData : function(e){
47256 var t = Roo.lib.Event.getTarget(e);
47257 var h = this.view.findHeaderCell(t);
47259 return {ddel: h.firstChild, header:h};
47264 onInitDrag : function(e){
47265 this.view.headersDisabled = true;
47266 var clone = this.dragData.ddel.cloneNode(true);
47267 clone.id = Roo.id();
47268 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
47269 this.proxy.update(clone);
47273 afterValidDrop : function(){
47275 setTimeout(function(){
47276 v.headersDisabled = false;
47280 afterInvalidDrop : function(){
47282 setTimeout(function(){
47283 v.headersDisabled = false;
47289 * Ext JS Library 1.1.1
47290 * Copyright(c) 2006-2007, Ext JS, LLC.
47292 * Originally Released Under LGPL - original licence link has changed is not relivant.
47295 * <script type="text/javascript">
47298 // This is a support class used internally by the Grid components
47299 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
47301 this.view = grid.getView();
47302 // split the proxies so they don't interfere with mouse events
47303 this.proxyTop = Roo.DomHelper.append(document.body, {
47304 cls:"col-move-top", html:" "
47306 this.proxyBottom = Roo.DomHelper.append(document.body, {
47307 cls:"col-move-bottom", html:" "
47309 this.proxyTop.hide = this.proxyBottom.hide = function(){
47310 this.setLeftTop(-100,-100);
47311 this.setStyle("visibility", "hidden");
47313 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
47314 // temporarily disabled
47315 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
47316 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
47318 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
47319 proxyOffsets : [-4, -9],
47320 fly: Roo.Element.fly,
47322 getTargetFromEvent : function(e){
47323 var t = Roo.lib.Event.getTarget(e);
47324 var cindex = this.view.findCellIndex(t);
47325 if(cindex !== false){
47326 return this.view.getHeaderCell(cindex);
47331 nextVisible : function(h){
47332 var v = this.view, cm = this.grid.colModel;
47335 if(!cm.isHidden(v.getCellIndex(h))){
47343 prevVisible : function(h){
47344 var v = this.view, cm = this.grid.colModel;
47347 if(!cm.isHidden(v.getCellIndex(h))){
47355 positionIndicator : function(h, n, e){
47356 var x = Roo.lib.Event.getPageX(e);
47357 var r = Roo.lib.Dom.getRegion(n.firstChild);
47358 var px, pt, py = r.top + this.proxyOffsets[1];
47359 if((r.right - x) <= (r.right-r.left)/2){
47360 px = r.right+this.view.borderWidth;
47366 var oldIndex = this.view.getCellIndex(h);
47367 var newIndex = this.view.getCellIndex(n);
47369 if(this.grid.colModel.isFixed(newIndex)){
47373 var locked = this.grid.colModel.isLocked(newIndex);
47378 if(oldIndex < newIndex){
47381 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
47384 px += this.proxyOffsets[0];
47385 this.proxyTop.setLeftTop(px, py);
47386 this.proxyTop.show();
47387 if(!this.bottomOffset){
47388 this.bottomOffset = this.view.mainHd.getHeight();
47390 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
47391 this.proxyBottom.show();
47395 onNodeEnter : function(n, dd, e, data){
47396 if(data.header != n){
47397 this.positionIndicator(data.header, n, e);
47401 onNodeOver : function(n, dd, e, data){
47402 var result = false;
47403 if(data.header != n){
47404 result = this.positionIndicator(data.header, n, e);
47407 this.proxyTop.hide();
47408 this.proxyBottom.hide();
47410 return result ? this.dropAllowed : this.dropNotAllowed;
47413 onNodeOut : function(n, dd, e, data){
47414 this.proxyTop.hide();
47415 this.proxyBottom.hide();
47418 onNodeDrop : function(n, dd, e, data){
47419 var h = data.header;
47421 var cm = this.grid.colModel;
47422 var x = Roo.lib.Event.getPageX(e);
47423 var r = Roo.lib.Dom.getRegion(n.firstChild);
47424 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
47425 var oldIndex = this.view.getCellIndex(h);
47426 var newIndex = this.view.getCellIndex(n);
47427 var locked = cm.isLocked(newIndex);
47431 if(oldIndex < newIndex){
47434 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
47437 cm.setLocked(oldIndex, locked, true);
47438 cm.moveColumn(oldIndex, newIndex);
47439 this.grid.fireEvent("columnmove", oldIndex, newIndex);
47447 * Ext JS Library 1.1.1
47448 * Copyright(c) 2006-2007, Ext JS, LLC.
47450 * Originally Released Under LGPL - original licence link has changed is not relivant.
47453 * <script type="text/javascript">
47457 * @class Roo.grid.GridView
47458 * @extends Roo.util.Observable
47461 * @param {Object} config
47463 Roo.grid.GridView = function(config){
47464 Roo.grid.GridView.superclass.constructor.call(this);
47467 Roo.apply(this, config);
47470 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
47473 * Override this function to apply custom css classes to rows during rendering
47474 * @param {Record} record The record
47475 * @param {Number} index
47476 * @method getRowClass
47478 rowClass : "x-grid-row",
47480 cellClass : "x-grid-col",
47482 tdClass : "x-grid-td",
47484 hdClass : "x-grid-hd",
47486 splitClass : "x-grid-split",
47488 sortClasses : ["sort-asc", "sort-desc"],
47490 enableMoveAnim : false,
47494 dh : Roo.DomHelper,
47496 fly : Roo.Element.fly,
47498 css : Roo.util.CSS,
47504 scrollIncrement : 22,
47506 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
47508 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
47510 bind : function(ds, cm){
47512 this.ds.un("load", this.onLoad, this);
47513 this.ds.un("datachanged", this.onDataChange, this);
47514 this.ds.un("add", this.onAdd, this);
47515 this.ds.un("remove", this.onRemove, this);
47516 this.ds.un("update", this.onUpdate, this);
47517 this.ds.un("clear", this.onClear, this);
47520 ds.on("load", this.onLoad, this);
47521 ds.on("datachanged", this.onDataChange, this);
47522 ds.on("add", this.onAdd, this);
47523 ds.on("remove", this.onRemove, this);
47524 ds.on("update", this.onUpdate, this);
47525 ds.on("clear", this.onClear, this);
47530 this.cm.un("widthchange", this.onColWidthChange, this);
47531 this.cm.un("headerchange", this.onHeaderChange, this);
47532 this.cm.un("hiddenchange", this.onHiddenChange, this);
47533 this.cm.un("columnmoved", this.onColumnMove, this);
47534 this.cm.un("columnlockchange", this.onColumnLock, this);
47537 this.generateRules(cm);
47538 cm.on("widthchange", this.onColWidthChange, this);
47539 cm.on("headerchange", this.onHeaderChange, this);
47540 cm.on("hiddenchange", this.onHiddenChange, this);
47541 cm.on("columnmoved", this.onColumnMove, this);
47542 cm.on("columnlockchange", this.onColumnLock, this);
47547 init: function(grid){
47548 Roo.grid.GridView.superclass.init.call(this, grid);
47550 this.bind(grid.dataSource, grid.colModel);
47552 grid.on("headerclick", this.handleHeaderClick, this);
47554 if(grid.trackMouseOver){
47555 grid.on("mouseover", this.onRowOver, this);
47556 grid.on("mouseout", this.onRowOut, this);
47558 grid.cancelTextSelection = function(){};
47559 this.gridId = grid.id;
47561 var tpls = this.templates || {};
47564 tpls.master = new Roo.Template(
47565 '<div class="x-grid" hidefocus="true">',
47566 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
47567 '<div class="x-grid-topbar"></div>',
47568 '<div class="x-grid-scroller"><div></div></div>',
47569 '<div class="x-grid-locked">',
47570 '<div class="x-grid-header">{lockedHeader}</div>',
47571 '<div class="x-grid-body">{lockedBody}</div>',
47573 '<div class="x-grid-viewport">',
47574 '<div class="x-grid-header">{header}</div>',
47575 '<div class="x-grid-body">{body}</div>',
47577 '<div class="x-grid-bottombar"></div>',
47579 '<div class="x-grid-resize-proxy"> </div>',
47582 tpls.master.disableformats = true;
47586 tpls.header = new Roo.Template(
47587 '<table border="0" cellspacing="0" cellpadding="0">',
47588 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
47591 tpls.header.disableformats = true;
47593 tpls.header.compile();
47596 tpls.hcell = new Roo.Template(
47597 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
47598 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
47601 tpls.hcell.disableFormats = true;
47603 tpls.hcell.compile();
47606 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
47607 tpls.hsplit.disableFormats = true;
47609 tpls.hsplit.compile();
47612 tpls.body = new Roo.Template(
47613 '<table border="0" cellspacing="0" cellpadding="0">',
47614 "<tbody>{rows}</tbody>",
47617 tpls.body.disableFormats = true;
47619 tpls.body.compile();
47622 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
47623 tpls.row.disableFormats = true;
47625 tpls.row.compile();
47628 tpls.cell = new Roo.Template(
47629 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
47630 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
47633 tpls.cell.disableFormats = true;
47635 tpls.cell.compile();
47637 this.templates = tpls;
47640 // remap these for backwards compat
47641 onColWidthChange : function(){
47642 this.updateColumns.apply(this, arguments);
47644 onHeaderChange : function(){
47645 this.updateHeaders.apply(this, arguments);
47647 onHiddenChange : function(){
47648 this.handleHiddenChange.apply(this, arguments);
47650 onColumnMove : function(){
47651 this.handleColumnMove.apply(this, arguments);
47653 onColumnLock : function(){
47654 this.handleLockChange.apply(this, arguments);
47657 onDataChange : function(){
47659 this.updateHeaderSortState();
47662 onClear : function(){
47666 onUpdate : function(ds, record){
47667 this.refreshRow(record);
47670 refreshRow : function(record){
47671 var ds = this.ds, index;
47672 if(typeof record == 'number'){
47674 record = ds.getAt(index);
47676 index = ds.indexOf(record);
47678 this.insertRows(ds, index, index, true);
47679 this.onRemove(ds, record, index+1, true);
47680 this.syncRowHeights(index, index);
47682 this.fireEvent("rowupdated", this, index, record);
47685 onAdd : function(ds, records, index){
47686 this.insertRows(ds, index, index + (records.length-1));
47689 onRemove : function(ds, record, index, isUpdate){
47690 if(isUpdate !== true){
47691 this.fireEvent("beforerowremoved", this, index, record);
47693 var bt = this.getBodyTable(), lt = this.getLockedTable();
47694 if(bt.rows[index]){
47695 bt.firstChild.removeChild(bt.rows[index]);
47697 if(lt.rows[index]){
47698 lt.firstChild.removeChild(lt.rows[index]);
47700 if(isUpdate !== true){
47701 this.stripeRows(index);
47702 this.syncRowHeights(index, index);
47704 this.fireEvent("rowremoved", this, index, record);
47708 onLoad : function(){
47709 this.scrollToTop();
47713 * Scrolls the grid to the top
47715 scrollToTop : function(){
47717 this.scroller.dom.scrollTop = 0;
47723 * Gets a panel in the header of the grid that can be used for toolbars etc.
47724 * After modifying the contents of this panel a call to grid.autoSize() may be
47725 * required to register any changes in size.
47726 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
47727 * @return Roo.Element
47729 getHeaderPanel : function(doShow){
47731 this.headerPanel.show();
47733 return this.headerPanel;
47737 * Gets a panel in the footer of the grid that can be used for toolbars etc.
47738 * After modifying the contents of this panel a call to grid.autoSize() may be
47739 * required to register any changes in size.
47740 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
47741 * @return Roo.Element
47743 getFooterPanel : function(doShow){
47745 this.footerPanel.show();
47747 return this.footerPanel;
47750 initElements : function(){
47751 var E = Roo.Element;
47752 var el = this.grid.getGridEl().dom.firstChild;
47753 var cs = el.childNodes;
47755 this.el = new E(el);
47757 this.focusEl = new E(el.firstChild);
47758 this.focusEl.swallowEvent("click", true);
47760 this.headerPanel = new E(cs[1]);
47761 this.headerPanel.enableDisplayMode("block");
47763 this.scroller = new E(cs[2]);
47764 this.scrollSizer = new E(this.scroller.dom.firstChild);
47766 this.lockedWrap = new E(cs[3]);
47767 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
47768 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
47770 this.mainWrap = new E(cs[4]);
47771 this.mainHd = new E(this.mainWrap.dom.firstChild);
47772 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
47774 this.footerPanel = new E(cs[5]);
47775 this.footerPanel.enableDisplayMode("block");
47777 this.resizeProxy = new E(cs[6]);
47779 this.headerSelector = String.format(
47780 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
47781 this.lockedHd.id, this.mainHd.id
47784 this.splitterSelector = String.format(
47785 '#{0} div.x-grid-split, #{1} div.x-grid-split',
47786 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
47789 idToCssName : function(s)
47791 return s.replace(/[^a-z0-9]+/ig, '-');
47794 getHeaderCell : function(index){
47795 return Roo.DomQuery.select(this.headerSelector)[index];
47798 getHeaderCellMeasure : function(index){
47799 return this.getHeaderCell(index).firstChild;
47802 getHeaderCellText : function(index){
47803 return this.getHeaderCell(index).firstChild.firstChild;
47806 getLockedTable : function(){
47807 return this.lockedBody.dom.firstChild;
47810 getBodyTable : function(){
47811 return this.mainBody.dom.firstChild;
47814 getLockedRow : function(index){
47815 return this.getLockedTable().rows[index];
47818 getRow : function(index){
47819 return this.getBodyTable().rows[index];
47822 getRowComposite : function(index){
47824 this.rowEl = new Roo.CompositeElementLite();
47826 var els = [], lrow, mrow;
47827 if(lrow = this.getLockedRow(index)){
47830 if(mrow = this.getRow(index)){
47833 this.rowEl.elements = els;
47837 getCell : function(rowIndex, colIndex){
47838 var locked = this.cm.getLockedCount();
47840 if(colIndex < locked){
47841 source = this.lockedBody.dom.firstChild;
47843 source = this.mainBody.dom.firstChild;
47844 colIndex -= locked;
47846 return source.rows[rowIndex].childNodes[colIndex];
47849 getCellText : function(rowIndex, colIndex){
47850 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
47853 getCellBox : function(cell){
47854 var b = this.fly(cell).getBox();
47855 if(Roo.isOpera){ // opera fails to report the Y
47856 b.y = cell.offsetTop + this.mainBody.getY();
47861 getCellIndex : function(cell){
47862 var id = String(cell.className).match(this.cellRE);
47864 return parseInt(id[1], 10);
47869 findHeaderIndex : function(n){
47870 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47871 return r ? this.getCellIndex(r) : false;
47874 findHeaderCell : function(n){
47875 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47876 return r ? r : false;
47879 findRowIndex : function(n){
47883 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
47884 return r ? r.rowIndex : false;
47887 findCellIndex : function(node){
47888 var stop = this.el.dom;
47889 while(node && node != stop){
47890 if(this.findRE.test(node.className)){
47891 return this.getCellIndex(node);
47893 node = node.parentNode;
47898 getColumnId : function(index){
47899 return this.cm.getColumnId(index);
47902 getSplitters : function()
47904 if(this.splitterSelector){
47905 return Roo.DomQuery.select(this.splitterSelector);
47911 getSplitter : function(index){
47912 return this.getSplitters()[index];
47915 onRowOver : function(e, t){
47917 if((row = this.findRowIndex(t)) !== false){
47918 this.getRowComposite(row).addClass("x-grid-row-over");
47922 onRowOut : function(e, t){
47924 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
47925 this.getRowComposite(row).removeClass("x-grid-row-over");
47929 renderHeaders : function(){
47931 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
47932 var cb = [], lb = [], sb = [], lsb = [], p = {};
47933 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47934 p.cellId = "x-grid-hd-0-" + i;
47935 p.splitId = "x-grid-csplit-0-" + i;
47936 p.id = cm.getColumnId(i);
47937 p.title = cm.getColumnTooltip(i) || "";
47938 p.value = cm.getColumnHeader(i) || "";
47939 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
47940 if(!cm.isLocked(i)){
47941 cb[cb.length] = ct.apply(p);
47942 sb[sb.length] = st.apply(p);
47944 lb[lb.length] = ct.apply(p);
47945 lsb[lsb.length] = st.apply(p);
47948 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
47949 ht.apply({cells: cb.join(""), splits:sb.join("")})];
47952 updateHeaders : function(){
47953 var html = this.renderHeaders();
47954 this.lockedHd.update(html[0]);
47955 this.mainHd.update(html[1]);
47959 * Focuses the specified row.
47960 * @param {Number} row The row index
47962 focusRow : function(row)
47964 //Roo.log('GridView.focusRow');
47965 var x = this.scroller.dom.scrollLeft;
47966 this.focusCell(row, 0, false);
47967 this.scroller.dom.scrollLeft = x;
47971 * Focuses the specified cell.
47972 * @param {Number} row The row index
47973 * @param {Number} col The column index
47974 * @param {Boolean} hscroll false to disable horizontal scrolling
47976 focusCell : function(row, col, hscroll)
47978 //Roo.log('GridView.focusCell');
47979 var el = this.ensureVisible(row, col, hscroll);
47980 this.focusEl.alignTo(el, "tl-tl");
47982 this.focusEl.focus();
47984 this.focusEl.focus.defer(1, this.focusEl);
47989 * Scrolls the specified cell into view
47990 * @param {Number} row The row index
47991 * @param {Number} col The column index
47992 * @param {Boolean} hscroll false to disable horizontal scrolling
47994 ensureVisible : function(row, col, hscroll)
47996 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
47997 //return null; //disable for testing.
47998 if(typeof row != "number"){
47999 row = row.rowIndex;
48001 if(row < 0 && row >= this.ds.getCount()){
48004 col = (col !== undefined ? col : 0);
48005 var cm = this.grid.colModel;
48006 while(cm.isHidden(col)){
48010 var el = this.getCell(row, col);
48014 var c = this.scroller.dom;
48016 var ctop = parseInt(el.offsetTop, 10);
48017 var cleft = parseInt(el.offsetLeft, 10);
48018 var cbot = ctop + el.offsetHeight;
48019 var cright = cleft + el.offsetWidth;
48021 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
48022 var stop = parseInt(c.scrollTop, 10);
48023 var sleft = parseInt(c.scrollLeft, 10);
48024 var sbot = stop + ch;
48025 var sright = sleft + c.clientWidth;
48027 Roo.log('GridView.ensureVisible:' +
48029 ' c.clientHeight:' + c.clientHeight +
48030 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
48038 c.scrollTop = ctop;
48039 //Roo.log("set scrolltop to ctop DISABLE?");
48040 }else if(cbot > sbot){
48041 //Roo.log("set scrolltop to cbot-ch");
48042 c.scrollTop = cbot-ch;
48045 if(hscroll !== false){
48047 c.scrollLeft = cleft;
48048 }else if(cright > sright){
48049 c.scrollLeft = cright-c.clientWidth;
48056 updateColumns : function(){
48057 this.grid.stopEditing();
48058 var cm = this.grid.colModel, colIds = this.getColumnIds();
48059 //var totalWidth = cm.getTotalWidth();
48061 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48062 //if(cm.isHidden(i)) continue;
48063 var w = cm.getColumnWidth(i);
48064 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48065 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48067 this.updateSplitters();
48070 generateRules : function(cm){
48071 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
48072 Roo.util.CSS.removeStyleSheet(rulesId);
48073 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48074 var cid = cm.getColumnId(i);
48076 if(cm.config[i].align){
48077 align = 'text-align:'+cm.config[i].align+';';
48080 if(cm.isHidden(i)){
48081 hidden = 'display:none;';
48083 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
48085 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
48086 this.hdSelector, cid, " {\n", align, width, "}\n",
48087 this.tdSelector, cid, " {\n",hidden,"\n}\n",
48088 this.splitSelector, cid, " {\n", hidden , "\n}\n");
48090 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
48093 updateSplitters : function(){
48094 var cm = this.cm, s = this.getSplitters();
48095 if(s){ // splitters not created yet
48096 var pos = 0, locked = true;
48097 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48098 if(cm.isHidden(i)) continue;
48099 var w = cm.getColumnWidth(i); // make sure it's a number
48100 if(!cm.isLocked(i) && locked){
48105 s[i].style.left = (pos-this.splitOffset) + "px";
48110 handleHiddenChange : function(colModel, colIndex, hidden){
48112 this.hideColumn(colIndex);
48114 this.unhideColumn(colIndex);
48118 hideColumn : function(colIndex){
48119 var cid = this.getColumnId(colIndex);
48120 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
48121 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
48123 this.updateHeaders();
48125 this.updateSplitters();
48129 unhideColumn : function(colIndex){
48130 var cid = this.getColumnId(colIndex);
48131 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
48132 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
48135 this.updateHeaders();
48137 this.updateSplitters();
48141 insertRows : function(dm, firstRow, lastRow, isUpdate){
48142 if(firstRow == 0 && lastRow == dm.getCount()-1){
48146 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
48148 var s = this.getScrollState();
48149 var markup = this.renderRows(firstRow, lastRow);
48150 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
48151 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
48152 this.restoreScroll(s);
48154 this.fireEvent("rowsinserted", this, firstRow, lastRow);
48155 this.syncRowHeights(firstRow, lastRow);
48156 this.stripeRows(firstRow);
48162 bufferRows : function(markup, target, index){
48163 var before = null, trows = target.rows, tbody = target.tBodies[0];
48164 if(index < trows.length){
48165 before = trows[index];
48167 var b = document.createElement("div");
48168 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
48169 var rows = b.firstChild.rows;
48170 for(var i = 0, len = rows.length; i < len; i++){
48172 tbody.insertBefore(rows[0], before);
48174 tbody.appendChild(rows[0]);
48181 deleteRows : function(dm, firstRow, lastRow){
48182 if(dm.getRowCount()<1){
48183 this.fireEvent("beforerefresh", this);
48184 this.mainBody.update("");
48185 this.lockedBody.update("");
48186 this.fireEvent("refresh", this);
48188 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
48189 var bt = this.getBodyTable();
48190 var tbody = bt.firstChild;
48191 var rows = bt.rows;
48192 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
48193 tbody.removeChild(rows[firstRow]);
48195 this.stripeRows(firstRow);
48196 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
48200 updateRows : function(dataSource, firstRow, lastRow){
48201 var s = this.getScrollState();
48203 this.restoreScroll(s);
48206 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
48210 this.updateHeaderSortState();
48213 getScrollState : function(){
48215 var sb = this.scroller.dom;
48216 return {left: sb.scrollLeft, top: sb.scrollTop};
48219 stripeRows : function(startRow){
48220 if(!this.grid.stripeRows || this.ds.getCount() < 1){
48223 startRow = startRow || 0;
48224 var rows = this.getBodyTable().rows;
48225 var lrows = this.getLockedTable().rows;
48226 var cls = ' x-grid-row-alt ';
48227 for(var i = startRow, len = rows.length; i < len; i++){
48228 var row = rows[i], lrow = lrows[i];
48229 var isAlt = ((i+1) % 2 == 0);
48230 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
48231 if(isAlt == hasAlt){
48235 row.className += " x-grid-row-alt";
48237 row.className = row.className.replace("x-grid-row-alt", "");
48240 lrow.className = row.className;
48245 restoreScroll : function(state){
48246 //Roo.log('GridView.restoreScroll');
48247 var sb = this.scroller.dom;
48248 sb.scrollLeft = state.left;
48249 sb.scrollTop = state.top;
48253 syncScroll : function(){
48254 //Roo.log('GridView.syncScroll');
48255 var sb = this.scroller.dom;
48256 var sh = this.mainHd.dom;
48257 var bs = this.mainBody.dom;
48258 var lv = this.lockedBody.dom;
48259 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
48260 lv.scrollTop = bs.scrollTop = sb.scrollTop;
48263 handleScroll : function(e){
48265 var sb = this.scroller.dom;
48266 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
48270 handleWheel : function(e){
48271 var d = e.getWheelDelta();
48272 this.scroller.dom.scrollTop -= d*22;
48273 // set this here to prevent jumpy scrolling on large tables
48274 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
48278 renderRows : function(startRow, endRow){
48279 // pull in all the crap needed to render rows
48280 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
48281 var colCount = cm.getColumnCount();
48283 if(ds.getCount() < 1){
48287 // build a map for all the columns
48289 for(var i = 0; i < colCount; i++){
48290 var name = cm.getDataIndex(i);
48292 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
48293 renderer : cm.getRenderer(i),
48294 id : cm.getColumnId(i),
48295 locked : cm.isLocked(i)
48299 startRow = startRow || 0;
48300 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
48302 // records to render
48303 var rs = ds.getRange(startRow, endRow);
48305 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
48308 // As much as I hate to duplicate code, this was branched because FireFox really hates
48309 // [].join("") on strings. The performance difference was substantial enough to
48310 // branch this function
48311 doRender : Roo.isGecko ?
48312 function(cs, rs, ds, startRow, colCount, stripe){
48313 var ts = this.templates, ct = ts.cell, rt = ts.row;
48315 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
48317 var hasListener = this.grid.hasListener('rowclass');
48319 for(var j = 0, len = rs.length; j < len; j++){
48320 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
48321 for(var i = 0; i < colCount; i++){
48323 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
48325 p.css = p.attr = "";
48326 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
48327 if(p.value == undefined || p.value === "") p.value = " ";
48328 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
48329 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
48331 var markup = ct.apply(p);
48339 if(stripe && ((rowIndex+1) % 2 == 0)){
48340 alt.push("x-grid-row-alt")
48343 alt.push( " x-grid-dirty-row");
48346 if(this.getRowClass){
48347 alt.push(this.getRowClass(r, rowIndex));
48353 rowIndex : rowIndex,
48356 this.grid.fireEvent('rowclass', this, rowcfg);
48357 alt.push(rowcfg.rowClass);
48359 rp.alt = alt.join(" ");
48360 lbuf+= rt.apply(rp);
48362 buf+= rt.apply(rp);
48364 return [lbuf, buf];
48366 function(cs, rs, ds, startRow, colCount, stripe){
48367 var ts = this.templates, ct = ts.cell, rt = ts.row;
48369 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
48370 var hasListener = this.grid.hasListener('rowclass');
48372 for(var j = 0, len = rs.length; j < len; j++){
48373 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
48374 for(var i = 0; i < colCount; i++){
48376 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
48378 p.css = p.attr = "";
48379 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
48380 if(p.value == undefined || p.value === "") p.value = " ";
48381 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
48382 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
48384 var markup = ct.apply(p);
48386 cb[cb.length] = markup;
48388 lcb[lcb.length] = markup;
48392 if(stripe && ((rowIndex+1) % 2 == 0)){
48393 alt.push( "x-grid-row-alt");
48396 alt.push(" x-grid-dirty-row");
48399 if(this.getRowClass){
48400 alt.push( this.getRowClass(r, rowIndex));
48406 rowIndex : rowIndex,
48409 this.grid.fireEvent('rowclass', this, rowcfg);
48410 alt.push(rowcfg.rowClass);
48412 rp.alt = alt.join(" ");
48413 rp.cells = lcb.join("");
48414 lbuf[lbuf.length] = rt.apply(rp);
48415 rp.cells = cb.join("");
48416 buf[buf.length] = rt.apply(rp);
48418 return [lbuf.join(""), buf.join("")];
48421 renderBody : function(){
48422 var markup = this.renderRows();
48423 var bt = this.templates.body;
48424 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
48428 * Refreshes the grid
48429 * @param {Boolean} headersToo
48431 refresh : function(headersToo){
48432 this.fireEvent("beforerefresh", this);
48433 this.grid.stopEditing();
48434 var result = this.renderBody();
48435 this.lockedBody.update(result[0]);
48436 this.mainBody.update(result[1]);
48437 if(headersToo === true){
48438 this.updateHeaders();
48439 this.updateColumns();
48440 this.updateSplitters();
48441 this.updateHeaderSortState();
48443 this.syncRowHeights();
48445 this.fireEvent("refresh", this);
48448 handleColumnMove : function(cm, oldIndex, newIndex){
48449 this.indexMap = null;
48450 var s = this.getScrollState();
48451 this.refresh(true);
48452 this.restoreScroll(s);
48453 this.afterMove(newIndex);
48456 afterMove : function(colIndex){
48457 if(this.enableMoveAnim && Roo.enableFx){
48458 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
48460 // if multisort - fix sortOrder, and reload..
48461 if (this.grid.dataSource.multiSort) {
48462 // the we can call sort again..
48463 var dm = this.grid.dataSource;
48464 var cm = this.grid.colModel;
48466 for(var i = 0; i < cm.config.length; i++ ) {
48468 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
48469 continue; // dont' bother, it's not in sort list or being set.
48472 so.push(cm.config[i].dataIndex);
48475 dm.load(dm.lastOptions);
48482 updateCell : function(dm, rowIndex, dataIndex){
48483 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
48484 if(typeof colIndex == "undefined"){ // not present in grid
48487 var cm = this.grid.colModel;
48488 var cell = this.getCell(rowIndex, colIndex);
48489 var cellText = this.getCellText(rowIndex, colIndex);
48492 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
48493 id : cm.getColumnId(colIndex),
48494 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
48496 var renderer = cm.getRenderer(colIndex);
48497 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
48498 if(typeof val == "undefined" || val === "") val = " ";
48499 cellText.innerHTML = val;
48500 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
48501 this.syncRowHeights(rowIndex, rowIndex);
48504 calcColumnWidth : function(colIndex, maxRowsToMeasure){
48506 if(this.grid.autoSizeHeaders){
48507 var h = this.getHeaderCellMeasure(colIndex);
48508 maxWidth = Math.max(maxWidth, h.scrollWidth);
48511 if(this.cm.isLocked(colIndex)){
48512 tb = this.getLockedTable();
48515 tb = this.getBodyTable();
48516 index = colIndex - this.cm.getLockedCount();
48519 var rows = tb.rows;
48520 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
48521 for(var i = 0; i < stopIndex; i++){
48522 var cell = rows[i].childNodes[index].firstChild;
48523 maxWidth = Math.max(maxWidth, cell.scrollWidth);
48526 return maxWidth + /*margin for error in IE*/ 5;
48529 * Autofit a column to its content.
48530 * @param {Number} colIndex
48531 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
48533 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
48534 if(this.cm.isHidden(colIndex)){
48535 return; // can't calc a hidden column
48538 var cid = this.cm.getColumnId(colIndex);
48539 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
48540 if(this.grid.autoSizeHeaders){
48541 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
48544 var newWidth = this.calcColumnWidth(colIndex);
48545 this.cm.setColumnWidth(colIndex,
48546 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
48547 if(!suppressEvent){
48548 this.grid.fireEvent("columnresize", colIndex, newWidth);
48553 * Autofits all columns to their content and then expands to fit any extra space in the grid
48555 autoSizeColumns : function(){
48556 var cm = this.grid.colModel;
48557 var colCount = cm.getColumnCount();
48558 for(var i = 0; i < colCount; i++){
48559 this.autoSizeColumn(i, true, true);
48561 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
48564 this.updateColumns();
48570 * Autofits all columns to the grid's width proportionate with their current size
48571 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
48573 fitColumns : function(reserveScrollSpace){
48574 var cm = this.grid.colModel;
48575 var colCount = cm.getColumnCount();
48579 for (i = 0; i < colCount; i++){
48580 if(!cm.isHidden(i) && !cm.isFixed(i)){
48581 w = cm.getColumnWidth(i);
48587 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
48588 if(reserveScrollSpace){
48591 var frac = (avail - cm.getTotalWidth())/width;
48592 while (cols.length){
48595 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
48597 this.updateColumns();
48601 onRowSelect : function(rowIndex){
48602 var row = this.getRowComposite(rowIndex);
48603 row.addClass("x-grid-row-selected");
48606 onRowDeselect : function(rowIndex){
48607 var row = this.getRowComposite(rowIndex);
48608 row.removeClass("x-grid-row-selected");
48611 onCellSelect : function(row, col){
48612 var cell = this.getCell(row, col);
48614 Roo.fly(cell).addClass("x-grid-cell-selected");
48618 onCellDeselect : function(row, col){
48619 var cell = this.getCell(row, col);
48621 Roo.fly(cell).removeClass("x-grid-cell-selected");
48625 updateHeaderSortState : function(){
48627 // sort state can be single { field: xxx, direction : yyy}
48628 // or { xxx=>ASC , yyy : DESC ..... }
48631 if (!this.ds.multiSort) {
48632 var state = this.ds.getSortState();
48636 mstate[state.field] = state.direction;
48637 // FIXME... - this is not used here.. but might be elsewhere..
48638 this.sortState = state;
48641 mstate = this.ds.sortToggle;
48643 //remove existing sort classes..
48645 var sc = this.sortClasses;
48646 var hds = this.el.select(this.headerSelector).removeClass(sc);
48648 for(var f in mstate) {
48650 var sortColumn = this.cm.findColumnIndex(f);
48652 if(sortColumn != -1){
48653 var sortDir = mstate[f];
48654 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
48663 handleHeaderClick : function(g, index){
48664 if(this.headersDisabled){
48667 var dm = g.dataSource, cm = g.colModel;
48668 if(!cm.isSortable(index)){
48673 if (dm.multiSort) {
48674 // update the sortOrder
48676 for(var i = 0; i < cm.config.length; i++ ) {
48678 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
48679 continue; // dont' bother, it's not in sort list or being set.
48682 so.push(cm.config[i].dataIndex);
48688 dm.sort(cm.getDataIndex(index));
48692 destroy : function(){
48694 this.colMenu.removeAll();
48695 Roo.menu.MenuMgr.unregister(this.colMenu);
48696 this.colMenu.getEl().remove();
48697 delete this.colMenu;
48700 this.hmenu.removeAll();
48701 Roo.menu.MenuMgr.unregister(this.hmenu);
48702 this.hmenu.getEl().remove();
48705 if(this.grid.enableColumnMove){
48706 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48708 for(var dd in dds){
48709 if(!dds[dd].config.isTarget && dds[dd].dragElId){
48710 var elid = dds[dd].dragElId;
48712 Roo.get(elid).remove();
48713 } else if(dds[dd].config.isTarget){
48714 dds[dd].proxyTop.remove();
48715 dds[dd].proxyBottom.remove();
48718 if(Roo.dd.DDM.locationCache[dd]){
48719 delete Roo.dd.DDM.locationCache[dd];
48722 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48725 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
48726 this.bind(null, null);
48727 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
48730 handleLockChange : function(){
48731 this.refresh(true);
48734 onDenyColumnLock : function(){
48738 onDenyColumnHide : function(){
48742 handleHdMenuClick : function(item){
48743 var index = this.hdCtxIndex;
48744 var cm = this.cm, ds = this.ds;
48747 ds.sort(cm.getDataIndex(index), "ASC");
48750 ds.sort(cm.getDataIndex(index), "DESC");
48753 var lc = cm.getLockedCount();
48754 if(cm.getColumnCount(true) <= lc+1){
48755 this.onDenyColumnLock();
48759 cm.setLocked(index, true, true);
48760 cm.moveColumn(index, lc);
48761 this.grid.fireEvent("columnmove", index, lc);
48763 cm.setLocked(index, true);
48767 var lc = cm.getLockedCount();
48768 if((lc-1) != index){
48769 cm.setLocked(index, false, true);
48770 cm.moveColumn(index, lc-1);
48771 this.grid.fireEvent("columnmove", index, lc-1);
48773 cm.setLocked(index, false);
48777 index = cm.getIndexById(item.id.substr(4));
48779 if(item.checked && cm.getColumnCount(true) <= 1){
48780 this.onDenyColumnHide();
48783 cm.setHidden(index, item.checked);
48789 beforeColMenuShow : function(){
48790 var cm = this.cm, colCount = cm.getColumnCount();
48791 this.colMenu.removeAll();
48792 for(var i = 0; i < colCount; i++){
48793 this.colMenu.add(new Roo.menu.CheckItem({
48794 id: "col-"+cm.getColumnId(i),
48795 text: cm.getColumnHeader(i),
48796 checked: !cm.isHidden(i),
48802 handleHdCtx : function(g, index, e){
48804 var hd = this.getHeaderCell(index);
48805 this.hdCtxIndex = index;
48806 var ms = this.hmenu.items, cm = this.cm;
48807 ms.get("asc").setDisabled(!cm.isSortable(index));
48808 ms.get("desc").setDisabled(!cm.isSortable(index));
48809 if(this.grid.enableColLock !== false){
48810 ms.get("lock").setDisabled(cm.isLocked(index));
48811 ms.get("unlock").setDisabled(!cm.isLocked(index));
48813 this.hmenu.show(hd, "tl-bl");
48816 handleHdOver : function(e){
48817 var hd = this.findHeaderCell(e.getTarget());
48818 if(hd && !this.headersDisabled){
48819 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
48820 this.fly(hd).addClass("x-grid-hd-over");
48825 handleHdOut : function(e){
48826 var hd = this.findHeaderCell(e.getTarget());
48828 this.fly(hd).removeClass("x-grid-hd-over");
48832 handleSplitDblClick : function(e, t){
48833 var i = this.getCellIndex(t);
48834 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
48835 this.autoSizeColumn(i, true);
48840 render : function(){
48843 var colCount = cm.getColumnCount();
48845 if(this.grid.monitorWindowResize === true){
48846 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48848 var header = this.renderHeaders();
48849 var body = this.templates.body.apply({rows:""});
48850 var html = this.templates.master.apply({
48853 lockedHeader: header[0],
48857 //this.updateColumns();
48859 this.grid.getGridEl().dom.innerHTML = html;
48861 this.initElements();
48863 // a kludge to fix the random scolling effect in webkit
48864 this.el.on("scroll", function() {
48865 this.el.dom.scrollTop=0; // hopefully not recursive..
48868 this.scroller.on("scroll", this.handleScroll, this);
48869 this.lockedBody.on("mousewheel", this.handleWheel, this);
48870 this.mainBody.on("mousewheel", this.handleWheel, this);
48872 this.mainHd.on("mouseover", this.handleHdOver, this);
48873 this.mainHd.on("mouseout", this.handleHdOut, this);
48874 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
48875 {delegate: "."+this.splitClass});
48877 this.lockedHd.on("mouseover", this.handleHdOver, this);
48878 this.lockedHd.on("mouseout", this.handleHdOut, this);
48879 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
48880 {delegate: "."+this.splitClass});
48882 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
48883 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48886 this.updateSplitters();
48888 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
48889 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48890 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48893 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
48894 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
48896 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
48897 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
48899 if(this.grid.enableColLock !== false){
48900 this.hmenu.add('-',
48901 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
48902 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
48905 if(this.grid.enableColumnHide !== false){
48907 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
48908 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
48909 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
48911 this.hmenu.add('-',
48912 {id:"columns", text: this.columnsText, menu: this.colMenu}
48915 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
48917 this.grid.on("headercontextmenu", this.handleHdCtx, this);
48920 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
48921 this.dd = new Roo.grid.GridDragZone(this.grid, {
48922 ddGroup : this.grid.ddGroup || 'GridDD'
48927 for(var i = 0; i < colCount; i++){
48928 if(cm.isHidden(i)){
48929 this.hideColumn(i);
48931 if(cm.config[i].align){
48932 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
48933 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
48937 this.updateHeaderSortState();
48939 this.beforeInitialResize();
48942 // two part rendering gives faster view to the user
48943 this.renderPhase2.defer(1, this);
48946 renderPhase2 : function(){
48947 // render the rows now
48949 if(this.grid.autoSizeColumns){
48950 this.autoSizeColumns();
48954 beforeInitialResize : function(){
48958 onColumnSplitterMoved : function(i, w){
48959 this.userResized = true;
48960 var cm = this.grid.colModel;
48961 cm.setColumnWidth(i, w, true);
48962 var cid = cm.getColumnId(i);
48963 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48964 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48965 this.updateSplitters();
48967 this.grid.fireEvent("columnresize", i, w);
48970 syncRowHeights : function(startIndex, endIndex){
48971 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
48972 startIndex = startIndex || 0;
48973 var mrows = this.getBodyTable().rows;
48974 var lrows = this.getLockedTable().rows;
48975 var len = mrows.length-1;
48976 endIndex = Math.min(endIndex || len, len);
48977 for(var i = startIndex; i <= endIndex; i++){
48978 var m = mrows[i], l = lrows[i];
48979 var h = Math.max(m.offsetHeight, l.offsetHeight);
48980 m.style.height = l.style.height = h + "px";
48985 layout : function(initialRender, is2ndPass){
48987 var auto = g.autoHeight;
48988 var scrollOffset = 16;
48989 var c = g.getGridEl(), cm = this.cm,
48990 expandCol = g.autoExpandColumn,
48992 //c.beginMeasure();
48994 if(!c.dom.offsetWidth){ // display:none?
48996 this.lockedWrap.show();
48997 this.mainWrap.show();
49002 var hasLock = this.cm.isLocked(0);
49004 var tbh = this.headerPanel.getHeight();
49005 var bbh = this.footerPanel.getHeight();
49008 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
49009 var newHeight = ch + c.getBorderWidth("tb");
49011 newHeight = Math.min(g.maxHeight, newHeight);
49013 c.setHeight(newHeight);
49017 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
49020 var s = this.scroller;
49022 var csize = c.getSize(true);
49024 this.el.setSize(csize.width, csize.height);
49026 this.headerPanel.setWidth(csize.width);
49027 this.footerPanel.setWidth(csize.width);
49029 var hdHeight = this.mainHd.getHeight();
49030 var vw = csize.width;
49031 var vh = csize.height - (tbh + bbh);
49035 var bt = this.getBodyTable();
49036 var ltWidth = hasLock ?
49037 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
49039 var scrollHeight = bt.offsetHeight;
49040 var scrollWidth = ltWidth + bt.offsetWidth;
49041 var vscroll = false, hscroll = false;
49043 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
49045 var lw = this.lockedWrap, mw = this.mainWrap;
49046 var lb = this.lockedBody, mb = this.mainBody;
49048 setTimeout(function(){
49049 var t = s.dom.offsetTop;
49050 var w = s.dom.clientWidth,
49051 h = s.dom.clientHeight;
49054 lw.setSize(ltWidth, h);
49056 mw.setLeftTop(ltWidth, t);
49057 mw.setSize(w-ltWidth, h);
49059 lb.setHeight(h-hdHeight);
49060 mb.setHeight(h-hdHeight);
49062 if(is2ndPass !== true && !gv.userResized && expandCol){
49063 // high speed resize without full column calculation
49065 var ci = cm.getIndexById(expandCol);
49067 ci = cm.findColumnIndex(expandCol);
49069 ci = Math.max(0, ci); // make sure it's got at least the first col.
49070 var expandId = cm.getColumnId(ci);
49071 var tw = cm.getTotalWidth(false);
49072 var currentWidth = cm.getColumnWidth(ci);
49073 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
49074 if(currentWidth != cw){
49075 cm.setColumnWidth(ci, cw, true);
49076 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
49077 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
49078 gv.updateSplitters();
49079 gv.layout(false, true);
49091 onWindowResize : function(){
49092 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
49098 appendFooter : function(parentEl){
49102 sortAscText : "Sort Ascending",
49103 sortDescText : "Sort Descending",
49104 lockText : "Lock Column",
49105 unlockText : "Unlock Column",
49106 columnsText : "Columns"
49110 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
49111 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
49112 this.proxy.el.addClass('x-grid3-col-dd');
49115 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
49116 handleMouseDown : function(e){
49120 callHandleMouseDown : function(e){
49121 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
49126 * Ext JS Library 1.1.1
49127 * Copyright(c) 2006-2007, Ext JS, LLC.
49129 * Originally Released Under LGPL - original licence link has changed is not relivant.
49132 * <script type="text/javascript">
49136 // This is a support class used internally by the Grid components
49137 Roo.grid.SplitDragZone = function(grid, hd, hd2){
49139 this.view = grid.getView();
49140 this.proxy = this.view.resizeProxy;
49141 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
49142 "gridSplitters" + this.grid.getGridEl().id, {
49143 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
49145 this.setHandleElId(Roo.id(hd));
49146 this.setOuterHandleElId(Roo.id(hd2));
49147 this.scroll = false;
49149 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
49150 fly: Roo.Element.fly,
49152 b4StartDrag : function(x, y){
49153 this.view.headersDisabled = true;
49154 this.proxy.setHeight(this.view.mainWrap.getHeight());
49155 var w = this.cm.getColumnWidth(this.cellIndex);
49156 var minw = Math.max(w-this.grid.minColumnWidth, 0);
49157 this.resetConstraints();
49158 this.setXConstraint(minw, 1000);
49159 this.setYConstraint(0, 0);
49160 this.minX = x - minw;
49161 this.maxX = x + 1000;
49163 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
49167 handleMouseDown : function(e){
49168 ev = Roo.EventObject.setEvent(e);
49169 var t = this.fly(ev.getTarget());
49170 if(t.hasClass("x-grid-split")){
49171 this.cellIndex = this.view.getCellIndex(t.dom);
49172 this.split = t.dom;
49173 this.cm = this.grid.colModel;
49174 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
49175 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
49180 endDrag : function(e){
49181 this.view.headersDisabled = false;
49182 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
49183 var diff = endX - this.startPos;
49184 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
49187 autoOffset : function(){
49188 this.setDelta(0,0);
49192 * Ext JS Library 1.1.1
49193 * Copyright(c) 2006-2007, Ext JS, LLC.
49195 * Originally Released Under LGPL - original licence link has changed is not relivant.
49198 * <script type="text/javascript">
49202 // This is a support class used internally by the Grid components
49203 Roo.grid.GridDragZone = function(grid, config){
49204 this.view = grid.getView();
49205 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
49206 if(this.view.lockedBody){
49207 this.setHandleElId(Roo.id(this.view.mainBody.dom));
49208 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
49210 this.scroll = false;
49212 this.ddel = document.createElement('div');
49213 this.ddel.className = 'x-grid-dd-wrap';
49216 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
49217 ddGroup : "GridDD",
49219 getDragData : function(e){
49220 var t = Roo.lib.Event.getTarget(e);
49221 var rowIndex = this.view.findRowIndex(t);
49222 if(rowIndex !== false){
49223 var sm = this.grid.selModel;
49224 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
49225 // sm.mouseDown(e, t);
49227 if (e.hasModifier()){
49228 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
49230 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
49235 onInitDrag : function(e){
49236 var data = this.dragData;
49237 this.ddel.innerHTML = this.grid.getDragDropText();
49238 this.proxy.update(this.ddel);
49239 // fire start drag?
49242 afterRepair : function(){
49243 this.dragging = false;
49246 getRepairXY : function(e, data){
49250 onEndDrag : function(data, e){
49254 onValidDrop : function(dd, e, id){
49259 beforeInvalidDrop : function(e, id){
49264 * Ext JS Library 1.1.1
49265 * Copyright(c) 2006-2007, Ext JS, LLC.
49267 * Originally Released Under LGPL - original licence link has changed is not relivant.
49270 * <script type="text/javascript">
49275 * @class Roo.grid.ColumnModel
49276 * @extends Roo.util.Observable
49277 * This is the default implementation of a ColumnModel used by the Grid. It defines
49278 * the columns in the grid.
49281 var colModel = new Roo.grid.ColumnModel([
49282 {header: "Ticker", width: 60, sortable: true, locked: true},
49283 {header: "Company Name", width: 150, sortable: true},
49284 {header: "Market Cap.", width: 100, sortable: true},
49285 {header: "$ Sales", width: 100, sortable: true, renderer: money},
49286 {header: "Employees", width: 100, sortable: true, resizable: false}
49291 * The config options listed for this class are options which may appear in each
49292 * individual column definition.
49293 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
49295 * @param {Object} config An Array of column config objects. See this class's
49296 * config objects for details.
49298 Roo.grid.ColumnModel = function(config){
49300 * The config passed into the constructor
49302 this.config = config;
49305 // if no id, create one
49306 // if the column does not have a dataIndex mapping,
49307 // map it to the order it is in the config
49308 for(var i = 0, len = config.length; i < len; i++){
49310 if(typeof c.dataIndex == "undefined"){
49313 if(typeof c.renderer == "string"){
49314 c.renderer = Roo.util.Format[c.renderer];
49316 if(typeof c.id == "undefined"){
49319 if(c.editor && c.editor.xtype){
49320 c.editor = Roo.factory(c.editor, Roo.grid);
49322 if(c.editor && c.editor.isFormField){
49323 c.editor = new Roo.grid.GridEditor(c.editor);
49325 this.lookup[c.id] = c;
49329 * The width of columns which have no width specified (defaults to 100)
49332 this.defaultWidth = 100;
49335 * Default sortable of columns which have no sortable specified (defaults to false)
49338 this.defaultSortable = false;
49342 * @event widthchange
49343 * Fires when the width of a column changes.
49344 * @param {ColumnModel} this
49345 * @param {Number} columnIndex The column index
49346 * @param {Number} newWidth The new width
49348 "widthchange": true,
49350 * @event headerchange
49351 * Fires when the text of a header changes.
49352 * @param {ColumnModel} this
49353 * @param {Number} columnIndex The column index
49354 * @param {Number} newText The new header text
49356 "headerchange": true,
49358 * @event hiddenchange
49359 * Fires when a column is hidden or "unhidden".
49360 * @param {ColumnModel} this
49361 * @param {Number} columnIndex The column index
49362 * @param {Boolean} hidden true if hidden, false otherwise
49364 "hiddenchange": true,
49366 * @event columnmoved
49367 * Fires when a column is moved.
49368 * @param {ColumnModel} this
49369 * @param {Number} oldIndex
49370 * @param {Number} newIndex
49372 "columnmoved" : true,
49374 * @event columlockchange
49375 * Fires when a column's locked state is changed
49376 * @param {ColumnModel} this
49377 * @param {Number} colIndex
49378 * @param {Boolean} locked true if locked
49380 "columnlockchange" : true
49382 Roo.grid.ColumnModel.superclass.constructor.call(this);
49384 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
49386 * @cfg {String} header The header text to display in the Grid view.
49389 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
49390 * {@link Roo.data.Record} definition from which to draw the column's value. If not
49391 * specified, the column's index is used as an index into the Record's data Array.
49394 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
49395 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
49398 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
49399 * Defaults to the value of the {@link #defaultSortable} property.
49400 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
49403 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
49406 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
49409 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
49412 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
49415 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
49416 * given the cell's data value. See {@link #setRenderer}. If not specified, the
49417 * default renderer uses the raw data value.
49420 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
49423 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
49427 * Returns the id of the column at the specified index.
49428 * @param {Number} index The column index
49429 * @return {String} the id
49431 getColumnId : function(index){
49432 return this.config[index].id;
49436 * Returns the column for a specified id.
49437 * @param {String} id The column id
49438 * @return {Object} the column
49440 getColumnById : function(id){
49441 return this.lookup[id];
49446 * Returns the column for a specified dataIndex.
49447 * @param {String} dataIndex The column dataIndex
49448 * @return {Object|Boolean} the column or false if not found
49450 getColumnByDataIndex: function(dataIndex){
49451 var index = this.findColumnIndex(dataIndex);
49452 return index > -1 ? this.config[index] : false;
49456 * Returns the index for a specified column id.
49457 * @param {String} id The column id
49458 * @return {Number} the index, or -1 if not found
49460 getIndexById : function(id){
49461 for(var i = 0, len = this.config.length; i < len; i++){
49462 if(this.config[i].id == id){
49470 * Returns the index for a specified column dataIndex.
49471 * @param {String} dataIndex The column dataIndex
49472 * @return {Number} the index, or -1 if not found
49475 findColumnIndex : function(dataIndex){
49476 for(var i = 0, len = this.config.length; i < len; i++){
49477 if(this.config[i].dataIndex == dataIndex){
49485 moveColumn : function(oldIndex, newIndex){
49486 var c = this.config[oldIndex];
49487 this.config.splice(oldIndex, 1);
49488 this.config.splice(newIndex, 0, c);
49489 this.dataMap = null;
49490 this.fireEvent("columnmoved", this, oldIndex, newIndex);
49493 isLocked : function(colIndex){
49494 return this.config[colIndex].locked === true;
49497 setLocked : function(colIndex, value, suppressEvent){
49498 if(this.isLocked(colIndex) == value){
49501 this.config[colIndex].locked = value;
49502 if(!suppressEvent){
49503 this.fireEvent("columnlockchange", this, colIndex, value);
49507 getTotalLockedWidth : function(){
49508 var totalWidth = 0;
49509 for(var i = 0; i < this.config.length; i++){
49510 if(this.isLocked(i) && !this.isHidden(i)){
49511 this.totalWidth += this.getColumnWidth(i);
49517 getLockedCount : function(){
49518 for(var i = 0, len = this.config.length; i < len; i++){
49519 if(!this.isLocked(i)){
49526 * Returns the number of columns.
49529 getColumnCount : function(visibleOnly){
49530 if(visibleOnly === true){
49532 for(var i = 0, len = this.config.length; i < len; i++){
49533 if(!this.isHidden(i)){
49539 return this.config.length;
49543 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
49544 * @param {Function} fn
49545 * @param {Object} scope (optional)
49546 * @return {Array} result
49548 getColumnsBy : function(fn, scope){
49550 for(var i = 0, len = this.config.length; i < len; i++){
49551 var c = this.config[i];
49552 if(fn.call(scope||this, c, i) === true){
49560 * Returns true if the specified column is sortable.
49561 * @param {Number} col The column index
49562 * @return {Boolean}
49564 isSortable : function(col){
49565 if(typeof this.config[col].sortable == "undefined"){
49566 return this.defaultSortable;
49568 return this.config[col].sortable;
49572 * Returns the rendering (formatting) function defined for the column.
49573 * @param {Number} col The column index.
49574 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
49576 getRenderer : function(col){
49577 if(!this.config[col].renderer){
49578 return Roo.grid.ColumnModel.defaultRenderer;
49580 return this.config[col].renderer;
49584 * Sets the rendering (formatting) function for a column.
49585 * @param {Number} col The column index
49586 * @param {Function} fn The function to use to process the cell's raw data
49587 * to return HTML markup for the grid view. The render function is called with
49588 * the following parameters:<ul>
49589 * <li>Data value.</li>
49590 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
49591 * <li>css A CSS style string to apply to the table cell.</li>
49592 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
49593 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
49594 * <li>Row index</li>
49595 * <li>Column index</li>
49596 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
49598 setRenderer : function(col, fn){
49599 this.config[col].renderer = fn;
49603 * Returns the width for the specified column.
49604 * @param {Number} col The column index
49607 getColumnWidth : function(col){
49608 return this.config[col].width * 1 || this.defaultWidth;
49612 * Sets the width for a column.
49613 * @param {Number} col The column index
49614 * @param {Number} width The new width
49616 setColumnWidth : function(col, width, suppressEvent){
49617 this.config[col].width = width;
49618 this.totalWidth = null;
49619 if(!suppressEvent){
49620 this.fireEvent("widthchange", this, col, width);
49625 * Returns the total width of all columns.
49626 * @param {Boolean} includeHidden True to include hidden column widths
49629 getTotalWidth : function(includeHidden){
49630 if(!this.totalWidth){
49631 this.totalWidth = 0;
49632 for(var i = 0, len = this.config.length; i < len; i++){
49633 if(includeHidden || !this.isHidden(i)){
49634 this.totalWidth += this.getColumnWidth(i);
49638 return this.totalWidth;
49642 * Returns the header for the specified column.
49643 * @param {Number} col The column index
49646 getColumnHeader : function(col){
49647 return this.config[col].header;
49651 * Sets the header for a column.
49652 * @param {Number} col The column index
49653 * @param {String} header The new header
49655 setColumnHeader : function(col, header){
49656 this.config[col].header = header;
49657 this.fireEvent("headerchange", this, col, header);
49661 * Returns the tooltip for the specified column.
49662 * @param {Number} col The column index
49665 getColumnTooltip : function(col){
49666 return this.config[col].tooltip;
49669 * Sets the tooltip for a column.
49670 * @param {Number} col The column index
49671 * @param {String} tooltip The new tooltip
49673 setColumnTooltip : function(col, tooltip){
49674 this.config[col].tooltip = tooltip;
49678 * Returns the dataIndex for the specified column.
49679 * @param {Number} col The column index
49682 getDataIndex : function(col){
49683 return this.config[col].dataIndex;
49687 * Sets the dataIndex for a column.
49688 * @param {Number} col The column index
49689 * @param {Number} dataIndex The new dataIndex
49691 setDataIndex : function(col, dataIndex){
49692 this.config[col].dataIndex = dataIndex;
49698 * Returns true if the cell is editable.
49699 * @param {Number} colIndex The column index
49700 * @param {Number} rowIndex The row index
49701 * @return {Boolean}
49703 isCellEditable : function(colIndex, rowIndex){
49704 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
49708 * Returns the editor defined for the cell/column.
49709 * return false or null to disable editing.
49710 * @param {Number} colIndex The column index
49711 * @param {Number} rowIndex The row index
49714 getCellEditor : function(colIndex, rowIndex){
49715 return this.config[colIndex].editor;
49719 * Sets if a column is editable.
49720 * @param {Number} col The column index
49721 * @param {Boolean} editable True if the column is editable
49723 setEditable : function(col, editable){
49724 this.config[col].editable = editable;
49729 * Returns true if the column is hidden.
49730 * @param {Number} colIndex The column index
49731 * @return {Boolean}
49733 isHidden : function(colIndex){
49734 return this.config[colIndex].hidden;
49739 * Returns true if the column width cannot be changed
49741 isFixed : function(colIndex){
49742 return this.config[colIndex].fixed;
49746 * Returns true if the column can be resized
49747 * @return {Boolean}
49749 isResizable : function(colIndex){
49750 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
49753 * Sets if a column is hidden.
49754 * @param {Number} colIndex The column index
49755 * @param {Boolean} hidden True if the column is hidden
49757 setHidden : function(colIndex, hidden){
49758 this.config[colIndex].hidden = hidden;
49759 this.totalWidth = null;
49760 this.fireEvent("hiddenchange", this, colIndex, hidden);
49764 * Sets the editor for a column.
49765 * @param {Number} col The column index
49766 * @param {Object} editor The editor object
49768 setEditor : function(col, editor){
49769 this.config[col].editor = editor;
49773 Roo.grid.ColumnModel.defaultRenderer = function(value){
49774 if(typeof value == "string" && value.length < 1){
49780 // Alias for backwards compatibility
49781 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
49784 * Ext JS Library 1.1.1
49785 * Copyright(c) 2006-2007, Ext JS, LLC.
49787 * Originally Released Under LGPL - original licence link has changed is not relivant.
49790 * <script type="text/javascript">
49794 * @class Roo.grid.AbstractSelectionModel
49795 * @extends Roo.util.Observable
49796 * Abstract base class for grid SelectionModels. It provides the interface that should be
49797 * implemented by descendant classes. This class should not be directly instantiated.
49800 Roo.grid.AbstractSelectionModel = function(){
49801 this.locked = false;
49802 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
49805 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
49806 /** @ignore Called by the grid automatically. Do not call directly. */
49807 init : function(grid){
49813 * Locks the selections.
49816 this.locked = true;
49820 * Unlocks the selections.
49822 unlock : function(){
49823 this.locked = false;
49827 * Returns true if the selections are locked.
49828 * @return {Boolean}
49830 isLocked : function(){
49831 return this.locked;
49835 * Ext JS Library 1.1.1
49836 * Copyright(c) 2006-2007, Ext JS, LLC.
49838 * Originally Released Under LGPL - original licence link has changed is not relivant.
49841 * <script type="text/javascript">
49844 * @extends Roo.grid.AbstractSelectionModel
49845 * @class Roo.grid.RowSelectionModel
49846 * The default SelectionModel used by {@link Roo.grid.Grid}.
49847 * It supports multiple selections and keyboard selection/navigation.
49849 * @param {Object} config
49851 Roo.grid.RowSelectionModel = function(config){
49852 Roo.apply(this, config);
49853 this.selections = new Roo.util.MixedCollection(false, function(o){
49858 this.lastActive = false;
49862 * @event selectionchange
49863 * Fires when the selection changes
49864 * @param {SelectionModel} this
49866 "selectionchange" : true,
49868 * @event afterselectionchange
49869 * Fires after the selection changes (eg. by key press or clicking)
49870 * @param {SelectionModel} this
49872 "afterselectionchange" : true,
49874 * @event beforerowselect
49875 * Fires when a row is selected being selected, return false to cancel.
49876 * @param {SelectionModel} this
49877 * @param {Number} rowIndex The selected index
49878 * @param {Boolean} keepExisting False if other selections will be cleared
49880 "beforerowselect" : true,
49883 * Fires when a row is selected.
49884 * @param {SelectionModel} this
49885 * @param {Number} rowIndex The selected index
49886 * @param {Roo.data.Record} r The record
49888 "rowselect" : true,
49890 * @event rowdeselect
49891 * Fires when a row is deselected.
49892 * @param {SelectionModel} this
49893 * @param {Number} rowIndex The selected index
49895 "rowdeselect" : true
49897 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
49898 this.locked = false;
49901 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
49903 * @cfg {Boolean} singleSelect
49904 * True to allow selection of only one row at a time (defaults to false)
49906 singleSelect : false,
49909 initEvents : function(){
49911 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
49912 this.grid.on("mousedown", this.handleMouseDown, this);
49913 }else{ // allow click to work like normal
49914 this.grid.on("rowclick", this.handleDragableRowClick, this);
49917 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
49918 "up" : function(e){
49920 this.selectPrevious(e.shiftKey);
49921 }else if(this.last !== false && this.lastActive !== false){
49922 var last = this.last;
49923 this.selectRange(this.last, this.lastActive-1);
49924 this.grid.getView().focusRow(this.lastActive);
49925 if(last !== false){
49929 this.selectFirstRow();
49931 this.fireEvent("afterselectionchange", this);
49933 "down" : function(e){
49935 this.selectNext(e.shiftKey);
49936 }else if(this.last !== false && this.lastActive !== false){
49937 var last = this.last;
49938 this.selectRange(this.last, this.lastActive+1);
49939 this.grid.getView().focusRow(this.lastActive);
49940 if(last !== false){
49944 this.selectFirstRow();
49946 this.fireEvent("afterselectionchange", this);
49951 var view = this.grid.view;
49952 view.on("refresh", this.onRefresh, this);
49953 view.on("rowupdated", this.onRowUpdated, this);
49954 view.on("rowremoved", this.onRemove, this);
49958 onRefresh : function(){
49959 var ds = this.grid.dataSource, i, v = this.grid.view;
49960 var s = this.selections;
49961 s.each(function(r){
49962 if((i = ds.indexOfId(r.id)) != -1){
49971 onRemove : function(v, index, r){
49972 this.selections.remove(r);
49976 onRowUpdated : function(v, index, r){
49977 if(this.isSelected(r)){
49978 v.onRowSelect(index);
49984 * @param {Array} records The records to select
49985 * @param {Boolean} keepExisting (optional) True to keep existing selections
49987 selectRecords : function(records, keepExisting){
49989 this.clearSelections();
49991 var ds = this.grid.dataSource;
49992 for(var i = 0, len = records.length; i < len; i++){
49993 this.selectRow(ds.indexOf(records[i]), true);
49998 * Gets the number of selected rows.
50001 getCount : function(){
50002 return this.selections.length;
50006 * Selects the first row in the grid.
50008 selectFirstRow : function(){
50013 * Select the last row.
50014 * @param {Boolean} keepExisting (optional) True to keep existing selections
50016 selectLastRow : function(keepExisting){
50017 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
50021 * Selects the row immediately following the last selected row.
50022 * @param {Boolean} keepExisting (optional) True to keep existing selections
50024 selectNext : function(keepExisting){
50025 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
50026 this.selectRow(this.last+1, keepExisting);
50027 this.grid.getView().focusRow(this.last);
50032 * Selects the row that precedes the last selected row.
50033 * @param {Boolean} keepExisting (optional) True to keep existing selections
50035 selectPrevious : function(keepExisting){
50037 this.selectRow(this.last-1, keepExisting);
50038 this.grid.getView().focusRow(this.last);
50043 * Returns the selected records
50044 * @return {Array} Array of selected records
50046 getSelections : function(){
50047 return [].concat(this.selections.items);
50051 * Returns the first selected record.
50054 getSelected : function(){
50055 return this.selections.itemAt(0);
50060 * Clears all selections.
50062 clearSelections : function(fast){
50063 if(this.locked) return;
50065 var ds = this.grid.dataSource;
50066 var s = this.selections;
50067 s.each(function(r){
50068 this.deselectRow(ds.indexOfId(r.id));
50072 this.selections.clear();
50079 * Selects all rows.
50081 selectAll : function(){
50082 if(this.locked) return;
50083 this.selections.clear();
50084 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
50085 this.selectRow(i, true);
50090 * Returns True if there is a selection.
50091 * @return {Boolean}
50093 hasSelection : function(){
50094 return this.selections.length > 0;
50098 * Returns True if the specified row is selected.
50099 * @param {Number/Record} record The record or index of the record to check
50100 * @return {Boolean}
50102 isSelected : function(index){
50103 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
50104 return (r && this.selections.key(r.id) ? true : false);
50108 * Returns True if the specified record id is selected.
50109 * @param {String} id The id of record to check
50110 * @return {Boolean}
50112 isIdSelected : function(id){
50113 return (this.selections.key(id) ? true : false);
50117 handleMouseDown : function(e, t){
50118 var view = this.grid.getView(), rowIndex;
50119 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
50122 if(e.shiftKey && this.last !== false){
50123 var last = this.last;
50124 this.selectRange(last, rowIndex, e.ctrlKey);
50125 this.last = last; // reset the last
50126 view.focusRow(rowIndex);
50128 var isSelected = this.isSelected(rowIndex);
50129 if(e.button !== 0 && isSelected){
50130 view.focusRow(rowIndex);
50131 }else if(e.ctrlKey && isSelected){
50132 this.deselectRow(rowIndex);
50133 }else if(!isSelected){
50134 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
50135 view.focusRow(rowIndex);
50138 this.fireEvent("afterselectionchange", this);
50141 handleDragableRowClick : function(grid, rowIndex, e)
50143 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
50144 this.selectRow(rowIndex, false);
50145 grid.view.focusRow(rowIndex);
50146 this.fireEvent("afterselectionchange", this);
50151 * Selects multiple rows.
50152 * @param {Array} rows Array of the indexes of the row to select
50153 * @param {Boolean} keepExisting (optional) True to keep existing selections
50155 selectRows : function(rows, keepExisting){
50157 this.clearSelections();
50159 for(var i = 0, len = rows.length; i < len; i++){
50160 this.selectRow(rows[i], true);
50165 * Selects a range of rows. All rows in between startRow and endRow are also selected.
50166 * @param {Number} startRow The index of the first row in the range
50167 * @param {Number} endRow The index of the last row in the range
50168 * @param {Boolean} keepExisting (optional) True to retain existing selections
50170 selectRange : function(startRow, endRow, keepExisting){
50171 if(this.locked) return;
50173 this.clearSelections();
50175 if(startRow <= endRow){
50176 for(var i = startRow; i <= endRow; i++){
50177 this.selectRow(i, true);
50180 for(var i = startRow; i >= endRow; i--){
50181 this.selectRow(i, true);
50187 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
50188 * @param {Number} startRow The index of the first row in the range
50189 * @param {Number} endRow The index of the last row in the range
50191 deselectRange : function(startRow, endRow, preventViewNotify){
50192 if(this.locked) return;
50193 for(var i = startRow; i <= endRow; i++){
50194 this.deselectRow(i, preventViewNotify);
50200 * @param {Number} row The index of the row to select
50201 * @param {Boolean} keepExisting (optional) True to keep existing selections
50203 selectRow : function(index, keepExisting, preventViewNotify){
50204 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
50205 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
50206 if(!keepExisting || this.singleSelect){
50207 this.clearSelections();
50209 var r = this.grid.dataSource.getAt(index);
50210 this.selections.add(r);
50211 this.last = this.lastActive = index;
50212 if(!preventViewNotify){
50213 this.grid.getView().onRowSelect(index);
50215 this.fireEvent("rowselect", this, index, r);
50216 this.fireEvent("selectionchange", this);
50222 * @param {Number} row The index of the row to deselect
50224 deselectRow : function(index, preventViewNotify){
50225 if(this.locked) return;
50226 if(this.last == index){
50229 if(this.lastActive == index){
50230 this.lastActive = false;
50232 var r = this.grid.dataSource.getAt(index);
50233 this.selections.remove(r);
50234 if(!preventViewNotify){
50235 this.grid.getView().onRowDeselect(index);
50237 this.fireEvent("rowdeselect", this, index);
50238 this.fireEvent("selectionchange", this);
50242 restoreLast : function(){
50244 this.last = this._last;
50249 acceptsNav : function(row, col, cm){
50250 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50254 onEditorKey : function(field, e){
50255 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50260 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50262 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50264 }else if(k == e.ENTER && !e.ctrlKey){
50268 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
50270 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
50272 }else if(k == e.ESC){
50276 g.startEditing(newCell[0], newCell[1]);
50281 * Ext JS Library 1.1.1
50282 * Copyright(c) 2006-2007, Ext JS, LLC.
50284 * Originally Released Under LGPL - original licence link has changed is not relivant.
50287 * <script type="text/javascript">
50290 * @class Roo.grid.CellSelectionModel
50291 * @extends Roo.grid.AbstractSelectionModel
50292 * This class provides the basic implementation for cell selection in a grid.
50294 * @param {Object} config The object containing the configuration of this model.
50296 Roo.grid.CellSelectionModel = function(config){
50297 Roo.apply(this, config);
50299 this.selection = null;
50303 * @event beforerowselect
50304 * Fires before a cell is selected.
50305 * @param {SelectionModel} this
50306 * @param {Number} rowIndex The selected row index
50307 * @param {Number} colIndex The selected cell index
50309 "beforecellselect" : true,
50311 * @event cellselect
50312 * Fires when a cell is selected.
50313 * @param {SelectionModel} this
50314 * @param {Number} rowIndex The selected row index
50315 * @param {Number} colIndex The selected cell index
50317 "cellselect" : true,
50319 * @event selectionchange
50320 * Fires when the active selection changes.
50321 * @param {SelectionModel} this
50322 * @param {Object} selection null for no selection or an object (o) with two properties
50324 <li>o.record: the record object for the row the selection is in</li>
50325 <li>o.cell: An array of [rowIndex, columnIndex]</li>
50328 "selectionchange" : true
50330 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
50333 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
50336 initEvents : function(){
50337 this.grid.on("mousedown", this.handleMouseDown, this);
50338 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
50339 var view = this.grid.view;
50340 view.on("refresh", this.onViewChange, this);
50341 view.on("rowupdated", this.onRowUpdated, this);
50342 view.on("beforerowremoved", this.clearSelections, this);
50343 view.on("beforerowsinserted", this.clearSelections, this);
50344 if(this.grid.isEditor){
50345 this.grid.on("beforeedit", this.beforeEdit, this);
50350 beforeEdit : function(e){
50351 this.select(e.row, e.column, false, true, e.record);
50355 onRowUpdated : function(v, index, r){
50356 if(this.selection && this.selection.record == r){
50357 v.onCellSelect(index, this.selection.cell[1]);
50362 onViewChange : function(){
50363 this.clearSelections(true);
50367 * Returns the currently selected cell,.
50368 * @return {Array} The selected cell (row, column) or null if none selected.
50370 getSelectedCell : function(){
50371 return this.selection ? this.selection.cell : null;
50375 * Clears all selections.
50376 * @param {Boolean} true to prevent the gridview from being notified about the change.
50378 clearSelections : function(preventNotify){
50379 var s = this.selection;
50381 if(preventNotify !== true){
50382 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
50384 this.selection = null;
50385 this.fireEvent("selectionchange", this, null);
50390 * Returns true if there is a selection.
50391 * @return {Boolean}
50393 hasSelection : function(){
50394 return this.selection ? true : false;
50398 handleMouseDown : function(e, t){
50399 var v = this.grid.getView();
50400 if(this.isLocked()){
50403 var row = v.findRowIndex(t);
50404 var cell = v.findCellIndex(t);
50405 if(row !== false && cell !== false){
50406 this.select(row, cell);
50412 * @param {Number} rowIndex
50413 * @param {Number} collIndex
50415 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
50416 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
50417 this.clearSelections();
50418 r = r || this.grid.dataSource.getAt(rowIndex);
50421 cell : [rowIndex, colIndex]
50423 if(!preventViewNotify){
50424 var v = this.grid.getView();
50425 v.onCellSelect(rowIndex, colIndex);
50426 if(preventFocus !== true){
50427 v.focusCell(rowIndex, colIndex);
50430 this.fireEvent("cellselect", this, rowIndex, colIndex);
50431 this.fireEvent("selectionchange", this, this.selection);
50436 isSelectable : function(rowIndex, colIndex, cm){
50437 return !cm.isHidden(colIndex);
50441 handleKeyDown : function(e){
50442 Roo.log('Cell Sel Model handleKeyDown');
50443 if(!e.isNavKeyPress()){
50446 var g = this.grid, s = this.selection;
50449 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
50451 this.select(cell[0], cell[1]);
50456 var walk = function(row, col, step){
50457 return g.walkCells(row, col, step, sm.isSelectable, sm);
50459 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
50464 // handled by onEditorKey
50465 if (g.isEditor && g.editing) {
50469 newCell = walk(r, c-1, -1);
50471 newCell = walk(r, c+1, 1);
50475 newCell = walk(r+1, c, 1);
50478 newCell = walk(r-1, c, -1);
50481 newCell = walk(r, c+1, 1);
50484 newCell = walk(r, c-1, -1);
50487 if(g.isEditor && !g.editing){
50488 g.startEditing(r, c);
50495 this.select(newCell[0], newCell[1]);
50500 acceptsNav : function(row, col, cm){
50501 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50504 onEditorKey : function(field, e){
50506 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50507 ///Roo.log('onEditorKey' + k);
50511 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50513 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50516 }else if(k == e.ENTER && !e.ctrlKey){
50519 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50520 }else if(k == e.ESC){
50526 //Roo.log('next cell after edit');
50527 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
50532 * Ext JS Library 1.1.1
50533 * Copyright(c) 2006-2007, Ext JS, LLC.
50535 * Originally Released Under LGPL - original licence link has changed is not relivant.
50538 * <script type="text/javascript">
50542 * @class Roo.grid.EditorGrid
50543 * @extends Roo.grid.Grid
50544 * Class for creating and editable grid.
50545 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50546 * The container MUST have some type of size defined for the grid to fill. The container will be
50547 * automatically set to position relative if it isn't already.
50548 * @param {Object} dataSource The data model to bind to
50549 * @param {Object} colModel The column model with info about this grid's columns
50551 Roo.grid.EditorGrid = function(container, config){
50552 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
50553 this.getGridEl().addClass("xedit-grid");
50555 if(!this.selModel){
50556 this.selModel = new Roo.grid.CellSelectionModel();
50559 this.activeEditor = null;
50563 * @event beforeedit
50564 * Fires before cell editing is triggered. The edit event object has the following properties <br />
50565 * <ul style="padding:5px;padding-left:16px;">
50566 * <li>grid - This grid</li>
50567 * <li>record - The record being edited</li>
50568 * <li>field - The field name being edited</li>
50569 * <li>value - The value for the field being edited.</li>
50570 * <li>row - The grid row index</li>
50571 * <li>column - The grid column index</li>
50572 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50574 * @param {Object} e An edit event (see above for description)
50576 "beforeedit" : true,
50579 * Fires after a cell is edited. <br />
50580 * <ul style="padding:5px;padding-left:16px;">
50581 * <li>grid - This grid</li>
50582 * <li>record - The record being edited</li>
50583 * <li>field - The field name being edited</li>
50584 * <li>value - The value being set</li>
50585 * <li>originalValue - The original value for the field, before the edit.</li>
50586 * <li>row - The grid row index</li>
50587 * <li>column - The grid column index</li>
50589 * @param {Object} e An edit event (see above for description)
50591 "afteredit" : true,
50593 * @event validateedit
50594 * Fires after a cell is edited, but before the value is set in the record.
50595 * You can use this to modify the value being set in the field, Return false
50596 * to cancel the change. The edit event object has the following properties <br />
50597 * <ul style="padding:5px;padding-left:16px;">
50598 * <li>editor - This editor</li>
50599 * <li>grid - This grid</li>
50600 * <li>record - The record being edited</li>
50601 * <li>field - The field name being edited</li>
50602 * <li>value - The value being set</li>
50603 * <li>originalValue - The original value for the field, before the edit.</li>
50604 * <li>row - The grid row index</li>
50605 * <li>column - The grid column index</li>
50606 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50608 * @param {Object} e An edit event (see above for description)
50610 "validateedit" : true
50612 this.on("bodyscroll", this.stopEditing, this);
50613 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
50616 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
50618 * @cfg {Number} clicksToEdit
50619 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
50626 trackMouseOver: false, // causes very odd FF errors
50628 onCellDblClick : function(g, row, col){
50629 this.startEditing(row, col);
50632 onEditComplete : function(ed, value, startValue){
50633 this.editing = false;
50634 this.activeEditor = null;
50635 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
50637 var field = this.colModel.getDataIndex(ed.col);
50642 originalValue: startValue,
50649 if(String(value) !== String(startValue)){
50651 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
50652 r.set(field, e.value);
50653 // if we are dealing with a combo box..
50654 // then we also set the 'name' colum to be the displayField
50655 if (ed.field.displayField && ed.field.name) {
50656 r.set(ed.field.name, ed.field.el.dom.value);
50659 delete e.cancel; //?? why!!!
50660 this.fireEvent("afteredit", e);
50663 this.fireEvent("afteredit", e); // always fire it!
50665 this.view.focusCell(ed.row, ed.col);
50669 * Starts editing the specified for the specified row/column
50670 * @param {Number} rowIndex
50671 * @param {Number} colIndex
50673 startEditing : function(row, col){
50674 this.stopEditing();
50675 if(this.colModel.isCellEditable(col, row)){
50676 this.view.ensureVisible(row, col, true);
50677 var r = this.dataSource.getAt(row);
50678 var field = this.colModel.getDataIndex(col);
50683 value: r.data[field],
50688 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
50689 this.editing = true;
50690 var ed = this.colModel.getCellEditor(col, row);
50696 ed.render(ed.parentEl || document.body);
50699 (function(){ // complex but required for focus issues in safari, ie and opera
50703 ed.on("complete", this.onEditComplete, this, {single: true});
50704 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
50705 this.activeEditor = ed;
50706 var v = r.data[field];
50707 ed.startEdit(this.view.getCell(row, col), v);
50708 // combo's with 'displayField and name set
50709 if (ed.field.displayField && ed.field.name) {
50710 ed.field.el.dom.value = r.data[ed.field.name];
50714 }).defer(50, this);
50720 * Stops any active editing
50722 stopEditing : function(){
50723 if(this.activeEditor){
50724 this.activeEditor.completeEdit();
50726 this.activeEditor = null;
50730 * Ext JS Library 1.1.1
50731 * Copyright(c) 2006-2007, Ext JS, LLC.
50733 * Originally Released Under LGPL - original licence link has changed is not relivant.
50736 * <script type="text/javascript">
50739 // private - not really -- you end up using it !
50740 // This is a support class used internally by the Grid components
50743 * @class Roo.grid.GridEditor
50744 * @extends Roo.Editor
50745 * Class for creating and editable grid elements.
50746 * @param {Object} config any settings (must include field)
50748 Roo.grid.GridEditor = function(field, config){
50749 if (!config && field.field) {
50751 field = Roo.factory(config.field, Roo.form);
50753 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
50754 field.monitorTab = false;
50757 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
50760 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
50763 alignment: "tl-tl",
50766 cls: "x-small-editor x-grid-editor",
50771 * Ext JS Library 1.1.1
50772 * Copyright(c) 2006-2007, Ext JS, LLC.
50774 * Originally Released Under LGPL - original licence link has changed is not relivant.
50777 * <script type="text/javascript">
50782 Roo.grid.PropertyRecord = Roo.data.Record.create([
50783 {name:'name',type:'string'}, 'value'
50787 Roo.grid.PropertyStore = function(grid, source){
50789 this.store = new Roo.data.Store({
50790 recordType : Roo.grid.PropertyRecord
50792 this.store.on('update', this.onUpdate, this);
50794 this.setSource(source);
50796 Roo.grid.PropertyStore.superclass.constructor.call(this);
50801 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
50802 setSource : function(o){
50804 this.store.removeAll();
50807 if(this.isEditableValue(o[k])){
50808 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
50811 this.store.loadRecords({records: data}, {}, true);
50814 onUpdate : function(ds, record, type){
50815 if(type == Roo.data.Record.EDIT){
50816 var v = record.data['value'];
50817 var oldValue = record.modified['value'];
50818 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
50819 this.source[record.id] = v;
50821 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
50828 getProperty : function(row){
50829 return this.store.getAt(row);
50832 isEditableValue: function(val){
50833 if(val && val instanceof Date){
50835 }else if(typeof val == 'object' || typeof val == 'function'){
50841 setValue : function(prop, value){
50842 this.source[prop] = value;
50843 this.store.getById(prop).set('value', value);
50846 getSource : function(){
50847 return this.source;
50851 Roo.grid.PropertyColumnModel = function(grid, store){
50854 g.PropertyColumnModel.superclass.constructor.call(this, [
50855 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
50856 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
50858 this.store = store;
50859 this.bselect = Roo.DomHelper.append(document.body, {
50860 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
50861 {tag: 'option', value: 'true', html: 'true'},
50862 {tag: 'option', value: 'false', html: 'false'}
50865 Roo.id(this.bselect);
50868 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
50869 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
50870 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
50871 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
50872 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
50874 this.renderCellDelegate = this.renderCell.createDelegate(this);
50875 this.renderPropDelegate = this.renderProp.createDelegate(this);
50878 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
50882 valueText : 'Value',
50884 dateFormat : 'm/j/Y',
50887 renderDate : function(dateVal){
50888 return dateVal.dateFormat(this.dateFormat);
50891 renderBool : function(bVal){
50892 return bVal ? 'true' : 'false';
50895 isCellEditable : function(colIndex, rowIndex){
50896 return colIndex == 1;
50899 getRenderer : function(col){
50901 this.renderCellDelegate : this.renderPropDelegate;
50904 renderProp : function(v){
50905 return this.getPropertyName(v);
50908 renderCell : function(val){
50910 if(val instanceof Date){
50911 rv = this.renderDate(val);
50912 }else if(typeof val == 'boolean'){
50913 rv = this.renderBool(val);
50915 return Roo.util.Format.htmlEncode(rv);
50918 getPropertyName : function(name){
50919 var pn = this.grid.propertyNames;
50920 return pn && pn[name] ? pn[name] : name;
50923 getCellEditor : function(colIndex, rowIndex){
50924 var p = this.store.getProperty(rowIndex);
50925 var n = p.data['name'], val = p.data['value'];
50927 if(typeof(this.grid.customEditors[n]) == 'string'){
50928 return this.editors[this.grid.customEditors[n]];
50930 if(typeof(this.grid.customEditors[n]) != 'undefined'){
50931 return this.grid.customEditors[n];
50933 if(val instanceof Date){
50934 return this.editors['date'];
50935 }else if(typeof val == 'number'){
50936 return this.editors['number'];
50937 }else if(typeof val == 'boolean'){
50938 return this.editors['boolean'];
50940 return this.editors['string'];
50946 * @class Roo.grid.PropertyGrid
50947 * @extends Roo.grid.EditorGrid
50948 * This class represents the interface of a component based property grid control.
50949 * <br><br>Usage:<pre><code>
50950 var grid = new Roo.grid.PropertyGrid("my-container-id", {
50958 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50959 * The container MUST have some type of size defined for the grid to fill. The container will be
50960 * automatically set to position relative if it isn't already.
50961 * @param {Object} config A config object that sets properties on this grid.
50963 Roo.grid.PropertyGrid = function(container, config){
50964 config = config || {};
50965 var store = new Roo.grid.PropertyStore(this);
50966 this.store = store;
50967 var cm = new Roo.grid.PropertyColumnModel(this, store);
50968 store.store.sort('name', 'ASC');
50969 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
50972 enableColLock:false,
50973 enableColumnMove:false,
50975 trackMouseOver: false,
50978 this.getGridEl().addClass('x-props-grid');
50979 this.lastEditRow = null;
50980 this.on('columnresize', this.onColumnResize, this);
50983 * @event beforepropertychange
50984 * Fires before a property changes (return false to stop?)
50985 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50986 * @param {String} id Record Id
50987 * @param {String} newval New Value
50988 * @param {String} oldval Old Value
50990 "beforepropertychange": true,
50992 * @event propertychange
50993 * Fires after a property changes
50994 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50995 * @param {String} id Record Id
50996 * @param {String} newval New Value
50997 * @param {String} oldval Old Value
50999 "propertychange": true
51001 this.customEditors = this.customEditors || {};
51003 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
51006 * @cfg {Object} customEditors map of colnames=> custom editors.
51007 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
51008 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
51009 * false disables editing of the field.
51013 * @cfg {Object} propertyNames map of property Names to their displayed value
51016 render : function(){
51017 Roo.grid.PropertyGrid.superclass.render.call(this);
51018 this.autoSize.defer(100, this);
51021 autoSize : function(){
51022 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
51024 this.view.fitColumns();
51028 onColumnResize : function(){
51029 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
51033 * Sets the data for the Grid
51034 * accepts a Key => Value object of all the elements avaiable.
51035 * @param {Object} data to appear in grid.
51037 setSource : function(source){
51038 this.store.setSource(source);
51042 * Gets all the data from the grid.
51043 * @return {Object} data data stored in grid
51045 getSource : function(){
51046 return this.store.getSource();
51050 * Ext JS Library 1.1.1
51051 * Copyright(c) 2006-2007, Ext JS, LLC.
51053 * Originally Released Under LGPL - original licence link has changed is not relivant.
51056 * <script type="text/javascript">
51060 * @class Roo.LoadMask
51061 * A simple utility class for generically masking elements while loading data. If the element being masked has
51062 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
51063 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
51064 * element's UpdateManager load indicator and will be destroyed after the initial load.
51066 * Create a new LoadMask
51067 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
51068 * @param {Object} config The config object
51070 Roo.LoadMask = function(el, config){
51071 this.el = Roo.get(el);
51072 Roo.apply(this, config);
51074 this.store.on('beforeload', this.onBeforeLoad, this);
51075 this.store.on('load', this.onLoad, this);
51076 this.store.on('loadexception', this.onLoad, this);
51077 this.removeMask = false;
51079 var um = this.el.getUpdateManager();
51080 um.showLoadIndicator = false; // disable the default indicator
51081 um.on('beforeupdate', this.onBeforeLoad, this);
51082 um.on('update', this.onLoad, this);
51083 um.on('failure', this.onLoad, this);
51084 this.removeMask = true;
51088 Roo.LoadMask.prototype = {
51090 * @cfg {Boolean} removeMask
51091 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
51092 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
51095 * @cfg {String} msg
51096 * The text to display in a centered loading message box (defaults to 'Loading...')
51098 msg : 'Loading...',
51100 * @cfg {String} msgCls
51101 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
51103 msgCls : 'x-mask-loading',
51106 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
51112 * Disables the mask to prevent it from being displayed
51114 disable : function(){
51115 this.disabled = true;
51119 * Enables the mask so that it can be displayed
51121 enable : function(){
51122 this.disabled = false;
51126 onLoad : function(){
51127 this.el.unmask(this.removeMask);
51131 onBeforeLoad : function(){
51132 if(!this.disabled){
51133 this.el.mask(this.msg, this.msgCls);
51138 destroy : function(){
51140 this.store.un('beforeload', this.onBeforeLoad, this);
51141 this.store.un('load', this.onLoad, this);
51142 this.store.un('loadexception', this.onLoad, this);
51144 var um = this.el.getUpdateManager();
51145 um.un('beforeupdate', this.onBeforeLoad, this);
51146 um.un('update', this.onLoad, this);
51147 um.un('failure', this.onLoad, this);
51152 * Ext JS Library 1.1.1
51153 * Copyright(c) 2006-2007, Ext JS, LLC.
51155 * Originally Released Under LGPL - original licence link has changed is not relivant.
51158 * <script type="text/javascript">
51160 Roo.XTemplate = function(){
51161 Roo.XTemplate.superclass.constructor.apply(this, arguments);
51164 s = ['<tpl>', s, '</tpl>'].join('');
51166 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
51168 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
51169 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
51170 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
51174 while(m = s.match(re)){
51175 var m2 = m[0].match(nameRe);
51176 var m3 = m[0].match(ifRe);
51177 var m4 = m[0].match(execRe);
51178 var exp = null, fn = null, exec = null;
51179 var name = m2 && m2[1] ? m2[1] : '';
51181 exp = m3 && m3[1] ? m3[1] : null;
51183 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
51187 exp = m4 && m4[1] ? m4[1] : null;
51189 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
51194 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
51195 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
51196 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
51206 s = s.replace(m[0], '{xtpl'+ id + '}');
51209 for(var i = tpls.length-1; i >= 0; --i){
51210 this.compileTpl(tpls[i]);
51212 this.master = tpls[tpls.length-1];
51215 Roo.extend(Roo.XTemplate, Roo.Template, {
51217 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
51219 applySubTemplate : function(id, values, parent){
51220 var t = this.tpls[id];
51221 if(t.test && !t.test.call(this, values, parent)){
51224 if(t.exec && t.exec.call(this, values, parent)){
51227 var vs = t.target ? t.target.call(this, values, parent) : values;
51228 parent = t.target ? values : parent;
51229 if(t.target && vs instanceof Array){
51231 for(var i = 0, len = vs.length; i < len; i++){
51232 buf[buf.length] = t.compiled.call(this, vs[i], parent);
51234 return buf.join('');
51236 return t.compiled.call(this, vs, parent);
51239 compileTpl : function(tpl){
51240 var fm = Roo.util.Format;
51241 var useF = this.disableFormats !== true;
51242 var sep = Roo.isGecko ? "+" : ",";
51243 var fn = function(m, name, format, args){
51244 if(name.substr(0, 4) == 'xtpl'){
51245 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
51248 if(name.indexOf('.') != -1){
51251 v = "values['" + name + "']";
51253 if(format && useF){
51254 args = args ? ',' + args : "";
51255 if(format.substr(0, 5) != "this."){
51256 format = "fm." + format + '(';
51258 format = 'this.call("'+ format.substr(5) + '", ';
51262 args= ''; format = "("+v+" === undefined ? '' : ";
51264 return "'"+ sep + format + v + args + ")"+sep+"'";
51267 // branched to use + in gecko and [].join() in others
51269 body = "tpl.compiled = function(values, parent){ return '" +
51270 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
51273 body = ["tpl.compiled = function(values, parent){ return ['"];
51274 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
51275 body.push("'].join('');};");
51276 body = body.join('');
51278 /** eval:var:zzzzzzz */
51283 applyTemplate : function(values){
51284 return this.master.compiled.call(this, values, {});
51288 apply : function(){
51289 return this.applyTemplate.apply(this, arguments);
51292 compile : function(){return this;}
51295 Roo.XTemplate.from = function(el){
51296 el = Roo.getDom(el);
51297 return new Roo.XTemplate(el.value || el.innerHTML);
51299 * Original code for Roojs - LGPL
51300 * <script type="text/javascript">
51304 * @class Roo.XComponent
51305 * A delayed Element creator...
51306 * Or a way to group chunks of interface together.
51308 * Mypart.xyx = new Roo.XComponent({
51310 parent : 'Mypart.xyz', // empty == document.element.!!
51314 disabled : function() {}
51316 tree : function() { // return an tree of xtype declared components
51320 xtype : 'NestedLayoutPanel',
51327 * It can be used to build a big heiracy, with parent etc.
51328 * or you can just use this to render a single compoent to a dom element
51329 * MYPART.render(Roo.Element | String(id) | dom_element )
51331 * @extends Roo.util.Observable
51333 * @param cfg {Object} configuration of component
51336 Roo.XComponent = function(cfg) {
51337 Roo.apply(this, cfg);
51341 * Fires when this the componnt is built
51342 * @param {Roo.XComponent} c the component
51346 * @event buildcomplete
51347 * Fires on the top level element when all elements have been built
51348 * @param {Roo.XComponent} c the top level component.
51350 'buildcomplete' : true
51353 this.region = this.region || 'center'; // default..
51354 Roo.XComponent.register(this);
51355 this.modules = false;
51356 this.el = false; // where the layout goes..
51360 Roo.extend(Roo.XComponent, Roo.util.Observable, {
51363 * The created element (with Roo.factory())
51364 * @type {Roo.Layout}
51370 * for BC - use el in new code
51371 * @type {Roo.Layout}
51377 * for BC - use el in new code
51378 * @type {Roo.Layout}
51383 * @cfg {Function|boolean} disabled
51384 * If this module is disabled by some rule, return true from the funtion
51389 * @cfg {String} parent
51390 * Name of parent element which it get xtype added to..
51395 * @cfg {String} order
51396 * Used to set the order in which elements are created (usefull for multiple tabs)
51401 * @cfg {String} name
51402 * String to display while loading.
51406 * @cfg {String} region
51407 * Region to render component to (defaults to center)
51412 * @cfg {Array} items
51413 * A single item array - the first element is the root of the tree..
51414 * It's done this way to stay compatible with the Xtype system...
51421 * render element to dom or tree
51422 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
51425 render : function(el)
51429 var hp = this.parent ? 1 : 0;
51431 if (!el && typeof(this.parent) == 'string' && this.parent[0] == '#') {
51432 // if parent is a '#.....' string, then let's use that..
51433 var ename = this.parent.substr(1)
51434 this.parent = false;
51435 el = Roo.get(ename);
51437 Roo.log("Warning - element can not be found :#" + ename );
51443 if (!this.parent) {
51445 el = el ? Roo.get(el) : false;
51447 // it's a top level one..
51449 el : new Roo.BorderLayout(el || document.body, {
51455 tabPosition: 'top',
51456 //resizeTabs: true,
51457 alwaysShowTabs: el && hp? false : true,
51458 hideTabs: el || !hp ? true : false,
51467 var tree = this.tree();
51468 tree.region = tree.region || this.region;
51469 this.el = this.parent.el.addxtype(tree);
51470 this.fireEvent('built', this);
51472 this.panel = this.el;
51473 this.layout = this.panel.layout;
51479 Roo.apply(Roo.XComponent, {
51482 * @property buildCompleted
51483 * True when the builder has completed building the interface.
51486 buildCompleted : false,
51489 * @property topModule
51490 * the upper most module - uses document.element as it's constructor.
51497 * @property modules
51498 * array of modules to be created by registration system.
51499 * @type {Array} of Roo.XComponent
51504 * @property elmodules
51505 * array of modules to be created by which use #ID
51506 * @type {Array} of Roo.XComponent
51513 * Register components to be built later.
51515 * This solves the following issues
51516 * - Building is not done on page load, but after an authentication process has occured.
51517 * - Interface elements are registered on page load
51518 * - Parent Interface elements may not be loaded before child, so this handles that..
51525 module : 'Pman.Tab.projectMgr',
51527 parent : 'Pman.layout',
51528 disabled : false, // or use a function..
51531 * * @param {Object} details about module
51533 register : function(obj) {
51534 this.modules.push(obj);
51538 * convert a string to an object..
51539 * eg. 'AAA.BBB' -> finds AAA.BBB
51543 toObject : function(str)
51545 if (!str || typeof(str) == 'object') {
51552 var ar = str.split('.');
51556 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
51558 throw "Module not found : " + str;
51560 Roo.each(ar, function(e) {
51561 if (typeof(o[e]) == 'undefined') {
51562 throw "Module not found : " + str;
51573 * move modules into their correct place in the tree..
51576 preBuild : function ()
51579 Roo.each(this.modules , function (obj)
51581 var opar = obj.parent;
51582 obj.parent = this.toObject(opar);
51585 this.topModule = obj;
51588 if (typeof(obj.parent) == 'string') {
51589 this.elmodules.push(obj);
51592 if (obj.parent.constructor != Roo.XComponent) {
51593 Roo.log("Object Parent is not instance of XComponent:" + obj.name)
51595 if (!obj.parent.modules) {
51596 obj.parent.modules = new Roo.util.MixedCollection(false,
51597 function(o) { return o.order + '' }
51601 obj.parent.modules.add(obj);
51606 * make a list of modules to build.
51607 * @return {Array} list of modules.
51610 buildOrder : function()
51613 var cmp = function(a,b) {
51614 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
51616 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
51617 throw "No top level modules to build";
51620 // make a flat list in order of modules to build.
51621 var mods = this.topModule ? [ this.topModule ] : [];
51622 Roo.each(this.elmodules,function(e) { mods.push(e) });
51625 // add modules to their parents..
51626 var addMod = function(m) {
51627 // Roo.debug && Roo.log(m.modKey);
51631 m.modules.keySort('ASC', cmp );
51632 m.modules.each(addMod);
51634 // not sure if this is used any more..
51636 m.finalize.name = m.name + " (clean up) ";
51637 mods.push(m.finalize);
51641 if (this.topModule) {
51642 this.topModule.modules.keySort('ASC', cmp );
51643 this.topModule.modules.each(addMod);
51649 * Build the registered modules.
51650 * @param {Object} parent element.
51651 * @param {Function} optional method to call after module has been added.
51659 var mods = this.buildOrder();
51661 //this.allmods = mods;
51662 //Roo.debug && Roo.log(mods);
51664 if (!mods.length) { // should not happen
51665 throw "NO modules!!!";
51670 // flash it up as modal - so we store the mask!?
51671 Roo.MessageBox.show({ title: 'loading' });
51672 Roo.MessageBox.show({
51673 title: "Please wait...",
51674 msg: "Building Interface...",
51681 var total = mods.length;
51684 var progressRun = function() {
51685 if (!mods.length) {
51686 Roo.debug && Roo.log('hide?');
51687 Roo.MessageBox.hide();
51688 if (_this.topModule) {
51689 _this.topModule.fireEvent('buildcomplete', _this.topModule);
51695 var m = mods.shift();
51698 Roo.debug && Roo.log(m);
51699 // not sure if this is supported any more.. - modules that are are just function
51700 if (typeof(m) == 'function') {
51702 return progressRun.defer(10, _this);
51707 Roo.MessageBox.updateProgress(
51708 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
51710 (m.name ? (' - ' + m.name) : '')
51714 // is the module disabled?
51715 var disabled = (typeof(m.disabled) == 'function') ?
51716 m.disabled.call(m.module.disabled) : m.disabled;
51720 return progressRun(); // we do not update the display!
51726 // it's 10 on top level, and 1 on others??? why...
51727 return progressRun.defer(10, _this);
51730 progressRun.defer(1, _this);
51741 //<script type="text/javascript">
51746 * @extends Roo.LayoutDialog
51747 * A generic Login Dialog..... - only one needed in theory!?!?
51749 * Fires XComponent builder on success...
51752 * username,password, lang = for login actions.
51753 * check = 1 for periodic checking that sesion is valid.
51754 * passwordRequest = email request password
51755 * logout = 1 = to logout
51757 * Affects: (this id="????" elements)
51758 * loading (removed) (used to indicate application is loading)
51759 * loading-mask (hides) (used to hide application when it's building loading)
51765 * Myapp.login = Roo.Login({
51781 Roo.Login = function(cfg)
51787 Roo.apply(this,cfg);
51789 Roo.onReady(function() {
51795 Roo.Login.superclass.constructor.call(this, this);
51796 //this.addxtype(this.items[0]);
51802 Roo.extend(Roo.Login, Roo.LayoutDialog, {
51805 * @cfg {String} method
51806 * Method used to query for login details.
51811 * @cfg {String} url
51812 * URL to query login data. - eg. baseURL + '/Login.php'
51818 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
51823 * @property checkFails
51824 * Number of times we have attempted to get authentication check, and failed.
51829 * @property intervalID
51830 * The window interval that does the constant login checking.
51836 onLoad : function() // called on page load...
51840 if (Roo.get('loading')) { // clear any loading indicator..
51841 Roo.get('loading').remove();
51844 //this.switchLang('en'); // set the language to english..
51847 success: function(response, opts) { // check successfull...
51849 var res = this.processResponse(response);
51850 this.checkFails =0;
51851 if (!res.success) { // error!
51852 this.checkFails = 5;
51853 //console.log('call failure');
51854 return this.failure(response,opts);
51857 if (!res.data.id) { // id=0 == login failure.
51858 return this.show();
51862 //console.log(success);
51863 this.fillAuth(res.data);
51864 this.checkFails =0;
51865 Roo.XComponent.build();
51867 failure : this.show
51873 check: function(cfg) // called every so often to refresh cookie etc..
51875 if (cfg.again) { // could be undefined..
51878 this.checkFails = 0;
51881 if (this.sending) {
51882 if ( this.checkFails > 4) {
51883 Roo.MessageBox.alert("Error",
51884 "Error getting authentication status. - try reloading, or wait a while", function() {
51885 _this.sending = false;
51890 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
51893 this.sending = true;
51900 method: this.method,
51901 success: cfg.success || this.success,
51902 failure : cfg.failure || this.failure,
51912 window.onbeforeunload = function() { }; // false does not work for IE..
51922 failure : function() {
51923 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
51924 document.location = document.location.toString() + '?ts=' + Math.random();
51928 success : function() {
51929 _this.user = false;
51930 this.checkFails =0;
51932 document.location = document.location.toString() + '?ts=' + Math.random();
51939 processResponse : function (response)
51943 res = Roo.decode(response.responseText);
51945 if (typeof(res) != 'object') {
51946 res = { success : false, errorMsg : res, errors : true };
51948 if (typeof(res.success) == 'undefined') {
51949 res.success = false;
51953 res = { success : false, errorMsg : response.responseText, errors : true };
51958 success : function(response, opts) // check successfull...
51960 this.sending = false;
51961 var res = this.processResponse(response);
51962 if (!res.success) {
51963 return this.failure(response, opts);
51965 if (!res.data || !res.data.id) {
51966 return this.failure(response,opts);
51968 //console.log(res);
51969 this.fillAuth(res.data);
51971 this.checkFails =0;
51976 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
51978 this.authUser = -1;
51979 this.sending = false;
51980 var res = this.processResponse(response);
51981 //console.log(res);
51982 if ( this.checkFails > 2) {
51984 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
51985 "Error getting authentication status. - try reloading");
51988 opts.callCfg.again = true;
51989 this.check.defer(1000, this, [ opts.callCfg ]);
51995 fillAuth: function(au) {
51996 this.startAuthCheck();
51997 this.authUserId = au.id;
51998 this.authUser = au;
51999 this.lastChecked = new Date();
52000 this.fireEvent('refreshed', au);
52001 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
52002 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
52003 au.lang = au.lang || 'en';
52004 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
52005 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
52006 this.switchLang(au.lang );
52009 // open system... - -on setyp..
52010 if (this.authUserId < 0) {
52011 Roo.MessageBox.alert("Warning",
52012 "This is an open system - please set up a admin user with a password.");
52015 //Pman.onload(); // which should do nothing if it's a re-auth result...
52020 startAuthCheck : function() // starter for timeout checking..
52022 if (this.intervalID) { // timer already in place...
52026 this.intervalID = window.setInterval(function() {
52027 _this.check(false);
52028 }, 120000); // every 120 secs = 2mins..
52034 switchLang : function (lang)
52036 _T = typeof(_T) == 'undefined' ? false : _T;
52037 if (!_T || !lang.length) {
52041 if (!_T && lang != 'en') {
52042 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
52046 if (typeof(_T.en) == 'undefined') {
52048 Roo.apply(_T.en, _T);
52051 if (typeof(_T[lang]) == 'undefined') {
52052 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
52057 Roo.apply(_T, _T[lang]);
52058 // just need to set the text values for everything...
52060 /* this will not work ...
52064 function formLabel(name, val) {
52065 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
52068 formLabel('password', "Password"+':');
52069 formLabel('username', "Email Address"+':');
52070 formLabel('lang', "Language"+':');
52071 this.dialog.setTitle("Login");
52072 this.dialog.buttons[0].setText("Forgot Password");
52073 this.dialog.buttons[1].setText("Login");
52092 collapsible: false,
52094 center: { // needed??
52097 // tabPosition: 'top',
52100 alwaysShowTabs: false
52104 show : function(dlg)
52106 //console.log(this);
52107 this.form = this.layout.getRegion('center').activePanel.form;
52108 this.form.dialog = dlg;
52109 this.buttons[0].form = this.form;
52110 this.buttons[0].dialog = dlg;
52111 this.buttons[1].form = this.form;
52112 this.buttons[1].dialog = dlg;
52114 //this.resizeToLogo.defer(1000,this);
52115 // this is all related to resizing for logos..
52116 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
52118 // this.resizeToLogo.defer(1000,this);
52121 //var w = Ext.lib.Dom.getViewWidth() - 100;
52122 //var h = Ext.lib.Dom.getViewHeight() - 100;
52123 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
52125 if (this.disabled) {
52130 if (this.user.id < 0) { // used for inital setup situations.
52134 if (this.intervalID) {
52135 // remove the timer
52136 window.clearInterval(this.intervalID);
52137 this.intervalID = false;
52141 if (Roo.get('loading')) {
52142 Roo.get('loading').remove();
52144 if (Roo.get('loading-mask')) {
52145 Roo.get('loading-mask').hide();
52148 //incomming._node = tnode;
52150 //this.dialog.modal = !modal;
52151 //this.dialog.show();
52155 this.form.setValues({
52156 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
52157 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
52160 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
52161 if (this.form.findField('username').getValue().length > 0 ){
52162 this.form.findField('password').focus();
52164 this.form.findField('username').focus();
52172 xtype : 'ContentPanel',
52184 style : 'margin: 10px;',
52187 actionfailed : function(f, act) {
52188 // form can return { errors: .... }
52190 //act.result.errors // invalid form element list...
52191 //act.result.errorMsg// invalid form element list...
52193 this.dialog.el.unmask();
52194 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
52195 "Login failed - communication error - try again.");
52198 actioncomplete: function(re, act) {
52200 Roo.state.Manager.set(
52201 this.dialog.realm + '.username',
52202 this.findField('username').getValue()
52204 Roo.state.Manager.set(
52205 this.dialog.realm + '.lang',
52206 this.findField('lang').getValue()
52209 this.dialog.fillAuth(act.result.data);
52211 this.dialog.hide();
52213 if (Roo.get('loading-mask')) {
52214 Roo.get('loading-mask').show();
52216 Roo.XComponent.build();
52224 xtype : 'TextField',
52226 fieldLabel: "Email Address",
52229 autoCreate : {tag: "input", type: "text", size: "20"}
52232 xtype : 'TextField',
52234 fieldLabel: "Password",
52235 inputType: 'password',
52238 autoCreate : {tag: "input", type: "text", size: "20"},
52240 specialkey : function(e,ev) {
52241 if (ev.keyCode == 13) {
52242 this.form.dialog.el.mask("Logging in");
52243 this.form.doAction('submit', {
52244 url: this.form.dialog.url,
52245 method: this.form.dialog.method
52252 xtype : 'ComboBox',
52254 fieldLabel: "Language",
52257 xtype : 'SimpleStore',
52258 fields: ['lang', 'ldisp'],
52260 [ 'en', 'English' ],
52261 [ 'zh_HK' , '\u7E41\u4E2D' ],
52262 [ 'zh_CN', '\u7C21\u4E2D' ]
52266 valueField : 'lang',
52267 hiddenName: 'lang',
52269 displayField:'ldisp',
52273 triggerAction: 'all',
52274 emptyText:'Select a Language...',
52275 selectOnFocus:true,
52277 select : function(cb, rec, ix) {
52278 this.form.switchLang(rec.data.lang);
52294 text : "Forgot Password",
52296 click : function() {
52297 //console.log(this);
52298 var n = this.form.findField('username').getValue();
52300 Roo.MessageBox.alert("Error", "Fill in your email address");
52304 url: this.dialog.url,
52308 method: this.dialog.method,
52309 success: function(response, opts) { // check successfull...
52311 var res = this.dialog.processResponse(response);
52312 if (!res.success) { // error!
52313 Roo.MessageBox.alert("Error" ,
52314 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
52317 Roo.MessageBox.alert("Notice" ,
52318 "Please check you email for the Password Reset message");
52320 failure : function() {
52321 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
52334 click : function () {
52336 this.dialog.el.mask("Logging in");
52337 this.form.doAction('submit', {
52338 url: this.dialog.url,
52339 method: this.dialog.method