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,
23670 * @event preparedata
23671 * Fires on every row to render, to allow you to change the data.
23672 * @param {Roo.View} this
23673 * @param {Object} data to be rendered (change this)
23674 * @param {Number} row being rendered
23675 * @param {Roo.data.Record} record being rendered.
23677 "preparedata" : true
23681 "click": this.onClick,
23682 "dblclick": this.onDblClick,
23683 "contextmenu": this.onContextMenu,
23687 this.selections = [];
23689 this.cmp = new Roo.CompositeElementLite([]);
23691 this.store = Roo.factory(this.store, Roo.data);
23692 this.setStore(this.store, true);
23694 Roo.View.superclass.constructor.call(this);
23697 Roo.extend(Roo.View, Roo.util.Observable, {
23700 * @cfg {Roo.data.Store} store Data store to load data from.
23705 * @cfg {String|Roo.Element} el The container element.
23710 * @cfg {String|Roo.Template} tpl The template used by this View
23715 * @cfg {String} selectedClass The css class to add to selected nodes
23717 selectedClass : "x-view-selected",
23719 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23723 * @cfg {Boolean} multiSelect Allow multiple selection
23726 multiSelect : false,
23728 * @cfg {Boolean} singleSelect Allow single selection
23730 singleSelect: false,
23733 * Returns the element this view is bound to.
23734 * @return {Roo.Element}
23736 getEl : function(){
23741 * Refreshes the view.
23743 refresh : function(){
23745 this.clearSelections();
23746 this.el.update("");
23748 var records = this.store.getRange();
23749 if(records.length < 1){
23750 this.el.update(this.emptyText);
23753 for(var i = 0, len = records.length; i < len; i++){
23754 var data = this.prepareData(records[i].data, i, records[i]);
23755 this.fireEvent("preparedata", this, data, i, records[i]);
23756 html[html.length] = t.apply(data);
23758 this.el.update(html.join(""));
23759 this.nodes = this.el.dom.childNodes;
23760 this.updateIndexes(0);
23764 * Function to override to reformat the data that is sent to
23765 * the template for each node.
23766 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23767 * a JSON object for an UpdateManager bound view).
23769 prepareData : function(data){
23773 onUpdate : function(ds, record){
23774 this.clearSelections();
23775 var index = this.store.indexOf(record);
23776 var n = this.nodes[index];
23777 this.tpl.insertBefore(n, this.prepareData(record.data));
23778 n.parentNode.removeChild(n);
23779 this.updateIndexes(index, index);
23782 onAdd : function(ds, records, index){
23783 this.clearSelections();
23784 if(this.nodes.length == 0){
23788 var n = this.nodes[index];
23789 for(var i = 0, len = records.length; i < len; i++){
23790 var d = this.prepareData(records[i].data);
23792 this.tpl.insertBefore(n, d);
23794 this.tpl.append(this.el, d);
23797 this.updateIndexes(index);
23800 onRemove : function(ds, record, index){
23801 this.clearSelections();
23802 this.el.dom.removeChild(this.nodes[index]);
23803 this.updateIndexes(index);
23807 * Refresh an individual node.
23808 * @param {Number} index
23810 refreshNode : function(index){
23811 this.onUpdate(this.store, this.store.getAt(index));
23814 updateIndexes : function(startIndex, endIndex){
23815 var ns = this.nodes;
23816 startIndex = startIndex || 0;
23817 endIndex = endIndex || ns.length - 1;
23818 for(var i = startIndex; i <= endIndex; i++){
23819 ns[i].nodeIndex = i;
23824 * Changes the data store this view uses and refresh the view.
23825 * @param {Store} store
23827 setStore : function(store, initial){
23828 if(!initial && this.store){
23829 this.store.un("datachanged", this.refresh);
23830 this.store.un("add", this.onAdd);
23831 this.store.un("remove", this.onRemove);
23832 this.store.un("update", this.onUpdate);
23833 this.store.un("clear", this.refresh);
23837 store.on("datachanged", this.refresh, this);
23838 store.on("add", this.onAdd, this);
23839 store.on("remove", this.onRemove, this);
23840 store.on("update", this.onUpdate, this);
23841 store.on("clear", this.refresh, this);
23850 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23851 * @param {HTMLElement} node
23852 * @return {HTMLElement} The template node
23854 findItemFromChild : function(node){
23855 var el = this.el.dom;
23856 if(!node || node.parentNode == el){
23859 var p = node.parentNode;
23860 while(p && p != el){
23861 if(p.parentNode == el){
23870 onClick : function(e){
23871 var item = this.findItemFromChild(e.getTarget());
23873 var index = this.indexOf(item);
23874 if(this.onItemClick(item, index, e) !== false){
23875 this.fireEvent("click", this, index, item, e);
23878 this.clearSelections();
23883 onContextMenu : function(e){
23884 var item = this.findItemFromChild(e.getTarget());
23886 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23891 onDblClick : function(e){
23892 var item = this.findItemFromChild(e.getTarget());
23894 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23898 onItemClick : function(item, index, e){
23899 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23902 if(this.multiSelect || this.singleSelect){
23903 if(this.multiSelect && e.shiftKey && this.lastSelection){
23904 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23906 this.select(item, this.multiSelect && e.ctrlKey);
23907 this.lastSelection = item;
23909 e.preventDefault();
23915 * Get the number of selected nodes.
23918 getSelectionCount : function(){
23919 return this.selections.length;
23923 * Get the currently selected nodes.
23924 * @return {Array} An array of HTMLElements
23926 getSelectedNodes : function(){
23927 return this.selections;
23931 * Get the indexes of the selected nodes.
23934 getSelectedIndexes : function(){
23935 var indexes = [], s = this.selections;
23936 for(var i = 0, len = s.length; i < len; i++){
23937 indexes.push(s[i].nodeIndex);
23943 * Clear all selections
23944 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23946 clearSelections : function(suppressEvent){
23947 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23948 this.cmp.elements = this.selections;
23949 this.cmp.removeClass(this.selectedClass);
23950 this.selections = [];
23951 if(!suppressEvent){
23952 this.fireEvent("selectionchange", this, this.selections);
23958 * Returns true if the passed node is selected
23959 * @param {HTMLElement/Number} node The node or node index
23960 * @return {Boolean}
23962 isSelected : function(node){
23963 var s = this.selections;
23967 node = this.getNode(node);
23968 return s.indexOf(node) !== -1;
23973 * @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
23974 * @param {Boolean} keepExisting (optional) true to keep existing selections
23975 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23977 select : function(nodeInfo, keepExisting, suppressEvent){
23978 if(nodeInfo instanceof Array){
23980 this.clearSelections(true);
23982 for(var i = 0, len = nodeInfo.length; i < len; i++){
23983 this.select(nodeInfo[i], true, true);
23986 var node = this.getNode(nodeInfo);
23987 if(node && !this.isSelected(node)){
23989 this.clearSelections(true);
23991 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23992 Roo.fly(node).addClass(this.selectedClass);
23993 this.selections.push(node);
23994 if(!suppressEvent){
23995 this.fireEvent("selectionchange", this, this.selections);
24003 * Gets a template node.
24004 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24005 * @return {HTMLElement} The node or null if it wasn't found
24007 getNode : function(nodeInfo){
24008 if(typeof nodeInfo == "string"){
24009 return document.getElementById(nodeInfo);
24010 }else if(typeof nodeInfo == "number"){
24011 return this.nodes[nodeInfo];
24017 * Gets a range template nodes.
24018 * @param {Number} startIndex
24019 * @param {Number} endIndex
24020 * @return {Array} An array of nodes
24022 getNodes : function(start, end){
24023 var ns = this.nodes;
24024 start = start || 0;
24025 end = typeof end == "undefined" ? ns.length - 1 : end;
24028 for(var i = start; i <= end; i++){
24032 for(var i = start; i >= end; i--){
24040 * Finds the index of the passed node
24041 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24042 * @return {Number} The index of the node or -1
24044 indexOf : function(node){
24045 node = this.getNode(node);
24046 if(typeof node.nodeIndex == "number"){
24047 return node.nodeIndex;
24049 var ns = this.nodes;
24050 for(var i = 0, len = ns.length; i < len; i++){
24060 * Ext JS Library 1.1.1
24061 * Copyright(c) 2006-2007, Ext JS, LLC.
24063 * Originally Released Under LGPL - original licence link has changed is not relivant.
24066 * <script type="text/javascript">
24070 * @class Roo.JsonView
24071 * @extends Roo.View
24072 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24074 var view = new Roo.JsonView({
24075 container: "my-element",
24076 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24081 // listen for node click?
24082 view.on("click", function(vw, index, node, e){
24083 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24086 // direct load of JSON data
24087 view.load("foobar.php");
24089 // Example from my blog list
24090 var tpl = new Roo.Template(
24091 '<div class="entry">' +
24092 '<a class="entry-title" href="{link}">{title}</a>' +
24093 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24094 "</div><hr />"
24097 var moreView = new Roo.JsonView({
24098 container : "entry-list",
24102 moreView.on("beforerender", this.sortEntries, this);
24104 url: "/blog/get-posts.php",
24105 params: "allposts=true",
24106 text: "Loading Blog Entries..."
24110 * Note: old code is supported with arguments : (container, template, config)
24114 * Create a new JsonView
24116 * @param {Object} config The config object
24119 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24122 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24124 var um = this.el.getUpdateManager();
24125 um.setRenderer(this);
24126 um.on("update", this.onLoad, this);
24127 um.on("failure", this.onLoadException, this);
24130 * @event beforerender
24131 * Fires before rendering of the downloaded JSON data.
24132 * @param {Roo.JsonView} this
24133 * @param {Object} data The JSON data loaded
24137 * Fires when data is loaded.
24138 * @param {Roo.JsonView} this
24139 * @param {Object} data The JSON data loaded
24140 * @param {Object} response The raw Connect response object
24143 * @event loadexception
24144 * Fires when loading fails.
24145 * @param {Roo.JsonView} this
24146 * @param {Object} response The raw Connect response object
24149 'beforerender' : true,
24151 'loadexception' : true
24154 Roo.extend(Roo.JsonView, Roo.View, {
24156 * @type {String} The root property in the loaded JSON object that contains the data
24161 * Refreshes the view.
24163 refresh : function(){
24164 this.clearSelections();
24165 this.el.update("");
24167 var o = this.jsonData;
24168 if(o && o.length > 0){
24169 for(var i = 0, len = o.length; i < len; i++){
24170 var data = this.prepareData(o[i], i, o);
24171 html[html.length] = this.tpl.apply(data);
24174 html.push(this.emptyText);
24176 this.el.update(html.join(""));
24177 this.nodes = this.el.dom.childNodes;
24178 this.updateIndexes(0);
24182 * 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.
24183 * @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:
24186 url: "your-url.php",
24187 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24188 callback: yourFunction,
24189 scope: yourObject, //(optional scope)
24192 text: "Loading...",
24197 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24198 * 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.
24199 * @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}
24200 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24201 * @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.
24204 var um = this.el.getUpdateManager();
24205 um.update.apply(um, arguments);
24208 render : function(el, response){
24209 this.clearSelections();
24210 this.el.update("");
24213 o = Roo.util.JSON.decode(response.responseText);
24216 o = o[this.jsonRoot];
24221 * The current JSON data or null
24224 this.beforeRender();
24229 * Get the number of records in the current JSON dataset
24232 getCount : function(){
24233 return this.jsonData ? this.jsonData.length : 0;
24237 * Returns the JSON object for the specified node(s)
24238 * @param {HTMLElement/Array} node The node or an array of nodes
24239 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24240 * you get the JSON object for the node
24242 getNodeData : function(node){
24243 if(node instanceof Array){
24245 for(var i = 0, len = node.length; i < len; i++){
24246 data.push(this.getNodeData(node[i]));
24250 return this.jsonData[this.indexOf(node)] || null;
24253 beforeRender : function(){
24254 this.snapshot = this.jsonData;
24256 this.sort.apply(this, this.sortInfo);
24258 this.fireEvent("beforerender", this, this.jsonData);
24261 onLoad : function(el, o){
24262 this.fireEvent("load", this, this.jsonData, o);
24265 onLoadException : function(el, o){
24266 this.fireEvent("loadexception", this, o);
24270 * Filter the data by a specific property.
24271 * @param {String} property A property on your JSON objects
24272 * @param {String/RegExp} value Either string that the property values
24273 * should start with, or a RegExp to test against the property
24275 filter : function(property, value){
24278 var ss = this.snapshot;
24279 if(typeof value == "string"){
24280 var vlen = value.length;
24282 this.clearFilter();
24285 value = value.toLowerCase();
24286 for(var i = 0, len = ss.length; i < len; i++){
24288 if(o[property].substr(0, vlen).toLowerCase() == value){
24292 } else if(value.exec){ // regex?
24293 for(var i = 0, len = ss.length; i < len; i++){
24295 if(value.test(o[property])){
24302 this.jsonData = data;
24308 * Filter by a function. The passed function will be called with each
24309 * object in the current dataset. If the function returns true the value is kept,
24310 * otherwise it is filtered.
24311 * @param {Function} fn
24312 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24314 filterBy : function(fn, scope){
24317 var ss = this.snapshot;
24318 for(var i = 0, len = ss.length; i < len; i++){
24320 if(fn.call(scope || this, o)){
24324 this.jsonData = data;
24330 * Clears the current filter.
24332 clearFilter : function(){
24333 if(this.snapshot && this.jsonData != this.snapshot){
24334 this.jsonData = this.snapshot;
24341 * Sorts the data for this view and refreshes it.
24342 * @param {String} property A property on your JSON objects to sort on
24343 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24344 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24346 sort : function(property, dir, sortType){
24347 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24350 var dsc = dir && dir.toLowerCase() == "desc";
24351 var f = function(o1, o2){
24352 var v1 = sortType ? sortType(o1[p]) : o1[p];
24353 var v2 = sortType ? sortType(o2[p]) : o2[p];
24356 return dsc ? +1 : -1;
24357 } else if(v1 > v2){
24358 return dsc ? -1 : +1;
24363 this.jsonData.sort(f);
24365 if(this.jsonData != this.snapshot){
24366 this.snapshot.sort(f);
24372 * Ext JS Library 1.1.1
24373 * Copyright(c) 2006-2007, Ext JS, LLC.
24375 * Originally Released Under LGPL - original licence link has changed is not relivant.
24378 * <script type="text/javascript">
24383 * @class Roo.ColorPalette
24384 * @extends Roo.Component
24385 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24386 * Here's an example of typical usage:
24388 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24389 cp.render('my-div');
24391 cp.on('select', function(palette, selColor){
24392 // do something with selColor
24396 * Create a new ColorPalette
24397 * @param {Object} config The config object
24399 Roo.ColorPalette = function(config){
24400 Roo.ColorPalette.superclass.constructor.call(this, config);
24404 * Fires when a color is selected
24405 * @param {ColorPalette} this
24406 * @param {String} color The 6-digit color hex code (without the # symbol)
24412 this.on("select", this.handler, this.scope, true);
24415 Roo.extend(Roo.ColorPalette, Roo.Component, {
24417 * @cfg {String} itemCls
24418 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24420 itemCls : "x-color-palette",
24422 * @cfg {String} value
24423 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24424 * the hex codes are case-sensitive.
24427 clickEvent:'click',
24429 ctype: "Roo.ColorPalette",
24432 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24434 allowReselect : false,
24437 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24438 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24439 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24440 * of colors with the width setting until the box is symmetrical.</p>
24441 * <p>You can override individual colors if needed:</p>
24443 var cp = new Roo.ColorPalette();
24444 cp.colors[0] = "FF0000"; // change the first box to red
24447 Or you can provide a custom array of your own for complete control:
24449 var cp = new Roo.ColorPalette();
24450 cp.colors = ["000000", "993300", "333300"];
24455 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24456 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24457 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24458 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24459 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24463 onRender : function(container, position){
24464 var t = new Roo.MasterTemplate(
24465 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24467 var c = this.colors;
24468 for(var i = 0, len = c.length; i < len; i++){
24471 var el = document.createElement("div");
24472 el.className = this.itemCls;
24474 container.dom.insertBefore(el, position);
24475 this.el = Roo.get(el);
24476 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24477 if(this.clickEvent != 'click'){
24478 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24483 afterRender : function(){
24484 Roo.ColorPalette.superclass.afterRender.call(this);
24486 var s = this.value;
24493 handleClick : function(e, t){
24494 e.preventDefault();
24495 if(!this.disabled){
24496 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24497 this.select(c.toUpperCase());
24502 * Selects the specified color in the palette (fires the select event)
24503 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24505 select : function(color){
24506 color = color.replace("#", "");
24507 if(color != this.value || this.allowReselect){
24510 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24512 el.child("a.color-"+color).addClass("x-color-palette-sel");
24513 this.value = color;
24514 this.fireEvent("select", this, color);
24519 * Ext JS Library 1.1.1
24520 * Copyright(c) 2006-2007, Ext JS, LLC.
24522 * Originally Released Under LGPL - original licence link has changed is not relivant.
24525 * <script type="text/javascript">
24529 * @class Roo.DatePicker
24530 * @extends Roo.Component
24531 * Simple date picker class.
24533 * Create a new DatePicker
24534 * @param {Object} config The config object
24536 Roo.DatePicker = function(config){
24537 Roo.DatePicker.superclass.constructor.call(this, config);
24539 this.value = config && config.value ?
24540 config.value.clearTime() : new Date().clearTime();
24545 * Fires when a date is selected
24546 * @param {DatePicker} this
24547 * @param {Date} date The selected date
24553 this.on("select", this.handler, this.scope || this);
24555 // build the disabledDatesRE
24556 if(!this.disabledDatesRE && this.disabledDates){
24557 var dd = this.disabledDates;
24559 for(var i = 0; i < dd.length; i++){
24561 if(i != dd.length-1) re += "|";
24563 this.disabledDatesRE = new RegExp(re + ")");
24567 Roo.extend(Roo.DatePicker, Roo.Component, {
24569 * @cfg {String} todayText
24570 * The text to display on the button that selects the current date (defaults to "Today")
24572 todayText : "Today",
24574 * @cfg {String} okText
24575 * The text to display on the ok button
24577 okText : " OK ", //   to give the user extra clicking room
24579 * @cfg {String} cancelText
24580 * The text to display on the cancel button
24582 cancelText : "Cancel",
24584 * @cfg {String} todayTip
24585 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24587 todayTip : "{0} (Spacebar)",
24589 * @cfg {Date} minDate
24590 * Minimum allowable date (JavaScript date object, defaults to null)
24594 * @cfg {Date} maxDate
24595 * Maximum allowable date (JavaScript date object, defaults to null)
24599 * @cfg {String} minText
24600 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24602 minText : "This date is before the minimum date",
24604 * @cfg {String} maxText
24605 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24607 maxText : "This date is after the maximum date",
24609 * @cfg {String} format
24610 * The default date format string which can be overriden for localization support. The format must be
24611 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24615 * @cfg {Array} disabledDays
24616 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24618 disabledDays : null,
24620 * @cfg {String} disabledDaysText
24621 * The tooltip to display when the date falls on a disabled day (defaults to "")
24623 disabledDaysText : "",
24625 * @cfg {RegExp} disabledDatesRE
24626 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24628 disabledDatesRE : null,
24630 * @cfg {String} disabledDatesText
24631 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24633 disabledDatesText : "",
24635 * @cfg {Boolean} constrainToViewport
24636 * True to constrain the date picker to the viewport (defaults to true)
24638 constrainToViewport : true,
24640 * @cfg {Array} monthNames
24641 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24643 monthNames : Date.monthNames,
24645 * @cfg {Array} dayNames
24646 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24648 dayNames : Date.dayNames,
24650 * @cfg {String} nextText
24651 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24653 nextText: 'Next Month (Control+Right)',
24655 * @cfg {String} prevText
24656 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24658 prevText: 'Previous Month (Control+Left)',
24660 * @cfg {String} monthYearText
24661 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24663 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24665 * @cfg {Number} startDay
24666 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24670 * @cfg {Bool} showClear
24671 * Show a clear button (usefull for date form elements that can be blank.)
24677 * Sets the value of the date field
24678 * @param {Date} value The date to set
24680 setValue : function(value){
24681 var old = this.value;
24682 this.value = value.clearTime(true);
24684 this.update(this.value);
24689 * Gets the current selected value of the date field
24690 * @return {Date} The selected date
24692 getValue : function(){
24697 focus : function(){
24699 this.update(this.activeDate);
24704 onRender : function(container, position){
24706 '<table cellspacing="0">',
24707 '<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>',
24708 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24709 var dn = this.dayNames;
24710 for(var i = 0; i < 7; i++){
24711 var d = this.startDay+i;
24715 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24717 m[m.length] = "</tr></thead><tbody><tr>";
24718 for(var i = 0; i < 42; i++) {
24719 if(i % 7 == 0 && i != 0){
24720 m[m.length] = "</tr><tr>";
24722 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24724 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24725 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24727 var el = document.createElement("div");
24728 el.className = "x-date-picker";
24729 el.innerHTML = m.join("");
24731 container.dom.insertBefore(el, position);
24733 this.el = Roo.get(el);
24734 this.eventEl = Roo.get(el.firstChild);
24736 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24737 handler: this.showPrevMonth,
24739 preventDefault:true,
24743 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24744 handler: this.showNextMonth,
24746 preventDefault:true,
24750 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24752 this.monthPicker = this.el.down('div.x-date-mp');
24753 this.monthPicker.enableDisplayMode('block');
24755 var kn = new Roo.KeyNav(this.eventEl, {
24756 "left" : function(e){
24758 this.showPrevMonth() :
24759 this.update(this.activeDate.add("d", -1));
24762 "right" : function(e){
24764 this.showNextMonth() :
24765 this.update(this.activeDate.add("d", 1));
24768 "up" : function(e){
24770 this.showNextYear() :
24771 this.update(this.activeDate.add("d", -7));
24774 "down" : function(e){
24776 this.showPrevYear() :
24777 this.update(this.activeDate.add("d", 7));
24780 "pageUp" : function(e){
24781 this.showNextMonth();
24784 "pageDown" : function(e){
24785 this.showPrevMonth();
24788 "enter" : function(e){
24789 e.stopPropagation();
24796 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24798 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24800 this.el.unselectable();
24802 this.cells = this.el.select("table.x-date-inner tbody td");
24803 this.textNodes = this.el.query("table.x-date-inner tbody span");
24805 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24807 tooltip: this.monthYearText
24810 this.mbtn.on('click', this.showMonthPicker, this);
24811 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24814 var today = (new Date()).dateFormat(this.format);
24816 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24817 if (this.showClear) {
24818 baseTb.add( new Roo.Toolbar.Fill());
24821 text: String.format(this.todayText, today),
24822 tooltip: String.format(this.todayTip, today),
24823 handler: this.selectToday,
24827 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24830 if (this.showClear) {
24832 baseTb.add( new Roo.Toolbar.Fill());
24835 cls: 'x-btn-icon x-btn-clear',
24836 handler: function() {
24838 this.fireEvent("select", this, '');
24848 this.update(this.value);
24851 createMonthPicker : function(){
24852 if(!this.monthPicker.dom.firstChild){
24853 var buf = ['<table border="0" cellspacing="0">'];
24854 for(var i = 0; i < 6; i++){
24856 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24857 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24859 '<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>' :
24860 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24864 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24866 '</button><button type="button" class="x-date-mp-cancel">',
24868 '</button></td></tr>',
24871 this.monthPicker.update(buf.join(''));
24872 this.monthPicker.on('click', this.onMonthClick, this);
24873 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24875 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24876 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24878 this.mpMonths.each(function(m, a, i){
24881 m.dom.xmonth = 5 + Math.round(i * .5);
24883 m.dom.xmonth = Math.round((i-1) * .5);
24889 showMonthPicker : function(){
24890 this.createMonthPicker();
24891 var size = this.el.getSize();
24892 this.monthPicker.setSize(size);
24893 this.monthPicker.child('table').setSize(size);
24895 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24896 this.updateMPMonth(this.mpSelMonth);
24897 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24898 this.updateMPYear(this.mpSelYear);
24900 this.monthPicker.slideIn('t', {duration:.2});
24903 updateMPYear : function(y){
24905 var ys = this.mpYears.elements;
24906 for(var i = 1; i <= 10; i++){
24907 var td = ys[i-1], y2;
24909 y2 = y + Math.round(i * .5);
24910 td.firstChild.innerHTML = y2;
24913 y2 = y - (5-Math.round(i * .5));
24914 td.firstChild.innerHTML = y2;
24917 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24921 updateMPMonth : function(sm){
24922 this.mpMonths.each(function(m, a, i){
24923 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24927 selectMPMonth: function(m){
24931 onMonthClick : function(e, t){
24933 var el = new Roo.Element(t), pn;
24934 if(el.is('button.x-date-mp-cancel')){
24935 this.hideMonthPicker();
24937 else if(el.is('button.x-date-mp-ok')){
24938 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24939 this.hideMonthPicker();
24941 else if(pn = el.up('td.x-date-mp-month', 2)){
24942 this.mpMonths.removeClass('x-date-mp-sel');
24943 pn.addClass('x-date-mp-sel');
24944 this.mpSelMonth = pn.dom.xmonth;
24946 else if(pn = el.up('td.x-date-mp-year', 2)){
24947 this.mpYears.removeClass('x-date-mp-sel');
24948 pn.addClass('x-date-mp-sel');
24949 this.mpSelYear = pn.dom.xyear;
24951 else if(el.is('a.x-date-mp-prev')){
24952 this.updateMPYear(this.mpyear-10);
24954 else if(el.is('a.x-date-mp-next')){
24955 this.updateMPYear(this.mpyear+10);
24959 onMonthDblClick : function(e, t){
24961 var el = new Roo.Element(t), pn;
24962 if(pn = el.up('td.x-date-mp-month', 2)){
24963 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24964 this.hideMonthPicker();
24966 else if(pn = el.up('td.x-date-mp-year', 2)){
24967 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24968 this.hideMonthPicker();
24972 hideMonthPicker : function(disableAnim){
24973 if(this.monthPicker){
24974 if(disableAnim === true){
24975 this.monthPicker.hide();
24977 this.monthPicker.slideOut('t', {duration:.2});
24983 showPrevMonth : function(e){
24984 this.update(this.activeDate.add("mo", -1));
24988 showNextMonth : function(e){
24989 this.update(this.activeDate.add("mo", 1));
24993 showPrevYear : function(){
24994 this.update(this.activeDate.add("y", -1));
24998 showNextYear : function(){
24999 this.update(this.activeDate.add("y", 1));
25003 handleMouseWheel : function(e){
25004 var delta = e.getWheelDelta();
25006 this.showPrevMonth();
25008 } else if(delta < 0){
25009 this.showNextMonth();
25015 handleDateClick : function(e, t){
25017 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25018 this.setValue(new Date(t.dateValue));
25019 this.fireEvent("select", this, this.value);
25024 selectToday : function(){
25025 this.setValue(new Date().clearTime());
25026 this.fireEvent("select", this, this.value);
25030 update : function(date){
25031 var vd = this.activeDate;
25032 this.activeDate = date;
25034 var t = date.getTime();
25035 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25036 this.cells.removeClass("x-date-selected");
25037 this.cells.each(function(c){
25038 if(c.dom.firstChild.dateValue == t){
25039 c.addClass("x-date-selected");
25040 setTimeout(function(){
25041 try{c.dom.firstChild.focus();}catch(e){}
25049 var days = date.getDaysInMonth();
25050 var firstOfMonth = date.getFirstDateOfMonth();
25051 var startingPos = firstOfMonth.getDay()-this.startDay;
25053 if(startingPos <= this.startDay){
25057 var pm = date.add("mo", -1);
25058 var prevStart = pm.getDaysInMonth()-startingPos;
25060 var cells = this.cells.elements;
25061 var textEls = this.textNodes;
25062 days += startingPos;
25064 // convert everything to numbers so it's fast
25065 var day = 86400000;
25066 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25067 var today = new Date().clearTime().getTime();
25068 var sel = date.clearTime().getTime();
25069 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25070 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25071 var ddMatch = this.disabledDatesRE;
25072 var ddText = this.disabledDatesText;
25073 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25074 var ddaysText = this.disabledDaysText;
25075 var format = this.format;
25077 var setCellClass = function(cal, cell){
25079 var t = d.getTime();
25080 cell.firstChild.dateValue = t;
25082 cell.className += " x-date-today";
25083 cell.title = cal.todayText;
25086 cell.className += " x-date-selected";
25087 setTimeout(function(){
25088 try{cell.firstChild.focus();}catch(e){}
25093 cell.className = " x-date-disabled";
25094 cell.title = cal.minText;
25098 cell.className = " x-date-disabled";
25099 cell.title = cal.maxText;
25103 if(ddays.indexOf(d.getDay()) != -1){
25104 cell.title = ddaysText;
25105 cell.className = " x-date-disabled";
25108 if(ddMatch && format){
25109 var fvalue = d.dateFormat(format);
25110 if(ddMatch.test(fvalue)){
25111 cell.title = ddText.replace("%0", fvalue);
25112 cell.className = " x-date-disabled";
25118 for(; i < startingPos; i++) {
25119 textEls[i].innerHTML = (++prevStart);
25120 d.setDate(d.getDate()+1);
25121 cells[i].className = "x-date-prevday";
25122 setCellClass(this, cells[i]);
25124 for(; i < days; i++){
25125 intDay = i - startingPos + 1;
25126 textEls[i].innerHTML = (intDay);
25127 d.setDate(d.getDate()+1);
25128 cells[i].className = "x-date-active";
25129 setCellClass(this, cells[i]);
25132 for(; i < 42; i++) {
25133 textEls[i].innerHTML = (++extraDays);
25134 d.setDate(d.getDate()+1);
25135 cells[i].className = "x-date-nextday";
25136 setCellClass(this, cells[i]);
25139 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25141 if(!this.internalRender){
25142 var main = this.el.dom.firstChild;
25143 var w = main.offsetWidth;
25144 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25145 Roo.fly(main).setWidth(w);
25146 this.internalRender = true;
25147 // opera does not respect the auto grow header center column
25148 // then, after it gets a width opera refuses to recalculate
25149 // without a second pass
25150 if(Roo.isOpera && !this.secondPass){
25151 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25152 this.secondPass = true;
25153 this.update.defer(10, this, [date]);
25159 * Ext JS Library 1.1.1
25160 * Copyright(c) 2006-2007, Ext JS, LLC.
25162 * Originally Released Under LGPL - original licence link has changed is not relivant.
25165 * <script type="text/javascript">
25168 * @class Roo.TabPanel
25169 * @extends Roo.util.Observable
25170 * A lightweight tab container.
25174 // basic tabs 1, built from existing content
25175 var tabs = new Roo.TabPanel("tabs1");
25176 tabs.addTab("script", "View Script");
25177 tabs.addTab("markup", "View Markup");
25178 tabs.activate("script");
25180 // more advanced tabs, built from javascript
25181 var jtabs = new Roo.TabPanel("jtabs");
25182 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25184 // set up the UpdateManager
25185 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25186 var updater = tab2.getUpdateManager();
25187 updater.setDefaultUrl("ajax1.htm");
25188 tab2.on('activate', updater.refresh, updater, true);
25190 // Use setUrl for Ajax loading
25191 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25192 tab3.setUrl("ajax2.htm", null, true);
25195 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25198 jtabs.activate("jtabs-1");
25201 * Create a new TabPanel.
25202 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25203 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25205 Roo.TabPanel = function(container, config){
25207 * The container element for this TabPanel.
25208 * @type Roo.Element
25210 this.el = Roo.get(container, true);
25212 if(typeof config == "boolean"){
25213 this.tabPosition = config ? "bottom" : "top";
25215 Roo.apply(this, config);
25218 if(this.tabPosition == "bottom"){
25219 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25220 this.el.addClass("x-tabs-bottom");
25222 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25223 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25224 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25226 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25228 if(this.tabPosition != "bottom"){
25229 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
25230 * @type Roo.Element
25232 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25233 this.el.addClass("x-tabs-top");
25237 this.bodyEl.setStyle("position", "relative");
25239 this.active = null;
25240 this.activateDelegate = this.activate.createDelegate(this);
25245 * Fires when the active tab changes
25246 * @param {Roo.TabPanel} this
25247 * @param {Roo.TabPanelItem} activePanel The new active tab
25251 * @event beforetabchange
25252 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25253 * @param {Roo.TabPanel} this
25254 * @param {Object} e Set cancel to true on this object to cancel the tab change
25255 * @param {Roo.TabPanelItem} tab The tab being changed to
25257 "beforetabchange" : true
25260 Roo.EventManager.onWindowResize(this.onResize, this);
25261 this.cpad = this.el.getPadding("lr");
25262 this.hiddenCount = 0;
25265 // toolbar on the tabbar support...
25266 if (this.toolbar) {
25267 var tcfg = this.toolbar;
25268 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
25269 this.toolbar = new Roo.Toolbar(tcfg);
25270 if (Roo.isSafari) {
25271 var tbl = tcfg.container.child('table', true);
25272 tbl.setAttribute('width', '100%');
25279 Roo.TabPanel.superclass.constructor.call(this);
25282 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25284 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25286 tabPosition : "top",
25288 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25290 currentTabWidth : 0,
25292 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25296 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25300 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25302 preferredTabWidth : 175,
25304 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25306 resizeTabs : false,
25308 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25310 monitorResize : true,
25312 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
25317 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25318 * @param {String} id The id of the div to use <b>or create</b>
25319 * @param {String} text The text for the tab
25320 * @param {String} content (optional) Content to put in the TabPanelItem body
25321 * @param {Boolean} closable (optional) True to create a close icon on the tab
25322 * @return {Roo.TabPanelItem} The created TabPanelItem
25324 addTab : function(id, text, content, closable){
25325 var item = new Roo.TabPanelItem(this, id, text, closable);
25326 this.addTabItem(item);
25328 item.setContent(content);
25334 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25335 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25336 * @return {Roo.TabPanelItem}
25338 getTab : function(id){
25339 return this.items[id];
25343 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25344 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25346 hideTab : function(id){
25347 var t = this.items[id];
25350 this.hiddenCount++;
25351 this.autoSizeTabs();
25356 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25357 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25359 unhideTab : function(id){
25360 var t = this.items[id];
25362 t.setHidden(false);
25363 this.hiddenCount--;
25364 this.autoSizeTabs();
25369 * Adds an existing {@link Roo.TabPanelItem}.
25370 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25372 addTabItem : function(item){
25373 this.items[item.id] = item;
25374 this.items.push(item);
25375 if(this.resizeTabs){
25376 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25377 this.autoSizeTabs();
25384 * Removes a {@link Roo.TabPanelItem}.
25385 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25387 removeTab : function(id){
25388 var items = this.items;
25389 var tab = items[id];
25390 if(!tab) { return; }
25391 var index = items.indexOf(tab);
25392 if(this.active == tab && items.length > 1){
25393 var newTab = this.getNextAvailable(index);
25398 this.stripEl.dom.removeChild(tab.pnode.dom);
25399 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25400 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25402 items.splice(index, 1);
25403 delete this.items[tab.id];
25404 tab.fireEvent("close", tab);
25405 tab.purgeListeners();
25406 this.autoSizeTabs();
25409 getNextAvailable : function(start){
25410 var items = this.items;
25412 // look for a next tab that will slide over to
25413 // replace the one being removed
25414 while(index < items.length){
25415 var item = items[++index];
25416 if(item && !item.isHidden()){
25420 // if one isn't found select the previous tab (on the left)
25423 var item = items[--index];
25424 if(item && !item.isHidden()){
25432 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25433 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25435 disableTab : function(id){
25436 var tab = this.items[id];
25437 if(tab && this.active != tab){
25443 * Enables a {@link Roo.TabPanelItem} that is disabled.
25444 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25446 enableTab : function(id){
25447 var tab = this.items[id];
25452 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25453 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25454 * @return {Roo.TabPanelItem} The TabPanelItem.
25456 activate : function(id){
25457 var tab = this.items[id];
25461 if(tab == this.active || tab.disabled){
25465 this.fireEvent("beforetabchange", this, e, tab);
25466 if(e.cancel !== true && !tab.disabled){
25468 this.active.hide();
25470 this.active = this.items[id];
25471 this.active.show();
25472 this.fireEvent("tabchange", this, this.active);
25478 * Gets the active {@link Roo.TabPanelItem}.
25479 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25481 getActiveTab : function(){
25482 return this.active;
25486 * Updates the tab body element to fit the height of the container element
25487 * for overflow scrolling
25488 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25490 syncHeight : function(targetHeight){
25491 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25492 var bm = this.bodyEl.getMargins();
25493 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25494 this.bodyEl.setHeight(newHeight);
25498 onResize : function(){
25499 if(this.monitorResize){
25500 this.autoSizeTabs();
25505 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25507 beginUpdate : function(){
25508 this.updating = true;
25512 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25514 endUpdate : function(){
25515 this.updating = false;
25516 this.autoSizeTabs();
25520 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25522 autoSizeTabs : function(){
25523 var count = this.items.length;
25524 var vcount = count - this.hiddenCount;
25525 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25526 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25527 var availWidth = Math.floor(w / vcount);
25528 var b = this.stripBody;
25529 if(b.getWidth() > w){
25530 var tabs = this.items;
25531 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25532 if(availWidth < this.minTabWidth){
25533 /*if(!this.sleft){ // incomplete scrolling code
25534 this.createScrollButtons();
25537 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25540 if(this.currentTabWidth < this.preferredTabWidth){
25541 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25547 * Returns the number of tabs in this TabPanel.
25550 getCount : function(){
25551 return this.items.length;
25555 * Resizes all the tabs to the passed width
25556 * @param {Number} The new width
25558 setTabWidth : function(width){
25559 this.currentTabWidth = width;
25560 for(var i = 0, len = this.items.length; i < len; i++) {
25561 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25566 * Destroys this TabPanel
25567 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25569 destroy : function(removeEl){
25570 Roo.EventManager.removeResizeListener(this.onResize, this);
25571 for(var i = 0, len = this.items.length; i < len; i++){
25572 this.items[i].purgeListeners();
25574 if(removeEl === true){
25575 this.el.update("");
25582 * @class Roo.TabPanelItem
25583 * @extends Roo.util.Observable
25584 * Represents an individual item (tab plus body) in a TabPanel.
25585 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25586 * @param {String} id The id of this TabPanelItem
25587 * @param {String} text The text for the tab of this TabPanelItem
25588 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25590 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25592 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25593 * @type Roo.TabPanel
25595 this.tabPanel = tabPanel;
25597 * The id for this TabPanelItem
25602 this.disabled = false;
25606 this.loaded = false;
25607 this.closable = closable;
25610 * The body element for this TabPanelItem.
25611 * @type Roo.Element
25613 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25614 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25615 this.bodyEl.setStyle("display", "block");
25616 this.bodyEl.setStyle("zoom", "1");
25619 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25621 this.el = Roo.get(els.el, true);
25622 this.inner = Roo.get(els.inner, true);
25623 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25624 this.pnode = Roo.get(els.el.parentNode, true);
25625 this.el.on("mousedown", this.onTabMouseDown, this);
25626 this.el.on("click", this.onTabClick, this);
25629 var c = Roo.get(els.close, true);
25630 c.dom.title = this.closeText;
25631 c.addClassOnOver("close-over");
25632 c.on("click", this.closeClick, this);
25638 * Fires when this tab becomes the active tab.
25639 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25640 * @param {Roo.TabPanelItem} this
25644 * @event beforeclose
25645 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25646 * @param {Roo.TabPanelItem} this
25647 * @param {Object} e Set cancel to true on this object to cancel the close.
25649 "beforeclose": true,
25652 * Fires when this tab is closed.
25653 * @param {Roo.TabPanelItem} this
25657 * @event deactivate
25658 * Fires when this tab is no longer the active tab.
25659 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25660 * @param {Roo.TabPanelItem} this
25662 "deactivate" : true
25664 this.hidden = false;
25666 Roo.TabPanelItem.superclass.constructor.call(this);
25669 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25670 purgeListeners : function(){
25671 Roo.util.Observable.prototype.purgeListeners.call(this);
25672 this.el.removeAllListeners();
25675 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25678 this.pnode.addClass("on");
25681 this.tabPanel.stripWrap.repaint();
25683 this.fireEvent("activate", this.tabPanel, this);
25687 * Returns true if this tab is the active tab.
25688 * @return {Boolean}
25690 isActive : function(){
25691 return this.tabPanel.getActiveTab() == this;
25695 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25698 this.pnode.removeClass("on");
25700 this.fireEvent("deactivate", this.tabPanel, this);
25703 hideAction : function(){
25704 this.bodyEl.hide();
25705 this.bodyEl.setStyle("position", "absolute");
25706 this.bodyEl.setLeft("-20000px");
25707 this.bodyEl.setTop("-20000px");
25710 showAction : function(){
25711 this.bodyEl.setStyle("position", "relative");
25712 this.bodyEl.setTop("");
25713 this.bodyEl.setLeft("");
25714 this.bodyEl.show();
25718 * Set the tooltip for the tab.
25719 * @param {String} tooltip The tab's tooltip
25721 setTooltip : function(text){
25722 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25723 this.textEl.dom.qtip = text;
25724 this.textEl.dom.removeAttribute('title');
25726 this.textEl.dom.title = text;
25730 onTabClick : function(e){
25731 e.preventDefault();
25732 this.tabPanel.activate(this.id);
25735 onTabMouseDown : function(e){
25736 e.preventDefault();
25737 this.tabPanel.activate(this.id);
25740 getWidth : function(){
25741 return this.inner.getWidth();
25744 setWidth : function(width){
25745 var iwidth = width - this.pnode.getPadding("lr");
25746 this.inner.setWidth(iwidth);
25747 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25748 this.pnode.setWidth(width);
25752 * Show or hide the tab
25753 * @param {Boolean} hidden True to hide or false to show.
25755 setHidden : function(hidden){
25756 this.hidden = hidden;
25757 this.pnode.setStyle("display", hidden ? "none" : "");
25761 * Returns true if this tab is "hidden"
25762 * @return {Boolean}
25764 isHidden : function(){
25765 return this.hidden;
25769 * Returns the text for this tab
25772 getText : function(){
25776 autoSize : function(){
25777 //this.el.beginMeasure();
25778 this.textEl.setWidth(1);
25779 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25780 //this.el.endMeasure();
25784 * Sets the text for the tab (Note: this also sets the tooltip text)
25785 * @param {String} text The tab's text and tooltip
25787 setText : function(text){
25789 this.textEl.update(text);
25790 this.setTooltip(text);
25791 if(!this.tabPanel.resizeTabs){
25796 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25798 activate : function(){
25799 this.tabPanel.activate(this.id);
25803 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25805 disable : function(){
25806 if(this.tabPanel.active != this){
25807 this.disabled = true;
25808 this.pnode.addClass("disabled");
25813 * Enables this TabPanelItem if it was previously disabled.
25815 enable : function(){
25816 this.disabled = false;
25817 this.pnode.removeClass("disabled");
25821 * Sets the content for this TabPanelItem.
25822 * @param {String} content The content
25823 * @param {Boolean} loadScripts true to look for and load scripts
25825 setContent : function(content, loadScripts){
25826 this.bodyEl.update(content, loadScripts);
25830 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25831 * @return {Roo.UpdateManager} The UpdateManager
25833 getUpdateManager : function(){
25834 return this.bodyEl.getUpdateManager();
25838 * Set a URL to be used to load the content for this TabPanelItem.
25839 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25840 * @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)
25841 * @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)
25842 * @return {Roo.UpdateManager} The UpdateManager
25844 setUrl : function(url, params, loadOnce){
25845 if(this.refreshDelegate){
25846 this.un('activate', this.refreshDelegate);
25848 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25849 this.on("activate", this.refreshDelegate);
25850 return this.bodyEl.getUpdateManager();
25854 _handleRefresh : function(url, params, loadOnce){
25855 if(!loadOnce || !this.loaded){
25856 var updater = this.bodyEl.getUpdateManager();
25857 updater.update(url, params, this._setLoaded.createDelegate(this));
25862 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25863 * Will fail silently if the setUrl method has not been called.
25864 * This does not activate the panel, just updates its content.
25866 refresh : function(){
25867 if(this.refreshDelegate){
25868 this.loaded = false;
25869 this.refreshDelegate();
25874 _setLoaded : function(){
25875 this.loaded = true;
25879 closeClick : function(e){
25882 this.fireEvent("beforeclose", this, o);
25883 if(o.cancel !== true){
25884 this.tabPanel.removeTab(this.id);
25888 * The text displayed in the tooltip for the close icon.
25891 closeText : "Close this tab"
25895 Roo.TabPanel.prototype.createStrip = function(container){
25896 var strip = document.createElement("div");
25897 strip.className = "x-tabs-wrap";
25898 container.appendChild(strip);
25902 Roo.TabPanel.prototype.createStripList = function(strip){
25903 // div wrapper for retard IE
25904 // returns the "tr" element.
25905 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
25906 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
25907 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
25908 return strip.firstChild.firstChild.firstChild.firstChild;
25911 Roo.TabPanel.prototype.createBody = function(container){
25912 var body = document.createElement("div");
25913 Roo.id(body, "tab-body");
25914 Roo.fly(body).addClass("x-tabs-body");
25915 container.appendChild(body);
25919 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25920 var body = Roo.getDom(id);
25922 body = document.createElement("div");
25925 Roo.fly(body).addClass("x-tabs-item-body");
25926 bodyEl.insertBefore(body, bodyEl.firstChild);
25930 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25931 var td = document.createElement("td");
25932 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
25933 //stripEl.appendChild(td);
25935 td.className = "x-tabs-closable";
25936 if(!this.closeTpl){
25937 this.closeTpl = new Roo.Template(
25938 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25939 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25940 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25943 var el = this.closeTpl.overwrite(td, {"text": text});
25944 var close = el.getElementsByTagName("div")[0];
25945 var inner = el.getElementsByTagName("em")[0];
25946 return {"el": el, "close": close, "inner": inner};
25949 this.tabTpl = new Roo.Template(
25950 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25951 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25954 var el = this.tabTpl.overwrite(td, {"text": text});
25955 var inner = el.getElementsByTagName("em")[0];
25956 return {"el": el, "inner": inner};
25960 * Ext JS Library 1.1.1
25961 * Copyright(c) 2006-2007, Ext JS, LLC.
25963 * Originally Released Under LGPL - original licence link has changed is not relivant.
25966 * <script type="text/javascript">
25970 * @class Roo.Button
25971 * @extends Roo.util.Observable
25972 * Simple Button class
25973 * @cfg {String} text The button text
25974 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25975 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25976 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25977 * @cfg {Object} scope The scope of the handler
25978 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25979 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25980 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25981 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25982 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25983 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25984 applies if enableToggle = true)
25985 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25986 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25987 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25989 * Create a new button
25990 * @param {Object} config The config object
25992 Roo.Button = function(renderTo, config)
25996 renderTo = config.renderTo || false;
25999 Roo.apply(this, config);
26003 * Fires when this button is clicked
26004 * @param {Button} this
26005 * @param {EventObject} e The click event
26010 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26011 * @param {Button} this
26012 * @param {Boolean} pressed
26017 * Fires when the mouse hovers over the button
26018 * @param {Button} this
26019 * @param {Event} e The event object
26021 'mouseover' : true,
26024 * Fires when the mouse exits the button
26025 * @param {Button} this
26026 * @param {Event} e The event object
26031 * Fires when the button is rendered
26032 * @param {Button} this
26037 this.menu = Roo.menu.MenuMgr.get(this.menu);
26039 // register listeners first!! - so render can be captured..
26040 Roo.util.Observable.call(this);
26042 this.render(renderTo);
26048 Roo.extend(Roo.Button, Roo.util.Observable, {
26054 * Read-only. True if this button is hidden
26059 * Read-only. True if this button is disabled
26064 * Read-only. True if this button is pressed (only if enableToggle = true)
26070 * @cfg {Number} tabIndex
26071 * The DOM tabIndex for this button (defaults to undefined)
26073 tabIndex : undefined,
26076 * @cfg {Boolean} enableToggle
26077 * True to enable pressed/not pressed toggling (defaults to false)
26079 enableToggle: false,
26081 * @cfg {Mixed} menu
26082 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26086 * @cfg {String} menuAlign
26087 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26089 menuAlign : "tl-bl?",
26092 * @cfg {String} iconCls
26093 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26095 iconCls : undefined,
26097 * @cfg {String} type
26098 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26103 menuClassTarget: 'tr',
26106 * @cfg {String} clickEvent
26107 * The type of event to map to the button's event handler (defaults to 'click')
26109 clickEvent : 'click',
26112 * @cfg {Boolean} handleMouseEvents
26113 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26115 handleMouseEvents : true,
26118 * @cfg {String} tooltipType
26119 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26121 tooltipType : 'qtip',
26124 * @cfg {String} cls
26125 * A CSS class to apply to the button's main element.
26129 * @cfg {Roo.Template} template (Optional)
26130 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26131 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26132 * require code modifications if required elements (e.g. a button) aren't present.
26136 render : function(renderTo){
26138 if(this.hideParent){
26139 this.parentEl = Roo.get(renderTo);
26141 if(!this.dhconfig){
26142 if(!this.template){
26143 if(!Roo.Button.buttonTemplate){
26144 // hideous table template
26145 Roo.Button.buttonTemplate = new Roo.Template(
26146 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26147 '<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>',
26148 "</tr></tbody></table>");
26150 this.template = Roo.Button.buttonTemplate;
26152 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26153 var btnEl = btn.child("button:first");
26154 btnEl.on('focus', this.onFocus, this);
26155 btnEl.on('blur', this.onBlur, this);
26157 btn.addClass(this.cls);
26160 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26163 btnEl.addClass(this.iconCls);
26165 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26168 if(this.tabIndex !== undefined){
26169 btnEl.dom.tabIndex = this.tabIndex;
26172 if(typeof this.tooltip == 'object'){
26173 Roo.QuickTips.tips(Roo.apply({
26177 btnEl.dom[this.tooltipType] = this.tooltip;
26181 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26185 this.el.dom.id = this.el.id = this.id;
26188 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26189 this.menu.on("show", this.onMenuShow, this);
26190 this.menu.on("hide", this.onMenuHide, this);
26192 btn.addClass("x-btn");
26193 if(Roo.isIE && !Roo.isIE7){
26194 this.autoWidth.defer(1, this);
26198 if(this.handleMouseEvents){
26199 btn.on("mouseover", this.onMouseOver, this);
26200 btn.on("mouseout", this.onMouseOut, this);
26201 btn.on("mousedown", this.onMouseDown, this);
26203 btn.on(this.clickEvent, this.onClick, this);
26204 //btn.on("mouseup", this.onMouseUp, this);
26211 Roo.ButtonToggleMgr.register(this);
26213 this.el.addClass("x-btn-pressed");
26216 var repeater = new Roo.util.ClickRepeater(btn,
26217 typeof this.repeat == "object" ? this.repeat : {}
26219 repeater.on("click", this.onClick, this);
26222 this.fireEvent('render', this);
26226 * Returns the button's underlying element
26227 * @return {Roo.Element} The element
26229 getEl : function(){
26234 * Destroys this Button and removes any listeners.
26236 destroy : function(){
26237 Roo.ButtonToggleMgr.unregister(this);
26238 this.el.removeAllListeners();
26239 this.purgeListeners();
26244 autoWidth : function(){
26246 this.el.setWidth("auto");
26247 if(Roo.isIE7 && Roo.isStrict){
26248 var ib = this.el.child('button');
26249 if(ib && ib.getWidth() > 20){
26251 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26256 this.el.beginMeasure();
26258 if(this.el.getWidth() < this.minWidth){
26259 this.el.setWidth(this.minWidth);
26262 this.el.endMeasure();
26269 * Assigns this button's click handler
26270 * @param {Function} handler The function to call when the button is clicked
26271 * @param {Object} scope (optional) Scope for the function passed in
26273 setHandler : function(handler, scope){
26274 this.handler = handler;
26275 this.scope = scope;
26279 * Sets this button's text
26280 * @param {String} text The button text
26282 setText : function(text){
26285 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26291 * Gets the text for this button
26292 * @return {String} The button text
26294 getText : function(){
26302 this.hidden = false;
26304 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26312 this.hidden = true;
26314 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26319 * Convenience function for boolean show/hide
26320 * @param {Boolean} visible True to show, false to hide
26322 setVisible: function(visible){
26331 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26332 * @param {Boolean} state (optional) Force a particular state
26334 toggle : function(state){
26335 state = state === undefined ? !this.pressed : state;
26336 if(state != this.pressed){
26338 this.el.addClass("x-btn-pressed");
26339 this.pressed = true;
26340 this.fireEvent("toggle", this, true);
26342 this.el.removeClass("x-btn-pressed");
26343 this.pressed = false;
26344 this.fireEvent("toggle", this, false);
26346 if(this.toggleHandler){
26347 this.toggleHandler.call(this.scope || this, this, state);
26355 focus : function(){
26356 this.el.child('button:first').focus();
26360 * Disable this button
26362 disable : function(){
26364 this.el.addClass("x-btn-disabled");
26366 this.disabled = true;
26370 * Enable this button
26372 enable : function(){
26374 this.el.removeClass("x-btn-disabled");
26376 this.disabled = false;
26380 * Convenience function for boolean enable/disable
26381 * @param {Boolean} enabled True to enable, false to disable
26383 setDisabled : function(v){
26384 this[v !== true ? "enable" : "disable"]();
26388 onClick : function(e){
26390 e.preventDefault();
26395 if(!this.disabled){
26396 if(this.enableToggle){
26399 if(this.menu && !this.menu.isVisible()){
26400 this.menu.show(this.el, this.menuAlign);
26402 this.fireEvent("click", this, e);
26404 this.el.removeClass("x-btn-over");
26405 this.handler.call(this.scope || this, this, e);
26410 onMouseOver : function(e){
26411 if(!this.disabled){
26412 this.el.addClass("x-btn-over");
26413 this.fireEvent('mouseover', this, e);
26417 onMouseOut : function(e){
26418 if(!e.within(this.el, true)){
26419 this.el.removeClass("x-btn-over");
26420 this.fireEvent('mouseout', this, e);
26424 onFocus : function(e){
26425 if(!this.disabled){
26426 this.el.addClass("x-btn-focus");
26430 onBlur : function(e){
26431 this.el.removeClass("x-btn-focus");
26434 onMouseDown : function(e){
26435 if(!this.disabled && e.button == 0){
26436 this.el.addClass("x-btn-click");
26437 Roo.get(document).on('mouseup', this.onMouseUp, this);
26441 onMouseUp : function(e){
26443 this.el.removeClass("x-btn-click");
26444 Roo.get(document).un('mouseup', this.onMouseUp, this);
26448 onMenuShow : function(e){
26449 this.el.addClass("x-btn-menu-active");
26452 onMenuHide : function(e){
26453 this.el.removeClass("x-btn-menu-active");
26457 // Private utility class used by Button
26458 Roo.ButtonToggleMgr = function(){
26461 function toggleGroup(btn, state){
26463 var g = groups[btn.toggleGroup];
26464 for(var i = 0, l = g.length; i < l; i++){
26466 g[i].toggle(false);
26473 register : function(btn){
26474 if(!btn.toggleGroup){
26477 var g = groups[btn.toggleGroup];
26479 g = groups[btn.toggleGroup] = [];
26482 btn.on("toggle", toggleGroup);
26485 unregister : function(btn){
26486 if(!btn.toggleGroup){
26489 var g = groups[btn.toggleGroup];
26492 btn.un("toggle", toggleGroup);
26498 * Ext JS Library 1.1.1
26499 * Copyright(c) 2006-2007, Ext JS, LLC.
26501 * Originally Released Under LGPL - original licence link has changed is not relivant.
26504 * <script type="text/javascript">
26508 * @class Roo.SplitButton
26509 * @extends Roo.Button
26510 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26511 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26512 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26513 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26514 * @cfg {String} arrowTooltip The title attribute of the arrow
26516 * Create a new menu button
26517 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26518 * @param {Object} config The config object
26520 Roo.SplitButton = function(renderTo, config){
26521 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26523 * @event arrowclick
26524 * Fires when this button's arrow is clicked
26525 * @param {SplitButton} this
26526 * @param {EventObject} e The click event
26528 this.addEvents({"arrowclick":true});
26531 Roo.extend(Roo.SplitButton, Roo.Button, {
26532 render : function(renderTo){
26533 // this is one sweet looking template!
26534 var tpl = new Roo.Template(
26535 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26536 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26537 '<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>',
26538 "</tbody></table></td><td>",
26539 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26540 '<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>',
26541 "</tbody></table></td></tr></table>"
26543 var btn = tpl.append(renderTo, [this.text, this.type], true);
26544 var btnEl = btn.child("button");
26546 btn.addClass(this.cls);
26549 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26552 btnEl.addClass(this.iconCls);
26554 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26558 if(this.handleMouseEvents){
26559 btn.on("mouseover", this.onMouseOver, this);
26560 btn.on("mouseout", this.onMouseOut, this);
26561 btn.on("mousedown", this.onMouseDown, this);
26562 btn.on("mouseup", this.onMouseUp, this);
26564 btn.on(this.clickEvent, this.onClick, this);
26566 if(typeof this.tooltip == 'object'){
26567 Roo.QuickTips.tips(Roo.apply({
26571 btnEl.dom[this.tooltipType] = this.tooltip;
26574 if(this.arrowTooltip){
26575 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26584 this.el.addClass("x-btn-pressed");
26586 if(Roo.isIE && !Roo.isIE7){
26587 this.autoWidth.defer(1, this);
26592 this.menu.on("show", this.onMenuShow, this);
26593 this.menu.on("hide", this.onMenuHide, this);
26595 this.fireEvent('render', this);
26599 autoWidth : function(){
26601 var tbl = this.el.child("table:first");
26602 var tbl2 = this.el.child("table:last");
26603 this.el.setWidth("auto");
26604 tbl.setWidth("auto");
26605 if(Roo.isIE7 && Roo.isStrict){
26606 var ib = this.el.child('button:first');
26607 if(ib && ib.getWidth() > 20){
26609 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26614 this.el.beginMeasure();
26616 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26617 tbl.setWidth(this.minWidth-tbl2.getWidth());
26620 this.el.endMeasure();
26623 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26627 * Sets this button's click handler
26628 * @param {Function} handler The function to call when the button is clicked
26629 * @param {Object} scope (optional) Scope for the function passed above
26631 setHandler : function(handler, scope){
26632 this.handler = handler;
26633 this.scope = scope;
26637 * Sets this button's arrow click handler
26638 * @param {Function} handler The function to call when the arrow is clicked
26639 * @param {Object} scope (optional) Scope for the function passed above
26641 setArrowHandler : function(handler, scope){
26642 this.arrowHandler = handler;
26643 this.scope = scope;
26649 focus : function(){
26651 this.el.child("button:first").focus();
26656 onClick : function(e){
26657 e.preventDefault();
26658 if(!this.disabled){
26659 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26660 if(this.menu && !this.menu.isVisible()){
26661 this.menu.show(this.el, this.menuAlign);
26663 this.fireEvent("arrowclick", this, e);
26664 if(this.arrowHandler){
26665 this.arrowHandler.call(this.scope || this, this, e);
26668 this.fireEvent("click", this, e);
26670 this.handler.call(this.scope || this, this, e);
26676 onMouseDown : function(e){
26677 if(!this.disabled){
26678 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26682 onMouseUp : function(e){
26683 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26688 // backwards compat
26689 Roo.MenuButton = Roo.SplitButton;/*
26691 * Ext JS Library 1.1.1
26692 * Copyright(c) 2006-2007, Ext JS, LLC.
26694 * Originally Released Under LGPL - original licence link has changed is not relivant.
26697 * <script type="text/javascript">
26701 * @class Roo.Toolbar
26702 * Basic Toolbar class.
26704 * Creates a new Toolbar
26705 * @param {Object} config The config object
26707 Roo.Toolbar = function(container, buttons, config)
26709 /// old consturctor format still supported..
26710 if(container instanceof Array){ // omit the container for later rendering
26711 buttons = container;
26715 if (typeof(container) == 'object' && container.xtype) {
26716 config = container;
26717 container = config.container;
26718 buttons = config.buttons; // not really - use items!!
26721 if (config && config.items) {
26722 xitems = config.items;
26723 delete config.items;
26725 Roo.apply(this, config);
26726 this.buttons = buttons;
26729 this.render(container);
26731 Roo.each(xitems, function(b) {
26737 Roo.Toolbar.prototype = {
26739 * @cfg {Roo.data.Store} items
26740 * array of button configs or elements to add
26744 * @cfg {String/HTMLElement/Element} container
26745 * The id or element that will contain the toolbar
26748 render : function(ct){
26749 this.el = Roo.get(ct);
26751 this.el.addClass(this.cls);
26753 // using a table allows for vertical alignment
26754 // 100% width is needed by Safari...
26755 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26756 this.tr = this.el.child("tr", true);
26758 this.items = new Roo.util.MixedCollection(false, function(o){
26759 return o.id || ("item" + (++autoId));
26762 this.add.apply(this, this.buttons);
26763 delete this.buttons;
26768 * Adds element(s) to the toolbar -- this function takes a variable number of
26769 * arguments of mixed type and adds them to the toolbar.
26770 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26772 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26773 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26774 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26775 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26776 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26777 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26778 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26779 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26780 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26782 * @param {Mixed} arg2
26783 * @param {Mixed} etc.
26786 var a = arguments, l = a.length;
26787 for(var i = 0; i < l; i++){
26792 _add : function(el) {
26795 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26798 if (el.applyTo){ // some kind of form field
26799 return this.addField(el);
26801 if (el.render){ // some kind of Toolbar.Item
26802 return this.addItem(el);
26804 if (typeof el == "string"){ // string
26805 if(el == "separator" || el == "-"){
26806 return this.addSeparator();
26809 return this.addSpacer();
26812 return this.addFill();
26814 return this.addText(el);
26817 if(el.tagName){ // element
26818 return this.addElement(el);
26820 if(typeof el == "object"){ // must be button config?
26821 return this.addButton(el);
26823 // and now what?!?!
26829 * Add an Xtype element
26830 * @param {Object} xtype Xtype Object
26831 * @return {Object} created Object
26833 addxtype : function(e){
26834 return this.add(e);
26838 * Returns the Element for this toolbar.
26839 * @return {Roo.Element}
26841 getEl : function(){
26847 * @return {Roo.Toolbar.Item} The separator item
26849 addSeparator : function(){
26850 return this.addItem(new Roo.Toolbar.Separator());
26854 * Adds a spacer element
26855 * @return {Roo.Toolbar.Spacer} The spacer item
26857 addSpacer : function(){
26858 return this.addItem(new Roo.Toolbar.Spacer());
26862 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26863 * @return {Roo.Toolbar.Fill} The fill item
26865 addFill : function(){
26866 return this.addItem(new Roo.Toolbar.Fill());
26870 * Adds any standard HTML element to the toolbar
26871 * @param {String/HTMLElement/Element} el The element or id of the element to add
26872 * @return {Roo.Toolbar.Item} The element's item
26874 addElement : function(el){
26875 return this.addItem(new Roo.Toolbar.Item(el));
26878 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26879 * @type Roo.util.MixedCollection
26884 * Adds any Toolbar.Item or subclass
26885 * @param {Roo.Toolbar.Item} item
26886 * @return {Roo.Toolbar.Item} The item
26888 addItem : function(item){
26889 var td = this.nextBlock();
26891 this.items.add(item);
26896 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26897 * @param {Object/Array} config A button config or array of configs
26898 * @return {Roo.Toolbar.Button/Array}
26900 addButton : function(config){
26901 if(config instanceof Array){
26903 for(var i = 0, len = config.length; i < len; i++) {
26904 buttons.push(this.addButton(config[i]));
26909 if(!(config instanceof Roo.Toolbar.Button)){
26911 new Roo.Toolbar.SplitButton(config) :
26912 new Roo.Toolbar.Button(config);
26914 var td = this.nextBlock();
26921 * Adds text to the toolbar
26922 * @param {String} text The text to add
26923 * @return {Roo.Toolbar.Item} The element's item
26925 addText : function(text){
26926 return this.addItem(new Roo.Toolbar.TextItem(text));
26930 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26931 * @param {Number} index The index where the item is to be inserted
26932 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26933 * @return {Roo.Toolbar.Button/Item}
26935 insertButton : function(index, item){
26936 if(item instanceof Array){
26938 for(var i = 0, len = item.length; i < len; i++) {
26939 buttons.push(this.insertButton(index + i, item[i]));
26943 if (!(item instanceof Roo.Toolbar.Button)){
26944 item = new Roo.Toolbar.Button(item);
26946 var td = document.createElement("td");
26947 this.tr.insertBefore(td, this.tr.childNodes[index]);
26949 this.items.insert(index, item);
26954 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26955 * @param {Object} config
26956 * @return {Roo.Toolbar.Item} The element's item
26958 addDom : function(config, returnEl){
26959 var td = this.nextBlock();
26960 Roo.DomHelper.overwrite(td, config);
26961 var ti = new Roo.Toolbar.Item(td.firstChild);
26963 this.items.add(ti);
26968 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26969 * @type Roo.util.MixedCollection
26974 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26975 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26976 * @param {Roo.form.Field} field
26977 * @return {Roo.ToolbarItem}
26981 addField : function(field) {
26982 if (!this.fields) {
26984 this.fields = new Roo.util.MixedCollection(false, function(o){
26985 return o.id || ("item" + (++autoId));
26990 var td = this.nextBlock();
26992 var ti = new Roo.Toolbar.Item(td.firstChild);
26994 this.items.add(ti);
26995 this.fields.add(field);
27006 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
27007 this.el.child('div').hide();
27015 this.el.child('div').show();
27019 nextBlock : function(){
27020 var td = document.createElement("td");
27021 this.tr.appendChild(td);
27026 destroy : function(){
27027 if(this.items){ // rendered?
27028 Roo.destroy.apply(Roo, this.items.items);
27030 if(this.fields){ // rendered?
27031 Roo.destroy.apply(Roo, this.fields.items);
27033 Roo.Element.uncache(this.el, this.tr);
27038 * @class Roo.Toolbar.Item
27039 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27041 * Creates a new Item
27042 * @param {HTMLElement} el
27044 Roo.Toolbar.Item = function(el){
27045 this.el = Roo.getDom(el);
27046 this.id = Roo.id(this.el);
27047 this.hidden = false;
27050 Roo.Toolbar.Item.prototype = {
27053 * Get this item's HTML Element
27054 * @return {HTMLElement}
27056 getEl : function(){
27061 render : function(td){
27063 td.appendChild(this.el);
27067 * Removes and destroys this item.
27069 destroy : function(){
27070 this.td.parentNode.removeChild(this.td);
27077 this.hidden = false;
27078 this.td.style.display = "";
27085 this.hidden = true;
27086 this.td.style.display = "none";
27090 * Convenience function for boolean show/hide.
27091 * @param {Boolean} visible true to show/false to hide
27093 setVisible: function(visible){
27102 * Try to focus this item.
27104 focus : function(){
27105 Roo.fly(this.el).focus();
27109 * Disables this item.
27111 disable : function(){
27112 Roo.fly(this.td).addClass("x-item-disabled");
27113 this.disabled = true;
27114 this.el.disabled = true;
27118 * Enables this item.
27120 enable : function(){
27121 Roo.fly(this.td).removeClass("x-item-disabled");
27122 this.disabled = false;
27123 this.el.disabled = false;
27129 * @class Roo.Toolbar.Separator
27130 * @extends Roo.Toolbar.Item
27131 * A simple toolbar separator class
27133 * Creates a new Separator
27135 Roo.Toolbar.Separator = function(){
27136 var s = document.createElement("span");
27137 s.className = "ytb-sep";
27138 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27140 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27141 enable:Roo.emptyFn,
27142 disable:Roo.emptyFn,
27147 * @class Roo.Toolbar.Spacer
27148 * @extends Roo.Toolbar.Item
27149 * A simple element that adds extra horizontal space to a toolbar.
27151 * Creates a new Spacer
27153 Roo.Toolbar.Spacer = function(){
27154 var s = document.createElement("div");
27155 s.className = "ytb-spacer";
27156 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27158 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27159 enable:Roo.emptyFn,
27160 disable:Roo.emptyFn,
27165 * @class Roo.Toolbar.Fill
27166 * @extends Roo.Toolbar.Spacer
27167 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27169 * Creates a new Spacer
27171 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27173 render : function(td){
27174 td.style.width = '100%';
27175 Roo.Toolbar.Fill.superclass.render.call(this, td);
27180 * @class Roo.Toolbar.TextItem
27181 * @extends Roo.Toolbar.Item
27182 * A simple class that renders text directly into a toolbar.
27184 * Creates a new TextItem
27185 * @param {String} text
27187 Roo.Toolbar.TextItem = function(text){
27188 if (typeof(text) == 'object') {
27191 var s = document.createElement("span");
27192 s.className = "ytb-text";
27193 s.innerHTML = text;
27194 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27196 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27197 enable:Roo.emptyFn,
27198 disable:Roo.emptyFn,
27203 * @class Roo.Toolbar.Button
27204 * @extends Roo.Button
27205 * A button that renders into a toolbar.
27207 * Creates a new Button
27208 * @param {Object} config A standard {@link Roo.Button} config object
27210 Roo.Toolbar.Button = function(config){
27211 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27213 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27214 render : function(td){
27216 Roo.Toolbar.Button.superclass.render.call(this, td);
27220 * Removes and destroys this button
27222 destroy : function(){
27223 Roo.Toolbar.Button.superclass.destroy.call(this);
27224 this.td.parentNode.removeChild(this.td);
27228 * Shows this button
27231 this.hidden = false;
27232 this.td.style.display = "";
27236 * Hides this button
27239 this.hidden = true;
27240 this.td.style.display = "none";
27244 * Disables this item
27246 disable : function(){
27247 Roo.fly(this.td).addClass("x-item-disabled");
27248 this.disabled = true;
27252 * Enables this item
27254 enable : function(){
27255 Roo.fly(this.td).removeClass("x-item-disabled");
27256 this.disabled = false;
27259 // backwards compat
27260 Roo.ToolbarButton = Roo.Toolbar.Button;
27263 * @class Roo.Toolbar.SplitButton
27264 * @extends Roo.SplitButton
27265 * A menu button that renders into a toolbar.
27267 * Creates a new SplitButton
27268 * @param {Object} config A standard {@link Roo.SplitButton} config object
27270 Roo.Toolbar.SplitButton = function(config){
27271 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27273 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27274 render : function(td){
27276 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27280 * Removes and destroys this button
27282 destroy : function(){
27283 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27284 this.td.parentNode.removeChild(this.td);
27288 * Shows this button
27291 this.hidden = false;
27292 this.td.style.display = "";
27296 * Hides this button
27299 this.hidden = true;
27300 this.td.style.display = "none";
27304 // backwards compat
27305 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27307 * Ext JS Library 1.1.1
27308 * Copyright(c) 2006-2007, Ext JS, LLC.
27310 * Originally Released Under LGPL - original licence link has changed is not relivant.
27313 * <script type="text/javascript">
27317 * @class Roo.PagingToolbar
27318 * @extends Roo.Toolbar
27319 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27321 * Create a new PagingToolbar
27322 * @param {Object} config The config object
27324 Roo.PagingToolbar = function(el, ds, config)
27326 // old args format still supported... - xtype is prefered..
27327 if (typeof(el) == 'object' && el.xtype) {
27328 // created from xtype...
27330 ds = el.dataSource;
27331 el = config.container;
27334 if (config.items) {
27335 items = config.items;
27339 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27342 this.renderButtons(this.el);
27345 // supprot items array.
27347 Roo.each(items, function(e) {
27348 this.add(Roo.factory(e));
27353 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27355 * @cfg {Roo.data.Store} dataSource
27356 * The underlying data store providing the paged data
27359 * @cfg {String/HTMLElement/Element} container
27360 * container The id or element that will contain the toolbar
27363 * @cfg {Boolean} displayInfo
27364 * True to display the displayMsg (defaults to false)
27367 * @cfg {Number} pageSize
27368 * The number of records to display per page (defaults to 20)
27372 * @cfg {String} displayMsg
27373 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27375 displayMsg : 'Displaying {0} - {1} of {2}',
27377 * @cfg {String} emptyMsg
27378 * The message to display when no records are found (defaults to "No data to display")
27380 emptyMsg : 'No data to display',
27382 * Customizable piece of the default paging text (defaults to "Page")
27385 beforePageText : "Page",
27387 * Customizable piece of the default paging text (defaults to "of %0")
27390 afterPageText : "of {0}",
27392 * Customizable piece of the default paging text (defaults to "First Page")
27395 firstText : "First Page",
27397 * Customizable piece of the default paging text (defaults to "Previous Page")
27400 prevText : "Previous Page",
27402 * Customizable piece of the default paging text (defaults to "Next Page")
27405 nextText : "Next Page",
27407 * Customizable piece of the default paging text (defaults to "Last Page")
27410 lastText : "Last Page",
27412 * Customizable piece of the default paging text (defaults to "Refresh")
27415 refreshText : "Refresh",
27418 renderButtons : function(el){
27419 Roo.PagingToolbar.superclass.render.call(this, el);
27420 this.first = this.addButton({
27421 tooltip: this.firstText,
27422 cls: "x-btn-icon x-grid-page-first",
27424 handler: this.onClick.createDelegate(this, ["first"])
27426 this.prev = this.addButton({
27427 tooltip: this.prevText,
27428 cls: "x-btn-icon x-grid-page-prev",
27430 handler: this.onClick.createDelegate(this, ["prev"])
27432 //this.addSeparator();
27433 this.add(this.beforePageText);
27434 this.field = Roo.get(this.addDom({
27439 cls: "x-grid-page-number"
27441 this.field.on("keydown", this.onPagingKeydown, this);
27442 this.field.on("focus", function(){this.dom.select();});
27443 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27444 this.field.setHeight(18);
27445 //this.addSeparator();
27446 this.next = this.addButton({
27447 tooltip: this.nextText,
27448 cls: "x-btn-icon x-grid-page-next",
27450 handler: this.onClick.createDelegate(this, ["next"])
27452 this.last = this.addButton({
27453 tooltip: this.lastText,
27454 cls: "x-btn-icon x-grid-page-last",
27456 handler: this.onClick.createDelegate(this, ["last"])
27458 //this.addSeparator();
27459 this.loading = this.addButton({
27460 tooltip: this.refreshText,
27461 cls: "x-btn-icon x-grid-loading",
27462 handler: this.onClick.createDelegate(this, ["refresh"])
27465 if(this.displayInfo){
27466 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27471 updateInfo : function(){
27472 if(this.displayEl){
27473 var count = this.ds.getCount();
27474 var msg = count == 0 ?
27478 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27480 this.displayEl.update(msg);
27485 onLoad : function(ds, r, o){
27486 this.cursor = o.params ? o.params.start : 0;
27487 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27489 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27490 this.field.dom.value = ap;
27491 this.first.setDisabled(ap == 1);
27492 this.prev.setDisabled(ap == 1);
27493 this.next.setDisabled(ap == ps);
27494 this.last.setDisabled(ap == ps);
27495 this.loading.enable();
27500 getPageData : function(){
27501 var total = this.ds.getTotalCount();
27504 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27505 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27510 onLoadError : function(){
27511 this.loading.enable();
27515 onPagingKeydown : function(e){
27516 var k = e.getKey();
27517 var d = this.getPageData();
27519 var v = this.field.dom.value, pageNum;
27520 if(!v || isNaN(pageNum = parseInt(v, 10))){
27521 this.field.dom.value = d.activePage;
27524 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27525 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27528 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))
27530 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27531 this.field.dom.value = pageNum;
27532 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27535 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27537 var v = this.field.dom.value, pageNum;
27538 var increment = (e.shiftKey) ? 10 : 1;
27539 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27541 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27542 this.field.dom.value = d.activePage;
27545 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27547 this.field.dom.value = parseInt(v, 10) + increment;
27548 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27549 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27556 beforeLoad : function(){
27558 this.loading.disable();
27563 onClick : function(which){
27567 ds.load({params:{start: 0, limit: this.pageSize}});
27570 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27573 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27576 var total = ds.getTotalCount();
27577 var extra = total % this.pageSize;
27578 var lastStart = extra ? (total - extra) : total-this.pageSize;
27579 ds.load({params:{start: lastStart, limit: this.pageSize}});
27582 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27588 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27589 * @param {Roo.data.Store} store The data store to unbind
27591 unbind : function(ds){
27592 ds.un("beforeload", this.beforeLoad, this);
27593 ds.un("load", this.onLoad, this);
27594 ds.un("loadexception", this.onLoadError, this);
27595 ds.un("remove", this.updateInfo, this);
27596 ds.un("add", this.updateInfo, this);
27597 this.ds = undefined;
27601 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27602 * @param {Roo.data.Store} store The data store to bind
27604 bind : function(ds){
27605 ds.on("beforeload", this.beforeLoad, this);
27606 ds.on("load", this.onLoad, this);
27607 ds.on("loadexception", this.onLoadError, this);
27608 ds.on("remove", this.updateInfo, this);
27609 ds.on("add", this.updateInfo, this);
27614 * Ext JS Library 1.1.1
27615 * Copyright(c) 2006-2007, Ext JS, LLC.
27617 * Originally Released Under LGPL - original licence link has changed is not relivant.
27620 * <script type="text/javascript">
27624 * @class Roo.Resizable
27625 * @extends Roo.util.Observable
27626 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27627 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27628 * 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
27629 * the element will be wrapped for you automatically.</p>
27630 * <p>Here is the list of valid resize handles:</p>
27633 ------ -------------------
27642 'hd' horizontal drag
27645 * <p>Here's an example showing the creation of a typical Resizable:</p>
27647 var resizer = new Roo.Resizable("element-id", {
27655 resizer.on("resize", myHandler);
27657 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27658 * resizer.east.setDisplayed(false);</p>
27659 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27660 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27661 * resize operation's new size (defaults to [0, 0])
27662 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27663 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27664 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27665 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27666 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27667 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27668 * @cfg {Number} width The width of the element in pixels (defaults to null)
27669 * @cfg {Number} height The height of the element in pixels (defaults to null)
27670 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27671 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27672 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27673 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27674 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27675 * in favor of the handles config option (defaults to false)
27676 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27677 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27678 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27679 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27680 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27681 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27682 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27683 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27684 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27685 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27686 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27688 * Create a new resizable component
27689 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27690 * @param {Object} config configuration options
27692 Roo.Resizable = function(el, config)
27694 this.el = Roo.get(el);
27696 if(config && config.wrap){
27697 config.resizeChild = this.el;
27698 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27699 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27700 this.el.setStyle("overflow", "hidden");
27701 this.el.setPositioning(config.resizeChild.getPositioning());
27702 config.resizeChild.clearPositioning();
27703 if(!config.width || !config.height){
27704 var csize = config.resizeChild.getSize();
27705 this.el.setSize(csize.width, csize.height);
27707 if(config.pinned && !config.adjustments){
27708 config.adjustments = "auto";
27712 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27713 this.proxy.unselectable();
27714 this.proxy.enableDisplayMode('block');
27716 Roo.apply(this, config);
27719 this.disableTrackOver = true;
27720 this.el.addClass("x-resizable-pinned");
27722 // if the element isn't positioned, make it relative
27723 var position = this.el.getStyle("position");
27724 if(position != "absolute" && position != "fixed"){
27725 this.el.setStyle("position", "relative");
27727 if(!this.handles){ // no handles passed, must be legacy style
27728 this.handles = 's,e,se';
27729 if(this.multiDirectional){
27730 this.handles += ',n,w';
27733 if(this.handles == "all"){
27734 this.handles = "n s e w ne nw se sw";
27736 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27737 var ps = Roo.Resizable.positions;
27738 for(var i = 0, len = hs.length; i < len; i++){
27739 if(hs[i] && ps[hs[i]]){
27740 var pos = ps[hs[i]];
27741 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27745 this.corner = this.southeast;
27747 // updateBox = the box can move..
27748 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27749 this.updateBox = true;
27752 this.activeHandle = null;
27754 if(this.resizeChild){
27755 if(typeof this.resizeChild == "boolean"){
27756 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27758 this.resizeChild = Roo.get(this.resizeChild, true);
27762 if(this.adjustments == "auto"){
27763 var rc = this.resizeChild;
27764 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27765 if(rc && (hw || hn)){
27766 rc.position("relative");
27767 rc.setLeft(hw ? hw.el.getWidth() : 0);
27768 rc.setTop(hn ? hn.el.getHeight() : 0);
27770 this.adjustments = [
27771 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27772 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27776 if(this.draggable){
27777 this.dd = this.dynamic ?
27778 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27779 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27785 * @event beforeresize
27786 * Fired before resize is allowed. Set enabled to false to cancel resize.
27787 * @param {Roo.Resizable} this
27788 * @param {Roo.EventObject} e The mousedown event
27790 "beforeresize" : true,
27793 * Fired after a resize.
27794 * @param {Roo.Resizable} this
27795 * @param {Number} width The new width
27796 * @param {Number} height The new height
27797 * @param {Roo.EventObject} e The mouseup event
27802 if(this.width !== null && this.height !== null){
27803 this.resizeTo(this.width, this.height);
27805 this.updateChildSize();
27808 this.el.dom.style.zoom = 1;
27810 Roo.Resizable.superclass.constructor.call(this);
27813 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27814 resizeChild : false,
27815 adjustments : [0, 0],
27825 multiDirectional : false,
27826 disableTrackOver : false,
27827 easing : 'easeOutStrong',
27828 widthIncrement : 0,
27829 heightIncrement : 0,
27833 preserveRatio : false,
27834 transparent: false,
27840 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27842 constrainTo: undefined,
27844 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27846 resizeRegion: undefined,
27850 * Perform a manual resize
27851 * @param {Number} width
27852 * @param {Number} height
27854 resizeTo : function(width, height){
27855 this.el.setSize(width, height);
27856 this.updateChildSize();
27857 this.fireEvent("resize", this, width, height, null);
27861 startSizing : function(e, handle){
27862 this.fireEvent("beforeresize", this, e);
27863 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27866 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27867 this.overlay.unselectable();
27868 this.overlay.enableDisplayMode("block");
27869 this.overlay.on("mousemove", this.onMouseMove, this);
27870 this.overlay.on("mouseup", this.onMouseUp, this);
27872 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27874 this.resizing = true;
27875 this.startBox = this.el.getBox();
27876 this.startPoint = e.getXY();
27877 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27878 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27880 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27881 this.overlay.show();
27883 if(this.constrainTo) {
27884 var ct = Roo.get(this.constrainTo);
27885 this.resizeRegion = ct.getRegion().adjust(
27886 ct.getFrameWidth('t'),
27887 ct.getFrameWidth('l'),
27888 -ct.getFrameWidth('b'),
27889 -ct.getFrameWidth('r')
27893 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27895 this.proxy.setBox(this.startBox);
27897 this.proxy.setStyle('visibility', 'visible');
27903 onMouseDown : function(handle, e){
27906 this.activeHandle = handle;
27907 this.startSizing(e, handle);
27912 onMouseUp : function(e){
27913 var size = this.resizeElement();
27914 this.resizing = false;
27916 this.overlay.hide();
27918 this.fireEvent("resize", this, size.width, size.height, e);
27922 updateChildSize : function(){
27923 if(this.resizeChild){
27925 var child = this.resizeChild;
27926 var adj = this.adjustments;
27927 if(el.dom.offsetWidth){
27928 var b = el.getSize(true);
27929 child.setSize(b.width+adj[0], b.height+adj[1]);
27931 // Second call here for IE
27932 // The first call enables instant resizing and
27933 // the second call corrects scroll bars if they
27936 setTimeout(function(){
27937 if(el.dom.offsetWidth){
27938 var b = el.getSize(true);
27939 child.setSize(b.width+adj[0], b.height+adj[1]);
27947 snap : function(value, inc, min){
27948 if(!inc || !value) return value;
27949 var newValue = value;
27950 var m = value % inc;
27953 newValue = value + (inc-m);
27955 newValue = value - m;
27958 return Math.max(min, newValue);
27962 resizeElement : function(){
27963 var box = this.proxy.getBox();
27964 if(this.updateBox){
27965 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27967 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27969 this.updateChildSize();
27977 constrain : function(v, diff, m, mx){
27980 }else if(v - diff > mx){
27987 onMouseMove : function(e){
27989 try{// try catch so if something goes wrong the user doesn't get hung
27991 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27995 //var curXY = this.startPoint;
27996 var curSize = this.curSize || this.startBox;
27997 var x = this.startBox.x, y = this.startBox.y;
27998 var ox = x, oy = y;
27999 var w = curSize.width, h = curSize.height;
28000 var ow = w, oh = h;
28001 var mw = this.minWidth, mh = this.minHeight;
28002 var mxw = this.maxWidth, mxh = this.maxHeight;
28003 var wi = this.widthIncrement;
28004 var hi = this.heightIncrement;
28006 var eventXY = e.getXY();
28007 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
28008 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28010 var pos = this.activeHandle.position;
28015 w = Math.min(Math.max(mw, w), mxw);
28020 h = Math.min(Math.max(mh, h), mxh);
28025 w = Math.min(Math.max(mw, w), mxw);
28026 h = Math.min(Math.max(mh, h), mxh);
28029 diffY = this.constrain(h, diffY, mh, mxh);
28036 var adiffX = Math.abs(diffX);
28037 var sub = (adiffX % wi); // how much
28038 if (sub > (wi/2)) { // far enough to snap
28039 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28041 // remove difference..
28042 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28046 x = Math.max(this.minX, x);
28049 diffX = this.constrain(w, diffX, mw, mxw);
28055 w = Math.min(Math.max(mw, w), mxw);
28056 diffY = this.constrain(h, diffY, mh, mxh);
28061 diffX = this.constrain(w, diffX, mw, mxw);
28062 diffY = this.constrain(h, diffY, mh, mxh);
28069 diffX = this.constrain(w, diffX, mw, mxw);
28071 h = Math.min(Math.max(mh, h), mxh);
28077 var sw = this.snap(w, wi, mw);
28078 var sh = this.snap(h, hi, mh);
28079 if(sw != w || sh != h){
28102 if(this.preserveRatio){
28107 h = Math.min(Math.max(mh, h), mxh);
28112 w = Math.min(Math.max(mw, w), mxw);
28117 w = Math.min(Math.max(mw, w), mxw);
28123 w = Math.min(Math.max(mw, w), mxw);
28129 h = Math.min(Math.max(mh, h), mxh);
28137 h = Math.min(Math.max(mh, h), mxh);
28147 h = Math.min(Math.max(mh, h), mxh);
28155 if (pos == 'hdrag') {
28158 this.proxy.setBounds(x, y, w, h);
28160 this.resizeElement();
28167 handleOver : function(){
28169 this.el.addClass("x-resizable-over");
28174 handleOut : function(){
28175 if(!this.resizing){
28176 this.el.removeClass("x-resizable-over");
28181 * Returns the element this component is bound to.
28182 * @return {Roo.Element}
28184 getEl : function(){
28189 * Returns the resizeChild element (or null).
28190 * @return {Roo.Element}
28192 getResizeChild : function(){
28193 return this.resizeChild;
28197 * Destroys this resizable. If the element was wrapped and
28198 * removeEl is not true then the element remains.
28199 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28201 destroy : function(removeEl){
28202 this.proxy.remove();
28204 this.overlay.removeAllListeners();
28205 this.overlay.remove();
28207 var ps = Roo.Resizable.positions;
28209 if(typeof ps[k] != "function" && this[ps[k]]){
28210 var h = this[ps[k]];
28211 h.el.removeAllListeners();
28216 this.el.update("");
28223 // hash to map config positions to true positions
28224 Roo.Resizable.positions = {
28225 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28230 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28232 // only initialize the template if resizable is used
28233 var tpl = Roo.DomHelper.createTemplate(
28234 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28237 Roo.Resizable.Handle.prototype.tpl = tpl;
28239 this.position = pos;
28241 // show north drag fro topdra
28242 var handlepos = pos == 'hdrag' ? 'north' : pos;
28244 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28245 if (pos == 'hdrag') {
28246 this.el.setStyle('cursor', 'pointer');
28248 this.el.unselectable();
28250 this.el.setOpacity(0);
28252 this.el.on("mousedown", this.onMouseDown, this);
28253 if(!disableTrackOver){
28254 this.el.on("mouseover", this.onMouseOver, this);
28255 this.el.on("mouseout", this.onMouseOut, this);
28260 Roo.Resizable.Handle.prototype = {
28261 afterResize : function(rz){
28265 onMouseDown : function(e){
28266 this.rz.onMouseDown(this, e);
28269 onMouseOver : function(e){
28270 this.rz.handleOver(this, e);
28273 onMouseOut : function(e){
28274 this.rz.handleOut(this, e);
28278 * Ext JS Library 1.1.1
28279 * Copyright(c) 2006-2007, Ext JS, LLC.
28281 * Originally Released Under LGPL - original licence link has changed is not relivant.
28284 * <script type="text/javascript">
28288 * @class Roo.Editor
28289 * @extends Roo.Component
28290 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28292 * Create a new Editor
28293 * @param {Roo.form.Field} field The Field object (or descendant)
28294 * @param {Object} config The config object
28296 Roo.Editor = function(field, config){
28297 Roo.Editor.superclass.constructor.call(this, config);
28298 this.field = field;
28301 * @event beforestartedit
28302 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28303 * false from the handler of this event.
28304 * @param {Editor} this
28305 * @param {Roo.Element} boundEl The underlying element bound to this editor
28306 * @param {Mixed} value The field value being set
28308 "beforestartedit" : true,
28311 * Fires when this editor is displayed
28312 * @param {Roo.Element} boundEl The underlying element bound to this editor
28313 * @param {Mixed} value The starting field value
28315 "startedit" : true,
28317 * @event beforecomplete
28318 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28319 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28320 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28321 * event will not fire since no edit actually occurred.
28322 * @param {Editor} this
28323 * @param {Mixed} value The current field value
28324 * @param {Mixed} startValue The original field value
28326 "beforecomplete" : true,
28329 * Fires after editing is complete and any changed value has been written to the underlying field.
28330 * @param {Editor} this
28331 * @param {Mixed} value The current field value
28332 * @param {Mixed} startValue The original field value
28336 * @event specialkey
28337 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28338 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28339 * @param {Roo.form.Field} this
28340 * @param {Roo.EventObject} e The event object
28342 "specialkey" : true
28346 Roo.extend(Roo.Editor, Roo.Component, {
28348 * @cfg {Boolean/String} autosize
28349 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28350 * or "height" to adopt the height only (defaults to false)
28353 * @cfg {Boolean} revertInvalid
28354 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28355 * validation fails (defaults to true)
28358 * @cfg {Boolean} ignoreNoChange
28359 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28360 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28361 * will never be ignored.
28364 * @cfg {Boolean} hideEl
28365 * False to keep the bound element visible while the editor is displayed (defaults to true)
28368 * @cfg {Mixed} value
28369 * The data value of the underlying field (defaults to "")
28373 * @cfg {String} alignment
28374 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28378 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28379 * for bottom-right shadow (defaults to "frame")
28383 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28387 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28389 completeOnEnter : false,
28391 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28393 cancelOnEsc : false,
28395 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28400 onRender : function(ct, position){
28401 this.el = new Roo.Layer({
28402 shadow: this.shadow,
28408 constrain: this.constrain
28410 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28411 if(this.field.msgTarget != 'title'){
28412 this.field.msgTarget = 'qtip';
28414 this.field.render(this.el);
28416 this.field.el.dom.setAttribute('autocomplete', 'off');
28418 this.field.on("specialkey", this.onSpecialKey, this);
28419 if(this.swallowKeys){
28420 this.field.el.swallowEvent(['keydown','keypress']);
28423 this.field.on("blur", this.onBlur, this);
28424 if(this.field.grow){
28425 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28429 onSpecialKey : function(field, e)
28431 //Roo.log('editor onSpecialKey');
28432 if(this.completeOnEnter && e.getKey() == e.ENTER){
28434 this.completeEdit();
28437 // do not fire special key otherwise it might hide close the editor...
28438 if(e.getKey() == e.ENTER){
28441 if(this.cancelOnEsc && e.getKey() == e.ESC){
28445 this.fireEvent('specialkey', field, e);
28450 * Starts the editing process and shows the editor.
28451 * @param {String/HTMLElement/Element} el The element to edit
28452 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28453 * to the innerHTML of el.
28455 startEdit : function(el, value){
28457 this.completeEdit();
28459 this.boundEl = Roo.get(el);
28460 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28461 if(!this.rendered){
28462 this.render(this.parentEl || document.body);
28464 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28467 this.startValue = v;
28468 this.field.setValue(v);
28470 var sz = this.boundEl.getSize();
28471 switch(this.autoSize){
28473 this.setSize(sz.width, "");
28476 this.setSize("", sz.height);
28479 this.setSize(sz.width, sz.height);
28482 this.el.alignTo(this.boundEl, this.alignment);
28483 this.editing = true;
28485 Roo.QuickTips.disable();
28491 * Sets the height and width of this editor.
28492 * @param {Number} width The new width
28493 * @param {Number} height The new height
28495 setSize : function(w, h){
28496 this.field.setSize(w, h);
28503 * Realigns the editor to the bound field based on the current alignment config value.
28505 realign : function(){
28506 this.el.alignTo(this.boundEl, this.alignment);
28510 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28511 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28513 completeEdit : function(remainVisible){
28517 var v = this.getValue();
28518 if(this.revertInvalid !== false && !this.field.isValid()){
28519 v = this.startValue;
28520 this.cancelEdit(true);
28522 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28523 this.editing = false;
28527 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28528 this.editing = false;
28529 if(this.updateEl && this.boundEl){
28530 this.boundEl.update(v);
28532 if(remainVisible !== true){
28535 this.fireEvent("complete", this, v, this.startValue);
28540 onShow : function(){
28542 if(this.hideEl !== false){
28543 this.boundEl.hide();
28546 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28547 this.fixIEFocus = true;
28548 this.deferredFocus.defer(50, this);
28550 this.field.focus();
28552 this.fireEvent("startedit", this.boundEl, this.startValue);
28555 deferredFocus : function(){
28557 this.field.focus();
28562 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28563 * reverted to the original starting value.
28564 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28565 * cancel (defaults to false)
28567 cancelEdit : function(remainVisible){
28569 this.setValue(this.startValue);
28570 if(remainVisible !== true){
28577 onBlur : function(){
28578 if(this.allowBlur !== true && this.editing){
28579 this.completeEdit();
28584 onHide : function(){
28586 this.completeEdit();
28590 if(this.field.collapse){
28591 this.field.collapse();
28594 if(this.hideEl !== false){
28595 this.boundEl.show();
28598 Roo.QuickTips.enable();
28603 * Sets the data value of the editor
28604 * @param {Mixed} value Any valid value supported by the underlying field
28606 setValue : function(v){
28607 this.field.setValue(v);
28611 * Gets the data value of the editor
28612 * @return {Mixed} The data value
28614 getValue : function(){
28615 return this.field.getValue();
28619 * Ext JS Library 1.1.1
28620 * Copyright(c) 2006-2007, Ext JS, LLC.
28622 * Originally Released Under LGPL - original licence link has changed is not relivant.
28625 * <script type="text/javascript">
28629 * @class Roo.BasicDialog
28630 * @extends Roo.util.Observable
28631 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28633 var dlg = new Roo.BasicDialog("my-dlg", {
28642 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28643 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28644 dlg.addButton('Cancel', dlg.hide, dlg);
28647 <b>A Dialog should always be a direct child of the body element.</b>
28648 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28649 * @cfg {String} title Default text to display in the title bar (defaults to null)
28650 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28651 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28652 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28653 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28654 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28655 * (defaults to null with no animation)
28656 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28657 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28658 * property for valid values (defaults to 'all')
28659 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28660 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28661 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28662 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28663 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28664 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28665 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28666 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28667 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28668 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28669 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28670 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28671 * draggable = true (defaults to false)
28672 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28673 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28674 * shadow (defaults to false)
28675 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28676 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28677 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28678 * @cfg {Array} buttons Array of buttons
28679 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28681 * Create a new BasicDialog.
28682 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28683 * @param {Object} config Configuration options
28685 Roo.BasicDialog = function(el, config){
28686 this.el = Roo.get(el);
28687 var dh = Roo.DomHelper;
28688 if(!this.el && config && config.autoCreate){
28689 if(typeof config.autoCreate == "object"){
28690 if(!config.autoCreate.id){
28691 config.autoCreate.id = el;
28693 this.el = dh.append(document.body,
28694 config.autoCreate, true);
28696 this.el = dh.append(document.body,
28697 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28701 el.setDisplayed(true);
28702 el.hide = this.hideAction;
28704 el.addClass("x-dlg");
28706 Roo.apply(this, config);
28708 this.proxy = el.createProxy("x-dlg-proxy");
28709 this.proxy.hide = this.hideAction;
28710 this.proxy.setOpacity(.5);
28714 el.setWidth(config.width);
28717 el.setHeight(config.height);
28719 this.size = el.getSize();
28720 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28721 this.xy = [config.x,config.y];
28723 this.xy = el.getCenterXY(true);
28725 /** The header element @type Roo.Element */
28726 this.header = el.child("> .x-dlg-hd");
28727 /** The body element @type Roo.Element */
28728 this.body = el.child("> .x-dlg-bd");
28729 /** The footer element @type Roo.Element */
28730 this.footer = el.child("> .x-dlg-ft");
28733 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28736 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28739 this.header.unselectable();
28741 this.header.update(this.title);
28743 // this element allows the dialog to be focused for keyboard event
28744 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28745 this.focusEl.swallowEvent("click", true);
28747 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28749 // wrap the body and footer for special rendering
28750 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28752 this.bwrap.dom.appendChild(this.footer.dom);
28755 this.bg = this.el.createChild({
28756 tag: "div", cls:"x-dlg-bg",
28757 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28759 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28762 if(this.autoScroll !== false && !this.autoTabs){
28763 this.body.setStyle("overflow", "auto");
28766 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28768 if(this.closable !== false){
28769 this.el.addClass("x-dlg-closable");
28770 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28771 this.close.on("click", this.closeClick, this);
28772 this.close.addClassOnOver("x-dlg-close-over");
28774 if(this.collapsible !== false){
28775 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28776 this.collapseBtn.on("click", this.collapseClick, this);
28777 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28778 this.header.on("dblclick", this.collapseClick, this);
28780 if(this.resizable !== false){
28781 this.el.addClass("x-dlg-resizable");
28782 this.resizer = new Roo.Resizable(el, {
28783 minWidth: this.minWidth || 80,
28784 minHeight:this.minHeight || 80,
28785 handles: this.resizeHandles || "all",
28788 this.resizer.on("beforeresize", this.beforeResize, this);
28789 this.resizer.on("resize", this.onResize, this);
28791 if(this.draggable !== false){
28792 el.addClass("x-dlg-draggable");
28793 if (!this.proxyDrag) {
28794 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28797 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28799 dd.setHandleElId(this.header.id);
28800 dd.endDrag = this.endMove.createDelegate(this);
28801 dd.startDrag = this.startMove.createDelegate(this);
28802 dd.onDrag = this.onDrag.createDelegate(this);
28807 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28808 this.mask.enableDisplayMode("block");
28810 this.el.addClass("x-dlg-modal");
28813 this.shadow = new Roo.Shadow({
28814 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28815 offset : this.shadowOffset
28818 this.shadowOffset = 0;
28820 if(Roo.useShims && this.shim !== false){
28821 this.shim = this.el.createShim();
28822 this.shim.hide = this.hideAction;
28830 if (this.buttons) {
28831 var bts= this.buttons;
28833 Roo.each(bts, function(b) {
28842 * Fires when a key is pressed
28843 * @param {Roo.BasicDialog} this
28844 * @param {Roo.EventObject} e
28849 * Fires when this dialog is moved by the user.
28850 * @param {Roo.BasicDialog} this
28851 * @param {Number} x The new page X
28852 * @param {Number} y The new page Y
28857 * Fires when this dialog is resized by the user.
28858 * @param {Roo.BasicDialog} this
28859 * @param {Number} width The new width
28860 * @param {Number} height The new height
28864 * @event beforehide
28865 * Fires before this dialog is hidden.
28866 * @param {Roo.BasicDialog} this
28868 "beforehide" : true,
28871 * Fires when this dialog is hidden.
28872 * @param {Roo.BasicDialog} this
28876 * @event beforeshow
28877 * Fires before this dialog is shown.
28878 * @param {Roo.BasicDialog} this
28880 "beforeshow" : true,
28883 * Fires when this dialog is shown.
28884 * @param {Roo.BasicDialog} this
28888 el.on("keydown", this.onKeyDown, this);
28889 el.on("mousedown", this.toFront, this);
28890 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28892 Roo.DialogManager.register(this);
28893 Roo.BasicDialog.superclass.constructor.call(this);
28896 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28897 shadowOffset: Roo.isIE ? 6 : 5,
28900 minButtonWidth: 75,
28901 defaultButton: null,
28902 buttonAlign: "right",
28907 * Sets the dialog title text
28908 * @param {String} text The title text to display
28909 * @return {Roo.BasicDialog} this
28911 setTitle : function(text){
28912 this.header.update(text);
28917 closeClick : function(){
28922 collapseClick : function(){
28923 this[this.collapsed ? "expand" : "collapse"]();
28927 * Collapses the dialog to its minimized state (only the title bar is visible).
28928 * Equivalent to the user clicking the collapse dialog button.
28930 collapse : function(){
28931 if(!this.collapsed){
28932 this.collapsed = true;
28933 this.el.addClass("x-dlg-collapsed");
28934 this.restoreHeight = this.el.getHeight();
28935 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28940 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28941 * clicking the expand dialog button.
28943 expand : function(){
28944 if(this.collapsed){
28945 this.collapsed = false;
28946 this.el.removeClass("x-dlg-collapsed");
28947 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28952 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28953 * @return {Roo.TabPanel} The tabs component
28955 initTabs : function(){
28956 var tabs = this.getTabs();
28957 while(tabs.getTab(0)){
28960 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28962 tabs.addTab(Roo.id(dom), dom.title);
28970 beforeResize : function(){
28971 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28975 onResize : function(){
28976 this.refreshSize();
28977 this.syncBodyHeight();
28978 this.adjustAssets();
28980 this.fireEvent("resize", this, this.size.width, this.size.height);
28984 onKeyDown : function(e){
28985 if(this.isVisible()){
28986 this.fireEvent("keydown", this, e);
28991 * Resizes the dialog.
28992 * @param {Number} width
28993 * @param {Number} height
28994 * @return {Roo.BasicDialog} this
28996 resizeTo : function(width, height){
28997 this.el.setSize(width, height);
28998 this.size = {width: width, height: height};
28999 this.syncBodyHeight();
29000 if(this.fixedcenter){
29003 if(this.isVisible()){
29004 this.constrainXY();
29005 this.adjustAssets();
29007 this.fireEvent("resize", this, width, height);
29013 * Resizes the dialog to fit the specified content size.
29014 * @param {Number} width
29015 * @param {Number} height
29016 * @return {Roo.BasicDialog} this
29018 setContentSize : function(w, h){
29019 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29020 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29021 //if(!this.el.isBorderBox()){
29022 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29023 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29026 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29027 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29029 this.resizeTo(w, h);
29034 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29035 * executed in response to a particular key being pressed while the dialog is active.
29036 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29037 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29038 * @param {Function} fn The function to call
29039 * @param {Object} scope (optional) The scope of the function
29040 * @return {Roo.BasicDialog} this
29042 addKeyListener : function(key, fn, scope){
29043 var keyCode, shift, ctrl, alt;
29044 if(typeof key == "object" && !(key instanceof Array)){
29045 keyCode = key["key"];
29046 shift = key["shift"];
29047 ctrl = key["ctrl"];
29052 var handler = function(dlg, e){
29053 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29054 var k = e.getKey();
29055 if(keyCode instanceof Array){
29056 for(var i = 0, len = keyCode.length; i < len; i++){
29057 if(keyCode[i] == k){
29058 fn.call(scope || window, dlg, k, e);
29064 fn.call(scope || window, dlg, k, e);
29069 this.on("keydown", handler);
29074 * Returns the TabPanel component (creates it if it doesn't exist).
29075 * Note: If you wish to simply check for the existence of tabs without creating them,
29076 * check for a null 'tabs' property.
29077 * @return {Roo.TabPanel} The tabs component
29079 getTabs : function(){
29081 this.el.addClass("x-dlg-auto-tabs");
29082 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29083 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29089 * Adds a button to the footer section of the dialog.
29090 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29091 * object or a valid Roo.DomHelper element config
29092 * @param {Function} handler The function called when the button is clicked
29093 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29094 * @return {Roo.Button} The new button
29096 addButton : function(config, handler, scope){
29097 var dh = Roo.DomHelper;
29099 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29101 if(!this.btnContainer){
29102 var tb = this.footer.createChild({
29104 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29105 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29107 this.btnContainer = tb.firstChild.firstChild.firstChild;
29112 minWidth: this.minButtonWidth,
29115 if(typeof config == "string"){
29116 bconfig.text = config;
29119 bconfig.dhconfig = config;
29121 Roo.apply(bconfig, config);
29125 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29126 bconfig.position = Math.max(0, bconfig.position);
29127 fc = this.btnContainer.childNodes[bconfig.position];
29130 var btn = new Roo.Button(
29132 this.btnContainer.insertBefore(document.createElement("td"),fc)
29133 : this.btnContainer.appendChild(document.createElement("td")),
29134 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29137 this.syncBodyHeight();
29140 * Array of all the buttons that have been added to this dialog via addButton
29145 this.buttons.push(btn);
29150 * Sets the default button to be focused when the dialog is displayed.
29151 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29152 * @return {Roo.BasicDialog} this
29154 setDefaultButton : function(btn){
29155 this.defaultButton = btn;
29160 getHeaderFooterHeight : function(safe){
29163 height += this.header.getHeight();
29166 var fm = this.footer.getMargins();
29167 height += (this.footer.getHeight()+fm.top+fm.bottom);
29169 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29170 height += this.centerBg.getPadding("tb");
29175 syncBodyHeight : function(){
29176 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29177 var height = this.size.height - this.getHeaderFooterHeight(false);
29178 bd.setHeight(height-bd.getMargins("tb"));
29179 var hh = this.header.getHeight();
29180 var h = this.size.height-hh;
29182 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29183 bw.setHeight(h-cb.getPadding("tb"));
29184 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29185 bd.setWidth(bw.getWidth(true));
29187 this.tabs.syncHeight();
29189 this.tabs.el.repaint();
29195 * Restores the previous state of the dialog if Roo.state is configured.
29196 * @return {Roo.BasicDialog} this
29198 restoreState : function(){
29199 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29200 if(box && box.width){
29201 this.xy = [box.x, box.y];
29202 this.resizeTo(box.width, box.height);
29208 beforeShow : function(){
29210 if(this.fixedcenter){
29211 this.xy = this.el.getCenterXY(true);
29214 Roo.get(document.body).addClass("x-body-masked");
29215 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29218 this.constrainXY();
29222 animShow : function(){
29223 var b = Roo.get(this.animateTarget).getBox();
29224 this.proxy.setSize(b.width, b.height);
29225 this.proxy.setLocation(b.x, b.y);
29227 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29228 true, .35, this.showEl.createDelegate(this));
29232 * Shows the dialog.
29233 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29234 * @return {Roo.BasicDialog} this
29236 show : function(animateTarget){
29237 if (this.fireEvent("beforeshow", this) === false){
29240 if(this.syncHeightBeforeShow){
29241 this.syncBodyHeight();
29242 }else if(this.firstShow){
29243 this.firstShow = false;
29244 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29246 this.animateTarget = animateTarget || this.animateTarget;
29247 if(!this.el.isVisible()){
29249 if(this.animateTarget && Roo.get(this.animateTarget)){
29259 showEl : function(){
29261 this.el.setXY(this.xy);
29263 this.adjustAssets(true);
29266 // IE peekaboo bug - fix found by Dave Fenwick
29270 this.fireEvent("show", this);
29274 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29275 * dialog itself will receive focus.
29277 focus : function(){
29278 if(this.defaultButton){
29279 this.defaultButton.focus();
29281 this.focusEl.focus();
29286 constrainXY : function(){
29287 if(this.constraintoviewport !== false){
29288 if(!this.viewSize){
29289 if(this.container){
29290 var s = this.container.getSize();
29291 this.viewSize = [s.width, s.height];
29293 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29296 var s = Roo.get(this.container||document).getScroll();
29298 var x = this.xy[0], y = this.xy[1];
29299 var w = this.size.width, h = this.size.height;
29300 var vw = this.viewSize[0], vh = this.viewSize[1];
29301 // only move it if it needs it
29303 // first validate right/bottom
29304 if(x + w > vw+s.left){
29308 if(y + h > vh+s.top){
29312 // then make sure top/left isn't negative
29324 if(this.isVisible()){
29325 this.el.setLocation(x, y);
29326 this.adjustAssets();
29333 onDrag : function(){
29334 if(!this.proxyDrag){
29335 this.xy = this.el.getXY();
29336 this.adjustAssets();
29341 adjustAssets : function(doShow){
29342 var x = this.xy[0], y = this.xy[1];
29343 var w = this.size.width, h = this.size.height;
29344 if(doShow === true){
29346 this.shadow.show(this.el);
29352 if(this.shadow && this.shadow.isVisible()){
29353 this.shadow.show(this.el);
29355 if(this.shim && this.shim.isVisible()){
29356 this.shim.setBounds(x, y, w, h);
29361 adjustViewport : function(w, h){
29363 w = Roo.lib.Dom.getViewWidth();
29364 h = Roo.lib.Dom.getViewHeight();
29367 this.viewSize = [w, h];
29368 if(this.modal && this.mask.isVisible()){
29369 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29370 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29372 if(this.isVisible()){
29373 this.constrainXY();
29378 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29379 * shadow, proxy, mask, etc.) Also removes all event listeners.
29380 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29382 destroy : function(removeEl){
29383 if(this.isVisible()){
29384 this.animateTarget = null;
29387 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29389 this.tabs.destroy(removeEl);
29402 for(var i = 0, len = this.buttons.length; i < len; i++){
29403 this.buttons[i].destroy();
29406 this.el.removeAllListeners();
29407 if(removeEl === true){
29408 this.el.update("");
29411 Roo.DialogManager.unregister(this);
29415 startMove : function(){
29416 if(this.proxyDrag){
29419 if(this.constraintoviewport !== false){
29420 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29425 endMove : function(){
29426 if(!this.proxyDrag){
29427 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29429 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29432 this.refreshSize();
29433 this.adjustAssets();
29435 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29439 * Brings this dialog to the front of any other visible dialogs
29440 * @return {Roo.BasicDialog} this
29442 toFront : function(){
29443 Roo.DialogManager.bringToFront(this);
29448 * Sends this dialog to the back (under) of any other visible dialogs
29449 * @return {Roo.BasicDialog} this
29451 toBack : function(){
29452 Roo.DialogManager.sendToBack(this);
29457 * Centers this dialog in the viewport
29458 * @return {Roo.BasicDialog} this
29460 center : function(){
29461 var xy = this.el.getCenterXY(true);
29462 this.moveTo(xy[0], xy[1]);
29467 * Moves the dialog's top-left corner to the specified point
29468 * @param {Number} x
29469 * @param {Number} y
29470 * @return {Roo.BasicDialog} this
29472 moveTo : function(x, y){
29474 if(this.isVisible()){
29475 this.el.setXY(this.xy);
29476 this.adjustAssets();
29482 * Aligns the dialog to the specified element
29483 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29484 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29485 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29486 * @return {Roo.BasicDialog} this
29488 alignTo : function(element, position, offsets){
29489 this.xy = this.el.getAlignToXY(element, position, offsets);
29490 if(this.isVisible()){
29491 this.el.setXY(this.xy);
29492 this.adjustAssets();
29498 * Anchors an element to another element and realigns it when the window is resized.
29499 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29500 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29501 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29502 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29503 * is a number, it is used as the buffer delay (defaults to 50ms).
29504 * @return {Roo.BasicDialog} this
29506 anchorTo : function(el, alignment, offsets, monitorScroll){
29507 var action = function(){
29508 this.alignTo(el, alignment, offsets);
29510 Roo.EventManager.onWindowResize(action, this);
29511 var tm = typeof monitorScroll;
29512 if(tm != 'undefined'){
29513 Roo.EventManager.on(window, 'scroll', action, this,
29514 {buffer: tm == 'number' ? monitorScroll : 50});
29521 * Returns true if the dialog is visible
29522 * @return {Boolean}
29524 isVisible : function(){
29525 return this.el.isVisible();
29529 animHide : function(callback){
29530 var b = Roo.get(this.animateTarget).getBox();
29532 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29534 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29535 this.hideEl.createDelegate(this, [callback]));
29539 * Hides the dialog.
29540 * @param {Function} callback (optional) Function to call when the dialog is hidden
29541 * @return {Roo.BasicDialog} this
29543 hide : function(callback){
29544 if (this.fireEvent("beforehide", this) === false){
29548 this.shadow.hide();
29553 // sometimes animateTarget seems to get set.. causing problems...
29554 // this just double checks..
29555 if(this.animateTarget && Roo.get(this.animateTarget)) {
29556 this.animHide(callback);
29559 this.hideEl(callback);
29565 hideEl : function(callback){
29569 Roo.get(document.body).removeClass("x-body-masked");
29571 this.fireEvent("hide", this);
29572 if(typeof callback == "function"){
29578 hideAction : function(){
29579 this.setLeft("-10000px");
29580 this.setTop("-10000px");
29581 this.setStyle("visibility", "hidden");
29585 refreshSize : function(){
29586 this.size = this.el.getSize();
29587 this.xy = this.el.getXY();
29588 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29592 // z-index is managed by the DialogManager and may be overwritten at any time
29593 setZIndex : function(index){
29595 this.mask.setStyle("z-index", index);
29598 this.shim.setStyle("z-index", ++index);
29601 this.shadow.setZIndex(++index);
29603 this.el.setStyle("z-index", ++index);
29605 this.proxy.setStyle("z-index", ++index);
29608 this.resizer.proxy.setStyle("z-index", ++index);
29611 this.lastZIndex = index;
29615 * Returns the element for this dialog
29616 * @return {Roo.Element} The underlying dialog Element
29618 getEl : function(){
29624 * @class Roo.DialogManager
29625 * Provides global access to BasicDialogs that have been created and
29626 * support for z-indexing (layering) multiple open dialogs.
29628 Roo.DialogManager = function(){
29630 var accessList = [];
29634 var sortDialogs = function(d1, d2){
29635 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29639 var orderDialogs = function(){
29640 accessList.sort(sortDialogs);
29641 var seed = Roo.DialogManager.zseed;
29642 for(var i = 0, len = accessList.length; i < len; i++){
29643 var dlg = accessList[i];
29645 dlg.setZIndex(seed + (i*10));
29652 * The starting z-index for BasicDialogs (defaults to 9000)
29653 * @type Number The z-index value
29658 register : function(dlg){
29659 list[dlg.id] = dlg;
29660 accessList.push(dlg);
29664 unregister : function(dlg){
29665 delete list[dlg.id];
29668 if(!accessList.indexOf){
29669 for( i = 0, len = accessList.length; i < len; i++){
29670 if(accessList[i] == dlg){
29671 accessList.splice(i, 1);
29676 i = accessList.indexOf(dlg);
29678 accessList.splice(i, 1);
29684 * Gets a registered dialog by id
29685 * @param {String/Object} id The id of the dialog or a dialog
29686 * @return {Roo.BasicDialog} this
29688 get : function(id){
29689 return typeof id == "object" ? id : list[id];
29693 * Brings the specified dialog to the front
29694 * @param {String/Object} dlg The id of the dialog or a dialog
29695 * @return {Roo.BasicDialog} this
29697 bringToFront : function(dlg){
29698 dlg = this.get(dlg);
29701 dlg._lastAccess = new Date().getTime();
29708 * Sends the specified dialog to the back
29709 * @param {String/Object} dlg The id of the dialog or a dialog
29710 * @return {Roo.BasicDialog} this
29712 sendToBack : function(dlg){
29713 dlg = this.get(dlg);
29714 dlg._lastAccess = -(new Date().getTime());
29720 * Hides all dialogs
29722 hideAll : function(){
29723 for(var id in list){
29724 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29733 * @class Roo.LayoutDialog
29734 * @extends Roo.BasicDialog
29735 * Dialog which provides adjustments for working with a layout in a Dialog.
29736 * Add your necessary layout config options to the dialog's config.<br>
29737 * Example usage (including a nested layout):
29740 dialog = new Roo.LayoutDialog("download-dlg", {
29749 // layout config merges with the dialog config
29751 tabPosition: "top",
29752 alwaysShowTabs: true
29755 dialog.addKeyListener(27, dialog.hide, dialog);
29756 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29757 dialog.addButton("Build It!", this.getDownload, this);
29759 // we can even add nested layouts
29760 var innerLayout = new Roo.BorderLayout("dl-inner", {
29770 innerLayout.beginUpdate();
29771 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29772 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29773 innerLayout.endUpdate(true);
29775 var layout = dialog.getLayout();
29776 layout.beginUpdate();
29777 layout.add("center", new Roo.ContentPanel("standard-panel",
29778 {title: "Download the Source", fitToFrame:true}));
29779 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29780 {title: "Build your own roo.js"}));
29781 layout.getRegion("center").showPanel(sp);
29782 layout.endUpdate();
29786 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29787 * @param {Object} config configuration options
29789 Roo.LayoutDialog = function(el, cfg){
29792 if (typeof(cfg) == 'undefined') {
29793 config = Roo.apply({}, el);
29794 // not sure why we use documentElement here.. - it should always be body.
29795 // IE7 borks horribly if we use documentElement.
29796 // webkit also does not like documentElement - it creates a body element...
29797 el = Roo.get( document.body || document.documentElement ).createChild();
29798 //config.autoCreate = true;
29802 config.autoTabs = false;
29803 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29804 this.body.setStyle({overflow:"hidden", position:"relative"});
29805 this.layout = new Roo.BorderLayout(this.body.dom, config);
29806 this.layout.monitorWindowResize = false;
29807 this.el.addClass("x-dlg-auto-layout");
29808 // fix case when center region overwrites center function
29809 this.center = Roo.BasicDialog.prototype.center;
29810 this.on("show", this.layout.layout, this.layout, true);
29811 if (config.items) {
29812 var xitems = config.items;
29813 delete config.items;
29814 Roo.each(xitems, this.addxtype, this);
29819 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29821 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29824 endUpdate : function(){
29825 this.layout.endUpdate();
29829 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29832 beginUpdate : function(){
29833 this.layout.beginUpdate();
29837 * Get the BorderLayout for this dialog
29838 * @return {Roo.BorderLayout}
29840 getLayout : function(){
29841 return this.layout;
29844 showEl : function(){
29845 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29847 this.layout.layout();
29852 // Use the syncHeightBeforeShow config option to control this automatically
29853 syncBodyHeight : function(){
29854 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29855 if(this.layout){this.layout.layout();}
29859 * Add an xtype element (actually adds to the layout.)
29860 * @return {Object} xdata xtype object data.
29863 addxtype : function(c) {
29864 return this.layout.addxtype(c);
29868 * Ext JS Library 1.1.1
29869 * Copyright(c) 2006-2007, Ext JS, LLC.
29871 * Originally Released Under LGPL - original licence link has changed is not relivant.
29874 * <script type="text/javascript">
29878 * @class Roo.MessageBox
29879 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29883 Roo.Msg.alert('Status', 'Changes saved successfully.');
29885 // Prompt for user data:
29886 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29888 // process text value...
29892 // Show a dialog using config options:
29894 title:'Save Changes?',
29895 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29896 buttons: Roo.Msg.YESNOCANCEL,
29903 Roo.MessageBox = function(){
29904 var dlg, opt, mask, waitTimer;
29905 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29906 var buttons, activeTextEl, bwidth;
29909 var handleButton = function(button){
29911 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29915 var handleHide = function(){
29916 if(opt && opt.cls){
29917 dlg.el.removeClass(opt.cls);
29920 Roo.TaskMgr.stop(waitTimer);
29926 var updateButtons = function(b){
29929 buttons["ok"].hide();
29930 buttons["cancel"].hide();
29931 buttons["yes"].hide();
29932 buttons["no"].hide();
29933 dlg.footer.dom.style.display = 'none';
29936 dlg.footer.dom.style.display = '';
29937 for(var k in buttons){
29938 if(typeof buttons[k] != "function"){
29941 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29942 width += buttons[k].el.getWidth()+15;
29952 var handleEsc = function(d, k, e){
29953 if(opt && opt.closable !== false){
29963 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29964 * @return {Roo.BasicDialog} The BasicDialog element
29966 getDialog : function(){
29968 dlg = new Roo.BasicDialog("x-msg-box", {
29973 constraintoviewport:false,
29975 collapsible : false,
29978 width:400, height:100,
29979 buttonAlign:"center",
29980 closeClick : function(){
29981 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29982 handleButton("no");
29984 handleButton("cancel");
29988 dlg.on("hide", handleHide);
29990 dlg.addKeyListener(27, handleEsc);
29992 var bt = this.buttonText;
29993 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29994 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29995 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29996 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29997 bodyEl = dlg.body.createChild({
29999 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>'
30001 msgEl = bodyEl.dom.firstChild;
30002 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
30003 textboxEl.enableDisplayMode();
30004 textboxEl.addKeyListener([10,13], function(){
30005 if(dlg.isVisible() && opt && opt.buttons){
30006 if(opt.buttons.ok){
30007 handleButton("ok");
30008 }else if(opt.buttons.yes){
30009 handleButton("yes");
30013 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
30014 textareaEl.enableDisplayMode();
30015 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
30016 progressEl.enableDisplayMode();
30017 var pf = progressEl.dom.firstChild;
30019 pp = Roo.get(pf.firstChild);
30020 pp.setHeight(pf.offsetHeight);
30028 * Updates the message box body text
30029 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30030 * the XHTML-compliant non-breaking space character '&#160;')
30031 * @return {Roo.MessageBox} This message box
30033 updateText : function(text){
30034 if(!dlg.isVisible() && !opt.width){
30035 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30037 msgEl.innerHTML = text || ' ';
30038 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
30039 Math.max(opt.minWidth || this.minWidth, bwidth));
30041 activeTextEl.setWidth(w);
30043 if(dlg.isVisible()){
30044 dlg.fixedcenter = false;
30046 dlg.setContentSize(w, bodyEl.getHeight());
30047 if(dlg.isVisible()){
30048 dlg.fixedcenter = true;
30054 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30055 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30056 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30057 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30058 * @return {Roo.MessageBox} This message box
30060 updateProgress : function(value, text){
30062 this.updateText(text);
30064 if (pp) { // weird bug on my firefox - for some reason this is not defined
30065 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30071 * Returns true if the message box is currently displayed
30072 * @return {Boolean} True if the message box is visible, else false
30074 isVisible : function(){
30075 return dlg && dlg.isVisible();
30079 * Hides the message box if it is displayed
30082 if(this.isVisible()){
30088 * Displays a new message box, or reinitializes an existing message box, based on the config options
30089 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30090 * The following config object properties are supported:
30092 Property Type Description
30093 ---------- --------------- ------------------------------------------------------------------------------------
30094 animEl String/Element An id or Element from which the message box should animate as it opens and
30095 closes (defaults to undefined)
30096 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30097 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30098 closable Boolean False to hide the top-right close button (defaults to true). Note that
30099 progress and wait dialogs will ignore this property and always hide the
30100 close button as they can only be closed programmatically.
30101 cls String A custom CSS class to apply to the message box element
30102 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30103 displayed (defaults to 75)
30104 fn Function A callback function to execute after closing the dialog. The arguments to the
30105 function will be btn (the name of the button that was clicked, if applicable,
30106 e.g. "ok"), and text (the value of the active text field, if applicable).
30107 Progress and wait dialogs will ignore this option since they do not respond to
30108 user actions and can only be closed programmatically, so any required function
30109 should be called by the same code after it closes the dialog.
30110 icon String A CSS class that provides a background image to be used as an icon for
30111 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30112 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30113 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30114 modal Boolean False to allow user interaction with the page while the message box is
30115 displayed (defaults to true)
30116 msg String A string that will replace the existing message box body text (defaults
30117 to the XHTML-compliant non-breaking space character ' ')
30118 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30119 progress Boolean True to display a progress bar (defaults to false)
30120 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30121 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30122 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30123 title String The title text
30124 value String The string value to set into the active textbox element if displayed
30125 wait Boolean True to display a progress bar (defaults to false)
30126 width Number The width of the dialog in pixels
30133 msg: 'Please enter your address:',
30135 buttons: Roo.MessageBox.OKCANCEL,
30138 animEl: 'addAddressBtn'
30141 * @param {Object} config Configuration options
30142 * @return {Roo.MessageBox} This message box
30144 show : function(options){
30145 if(this.isVisible()){
30148 var d = this.getDialog();
30150 d.setTitle(opt.title || " ");
30151 d.close.setDisplayed(opt.closable !== false);
30152 activeTextEl = textboxEl;
30153 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30158 textareaEl.setHeight(typeof opt.multiline == "number" ?
30159 opt.multiline : this.defaultTextHeight);
30160 activeTextEl = textareaEl;
30169 progressEl.setDisplayed(opt.progress === true);
30170 this.updateProgress(0);
30171 activeTextEl.dom.value = opt.value || "";
30173 dlg.setDefaultButton(activeTextEl);
30175 var bs = opt.buttons;
30178 db = buttons["ok"];
30179 }else if(bs && bs.yes){
30180 db = buttons["yes"];
30182 dlg.setDefaultButton(db);
30184 bwidth = updateButtons(opt.buttons);
30185 this.updateText(opt.msg);
30187 d.el.addClass(opt.cls);
30189 d.proxyDrag = opt.proxyDrag === true;
30190 d.modal = opt.modal !== false;
30191 d.mask = opt.modal !== false ? mask : false;
30192 if(!d.isVisible()){
30193 // force it to the end of the z-index stack so it gets a cursor in FF
30194 document.body.appendChild(dlg.el.dom);
30195 d.animateTarget = null;
30196 d.show(options.animEl);
30202 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30203 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30204 * and closing the message box when the process is complete.
30205 * @param {String} title The title bar text
30206 * @param {String} msg The message box body text
30207 * @return {Roo.MessageBox} This message box
30209 progress : function(title, msg){
30216 minWidth: this.minProgressWidth,
30223 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30224 * If a callback function is passed it will be called after the user clicks the button, and the
30225 * id of the button that was clicked will be passed as the only parameter to the callback
30226 * (could also be the top-right close button).
30227 * @param {String} title The title bar text
30228 * @param {String} msg The message box body text
30229 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30230 * @param {Object} scope (optional) The scope of the callback function
30231 * @return {Roo.MessageBox} This message box
30233 alert : function(title, msg, fn, scope){
30246 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30247 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30248 * You are responsible for closing the message box when the process is complete.
30249 * @param {String} msg The message box body text
30250 * @param {String} title (optional) The title bar text
30251 * @return {Roo.MessageBox} This message box
30253 wait : function(msg, title){
30264 waitTimer = Roo.TaskMgr.start({
30266 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30274 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30275 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30276 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30277 * @param {String} title The title bar text
30278 * @param {String} msg The message box body text
30279 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30280 * @param {Object} scope (optional) The scope of the callback function
30281 * @return {Roo.MessageBox} This message box
30283 confirm : function(title, msg, fn, scope){
30287 buttons: this.YESNO,
30296 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30297 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30298 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30299 * (could also be the top-right close button) and the text that was entered will be passed as the two
30300 * parameters to the callback.
30301 * @param {String} title The title bar text
30302 * @param {String} msg The message box body text
30303 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30304 * @param {Object} scope (optional) The scope of the callback function
30305 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30306 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30307 * @return {Roo.MessageBox} This message box
30309 prompt : function(title, msg, fn, scope, multiline){
30313 buttons: this.OKCANCEL,
30318 multiline: multiline,
30325 * Button config that displays a single OK button
30330 * Button config that displays Yes and No buttons
30333 YESNO : {yes:true, no:true},
30335 * Button config that displays OK and Cancel buttons
30338 OKCANCEL : {ok:true, cancel:true},
30340 * Button config that displays Yes, No and Cancel buttons
30343 YESNOCANCEL : {yes:true, no:true, cancel:true},
30346 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30349 defaultTextHeight : 75,
30351 * The maximum width in pixels of the message box (defaults to 600)
30356 * The minimum width in pixels of the message box (defaults to 100)
30361 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30362 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30365 minProgressWidth : 250,
30367 * An object containing the default button text strings that can be overriden for localized language support.
30368 * Supported properties are: ok, cancel, yes and no.
30369 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30382 * Shorthand for {@link Roo.MessageBox}
30384 Roo.Msg = Roo.MessageBox;/*
30386 * Ext JS Library 1.1.1
30387 * Copyright(c) 2006-2007, Ext JS, LLC.
30389 * Originally Released Under LGPL - original licence link has changed is not relivant.
30392 * <script type="text/javascript">
30395 * @class Roo.QuickTips
30396 * Provides attractive and customizable tooltips for any element.
30399 Roo.QuickTips = function(){
30400 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30401 var ce, bd, xy, dd;
30402 var visible = false, disabled = true, inited = false;
30403 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30405 var onOver = function(e){
30409 var t = e.getTarget();
30410 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30413 if(ce && t == ce.el){
30414 clearTimeout(hideProc);
30417 if(t && tagEls[t.id]){
30418 tagEls[t.id].el = t;
30419 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30422 var ttp, et = Roo.fly(t);
30423 var ns = cfg.namespace;
30424 if(tm.interceptTitles && t.title){
30427 t.removeAttribute("title");
30428 e.preventDefault();
30430 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30433 showProc = show.defer(tm.showDelay, tm, [{
30436 width: et.getAttributeNS(ns, cfg.width),
30437 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30438 title: et.getAttributeNS(ns, cfg.title),
30439 cls: et.getAttributeNS(ns, cfg.cls)
30444 var onOut = function(e){
30445 clearTimeout(showProc);
30446 var t = e.getTarget();
30447 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30448 hideProc = setTimeout(hide, tm.hideDelay);
30452 var onMove = function(e){
30458 if(tm.trackMouse && ce){
30463 var onDown = function(e){
30464 clearTimeout(showProc);
30465 clearTimeout(hideProc);
30467 if(tm.hideOnClick){
30470 tm.enable.defer(100, tm);
30475 var getPad = function(){
30476 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30479 var show = function(o){
30483 clearTimeout(dismissProc);
30485 if(removeCls){ // in case manually hidden
30486 el.removeClass(removeCls);
30490 el.addClass(ce.cls);
30491 removeCls = ce.cls;
30494 tipTitle.update(ce.title);
30497 tipTitle.update('');
30500 el.dom.style.width = tm.maxWidth+'px';
30501 //tipBody.dom.style.width = '';
30502 tipBodyText.update(o.text);
30503 var p = getPad(), w = ce.width;
30505 var td = tipBodyText.dom;
30506 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30507 if(aw > tm.maxWidth){
30509 }else if(aw < tm.minWidth){
30515 //tipBody.setWidth(w);
30516 el.setWidth(parseInt(w, 10) + p);
30517 if(ce.autoHide === false){
30518 close.setDisplayed(true);
30523 close.setDisplayed(false);
30529 el.avoidY = xy[1]-18;
30534 el.setStyle("visibility", "visible");
30535 el.fadeIn({callback: afterShow});
30541 var afterShow = function(){
30545 if(tm.autoDismiss && ce.autoHide !== false){
30546 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30551 var hide = function(noanim){
30552 clearTimeout(dismissProc);
30553 clearTimeout(hideProc);
30555 if(el.isVisible()){
30557 if(noanim !== true && tm.animate){
30558 el.fadeOut({callback: afterHide});
30565 var afterHide = function(){
30568 el.removeClass(removeCls);
30575 * @cfg {Number} minWidth
30576 * The minimum width of the quick tip (defaults to 40)
30580 * @cfg {Number} maxWidth
30581 * The maximum width of the quick tip (defaults to 300)
30585 * @cfg {Boolean} interceptTitles
30586 * True to automatically use the element's DOM title value if available (defaults to false)
30588 interceptTitles : false,
30590 * @cfg {Boolean} trackMouse
30591 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30593 trackMouse : false,
30595 * @cfg {Boolean} hideOnClick
30596 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30598 hideOnClick : true,
30600 * @cfg {Number} showDelay
30601 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30605 * @cfg {Number} hideDelay
30606 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30610 * @cfg {Boolean} autoHide
30611 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30612 * Used in conjunction with hideDelay.
30617 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30618 * (defaults to true). Used in conjunction with autoDismissDelay.
30620 autoDismiss : true,
30623 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30625 autoDismissDelay : 5000,
30627 * @cfg {Boolean} animate
30628 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30633 * @cfg {String} title
30634 * Title text to display (defaults to ''). This can be any valid HTML markup.
30638 * @cfg {String} text
30639 * Body text to display (defaults to ''). This can be any valid HTML markup.
30643 * @cfg {String} cls
30644 * A CSS class to apply to the base quick tip element (defaults to '').
30648 * @cfg {Number} width
30649 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30650 * minWidth or maxWidth.
30655 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30656 * or display QuickTips in a page.
30659 tm = Roo.QuickTips;
30660 cfg = tm.tagConfig;
30662 if(!Roo.isReady){ // allow calling of init() before onReady
30663 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30666 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30667 el.fxDefaults = {stopFx: true};
30668 // maximum custom styling
30669 //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>');
30670 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>');
30671 tipTitle = el.child('h3');
30672 tipTitle.enableDisplayMode("block");
30673 tipBody = el.child('div.x-tip-bd');
30674 tipBodyText = el.child('div.x-tip-bd-inner');
30675 //bdLeft = el.child('div.x-tip-bd-left');
30676 //bdRight = el.child('div.x-tip-bd-right');
30677 close = el.child('div.x-tip-close');
30678 close.enableDisplayMode("block");
30679 close.on("click", hide);
30680 var d = Roo.get(document);
30681 d.on("mousedown", onDown);
30682 d.on("mouseover", onOver);
30683 d.on("mouseout", onOut);
30684 d.on("mousemove", onMove);
30685 esc = d.addKeyListener(27, hide);
30688 dd = el.initDD("default", null, {
30689 onDrag : function(){
30693 dd.setHandleElId(tipTitle.id);
30702 * Configures a new quick tip instance and assigns it to a target element. The following config options
30705 Property Type Description
30706 ---------- --------------------- ------------------------------------------------------------------------
30707 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30709 * @param {Object} config The config object
30711 register : function(config){
30712 var cs = config instanceof Array ? config : arguments;
30713 for(var i = 0, len = cs.length; i < len; i++) {
30715 var target = c.target;
30717 if(target instanceof Array){
30718 for(var j = 0, jlen = target.length; j < jlen; j++){
30719 tagEls[target[j]] = c;
30722 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30729 * Removes this quick tip from its element and destroys it.
30730 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30732 unregister : function(el){
30733 delete tagEls[Roo.id(el)];
30737 * Enable this quick tip.
30739 enable : function(){
30740 if(inited && disabled){
30742 if(locks.length < 1){
30749 * Disable this quick tip.
30751 disable : function(){
30753 clearTimeout(showProc);
30754 clearTimeout(hideProc);
30755 clearTimeout(dismissProc);
30763 * Returns true if the quick tip is enabled, else false.
30765 isEnabled : function(){
30772 attribute : "qtip",
30782 // backwards compat
30783 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30785 * Ext JS Library 1.1.1
30786 * Copyright(c) 2006-2007, Ext JS, LLC.
30788 * Originally Released Under LGPL - original licence link has changed is not relivant.
30791 * <script type="text/javascript">
30796 * @class Roo.tree.TreePanel
30797 * @extends Roo.data.Tree
30799 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30800 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30801 * @cfg {Boolean} enableDD true to enable drag and drop
30802 * @cfg {Boolean} enableDrag true to enable just drag
30803 * @cfg {Boolean} enableDrop true to enable just drop
30804 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30805 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30806 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30807 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30808 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30809 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30810 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30811 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30812 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30813 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30814 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30815 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30816 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30817 * @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>
30818 * @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>
30821 * @param {String/HTMLElement/Element} el The container element
30822 * @param {Object} config
30824 Roo.tree.TreePanel = function(el, config){
30826 var loader = false;
30828 root = config.root;
30829 delete config.root;
30831 if (config.loader) {
30832 loader = config.loader;
30833 delete config.loader;
30836 Roo.apply(this, config);
30837 Roo.tree.TreePanel.superclass.constructor.call(this);
30838 this.el = Roo.get(el);
30839 this.el.addClass('x-tree');
30840 //console.log(root);
30842 this.setRootNode( Roo.factory(root, Roo.tree));
30845 this.loader = Roo.factory(loader, Roo.tree);
30848 * Read-only. The id of the container element becomes this TreePanel's id.
30850 this.id = this.el.id;
30853 * @event beforeload
30854 * Fires before a node is loaded, return false to cancel
30855 * @param {Node} node The node being loaded
30857 "beforeload" : true,
30860 * Fires when a node is loaded
30861 * @param {Node} node The node that was loaded
30865 * @event textchange
30866 * Fires when the text for a node is changed
30867 * @param {Node} node The node
30868 * @param {String} text The new text
30869 * @param {String} oldText The old text
30871 "textchange" : true,
30873 * @event beforeexpand
30874 * Fires before a node is expanded, return false to cancel.
30875 * @param {Node} node The node
30876 * @param {Boolean} deep
30877 * @param {Boolean} anim
30879 "beforeexpand" : true,
30881 * @event beforecollapse
30882 * Fires before a node is collapsed, return false to cancel.
30883 * @param {Node} node The node
30884 * @param {Boolean} deep
30885 * @param {Boolean} anim
30887 "beforecollapse" : true,
30890 * Fires when a node is expanded
30891 * @param {Node} node The node
30895 * @event disabledchange
30896 * Fires when the disabled status of a node changes
30897 * @param {Node} node The node
30898 * @param {Boolean} disabled
30900 "disabledchange" : true,
30903 * Fires when a node is collapsed
30904 * @param {Node} node The node
30908 * @event beforeclick
30909 * Fires before click processing on a node. Return false to cancel the default action.
30910 * @param {Node} node The node
30911 * @param {Roo.EventObject} e The event object
30913 "beforeclick":true,
30915 * @event checkchange
30916 * Fires when a node with a checkbox's checked property changes
30917 * @param {Node} this This node
30918 * @param {Boolean} checked
30920 "checkchange":true,
30923 * Fires when a node is clicked
30924 * @param {Node} node The node
30925 * @param {Roo.EventObject} e The event object
30930 * Fires when a node is double clicked
30931 * @param {Node} node The node
30932 * @param {Roo.EventObject} e The event object
30936 * @event contextmenu
30937 * Fires when a node is right clicked
30938 * @param {Node} node The node
30939 * @param {Roo.EventObject} e The event object
30941 "contextmenu":true,
30943 * @event beforechildrenrendered
30944 * Fires right before the child nodes for a node are rendered
30945 * @param {Node} node The node
30947 "beforechildrenrendered":true,
30950 * Fires when a node starts being dragged
30951 * @param {Roo.tree.TreePanel} this
30952 * @param {Roo.tree.TreeNode} node
30953 * @param {event} e The raw browser event
30955 "startdrag" : true,
30958 * Fires when a drag operation is complete
30959 * @param {Roo.tree.TreePanel} this
30960 * @param {Roo.tree.TreeNode} node
30961 * @param {event} e The raw browser event
30966 * Fires when a dragged node is dropped on a valid DD target
30967 * @param {Roo.tree.TreePanel} this
30968 * @param {Roo.tree.TreeNode} node
30969 * @param {DD} dd The dd it was dropped on
30970 * @param {event} e The raw browser event
30974 * @event beforenodedrop
30975 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30976 * passed to handlers has the following properties:<br />
30977 * <ul style="padding:5px;padding-left:16px;">
30978 * <li>tree - The TreePanel</li>
30979 * <li>target - The node being targeted for the drop</li>
30980 * <li>data - The drag data from the drag source</li>
30981 * <li>point - The point of the drop - append, above or below</li>
30982 * <li>source - The drag source</li>
30983 * <li>rawEvent - Raw mouse event</li>
30984 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30985 * to be inserted by setting them on this object.</li>
30986 * <li>cancel - Set this to true to cancel the drop.</li>
30988 * @param {Object} dropEvent
30990 "beforenodedrop" : true,
30993 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30994 * passed to handlers has the following properties:<br />
30995 * <ul style="padding:5px;padding-left:16px;">
30996 * <li>tree - The TreePanel</li>
30997 * <li>target - The node being targeted for the drop</li>
30998 * <li>data - The drag data from the drag source</li>
30999 * <li>point - The point of the drop - append, above or below</li>
31000 * <li>source - The drag source</li>
31001 * <li>rawEvent - Raw mouse event</li>
31002 * <li>dropNode - Dropped node(s).</li>
31004 * @param {Object} dropEvent
31008 * @event nodedragover
31009 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31010 * passed to handlers has the following properties:<br />
31011 * <ul style="padding:5px;padding-left:16px;">
31012 * <li>tree - The TreePanel</li>
31013 * <li>target - The node being targeted for the drop</li>
31014 * <li>data - The drag data from the drag source</li>
31015 * <li>point - The point of the drop - append, above or below</li>
31016 * <li>source - The drag source</li>
31017 * <li>rawEvent - Raw mouse event</li>
31018 * <li>dropNode - Drop node(s) provided by the source.</li>
31019 * <li>cancel - Set this to true to signal drop not allowed.</li>
31021 * @param {Object} dragOverEvent
31023 "nodedragover" : true
31026 if(this.singleExpand){
31027 this.on("beforeexpand", this.restrictExpand, this);
31030 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31031 rootVisible : true,
31032 animate: Roo.enableFx,
31035 hlDrop : Roo.enableFx,
31039 rendererTip: false,
31041 restrictExpand : function(node){
31042 var p = node.parentNode;
31044 if(p.expandedChild && p.expandedChild.parentNode == p){
31045 p.expandedChild.collapse();
31047 p.expandedChild = node;
31051 // private override
31052 setRootNode : function(node){
31053 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31054 if(!this.rootVisible){
31055 node.ui = new Roo.tree.RootTreeNodeUI(node);
31061 * Returns the container element for this TreePanel
31063 getEl : function(){
31068 * Returns the default TreeLoader for this TreePanel
31070 getLoader : function(){
31071 return this.loader;
31077 expandAll : function(){
31078 this.root.expand(true);
31082 * Collapse all nodes
31084 collapseAll : function(){
31085 this.root.collapse(true);
31089 * Returns the selection model used by this TreePanel
31091 getSelectionModel : function(){
31092 if(!this.selModel){
31093 this.selModel = new Roo.tree.DefaultSelectionModel();
31095 return this.selModel;
31099 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31100 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31101 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31104 getChecked : function(a, startNode){
31105 startNode = startNode || this.root;
31107 var f = function(){
31108 if(this.attributes.checked){
31109 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31112 startNode.cascade(f);
31117 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31118 * @param {String} path
31119 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31120 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31121 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31123 expandPath : function(path, attr, callback){
31124 attr = attr || "id";
31125 var keys = path.split(this.pathSeparator);
31126 var curNode = this.root;
31127 if(curNode.attributes[attr] != keys[1]){ // invalid root
31129 callback(false, null);
31134 var f = function(){
31135 if(++index == keys.length){
31137 callback(true, curNode);
31141 var c = curNode.findChild(attr, keys[index]);
31144 callback(false, curNode);
31149 c.expand(false, false, f);
31151 curNode.expand(false, false, f);
31155 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31156 * @param {String} path
31157 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31158 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31159 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31161 selectPath : function(path, attr, callback){
31162 attr = attr || "id";
31163 var keys = path.split(this.pathSeparator);
31164 var v = keys.pop();
31165 if(keys.length > 0){
31166 var f = function(success, node){
31167 if(success && node){
31168 var n = node.findChild(attr, v);
31174 }else if(callback){
31175 callback(false, n);
31179 callback(false, n);
31183 this.expandPath(keys.join(this.pathSeparator), attr, f);
31185 this.root.select();
31187 callback(true, this.root);
31192 getTreeEl : function(){
31197 * Trigger rendering of this TreePanel
31199 render : function(){
31200 if (this.innerCt) {
31201 return this; // stop it rendering more than once!!
31204 this.innerCt = this.el.createChild({tag:"ul",
31205 cls:"x-tree-root-ct " +
31206 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31208 if(this.containerScroll){
31209 Roo.dd.ScrollManager.register(this.el);
31211 if((this.enableDD || this.enableDrop) && !this.dropZone){
31213 * The dropZone used by this tree if drop is enabled
31214 * @type Roo.tree.TreeDropZone
31216 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31217 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31220 if((this.enableDD || this.enableDrag) && !this.dragZone){
31222 * The dragZone used by this tree if drag is enabled
31223 * @type Roo.tree.TreeDragZone
31225 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31226 ddGroup: this.ddGroup || "TreeDD",
31227 scroll: this.ddScroll
31230 this.getSelectionModel().init(this);
31232 console.log("ROOT not set in tree");
31235 this.root.render();
31236 if(!this.rootVisible){
31237 this.root.renderChildren();
31243 * Ext JS Library 1.1.1
31244 * Copyright(c) 2006-2007, Ext JS, LLC.
31246 * Originally Released Under LGPL - original licence link has changed is not relivant.
31249 * <script type="text/javascript">
31254 * @class Roo.tree.DefaultSelectionModel
31255 * @extends Roo.util.Observable
31256 * The default single selection for a TreePanel.
31258 Roo.tree.DefaultSelectionModel = function(){
31259 this.selNode = null;
31263 * @event selectionchange
31264 * Fires when the selected node changes
31265 * @param {DefaultSelectionModel} this
31266 * @param {TreeNode} node the new selection
31268 "selectionchange" : true,
31271 * @event beforeselect
31272 * Fires before the selected node changes, return false to cancel the change
31273 * @param {DefaultSelectionModel} this
31274 * @param {TreeNode} node the new selection
31275 * @param {TreeNode} node the old selection
31277 "beforeselect" : true
31281 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31282 init : function(tree){
31284 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31285 tree.on("click", this.onNodeClick, this);
31288 onNodeClick : function(node, e){
31289 if (e.ctrlKey && this.selNode == node) {
31290 this.unselect(node);
31298 * @param {TreeNode} node The node to select
31299 * @return {TreeNode} The selected node
31301 select : function(node){
31302 var last = this.selNode;
31303 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31305 last.ui.onSelectedChange(false);
31307 this.selNode = node;
31308 node.ui.onSelectedChange(true);
31309 this.fireEvent("selectionchange", this, node, last);
31316 * @param {TreeNode} node The node to unselect
31318 unselect : function(node){
31319 if(this.selNode == node){
31320 this.clearSelections();
31325 * Clear all selections
31327 clearSelections : function(){
31328 var n = this.selNode;
31330 n.ui.onSelectedChange(false);
31331 this.selNode = null;
31332 this.fireEvent("selectionchange", this, null);
31338 * Get the selected node
31339 * @return {TreeNode} The selected node
31341 getSelectedNode : function(){
31342 return this.selNode;
31346 * Returns true if the node is selected
31347 * @param {TreeNode} node The node to check
31348 * @return {Boolean}
31350 isSelected : function(node){
31351 return this.selNode == node;
31355 * Selects the node above the selected node in the tree, intelligently walking the nodes
31356 * @return TreeNode The new selection
31358 selectPrevious : function(){
31359 var s = this.selNode || this.lastSelNode;
31363 var ps = s.previousSibling;
31365 if(!ps.isExpanded() || ps.childNodes.length < 1){
31366 return this.select(ps);
31368 var lc = ps.lastChild;
31369 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31372 return this.select(lc);
31374 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31375 return this.select(s.parentNode);
31381 * Selects the node above the selected node in the tree, intelligently walking the nodes
31382 * @return TreeNode The new selection
31384 selectNext : function(){
31385 var s = this.selNode || this.lastSelNode;
31389 if(s.firstChild && s.isExpanded()){
31390 return this.select(s.firstChild);
31391 }else if(s.nextSibling){
31392 return this.select(s.nextSibling);
31393 }else if(s.parentNode){
31395 s.parentNode.bubble(function(){
31396 if(this.nextSibling){
31397 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31406 onKeyDown : function(e){
31407 var s = this.selNode || this.lastSelNode;
31408 // undesirable, but required
31413 var k = e.getKey();
31421 this.selectPrevious();
31424 e.preventDefault();
31425 if(s.hasChildNodes()){
31426 if(!s.isExpanded()){
31428 }else if(s.firstChild){
31429 this.select(s.firstChild, e);
31434 e.preventDefault();
31435 if(s.hasChildNodes() && s.isExpanded()){
31437 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31438 this.select(s.parentNode, e);
31446 * @class Roo.tree.MultiSelectionModel
31447 * @extends Roo.util.Observable
31448 * Multi selection for a TreePanel.
31450 Roo.tree.MultiSelectionModel = function(){
31451 this.selNodes = [];
31455 * @event selectionchange
31456 * Fires when the selected nodes change
31457 * @param {MultiSelectionModel} this
31458 * @param {Array} nodes Array of the selected nodes
31460 "selectionchange" : true
31464 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31465 init : function(tree){
31467 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31468 tree.on("click", this.onNodeClick, this);
31471 onNodeClick : function(node, e){
31472 this.select(node, e, e.ctrlKey);
31477 * @param {TreeNode} node The node to select
31478 * @param {EventObject} e (optional) An event associated with the selection
31479 * @param {Boolean} keepExisting True to retain existing selections
31480 * @return {TreeNode} The selected node
31482 select : function(node, e, keepExisting){
31483 if(keepExisting !== true){
31484 this.clearSelections(true);
31486 if(this.isSelected(node)){
31487 this.lastSelNode = node;
31490 this.selNodes.push(node);
31491 this.selMap[node.id] = node;
31492 this.lastSelNode = node;
31493 node.ui.onSelectedChange(true);
31494 this.fireEvent("selectionchange", this, this.selNodes);
31500 * @param {TreeNode} node The node to unselect
31502 unselect : function(node){
31503 if(this.selMap[node.id]){
31504 node.ui.onSelectedChange(false);
31505 var sn = this.selNodes;
31508 index = sn.indexOf(node);
31510 for(var i = 0, len = sn.length; i < len; i++){
31518 this.selNodes.splice(index, 1);
31520 delete this.selMap[node.id];
31521 this.fireEvent("selectionchange", this, this.selNodes);
31526 * Clear all selections
31528 clearSelections : function(suppressEvent){
31529 var sn = this.selNodes;
31531 for(var i = 0, len = sn.length; i < len; i++){
31532 sn[i].ui.onSelectedChange(false);
31534 this.selNodes = [];
31536 if(suppressEvent !== true){
31537 this.fireEvent("selectionchange", this, this.selNodes);
31543 * Returns true if the node is selected
31544 * @param {TreeNode} node The node to check
31545 * @return {Boolean}
31547 isSelected : function(node){
31548 return this.selMap[node.id] ? true : false;
31552 * Returns an array of the selected nodes
31555 getSelectedNodes : function(){
31556 return this.selNodes;
31559 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31561 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31563 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31566 * Ext JS Library 1.1.1
31567 * Copyright(c) 2006-2007, Ext JS, LLC.
31569 * Originally Released Under LGPL - original licence link has changed is not relivant.
31572 * <script type="text/javascript">
31576 * @class Roo.tree.TreeNode
31577 * @extends Roo.data.Node
31578 * @cfg {String} text The text for this node
31579 * @cfg {Boolean} expanded true to start the node expanded
31580 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31581 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31582 * @cfg {Boolean} disabled true to start the node disabled
31583 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31584 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31585 * @cfg {String} cls A css class to be added to the node
31586 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31587 * @cfg {String} href URL of the link used for the node (defaults to #)
31588 * @cfg {String} hrefTarget target frame for the link
31589 * @cfg {String} qtip An Ext QuickTip for the node
31590 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31591 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31592 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31593 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31594 * (defaults to undefined with no checkbox rendered)
31596 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31598 Roo.tree.TreeNode = function(attributes){
31599 attributes = attributes || {};
31600 if(typeof attributes == "string"){
31601 attributes = {text: attributes};
31603 this.childrenRendered = false;
31604 this.rendered = false;
31605 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31606 this.expanded = attributes.expanded === true;
31607 this.isTarget = attributes.isTarget !== false;
31608 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31609 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31612 * Read-only. The text for this node. To change it use setText().
31615 this.text = attributes.text;
31617 * True if this node is disabled.
31620 this.disabled = attributes.disabled === true;
31624 * @event textchange
31625 * Fires when the text for this node is changed
31626 * @param {Node} this This node
31627 * @param {String} text The new text
31628 * @param {String} oldText The old text
31630 "textchange" : true,
31632 * @event beforeexpand
31633 * Fires before this node is expanded, return false to cancel.
31634 * @param {Node} this This node
31635 * @param {Boolean} deep
31636 * @param {Boolean} anim
31638 "beforeexpand" : true,
31640 * @event beforecollapse
31641 * Fires before this node is collapsed, return false to cancel.
31642 * @param {Node} this This node
31643 * @param {Boolean} deep
31644 * @param {Boolean} anim
31646 "beforecollapse" : true,
31649 * Fires when this node is expanded
31650 * @param {Node} this This node
31654 * @event disabledchange
31655 * Fires when the disabled status of this node changes
31656 * @param {Node} this This node
31657 * @param {Boolean} disabled
31659 "disabledchange" : true,
31662 * Fires when this node is collapsed
31663 * @param {Node} this This node
31667 * @event beforeclick
31668 * Fires before click processing. Return false to cancel the default action.
31669 * @param {Node} this This node
31670 * @param {Roo.EventObject} e The event object
31672 "beforeclick":true,
31674 * @event checkchange
31675 * Fires when a node with a checkbox's checked property changes
31676 * @param {Node} this This node
31677 * @param {Boolean} checked
31679 "checkchange":true,
31682 * Fires when this node is clicked
31683 * @param {Node} this This node
31684 * @param {Roo.EventObject} e The event object
31689 * Fires when this node is double clicked
31690 * @param {Node} this This node
31691 * @param {Roo.EventObject} e The event object
31695 * @event contextmenu
31696 * Fires when this node is right clicked
31697 * @param {Node} this This node
31698 * @param {Roo.EventObject} e The event object
31700 "contextmenu":true,
31702 * @event beforechildrenrendered
31703 * Fires right before the child nodes for this node are rendered
31704 * @param {Node} this This node
31706 "beforechildrenrendered":true
31709 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31712 * Read-only. The UI for this node
31715 this.ui = new uiClass(this);
31717 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31718 preventHScroll: true,
31720 * Returns true if this node is expanded
31721 * @return {Boolean}
31723 isExpanded : function(){
31724 return this.expanded;
31728 * Returns the UI object for this node
31729 * @return {TreeNodeUI}
31731 getUI : function(){
31735 // private override
31736 setFirstChild : function(node){
31737 var of = this.firstChild;
31738 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31739 if(this.childrenRendered && of && node != of){
31740 of.renderIndent(true, true);
31743 this.renderIndent(true, true);
31747 // private override
31748 setLastChild : function(node){
31749 var ol = this.lastChild;
31750 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31751 if(this.childrenRendered && ol && node != ol){
31752 ol.renderIndent(true, true);
31755 this.renderIndent(true, true);
31759 // these methods are overridden to provide lazy rendering support
31760 // private override
31761 appendChild : function(){
31762 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31763 if(node && this.childrenRendered){
31766 this.ui.updateExpandIcon();
31770 // private override
31771 removeChild : function(node){
31772 this.ownerTree.getSelectionModel().unselect(node);
31773 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31774 // if it's been rendered remove dom node
31775 if(this.childrenRendered){
31778 if(this.childNodes.length < 1){
31779 this.collapse(false, false);
31781 this.ui.updateExpandIcon();
31783 if(!this.firstChild) {
31784 this.childrenRendered = false;
31789 // private override
31790 insertBefore : function(node, refNode){
31791 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31792 if(newNode && refNode && this.childrenRendered){
31795 this.ui.updateExpandIcon();
31800 * Sets the text for this node
31801 * @param {String} text
31803 setText : function(text){
31804 var oldText = this.text;
31806 this.attributes.text = text;
31807 if(this.rendered){ // event without subscribing
31808 this.ui.onTextChange(this, text, oldText);
31810 this.fireEvent("textchange", this, text, oldText);
31814 * Triggers selection of this node
31816 select : function(){
31817 this.getOwnerTree().getSelectionModel().select(this);
31821 * Triggers deselection of this node
31823 unselect : function(){
31824 this.getOwnerTree().getSelectionModel().unselect(this);
31828 * Returns true if this node is selected
31829 * @return {Boolean}
31831 isSelected : function(){
31832 return this.getOwnerTree().getSelectionModel().isSelected(this);
31836 * Expand this node.
31837 * @param {Boolean} deep (optional) True to expand all children as well
31838 * @param {Boolean} anim (optional) false to cancel the default animation
31839 * @param {Function} callback (optional) A callback to be called when
31840 * expanding this node completes (does not wait for deep expand to complete).
31841 * Called with 1 parameter, this node.
31843 expand : function(deep, anim, callback){
31844 if(!this.expanded){
31845 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31848 if(!this.childrenRendered){
31849 this.renderChildren();
31851 this.expanded = true;
31852 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31853 this.ui.animExpand(function(){
31854 this.fireEvent("expand", this);
31855 if(typeof callback == "function"){
31859 this.expandChildNodes(true);
31861 }.createDelegate(this));
31865 this.fireEvent("expand", this);
31866 if(typeof callback == "function"){
31871 if(typeof callback == "function"){
31876 this.expandChildNodes(true);
31880 isHiddenRoot : function(){
31881 return this.isRoot && !this.getOwnerTree().rootVisible;
31885 * Collapse this node.
31886 * @param {Boolean} deep (optional) True to collapse all children as well
31887 * @param {Boolean} anim (optional) false to cancel the default animation
31889 collapse : function(deep, anim){
31890 if(this.expanded && !this.isHiddenRoot()){
31891 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31894 this.expanded = false;
31895 if((this.getOwnerTree().animate && anim !== false) || anim){
31896 this.ui.animCollapse(function(){
31897 this.fireEvent("collapse", this);
31899 this.collapseChildNodes(true);
31901 }.createDelegate(this));
31904 this.ui.collapse();
31905 this.fireEvent("collapse", this);
31909 var cs = this.childNodes;
31910 for(var i = 0, len = cs.length; i < len; i++) {
31911 cs[i].collapse(true, false);
31917 delayedExpand : function(delay){
31918 if(!this.expandProcId){
31919 this.expandProcId = this.expand.defer(delay, this);
31924 cancelExpand : function(){
31925 if(this.expandProcId){
31926 clearTimeout(this.expandProcId);
31928 this.expandProcId = false;
31932 * Toggles expanded/collapsed state of the node
31934 toggle : function(){
31943 * Ensures all parent nodes are expanded
31945 ensureVisible : function(callback){
31946 var tree = this.getOwnerTree();
31947 tree.expandPath(this.parentNode.getPath(), false, function(){
31948 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31949 Roo.callback(callback);
31950 }.createDelegate(this));
31954 * Expand all child nodes
31955 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31957 expandChildNodes : function(deep){
31958 var cs = this.childNodes;
31959 for(var i = 0, len = cs.length; i < len; i++) {
31960 cs[i].expand(deep);
31965 * Collapse all child nodes
31966 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31968 collapseChildNodes : function(deep){
31969 var cs = this.childNodes;
31970 for(var i = 0, len = cs.length; i < len; i++) {
31971 cs[i].collapse(deep);
31976 * Disables this node
31978 disable : function(){
31979 this.disabled = true;
31981 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31982 this.ui.onDisableChange(this, true);
31984 this.fireEvent("disabledchange", this, true);
31988 * Enables this node
31990 enable : function(){
31991 this.disabled = false;
31992 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31993 this.ui.onDisableChange(this, false);
31995 this.fireEvent("disabledchange", this, false);
31999 renderChildren : function(suppressEvent){
32000 if(suppressEvent !== false){
32001 this.fireEvent("beforechildrenrendered", this);
32003 var cs = this.childNodes;
32004 for(var i = 0, len = cs.length; i < len; i++){
32005 cs[i].render(true);
32007 this.childrenRendered = true;
32011 sort : function(fn, scope){
32012 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32013 if(this.childrenRendered){
32014 var cs = this.childNodes;
32015 for(var i = 0, len = cs.length; i < len; i++){
32016 cs[i].render(true);
32022 render : function(bulkRender){
32023 this.ui.render(bulkRender);
32024 if(!this.rendered){
32025 this.rendered = true;
32027 this.expanded = false;
32028 this.expand(false, false);
32034 renderIndent : function(deep, refresh){
32036 this.ui.childIndent = null;
32038 this.ui.renderIndent();
32039 if(deep === true && this.childrenRendered){
32040 var cs = this.childNodes;
32041 for(var i = 0, len = cs.length; i < len; i++){
32042 cs[i].renderIndent(true, refresh);
32048 * Ext JS Library 1.1.1
32049 * Copyright(c) 2006-2007, Ext JS, LLC.
32051 * Originally Released Under LGPL - original licence link has changed is not relivant.
32054 * <script type="text/javascript">
32058 * @class Roo.tree.AsyncTreeNode
32059 * @extends Roo.tree.TreeNode
32060 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32062 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32064 Roo.tree.AsyncTreeNode = function(config){
32065 this.loaded = false;
32066 this.loading = false;
32067 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32069 * @event beforeload
32070 * Fires before this node is loaded, return false to cancel
32071 * @param {Node} this This node
32073 this.addEvents({'beforeload':true, 'load': true});
32076 * Fires when this node is loaded
32077 * @param {Node} this This node
32080 * The loader used by this node (defaults to using the tree's defined loader)
32085 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32086 expand : function(deep, anim, callback){
32087 if(this.loading){ // if an async load is already running, waiting til it's done
32089 var f = function(){
32090 if(!this.loading){ // done loading
32091 clearInterval(timer);
32092 this.expand(deep, anim, callback);
32094 }.createDelegate(this);
32095 timer = setInterval(f, 200);
32099 if(this.fireEvent("beforeload", this) === false){
32102 this.loading = true;
32103 this.ui.beforeLoad(this);
32104 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32106 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32110 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32114 * Returns true if this node is currently loading
32115 * @return {Boolean}
32117 isLoading : function(){
32118 return this.loading;
32121 loadComplete : function(deep, anim, callback){
32122 this.loading = false;
32123 this.loaded = true;
32124 this.ui.afterLoad(this);
32125 this.fireEvent("load", this);
32126 this.expand(deep, anim, callback);
32130 * Returns true if this node has been loaded
32131 * @return {Boolean}
32133 isLoaded : function(){
32134 return this.loaded;
32137 hasChildNodes : function(){
32138 if(!this.isLeaf() && !this.loaded){
32141 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32146 * Trigger a reload for this node
32147 * @param {Function} callback
32149 reload : function(callback){
32150 this.collapse(false, false);
32151 while(this.firstChild){
32152 this.removeChild(this.firstChild);
32154 this.childrenRendered = false;
32155 this.loaded = false;
32156 if(this.isHiddenRoot()){
32157 this.expanded = false;
32159 this.expand(false, false, callback);
32163 * Ext JS Library 1.1.1
32164 * Copyright(c) 2006-2007, Ext JS, LLC.
32166 * Originally Released Under LGPL - original licence link has changed is not relivant.
32169 * <script type="text/javascript">
32173 * @class Roo.tree.TreeNodeUI
32175 * @param {Object} node The node to render
32176 * The TreeNode UI implementation is separate from the
32177 * tree implementation. Unless you are customizing the tree UI,
32178 * you should never have to use this directly.
32180 Roo.tree.TreeNodeUI = function(node){
32182 this.rendered = false;
32183 this.animating = false;
32184 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32187 Roo.tree.TreeNodeUI.prototype = {
32188 removeChild : function(node){
32190 this.ctNode.removeChild(node.ui.getEl());
32194 beforeLoad : function(){
32195 this.addClass("x-tree-node-loading");
32198 afterLoad : function(){
32199 this.removeClass("x-tree-node-loading");
32202 onTextChange : function(node, text, oldText){
32204 this.textNode.innerHTML = text;
32208 onDisableChange : function(node, state){
32209 this.disabled = state;
32211 this.addClass("x-tree-node-disabled");
32213 this.removeClass("x-tree-node-disabled");
32217 onSelectedChange : function(state){
32220 this.addClass("x-tree-selected");
32223 this.removeClass("x-tree-selected");
32227 onMove : function(tree, node, oldParent, newParent, index, refNode){
32228 this.childIndent = null;
32230 var targetNode = newParent.ui.getContainer();
32231 if(!targetNode){//target not rendered
32232 this.holder = document.createElement("div");
32233 this.holder.appendChild(this.wrap);
32236 var insertBefore = refNode ? refNode.ui.getEl() : null;
32238 targetNode.insertBefore(this.wrap, insertBefore);
32240 targetNode.appendChild(this.wrap);
32242 this.node.renderIndent(true);
32246 addClass : function(cls){
32248 Roo.fly(this.elNode).addClass(cls);
32252 removeClass : function(cls){
32254 Roo.fly(this.elNode).removeClass(cls);
32258 remove : function(){
32260 this.holder = document.createElement("div");
32261 this.holder.appendChild(this.wrap);
32265 fireEvent : function(){
32266 return this.node.fireEvent.apply(this.node, arguments);
32269 initEvents : function(){
32270 this.node.on("move", this.onMove, this);
32271 var E = Roo.EventManager;
32272 var a = this.anchor;
32274 var el = Roo.fly(a, '_treeui');
32276 if(Roo.isOpera){ // opera render bug ignores the CSS
32277 el.setStyle("text-decoration", "none");
32280 el.on("click", this.onClick, this);
32281 el.on("dblclick", this.onDblClick, this);
32284 Roo.EventManager.on(this.checkbox,
32285 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32288 el.on("contextmenu", this.onContextMenu, this);
32290 var icon = Roo.fly(this.iconNode);
32291 icon.on("click", this.onClick, this);
32292 icon.on("dblclick", this.onDblClick, this);
32293 icon.on("contextmenu", this.onContextMenu, this);
32294 E.on(this.ecNode, "click", this.ecClick, this, true);
32296 if(this.node.disabled){
32297 this.addClass("x-tree-node-disabled");
32299 if(this.node.hidden){
32300 this.addClass("x-tree-node-disabled");
32302 var ot = this.node.getOwnerTree();
32303 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32304 if(dd && (!this.node.isRoot || ot.rootVisible)){
32305 Roo.dd.Registry.register(this.elNode, {
32307 handles: this.getDDHandles(),
32313 getDDHandles : function(){
32314 return [this.iconNode, this.textNode];
32319 this.wrap.style.display = "none";
32325 this.wrap.style.display = "";
32329 onContextMenu : function(e){
32330 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32331 e.preventDefault();
32333 this.fireEvent("contextmenu", this.node, e);
32337 onClick : function(e){
32342 if(this.fireEvent("beforeclick", this.node, e) !== false){
32343 if(!this.disabled && this.node.attributes.href){
32344 this.fireEvent("click", this.node, e);
32347 e.preventDefault();
32352 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32353 this.node.toggle();
32356 this.fireEvent("click", this.node, e);
32362 onDblClick : function(e){
32363 e.preventDefault();
32368 this.toggleCheck();
32370 if(!this.animating && this.node.hasChildNodes()){
32371 this.node.toggle();
32373 this.fireEvent("dblclick", this.node, e);
32376 onCheckChange : function(){
32377 var checked = this.checkbox.checked;
32378 this.node.attributes.checked = checked;
32379 this.fireEvent('checkchange', this.node, checked);
32382 ecClick : function(e){
32383 if(!this.animating && this.node.hasChildNodes()){
32384 this.node.toggle();
32388 startDrop : function(){
32389 this.dropping = true;
32392 // delayed drop so the click event doesn't get fired on a drop
32393 endDrop : function(){
32394 setTimeout(function(){
32395 this.dropping = false;
32396 }.createDelegate(this), 50);
32399 expand : function(){
32400 this.updateExpandIcon();
32401 this.ctNode.style.display = "";
32404 focus : function(){
32405 if(!this.node.preventHScroll){
32406 try{this.anchor.focus();
32408 }else if(!Roo.isIE){
32410 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32411 var l = noscroll.scrollLeft;
32412 this.anchor.focus();
32413 noscroll.scrollLeft = l;
32418 toggleCheck : function(value){
32419 var cb = this.checkbox;
32421 cb.checked = (value === undefined ? !cb.checked : value);
32427 this.anchor.blur();
32431 animExpand : function(callback){
32432 var ct = Roo.get(this.ctNode);
32434 if(!this.node.hasChildNodes()){
32435 this.updateExpandIcon();
32436 this.ctNode.style.display = "";
32437 Roo.callback(callback);
32440 this.animating = true;
32441 this.updateExpandIcon();
32444 callback : function(){
32445 this.animating = false;
32446 Roo.callback(callback);
32449 duration: this.node.ownerTree.duration || .25
32453 highlight : function(){
32454 var tree = this.node.getOwnerTree();
32455 Roo.fly(this.wrap).highlight(
32456 tree.hlColor || "C3DAF9",
32457 {endColor: tree.hlBaseColor}
32461 collapse : function(){
32462 this.updateExpandIcon();
32463 this.ctNode.style.display = "none";
32466 animCollapse : function(callback){
32467 var ct = Roo.get(this.ctNode);
32468 ct.enableDisplayMode('block');
32471 this.animating = true;
32472 this.updateExpandIcon();
32475 callback : function(){
32476 this.animating = false;
32477 Roo.callback(callback);
32480 duration: this.node.ownerTree.duration || .25
32484 getContainer : function(){
32485 return this.ctNode;
32488 getEl : function(){
32492 appendDDGhost : function(ghostNode){
32493 ghostNode.appendChild(this.elNode.cloneNode(true));
32496 getDDRepairXY : function(){
32497 return Roo.lib.Dom.getXY(this.iconNode);
32500 onRender : function(){
32504 render : function(bulkRender){
32505 var n = this.node, a = n.attributes;
32506 var targetNode = n.parentNode ?
32507 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32509 if(!this.rendered){
32510 this.rendered = true;
32512 this.renderElements(n, a, targetNode, bulkRender);
32515 if(this.textNode.setAttributeNS){
32516 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32518 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32521 this.textNode.setAttribute("ext:qtip", a.qtip);
32523 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32526 }else if(a.qtipCfg){
32527 a.qtipCfg.target = Roo.id(this.textNode);
32528 Roo.QuickTips.register(a.qtipCfg);
32531 if(!this.node.expanded){
32532 this.updateExpandIcon();
32535 if(bulkRender === true) {
32536 targetNode.appendChild(this.wrap);
32541 renderElements : function(n, a, targetNode, bulkRender){
32542 // add some indent caching, this helps performance when rendering a large tree
32543 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32544 var t = n.getOwnerTree();
32545 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32546 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32547 var cb = typeof a.checked == 'boolean';
32548 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32549 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32550 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32551 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32552 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32553 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32554 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32555 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32556 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32557 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32560 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32561 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32562 n.nextSibling.ui.getEl(), buf.join(""));
32564 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32567 this.elNode = this.wrap.childNodes[0];
32568 this.ctNode = this.wrap.childNodes[1];
32569 var cs = this.elNode.childNodes;
32570 this.indentNode = cs[0];
32571 this.ecNode = cs[1];
32572 this.iconNode = cs[2];
32575 this.checkbox = cs[3];
32578 this.anchor = cs[index];
32579 this.textNode = cs[index].firstChild;
32582 getAnchor : function(){
32583 return this.anchor;
32586 getTextEl : function(){
32587 return this.textNode;
32590 getIconEl : function(){
32591 return this.iconNode;
32594 isChecked : function(){
32595 return this.checkbox ? this.checkbox.checked : false;
32598 updateExpandIcon : function(){
32600 var n = this.node, c1, c2;
32601 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32602 var hasChild = n.hasChildNodes();
32606 c1 = "x-tree-node-collapsed";
32607 c2 = "x-tree-node-expanded";
32610 c1 = "x-tree-node-expanded";
32611 c2 = "x-tree-node-collapsed";
32614 this.removeClass("x-tree-node-leaf");
32615 this.wasLeaf = false;
32617 if(this.c1 != c1 || this.c2 != c2){
32618 Roo.fly(this.elNode).replaceClass(c1, c2);
32619 this.c1 = c1; this.c2 = c2;
32623 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32626 this.wasLeaf = true;
32629 var ecc = "x-tree-ec-icon "+cls;
32630 if(this.ecc != ecc){
32631 this.ecNode.className = ecc;
32637 getChildIndent : function(){
32638 if(!this.childIndent){
32642 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32644 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32646 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32651 this.childIndent = buf.join("");
32653 return this.childIndent;
32656 renderIndent : function(){
32659 var p = this.node.parentNode;
32661 indent = p.ui.getChildIndent();
32663 if(this.indentMarkup != indent){ // don't rerender if not required
32664 this.indentNode.innerHTML = indent;
32665 this.indentMarkup = indent;
32667 this.updateExpandIcon();
32672 Roo.tree.RootTreeNodeUI = function(){
32673 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32675 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32676 render : function(){
32677 if(!this.rendered){
32678 var targetNode = this.node.ownerTree.innerCt.dom;
32679 this.node.expanded = true;
32680 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32681 this.wrap = this.ctNode = targetNode.firstChild;
32684 collapse : function(){
32686 expand : function(){
32690 * Ext JS Library 1.1.1
32691 * Copyright(c) 2006-2007, Ext JS, LLC.
32693 * Originally Released Under LGPL - original licence link has changed is not relivant.
32696 * <script type="text/javascript">
32699 * @class Roo.tree.TreeLoader
32700 * @extends Roo.util.Observable
32701 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32702 * nodes from a specified URL. The response must be a javascript Array definition
32703 * who's elements are node definition objects. eg:
32705 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32706 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32709 * A server request is sent, and child nodes are loaded only when a node is expanded.
32710 * The loading node's id is passed to the server under the parameter name "node" to
32711 * enable the server to produce the correct child nodes.
32713 * To pass extra parameters, an event handler may be attached to the "beforeload"
32714 * event, and the parameters specified in the TreeLoader's baseParams property:
32716 myTreeLoader.on("beforeload", function(treeLoader, node) {
32717 this.baseParams.category = node.attributes.category;
32720 * This would pass an HTTP parameter called "category" to the server containing
32721 * the value of the Node's "category" attribute.
32723 * Creates a new Treeloader.
32724 * @param {Object} config A config object containing config properties.
32726 Roo.tree.TreeLoader = function(config){
32727 this.baseParams = {};
32728 this.requestMethod = "POST";
32729 Roo.apply(this, config);
32734 * @event beforeload
32735 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32736 * @param {Object} This TreeLoader object.
32737 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32738 * @param {Object} callback The callback function specified in the {@link #load} call.
32743 * Fires when the node has been successfuly loaded.
32744 * @param {Object} This TreeLoader object.
32745 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32746 * @param {Object} response The response object containing the data from the server.
32750 * @event loadexception
32751 * Fires if the network request failed.
32752 * @param {Object} This TreeLoader object.
32753 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32754 * @param {Object} response The response object containing the data from the server.
32756 loadexception : true,
32759 * Fires before a node is created, enabling you to return custom Node types
32760 * @param {Object} This TreeLoader object.
32761 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32766 Roo.tree.TreeLoader.superclass.constructor.call(this);
32769 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32771 * @cfg {String} dataUrl The URL from which to request a Json string which
32772 * specifies an array of node definition object representing the child nodes
32776 * @cfg {Object} baseParams (optional) An object containing properties which
32777 * specify HTTP parameters to be passed to each request for child nodes.
32780 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32781 * created by this loader. If the attributes sent by the server have an attribute in this object,
32782 * they take priority.
32785 * @cfg {Object} uiProviders (optional) An object containing properties which
32787 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32788 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32789 * <i>uiProvider</i> attribute of a returned child node is a string rather
32790 * than a reference to a TreeNodeUI implementation, this that string value
32791 * is used as a property name in the uiProviders object. You can define the provider named
32792 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32797 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32798 * child nodes before loading.
32800 clearOnLoad : true,
32803 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32804 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32805 * Grid query { data : [ .....] }
32810 * @cfg {String} queryParam (optional)
32811 * Name of the query as it will be passed on the querystring (defaults to 'node')
32812 * eg. the request will be ?node=[id]
32819 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32820 * This is called automatically when a node is expanded, but may be used to reload
32821 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32822 * @param {Roo.tree.TreeNode} node
32823 * @param {Function} callback
32825 load : function(node, callback){
32826 if(this.clearOnLoad){
32827 while(node.firstChild){
32828 node.removeChild(node.firstChild);
32831 if(node.attributes.children){ // preloaded json children
32832 var cs = node.attributes.children;
32833 for(var i = 0, len = cs.length; i < len; i++){
32834 node.appendChild(this.createNode(cs[i]));
32836 if(typeof callback == "function"){
32839 }else if(this.dataUrl){
32840 this.requestData(node, callback);
32844 getParams: function(node){
32845 var buf = [], bp = this.baseParams;
32846 for(var key in bp){
32847 if(typeof bp[key] != "function"){
32848 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32851 var n = this.queryParam === false ? 'node' : this.queryParam;
32852 buf.push(n + "=", encodeURIComponent(node.id));
32853 return buf.join("");
32856 requestData : function(node, callback){
32857 if(this.fireEvent("beforeload", this, node, callback) !== false){
32858 this.transId = Roo.Ajax.request({
32859 method:this.requestMethod,
32860 url: this.dataUrl||this.url,
32861 success: this.handleResponse,
32862 failure: this.handleFailure,
32864 argument: {callback: callback, node: node},
32865 params: this.getParams(node)
32868 // if the load is cancelled, make sure we notify
32869 // the node that we are done
32870 if(typeof callback == "function"){
32876 isLoading : function(){
32877 return this.transId ? true : false;
32880 abort : function(){
32881 if(this.isLoading()){
32882 Roo.Ajax.abort(this.transId);
32887 createNode : function(attr){
32888 // apply baseAttrs, nice idea Corey!
32889 if(this.baseAttrs){
32890 Roo.applyIf(attr, this.baseAttrs);
32892 if(this.applyLoader !== false){
32893 attr.loader = this;
32895 // uiProvider = depreciated..
32897 if(typeof(attr.uiProvider) == 'string'){
32898 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32899 /** eval:var:attr */ eval(attr.uiProvider);
32901 if(typeof(this.uiProviders['default']) != 'undefined') {
32902 attr.uiProvider = this.uiProviders['default'];
32905 this.fireEvent('create', this, attr);
32907 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32909 new Roo.tree.TreeNode(attr) :
32910 new Roo.tree.AsyncTreeNode(attr));
32913 processResponse : function(response, node, callback){
32914 var json = response.responseText;
32917 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32918 if (this.root !== false) {
32922 for(var i = 0, len = o.length; i < len; i++){
32923 var n = this.createNode(o[i]);
32925 node.appendChild(n);
32928 if(typeof callback == "function"){
32929 callback(this, node);
32932 this.handleFailure(response);
32936 handleResponse : function(response){
32937 this.transId = false;
32938 var a = response.argument;
32939 this.processResponse(response, a.node, a.callback);
32940 this.fireEvent("load", this, a.node, response);
32943 handleFailure : function(response){
32944 this.transId = false;
32945 var a = response.argument;
32946 this.fireEvent("loadexception", this, a.node, response);
32947 if(typeof a.callback == "function"){
32948 a.callback(this, a.node);
32953 * Ext JS Library 1.1.1
32954 * Copyright(c) 2006-2007, Ext JS, LLC.
32956 * Originally Released Under LGPL - original licence link has changed is not relivant.
32959 * <script type="text/javascript">
32963 * @class Roo.tree.TreeFilter
32964 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32965 * @param {TreePanel} tree
32966 * @param {Object} config (optional)
32968 Roo.tree.TreeFilter = function(tree, config){
32970 this.filtered = {};
32971 Roo.apply(this, config);
32974 Roo.tree.TreeFilter.prototype = {
32981 * Filter the data by a specific attribute.
32982 * @param {String/RegExp} value Either string that the attribute value
32983 * should start with or a RegExp to test against the attribute
32984 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32985 * @param {TreeNode} startNode (optional) The node to start the filter at.
32987 filter : function(value, attr, startNode){
32988 attr = attr || "text";
32990 if(typeof value == "string"){
32991 var vlen = value.length;
32992 // auto clear empty filter
32993 if(vlen == 0 && this.clearBlank){
32997 value = value.toLowerCase();
32999 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
33001 }else if(value.exec){ // regex?
33003 return value.test(n.attributes[attr]);
33006 throw 'Illegal filter type, must be string or regex';
33008 this.filterBy(f, null, startNode);
33012 * Filter by a function. The passed function will be called with each
33013 * node in the tree (or from the startNode). If the function returns true, the node is kept
33014 * otherwise it is filtered. If a node is filtered, its children are also filtered.
33015 * @param {Function} fn The filter function
33016 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33018 filterBy : function(fn, scope, startNode){
33019 startNode = startNode || this.tree.root;
33020 if(this.autoClear){
33023 var af = this.filtered, rv = this.reverse;
33024 var f = function(n){
33025 if(n == startNode){
33031 var m = fn.call(scope || n, n);
33039 startNode.cascade(f);
33042 if(typeof id != "function"){
33044 if(n && n.parentNode){
33045 n.parentNode.removeChild(n);
33053 * Clears the current filter. Note: with the "remove" option
33054 * set a filter cannot be cleared.
33056 clear : function(){
33058 var af = this.filtered;
33060 if(typeof id != "function"){
33067 this.filtered = {};
33072 * Ext JS Library 1.1.1
33073 * Copyright(c) 2006-2007, Ext JS, LLC.
33075 * Originally Released Under LGPL - original licence link has changed is not relivant.
33078 * <script type="text/javascript">
33083 * @class Roo.tree.TreeSorter
33084 * Provides sorting of nodes in a TreePanel
33086 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33087 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33088 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33089 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33090 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33091 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33093 * @param {TreePanel} tree
33094 * @param {Object} config
33096 Roo.tree.TreeSorter = function(tree, config){
33097 Roo.apply(this, config);
33098 tree.on("beforechildrenrendered", this.doSort, this);
33099 tree.on("append", this.updateSort, this);
33100 tree.on("insert", this.updateSort, this);
33102 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33103 var p = this.property || "text";
33104 var sortType = this.sortType;
33105 var fs = this.folderSort;
33106 var cs = this.caseSensitive === true;
33107 var leafAttr = this.leafAttr || 'leaf';
33109 this.sortFn = function(n1, n2){
33111 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33114 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33118 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33119 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33121 return dsc ? +1 : -1;
33123 return dsc ? -1 : +1;
33130 Roo.tree.TreeSorter.prototype = {
33131 doSort : function(node){
33132 node.sort(this.sortFn);
33135 compareNodes : function(n1, n2){
33136 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33139 updateSort : function(tree, node){
33140 if(node.childrenRendered){
33141 this.doSort.defer(1, this, [node]);
33146 * Ext JS Library 1.1.1
33147 * Copyright(c) 2006-2007, Ext JS, LLC.
33149 * Originally Released Under LGPL - original licence link has changed is not relivant.
33152 * <script type="text/javascript">
33155 if(Roo.dd.DropZone){
33157 Roo.tree.TreeDropZone = function(tree, config){
33158 this.allowParentInsert = false;
33159 this.allowContainerDrop = false;
33160 this.appendOnly = false;
33161 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33163 this.lastInsertClass = "x-tree-no-status";
33164 this.dragOverData = {};
33167 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33168 ddGroup : "TreeDD",
33170 expandDelay : 1000,
33172 expandNode : function(node){
33173 if(node.hasChildNodes() && !node.isExpanded()){
33174 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33178 queueExpand : function(node){
33179 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33182 cancelExpand : function(){
33183 if(this.expandProcId){
33184 clearTimeout(this.expandProcId);
33185 this.expandProcId = false;
33189 isValidDropPoint : function(n, pt, dd, e, data){
33190 if(!n || !data){ return false; }
33191 var targetNode = n.node;
33192 var dropNode = data.node;
33193 // default drop rules
33194 if(!(targetNode && targetNode.isTarget && pt)){
33197 if(pt == "append" && targetNode.allowChildren === false){
33200 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33203 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33206 // reuse the object
33207 var overEvent = this.dragOverData;
33208 overEvent.tree = this.tree;
33209 overEvent.target = targetNode;
33210 overEvent.data = data;
33211 overEvent.point = pt;
33212 overEvent.source = dd;
33213 overEvent.rawEvent = e;
33214 overEvent.dropNode = dropNode;
33215 overEvent.cancel = false;
33216 var result = this.tree.fireEvent("nodedragover", overEvent);
33217 return overEvent.cancel === false && result !== false;
33220 getDropPoint : function(e, n, dd){
33223 return tn.allowChildren !== false ? "append" : false; // always append for root
33225 var dragEl = n.ddel;
33226 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33227 var y = Roo.lib.Event.getPageY(e);
33228 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33230 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33231 var noAppend = tn.allowChildren === false;
33232 if(this.appendOnly || tn.parentNode.allowChildren === false){
33233 return noAppend ? false : "append";
33235 var noBelow = false;
33236 if(!this.allowParentInsert){
33237 noBelow = tn.hasChildNodes() && tn.isExpanded();
33239 var q = (b - t) / (noAppend ? 2 : 3);
33240 if(y >= t && y < (t + q)){
33242 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33249 onNodeEnter : function(n, dd, e, data){
33250 this.cancelExpand();
33253 onNodeOver : function(n, dd, e, data){
33254 var pt = this.getDropPoint(e, n, dd);
33257 // auto node expand check
33258 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33259 this.queueExpand(node);
33260 }else if(pt != "append"){
33261 this.cancelExpand();
33264 // set the insert point style on the target node
33265 var returnCls = this.dropNotAllowed;
33266 if(this.isValidDropPoint(n, pt, dd, e, data)){
33271 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33272 cls = "x-tree-drag-insert-above";
33273 }else if(pt == "below"){
33274 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33275 cls = "x-tree-drag-insert-below";
33277 returnCls = "x-tree-drop-ok-append";
33278 cls = "x-tree-drag-append";
33280 if(this.lastInsertClass != cls){
33281 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33282 this.lastInsertClass = cls;
33289 onNodeOut : function(n, dd, e, data){
33290 this.cancelExpand();
33291 this.removeDropIndicators(n);
33294 onNodeDrop : function(n, dd, e, data){
33295 var point = this.getDropPoint(e, n, dd);
33296 var targetNode = n.node;
33297 targetNode.ui.startDrop();
33298 if(!this.isValidDropPoint(n, point, dd, e, data)){
33299 targetNode.ui.endDrop();
33302 // first try to find the drop node
33303 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33306 target: targetNode,
33311 dropNode: dropNode,
33314 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33315 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33316 targetNode.ui.endDrop();
33319 // allow target changing
33320 targetNode = dropEvent.target;
33321 if(point == "append" && !targetNode.isExpanded()){
33322 targetNode.expand(false, null, function(){
33323 this.completeDrop(dropEvent);
33324 }.createDelegate(this));
33326 this.completeDrop(dropEvent);
33331 completeDrop : function(de){
33332 var ns = de.dropNode, p = de.point, t = de.target;
33333 if(!(ns instanceof Array)){
33337 for(var i = 0, len = ns.length; i < len; i++){
33340 t.parentNode.insertBefore(n, t);
33341 }else if(p == "below"){
33342 t.parentNode.insertBefore(n, t.nextSibling);
33348 if(this.tree.hlDrop){
33352 this.tree.fireEvent("nodedrop", de);
33355 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33356 if(this.tree.hlDrop){
33357 dropNode.ui.focus();
33358 dropNode.ui.highlight();
33360 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33363 getTree : function(){
33367 removeDropIndicators : function(n){
33370 Roo.fly(el).removeClass([
33371 "x-tree-drag-insert-above",
33372 "x-tree-drag-insert-below",
33373 "x-tree-drag-append"]);
33374 this.lastInsertClass = "_noclass";
33378 beforeDragDrop : function(target, e, id){
33379 this.cancelExpand();
33383 afterRepair : function(data){
33384 if(data && Roo.enableFx){
33385 data.node.ui.highlight();
33394 * Ext JS Library 1.1.1
33395 * Copyright(c) 2006-2007, Ext JS, LLC.
33397 * Originally Released Under LGPL - original licence link has changed is not relivant.
33400 * <script type="text/javascript">
33404 if(Roo.dd.DragZone){
33405 Roo.tree.TreeDragZone = function(tree, config){
33406 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33410 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33411 ddGroup : "TreeDD",
33413 onBeforeDrag : function(data, e){
33415 return n && n.draggable && !n.disabled;
33418 onInitDrag : function(e){
33419 var data = this.dragData;
33420 this.tree.getSelectionModel().select(data.node);
33421 this.proxy.update("");
33422 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33423 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33426 getRepairXY : function(e, data){
33427 return data.node.ui.getDDRepairXY();
33430 onEndDrag : function(data, e){
33431 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33434 onValidDrop : function(dd, e, id){
33435 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33439 beforeInvalidDrop : function(e, id){
33440 // this scrolls the original position back into view
33441 var sm = this.tree.getSelectionModel();
33442 sm.clearSelections();
33443 sm.select(this.dragData.node);
33448 * Ext JS Library 1.1.1
33449 * Copyright(c) 2006-2007, Ext JS, LLC.
33451 * Originally Released Under LGPL - original licence link has changed is not relivant.
33454 * <script type="text/javascript">
33457 * @class Roo.tree.TreeEditor
33458 * @extends Roo.Editor
33459 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33460 * as the editor field.
33462 * @param {TreePanel} tree
33463 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33465 Roo.tree.TreeEditor = function(tree, config){
33466 config = config || {};
33467 var field = config.events ? config : new Roo.form.TextField(config);
33468 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33472 tree.on('beforeclick', this.beforeNodeClick, this);
33473 tree.getTreeEl().on('mousedown', this.hide, this);
33474 this.on('complete', this.updateNode, this);
33475 this.on('beforestartedit', this.fitToTree, this);
33476 this.on('startedit', this.bindScroll, this, {delay:10});
33477 this.on('specialkey', this.onSpecialKey, this);
33480 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33482 * @cfg {String} alignment
33483 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33489 * @cfg {Boolean} hideEl
33490 * True to hide the bound element while the editor is displayed (defaults to false)
33494 * @cfg {String} cls
33495 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33497 cls: "x-small-editor x-tree-editor",
33499 * @cfg {Boolean} shim
33500 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33506 * @cfg {Number} maxWidth
33507 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33508 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33509 * scroll and client offsets into account prior to each edit.
33516 fitToTree : function(ed, el){
33517 var td = this.tree.getTreeEl().dom, nd = el.dom;
33518 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33519 td.scrollLeft = nd.offsetLeft;
33523 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33524 this.setSize(w, '');
33528 triggerEdit : function(node){
33529 this.completeEdit();
33530 this.editNode = node;
33531 this.startEdit(node.ui.textNode, node.text);
33535 bindScroll : function(){
33536 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33540 beforeNodeClick : function(node, e){
33541 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33542 this.lastClick = new Date();
33543 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33545 this.triggerEdit(node);
33551 updateNode : function(ed, value){
33552 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33553 this.editNode.setText(value);
33557 onHide : function(){
33558 Roo.tree.TreeEditor.superclass.onHide.call(this);
33560 this.editNode.ui.focus();
33565 onSpecialKey : function(field, e){
33566 var k = e.getKey();
33570 }else if(k == e.ENTER && !e.hasModifier()){
33572 this.completeEdit();
33575 });//<Script type="text/javascript">
33578 * Ext JS Library 1.1.1
33579 * Copyright(c) 2006-2007, Ext JS, LLC.
33581 * Originally Released Under LGPL - original licence link has changed is not relivant.
33584 * <script type="text/javascript">
33588 * Not documented??? - probably should be...
33591 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33592 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33594 renderElements : function(n, a, targetNode, bulkRender){
33595 //consel.log("renderElements?");
33596 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33598 var t = n.getOwnerTree();
33599 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33601 var cols = t.columns;
33602 var bw = t.borderWidth;
33604 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33605 var cb = typeof a.checked == "boolean";
33606 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33607 var colcls = 'x-t-' + tid + '-c0';
33609 '<li class="x-tree-node">',
33612 '<div class="x-tree-node-el ', a.cls,'">',
33614 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33617 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33618 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33619 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33620 (a.icon ? ' x-tree-node-inline-icon' : ''),
33621 (a.iconCls ? ' '+a.iconCls : ''),
33622 '" unselectable="on" />',
33623 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33624 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33626 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33627 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33628 '<span unselectable="on" qtip="' + tx + '">',
33632 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33633 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33635 for(var i = 1, len = cols.length; i < len; i++){
33637 colcls = 'x-t-' + tid + '-c' +i;
33638 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33639 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33640 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33646 '<div class="x-clear"></div></div>',
33647 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33650 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33651 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33652 n.nextSibling.ui.getEl(), buf.join(""));
33654 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33656 var el = this.wrap.firstChild;
33658 this.elNode = el.firstChild;
33659 this.ranchor = el.childNodes[1];
33660 this.ctNode = this.wrap.childNodes[1];
33661 var cs = el.firstChild.childNodes;
33662 this.indentNode = cs[0];
33663 this.ecNode = cs[1];
33664 this.iconNode = cs[2];
33667 this.checkbox = cs[3];
33670 this.anchor = cs[index];
33672 this.textNode = cs[index].firstChild;
33674 //el.on("click", this.onClick, this);
33675 //el.on("dblclick", this.onDblClick, this);
33678 // console.log(this);
33680 initEvents : function(){
33681 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33684 var a = this.ranchor;
33686 var el = Roo.get(a);
33688 if(Roo.isOpera){ // opera render bug ignores the CSS
33689 el.setStyle("text-decoration", "none");
33692 el.on("click", this.onClick, this);
33693 el.on("dblclick", this.onDblClick, this);
33694 el.on("contextmenu", this.onContextMenu, this);
33698 /*onSelectedChange : function(state){
33701 this.addClass("x-tree-selected");
33704 this.removeClass("x-tree-selected");
33707 addClass : function(cls){
33709 Roo.fly(this.elRow).addClass(cls);
33715 removeClass : function(cls){
33717 Roo.fly(this.elRow).removeClass(cls);
33723 });//<Script type="text/javascript">
33727 * Ext JS Library 1.1.1
33728 * Copyright(c) 2006-2007, Ext JS, LLC.
33730 * Originally Released Under LGPL - original licence link has changed is not relivant.
33733 * <script type="text/javascript">
33738 * @class Roo.tree.ColumnTree
33739 * @extends Roo.data.TreePanel
33740 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33741 * @cfg {int} borderWidth compined right/left border allowance
33743 * @param {String/HTMLElement/Element} el The container element
33744 * @param {Object} config
33746 Roo.tree.ColumnTree = function(el, config)
33748 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33752 * Fire this event on a container when it resizes
33753 * @param {int} w Width
33754 * @param {int} h Height
33758 this.on('resize', this.onResize, this);
33761 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33765 borderWidth: Roo.isBorderBox ? 0 : 2,
33768 render : function(){
33769 // add the header.....
33771 Roo.tree.ColumnTree.superclass.render.apply(this);
33773 this.el.addClass('x-column-tree');
33775 this.headers = this.el.createChild(
33776 {cls:'x-tree-headers'},this.innerCt.dom);
33778 var cols = this.columns, c;
33779 var totalWidth = 0;
33781 var len = cols.length;
33782 for(var i = 0; i < len; i++){
33784 totalWidth += c.width;
33785 this.headEls.push(this.headers.createChild({
33786 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33788 cls:'x-tree-hd-text',
33791 style:'width:'+(c.width-this.borderWidth)+'px;'
33794 this.headers.createChild({cls:'x-clear'});
33795 // prevent floats from wrapping when clipped
33796 this.headers.setWidth(totalWidth);
33797 //this.innerCt.setWidth(totalWidth);
33798 this.innerCt.setStyle({ overflow: 'auto' });
33799 this.onResize(this.width, this.height);
33803 onResize : function(w,h)
33808 this.innerCt.setWidth(this.width);
33809 this.innerCt.setHeight(this.height-20);
33812 var cols = this.columns, c;
33813 var totalWidth = 0;
33815 var len = cols.length;
33816 for(var i = 0; i < len; i++){
33818 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33819 // it's the expander..
33820 expEl = this.headEls[i];
33823 totalWidth += c.width;
33827 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33829 this.headers.setWidth(w-20);
33838 * Ext JS Library 1.1.1
33839 * Copyright(c) 2006-2007, Ext JS, LLC.
33841 * Originally Released Under LGPL - original licence link has changed is not relivant.
33844 * <script type="text/javascript">
33848 * @class Roo.menu.Menu
33849 * @extends Roo.util.Observable
33850 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33851 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33853 * Creates a new Menu
33854 * @param {Object} config Configuration options
33856 Roo.menu.Menu = function(config){
33857 Roo.apply(this, config);
33858 this.id = this.id || Roo.id();
33861 * @event beforeshow
33862 * Fires before this menu is displayed
33863 * @param {Roo.menu.Menu} this
33867 * @event beforehide
33868 * Fires before this menu is hidden
33869 * @param {Roo.menu.Menu} this
33874 * Fires after this menu is displayed
33875 * @param {Roo.menu.Menu} this
33880 * Fires after this menu is hidden
33881 * @param {Roo.menu.Menu} this
33886 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33887 * @param {Roo.menu.Menu} this
33888 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33889 * @param {Roo.EventObject} e
33894 * Fires when the mouse is hovering over this menu
33895 * @param {Roo.menu.Menu} this
33896 * @param {Roo.EventObject} e
33897 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33902 * Fires when the mouse exits this menu
33903 * @param {Roo.menu.Menu} this
33904 * @param {Roo.EventObject} e
33905 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33910 * Fires when a menu item contained in this menu is clicked
33911 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33912 * @param {Roo.EventObject} e
33916 if (this.registerMenu) {
33917 Roo.menu.MenuMgr.register(this);
33920 var mis = this.items;
33921 this.items = new Roo.util.MixedCollection();
33923 this.add.apply(this, mis);
33927 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33929 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33933 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33934 * for bottom-right shadow (defaults to "sides")
33938 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33939 * this menu (defaults to "tl-tr?")
33941 subMenuAlign : "tl-tr?",
33943 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33944 * relative to its element of origin (defaults to "tl-bl?")
33946 defaultAlign : "tl-bl?",
33948 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33950 allowOtherMenus : false,
33952 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33954 registerMenu : true,
33959 render : function(){
33963 var el = this.el = new Roo.Layer({
33965 shadow:this.shadow,
33967 parentEl: this.parentEl || document.body,
33971 this.keyNav = new Roo.menu.MenuNav(this);
33974 el.addClass("x-menu-plain");
33977 el.addClass(this.cls);
33979 // generic focus element
33980 this.focusEl = el.createChild({
33981 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33983 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33984 ul.on("click", this.onClick, this);
33985 ul.on("mouseover", this.onMouseOver, this);
33986 ul.on("mouseout", this.onMouseOut, this);
33987 this.items.each(function(item){
33988 var li = document.createElement("li");
33989 li.className = "x-menu-list-item";
33990 ul.dom.appendChild(li);
33991 item.render(li, this);
33998 autoWidth : function(){
33999 var el = this.el, ul = this.ul;
34003 var w = this.width;
34006 }else if(Roo.isIE){
34007 el.setWidth(this.minWidth);
34008 var t = el.dom.offsetWidth; // force recalc
34009 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34014 delayAutoWidth : function(){
34017 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
34019 this.awTask.delay(20);
34024 findTargetItem : function(e){
34025 var t = e.getTarget(".x-menu-list-item", this.ul, true);
34026 if(t && t.menuItemId){
34027 return this.items.get(t.menuItemId);
34032 onClick : function(e){
34034 if(t = this.findTargetItem(e)){
34036 this.fireEvent("click", this, t, e);
34041 setActiveItem : function(item, autoExpand){
34042 if(item != this.activeItem){
34043 if(this.activeItem){
34044 this.activeItem.deactivate();
34046 this.activeItem = item;
34047 item.activate(autoExpand);
34048 }else if(autoExpand){
34054 tryActivate : function(start, step){
34055 var items = this.items;
34056 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34057 var item = items.get(i);
34058 if(!item.disabled && item.canActivate){
34059 this.setActiveItem(item, false);
34067 onMouseOver : function(e){
34069 if(t = this.findTargetItem(e)){
34070 if(t.canActivate && !t.disabled){
34071 this.setActiveItem(t, true);
34074 this.fireEvent("mouseover", this, e, t);
34078 onMouseOut : function(e){
34080 if(t = this.findTargetItem(e)){
34081 if(t == this.activeItem && t.shouldDeactivate(e)){
34082 this.activeItem.deactivate();
34083 delete this.activeItem;
34086 this.fireEvent("mouseout", this, e, t);
34090 * Read-only. Returns true if the menu is currently displayed, else false.
34093 isVisible : function(){
34094 return this.el && !this.hidden;
34098 * Displays this menu relative to another element
34099 * @param {String/HTMLElement/Roo.Element} element The element to align to
34100 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34101 * the element (defaults to this.defaultAlign)
34102 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34104 show : function(el, pos, parentMenu){
34105 this.parentMenu = parentMenu;
34109 this.fireEvent("beforeshow", this);
34110 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34114 * Displays this menu at a specific xy position
34115 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34116 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34118 showAt : function(xy, parentMenu, /* private: */_e){
34119 this.parentMenu = parentMenu;
34124 this.fireEvent("beforeshow", this);
34125 xy = this.el.adjustForConstraints(xy);
34129 this.hidden = false;
34131 this.fireEvent("show", this);
34134 focus : function(){
34136 this.doFocus.defer(50, this);
34140 doFocus : function(){
34142 this.focusEl.focus();
34147 * Hides this menu and optionally all parent menus
34148 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34150 hide : function(deep){
34151 if(this.el && this.isVisible()){
34152 this.fireEvent("beforehide", this);
34153 if(this.activeItem){
34154 this.activeItem.deactivate();
34155 this.activeItem = null;
34158 this.hidden = true;
34159 this.fireEvent("hide", this);
34161 if(deep === true && this.parentMenu){
34162 this.parentMenu.hide(true);
34167 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34168 * Any of the following are valid:
34170 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34171 * <li>An HTMLElement object which will be converted to a menu item</li>
34172 * <li>A menu item config object that will be created as a new menu item</li>
34173 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34174 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34179 var menu = new Roo.menu.Menu();
34181 // Create a menu item to add by reference
34182 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34184 // Add a bunch of items at once using different methods.
34185 // Only the last item added will be returned.
34186 var item = menu.add(
34187 menuItem, // add existing item by ref
34188 'Dynamic Item', // new TextItem
34189 '-', // new separator
34190 { text: 'Config Item' } // new item by config
34193 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34194 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34197 var a = arguments, l = a.length, item;
34198 for(var i = 0; i < l; i++){
34200 if ((typeof(el) == "object") && el.xtype && el.xns) {
34201 el = Roo.factory(el, Roo.menu);
34204 if(el.render){ // some kind of Item
34205 item = this.addItem(el);
34206 }else if(typeof el == "string"){ // string
34207 if(el == "separator" || el == "-"){
34208 item = this.addSeparator();
34210 item = this.addText(el);
34212 }else if(el.tagName || el.el){ // element
34213 item = this.addElement(el);
34214 }else if(typeof el == "object"){ // must be menu item config?
34215 item = this.addMenuItem(el);
34222 * Returns this menu's underlying {@link Roo.Element} object
34223 * @return {Roo.Element} The element
34225 getEl : function(){
34233 * Adds a separator bar to the menu
34234 * @return {Roo.menu.Item} The menu item that was added
34236 addSeparator : function(){
34237 return this.addItem(new Roo.menu.Separator());
34241 * Adds an {@link Roo.Element} object to the menu
34242 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34243 * @return {Roo.menu.Item} The menu item that was added
34245 addElement : function(el){
34246 return this.addItem(new Roo.menu.BaseItem(el));
34250 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34251 * @param {Roo.menu.Item} item The menu item to add
34252 * @return {Roo.menu.Item} The menu item that was added
34254 addItem : function(item){
34255 this.items.add(item);
34257 var li = document.createElement("li");
34258 li.className = "x-menu-list-item";
34259 this.ul.dom.appendChild(li);
34260 item.render(li, this);
34261 this.delayAutoWidth();
34267 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34268 * @param {Object} config A MenuItem config object
34269 * @return {Roo.menu.Item} The menu item that was added
34271 addMenuItem : function(config){
34272 if(!(config instanceof Roo.menu.Item)){
34273 if(typeof config.checked == "boolean"){ // must be check menu item config?
34274 config = new Roo.menu.CheckItem(config);
34276 config = new Roo.menu.Item(config);
34279 return this.addItem(config);
34283 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34284 * @param {String} text The text to display in the menu item
34285 * @return {Roo.menu.Item} The menu item that was added
34287 addText : function(text){
34288 return this.addItem(new Roo.menu.TextItem({ text : text }));
34292 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34293 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34294 * @param {Roo.menu.Item} item The menu item to add
34295 * @return {Roo.menu.Item} The menu item that was added
34297 insert : function(index, item){
34298 this.items.insert(index, item);
34300 var li = document.createElement("li");
34301 li.className = "x-menu-list-item";
34302 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34303 item.render(li, this);
34304 this.delayAutoWidth();
34310 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34311 * @param {Roo.menu.Item} item The menu item to remove
34313 remove : function(item){
34314 this.items.removeKey(item.id);
34319 * Removes and destroys all items in the menu
34321 removeAll : function(){
34323 while(f = this.items.first()){
34329 // MenuNav is a private utility class used internally by the Menu
34330 Roo.menu.MenuNav = function(menu){
34331 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34332 this.scope = this.menu = menu;
34335 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34336 doRelay : function(e, h){
34337 var k = e.getKey();
34338 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34339 this.menu.tryActivate(0, 1);
34342 return h.call(this.scope || this, e, this.menu);
34345 up : function(e, m){
34346 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34347 m.tryActivate(m.items.length-1, -1);
34351 down : function(e, m){
34352 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34353 m.tryActivate(0, 1);
34357 right : function(e, m){
34359 m.activeItem.expandMenu(true);
34363 left : function(e, m){
34365 if(m.parentMenu && m.parentMenu.activeItem){
34366 m.parentMenu.activeItem.activate();
34370 enter : function(e, m){
34372 e.stopPropagation();
34373 m.activeItem.onClick(e);
34374 m.fireEvent("click", this, m.activeItem);
34380 * Ext JS Library 1.1.1
34381 * Copyright(c) 2006-2007, Ext JS, LLC.
34383 * Originally Released Under LGPL - original licence link has changed is not relivant.
34386 * <script type="text/javascript">
34390 * @class Roo.menu.MenuMgr
34391 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34394 Roo.menu.MenuMgr = function(){
34395 var menus, active, groups = {}, attached = false, lastShow = new Date();
34397 // private - called when first menu is created
34400 active = new Roo.util.MixedCollection();
34401 Roo.get(document).addKeyListener(27, function(){
34402 if(active.length > 0){
34409 function hideAll(){
34410 if(active && active.length > 0){
34411 var c = active.clone();
34412 c.each(function(m){
34419 function onHide(m){
34421 if(active.length < 1){
34422 Roo.get(document).un("mousedown", onMouseDown);
34428 function onShow(m){
34429 var last = active.last();
34430 lastShow = new Date();
34433 Roo.get(document).on("mousedown", onMouseDown);
34437 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34438 m.parentMenu.activeChild = m;
34439 }else if(last && last.isVisible()){
34440 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34445 function onBeforeHide(m){
34447 m.activeChild.hide();
34449 if(m.autoHideTimer){
34450 clearTimeout(m.autoHideTimer);
34451 delete m.autoHideTimer;
34456 function onBeforeShow(m){
34457 var pm = m.parentMenu;
34458 if(!pm && !m.allowOtherMenus){
34460 }else if(pm && pm.activeChild && active != m){
34461 pm.activeChild.hide();
34466 function onMouseDown(e){
34467 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34473 function onBeforeCheck(mi, state){
34475 var g = groups[mi.group];
34476 for(var i = 0, l = g.length; i < l; i++){
34478 g[i].setChecked(false);
34487 * Hides all menus that are currently visible
34489 hideAll : function(){
34494 register : function(menu){
34498 menus[menu.id] = menu;
34499 menu.on("beforehide", onBeforeHide);
34500 menu.on("hide", onHide);
34501 menu.on("beforeshow", onBeforeShow);
34502 menu.on("show", onShow);
34503 var g = menu.group;
34504 if(g && menu.events["checkchange"]){
34508 groups[g].push(menu);
34509 menu.on("checkchange", onCheck);
34514 * Returns a {@link Roo.menu.Menu} object
34515 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34516 * be used to generate and return a new Menu instance.
34518 get : function(menu){
34519 if(typeof menu == "string"){ // menu id
34520 return menus[menu];
34521 }else if(menu.events){ // menu instance
34523 }else if(typeof menu.length == 'number'){ // array of menu items?
34524 return new Roo.menu.Menu({items:menu});
34525 }else{ // otherwise, must be a config
34526 return new Roo.menu.Menu(menu);
34531 unregister : function(menu){
34532 delete menus[menu.id];
34533 menu.un("beforehide", onBeforeHide);
34534 menu.un("hide", onHide);
34535 menu.un("beforeshow", onBeforeShow);
34536 menu.un("show", onShow);
34537 var g = menu.group;
34538 if(g && menu.events["checkchange"]){
34539 groups[g].remove(menu);
34540 menu.un("checkchange", onCheck);
34545 registerCheckable : function(menuItem){
34546 var g = menuItem.group;
34551 groups[g].push(menuItem);
34552 menuItem.on("beforecheckchange", onBeforeCheck);
34557 unregisterCheckable : function(menuItem){
34558 var g = menuItem.group;
34560 groups[g].remove(menuItem);
34561 menuItem.un("beforecheckchange", onBeforeCheck);
34567 * Ext JS Library 1.1.1
34568 * Copyright(c) 2006-2007, Ext JS, LLC.
34570 * Originally Released Under LGPL - original licence link has changed is not relivant.
34573 * <script type="text/javascript">
34578 * @class Roo.menu.BaseItem
34579 * @extends Roo.Component
34580 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34581 * management and base configuration options shared by all menu components.
34583 * Creates a new BaseItem
34584 * @param {Object} config Configuration options
34586 Roo.menu.BaseItem = function(config){
34587 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34592 * Fires when this item is clicked
34593 * @param {Roo.menu.BaseItem} this
34594 * @param {Roo.EventObject} e
34599 * Fires when this item is activated
34600 * @param {Roo.menu.BaseItem} this
34604 * @event deactivate
34605 * Fires when this item is deactivated
34606 * @param {Roo.menu.BaseItem} this
34612 this.on("click", this.handler, this.scope, true);
34616 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34618 * @cfg {Function} handler
34619 * A function that will handle the click event of this menu item (defaults to undefined)
34622 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34624 canActivate : false,
34626 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34628 activeClass : "x-menu-item-active",
34630 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34632 hideOnClick : true,
34634 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34639 ctype: "Roo.menu.BaseItem",
34642 actionMode : "container",
34645 render : function(container, parentMenu){
34646 this.parentMenu = parentMenu;
34647 Roo.menu.BaseItem.superclass.render.call(this, container);
34648 this.container.menuItemId = this.id;
34652 onRender : function(container, position){
34653 this.el = Roo.get(this.el);
34654 container.dom.appendChild(this.el.dom);
34658 onClick : function(e){
34659 if(!this.disabled && this.fireEvent("click", this, e) !== false
34660 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34661 this.handleClick(e);
34668 activate : function(){
34672 var li = this.container;
34673 li.addClass(this.activeClass);
34674 this.region = li.getRegion().adjust(2, 2, -2, -2);
34675 this.fireEvent("activate", this);
34680 deactivate : function(){
34681 this.container.removeClass(this.activeClass);
34682 this.fireEvent("deactivate", this);
34686 shouldDeactivate : function(e){
34687 return !this.region || !this.region.contains(e.getPoint());
34691 handleClick : function(e){
34692 if(this.hideOnClick){
34693 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34698 expandMenu : function(autoActivate){
34703 hideMenu : function(){
34708 * Ext JS Library 1.1.1
34709 * Copyright(c) 2006-2007, Ext JS, LLC.
34711 * Originally Released Under LGPL - original licence link has changed is not relivant.
34714 * <script type="text/javascript">
34718 * @class Roo.menu.Adapter
34719 * @extends Roo.menu.BaseItem
34720 * 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.
34721 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34723 * Creates a new Adapter
34724 * @param {Object} config Configuration options
34726 Roo.menu.Adapter = function(component, config){
34727 Roo.menu.Adapter.superclass.constructor.call(this, config);
34728 this.component = component;
34730 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34732 canActivate : true,
34735 onRender : function(container, position){
34736 this.component.render(container);
34737 this.el = this.component.getEl();
34741 activate : function(){
34745 this.component.focus();
34746 this.fireEvent("activate", this);
34751 deactivate : function(){
34752 this.fireEvent("deactivate", this);
34756 disable : function(){
34757 this.component.disable();
34758 Roo.menu.Adapter.superclass.disable.call(this);
34762 enable : function(){
34763 this.component.enable();
34764 Roo.menu.Adapter.superclass.enable.call(this);
34768 * Ext JS Library 1.1.1
34769 * Copyright(c) 2006-2007, Ext JS, LLC.
34771 * Originally Released Under LGPL - original licence link has changed is not relivant.
34774 * <script type="text/javascript">
34778 * @class Roo.menu.TextItem
34779 * @extends Roo.menu.BaseItem
34780 * Adds a static text string to a menu, usually used as either a heading or group separator.
34781 * Note: old style constructor with text is still supported.
34784 * Creates a new TextItem
34785 * @param {Object} cfg Configuration
34787 Roo.menu.TextItem = function(cfg){
34788 if (typeof(cfg) == 'string') {
34791 Roo.apply(this,cfg);
34794 Roo.menu.TextItem.superclass.constructor.call(this);
34797 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34799 * @cfg {Boolean} text Text to show on item.
34804 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34806 hideOnClick : false,
34808 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34810 itemCls : "x-menu-text",
34813 onRender : function(){
34814 var s = document.createElement("span");
34815 s.className = this.itemCls;
34816 s.innerHTML = this.text;
34818 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34822 * Ext JS Library 1.1.1
34823 * Copyright(c) 2006-2007, Ext JS, LLC.
34825 * Originally Released Under LGPL - original licence link has changed is not relivant.
34828 * <script type="text/javascript">
34832 * @class Roo.menu.Separator
34833 * @extends Roo.menu.BaseItem
34834 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34835 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34837 * @param {Object} config Configuration options
34839 Roo.menu.Separator = function(config){
34840 Roo.menu.Separator.superclass.constructor.call(this, config);
34843 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34845 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34847 itemCls : "x-menu-sep",
34849 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34851 hideOnClick : false,
34854 onRender : function(li){
34855 var s = document.createElement("span");
34856 s.className = this.itemCls;
34857 s.innerHTML = " ";
34859 li.addClass("x-menu-sep-li");
34860 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34864 * Ext JS Library 1.1.1
34865 * Copyright(c) 2006-2007, Ext JS, LLC.
34867 * Originally Released Under LGPL - original licence link has changed is not relivant.
34870 * <script type="text/javascript">
34873 * @class Roo.menu.Item
34874 * @extends Roo.menu.BaseItem
34875 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34876 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34877 * activation and click handling.
34879 * Creates a new Item
34880 * @param {Object} config Configuration options
34882 Roo.menu.Item = function(config){
34883 Roo.menu.Item.superclass.constructor.call(this, config);
34885 this.menu = Roo.menu.MenuMgr.get(this.menu);
34888 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34891 * @cfg {String} text
34892 * The text to show on the menu item.
34896 * @cfg {String} HTML to render in menu
34897 * The text to show on the menu item (HTML version).
34901 * @cfg {String} icon
34902 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34906 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34908 itemCls : "x-menu-item",
34910 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34912 canActivate : true,
34914 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34917 // doc'd in BaseItem
34921 ctype: "Roo.menu.Item",
34924 onRender : function(container, position){
34925 var el = document.createElement("a");
34926 el.hideFocus = true;
34927 el.unselectable = "on";
34928 el.href = this.href || "#";
34929 if(this.hrefTarget){
34930 el.target = this.hrefTarget;
34932 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34934 var html = this.html.length ? this.html : String.format('{0}',this.text);
34936 el.innerHTML = String.format(
34937 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
34938 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
34940 Roo.menu.Item.superclass.onRender.call(this, container, position);
34944 * Sets the text to display in this menu item
34945 * @param {String} text The text to display
34946 * @param {Boolean} isHTML true to indicate text is pure html.
34948 setText : function(text, isHTML){
34956 var html = this.html.length ? this.html : String.format('{0}',this.text);
34958 this.el.update(String.format(
34959 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
34960 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34961 this.parentMenu.autoWidth();
34966 handleClick : function(e){
34967 if(!this.href){ // if no link defined, stop the event automatically
34970 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34974 activate : function(autoExpand){
34975 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34985 shouldDeactivate : function(e){
34986 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34987 if(this.menu && this.menu.isVisible()){
34988 return !this.menu.getEl().getRegion().contains(e.getPoint());
34996 deactivate : function(){
34997 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
35002 expandMenu : function(autoActivate){
35003 if(!this.disabled && this.menu){
35004 clearTimeout(this.hideTimer);
35005 delete this.hideTimer;
35006 if(!this.menu.isVisible() && !this.showTimer){
35007 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
35008 }else if (this.menu.isVisible() && autoActivate){
35009 this.menu.tryActivate(0, 1);
35015 deferExpand : function(autoActivate){
35016 delete this.showTimer;
35017 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35019 this.menu.tryActivate(0, 1);
35024 hideMenu : function(){
35025 clearTimeout(this.showTimer);
35026 delete this.showTimer;
35027 if(!this.hideTimer && this.menu && this.menu.isVisible()){
35028 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35033 deferHide : function(){
35034 delete this.hideTimer;
35039 * Ext JS Library 1.1.1
35040 * Copyright(c) 2006-2007, Ext JS, LLC.
35042 * Originally Released Under LGPL - original licence link has changed is not relivant.
35045 * <script type="text/javascript">
35049 * @class Roo.menu.CheckItem
35050 * @extends Roo.menu.Item
35051 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35053 * Creates a new CheckItem
35054 * @param {Object} config Configuration options
35056 Roo.menu.CheckItem = function(config){
35057 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35060 * @event beforecheckchange
35061 * Fires before the checked value is set, providing an opportunity to cancel if needed
35062 * @param {Roo.menu.CheckItem} this
35063 * @param {Boolean} checked The new checked value that will be set
35065 "beforecheckchange" : true,
35067 * @event checkchange
35068 * Fires after the checked value has been set
35069 * @param {Roo.menu.CheckItem} this
35070 * @param {Boolean} checked The checked value that was set
35072 "checkchange" : true
35074 if(this.checkHandler){
35075 this.on('checkchange', this.checkHandler, this.scope);
35078 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35080 * @cfg {String} group
35081 * All check items with the same group name will automatically be grouped into a single-select
35082 * radio button group (defaults to '')
35085 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35087 itemCls : "x-menu-item x-menu-check-item",
35089 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35091 groupClass : "x-menu-group-item",
35094 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35095 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35096 * initialized with checked = true will be rendered as checked.
35101 ctype: "Roo.menu.CheckItem",
35104 onRender : function(c){
35105 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35107 this.el.addClass(this.groupClass);
35109 Roo.menu.MenuMgr.registerCheckable(this);
35111 this.checked = false;
35112 this.setChecked(true, true);
35117 destroy : function(){
35119 Roo.menu.MenuMgr.unregisterCheckable(this);
35121 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35125 * Set the checked state of this item
35126 * @param {Boolean} checked The new checked value
35127 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35129 setChecked : function(state, suppressEvent){
35130 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35131 if(this.container){
35132 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35134 this.checked = state;
35135 if(suppressEvent !== true){
35136 this.fireEvent("checkchange", this, state);
35142 handleClick : function(e){
35143 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35144 this.setChecked(!this.checked);
35146 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35150 * Ext JS Library 1.1.1
35151 * Copyright(c) 2006-2007, Ext JS, LLC.
35153 * Originally Released Under LGPL - original licence link has changed is not relivant.
35156 * <script type="text/javascript">
35160 * @class Roo.menu.DateItem
35161 * @extends Roo.menu.Adapter
35162 * A menu item that wraps the {@link Roo.DatPicker} component.
35164 * Creates a new DateItem
35165 * @param {Object} config Configuration options
35167 Roo.menu.DateItem = function(config){
35168 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35169 /** The Roo.DatePicker object @type Roo.DatePicker */
35170 this.picker = this.component;
35171 this.addEvents({select: true});
35173 this.picker.on("render", function(picker){
35174 picker.getEl().swallowEvent("click");
35175 picker.container.addClass("x-menu-date-item");
35178 this.picker.on("select", this.onSelect, this);
35181 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35183 onSelect : function(picker, date){
35184 this.fireEvent("select", this, date, picker);
35185 Roo.menu.DateItem.superclass.handleClick.call(this);
35189 * Ext JS Library 1.1.1
35190 * Copyright(c) 2006-2007, Ext JS, LLC.
35192 * Originally Released Under LGPL - original licence link has changed is not relivant.
35195 * <script type="text/javascript">
35199 * @class Roo.menu.ColorItem
35200 * @extends Roo.menu.Adapter
35201 * A menu item that wraps the {@link Roo.ColorPalette} component.
35203 * Creates a new ColorItem
35204 * @param {Object} config Configuration options
35206 Roo.menu.ColorItem = function(config){
35207 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35208 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35209 this.palette = this.component;
35210 this.relayEvents(this.palette, ["select"]);
35211 if(this.selectHandler){
35212 this.on('select', this.selectHandler, this.scope);
35215 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35217 * Ext JS Library 1.1.1
35218 * Copyright(c) 2006-2007, Ext JS, LLC.
35220 * Originally Released Under LGPL - original licence link has changed is not relivant.
35223 * <script type="text/javascript">
35228 * @class Roo.menu.DateMenu
35229 * @extends Roo.menu.Menu
35230 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35232 * Creates a new DateMenu
35233 * @param {Object} config Configuration options
35235 Roo.menu.DateMenu = function(config){
35236 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35238 var di = new Roo.menu.DateItem(config);
35241 * The {@link Roo.DatePicker} instance for this DateMenu
35244 this.picker = di.picker;
35247 * @param {DatePicker} picker
35248 * @param {Date} date
35250 this.relayEvents(di, ["select"]);
35252 this.on('beforeshow', function(){
35254 this.picker.hideMonthPicker(true);
35258 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35262 * Ext JS Library 1.1.1
35263 * Copyright(c) 2006-2007, Ext JS, LLC.
35265 * Originally Released Under LGPL - original licence link has changed is not relivant.
35268 * <script type="text/javascript">
35273 * @class Roo.menu.ColorMenu
35274 * @extends Roo.menu.Menu
35275 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35277 * Creates a new ColorMenu
35278 * @param {Object} config Configuration options
35280 Roo.menu.ColorMenu = function(config){
35281 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35283 var ci = new Roo.menu.ColorItem(config);
35286 * The {@link Roo.ColorPalette} instance for this ColorMenu
35287 * @type ColorPalette
35289 this.palette = ci.palette;
35292 * @param {ColorPalette} palette
35293 * @param {String} color
35295 this.relayEvents(ci, ["select"]);
35297 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35299 * Ext JS Library 1.1.1
35300 * Copyright(c) 2006-2007, Ext JS, LLC.
35302 * Originally Released Under LGPL - original licence link has changed is not relivant.
35305 * <script type="text/javascript">
35309 * @class Roo.form.Field
35310 * @extends Roo.BoxComponent
35311 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35313 * Creates a new Field
35314 * @param {Object} config Configuration options
35316 Roo.form.Field = function(config){
35317 Roo.form.Field.superclass.constructor.call(this, config);
35320 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35322 * @cfg {String} fieldLabel Label to use when rendering a form.
35325 * @cfg {String} qtip Mouse over tip
35329 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35331 invalidClass : "x-form-invalid",
35333 * @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")
35335 invalidText : "The value in this field is invalid",
35337 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35339 focusClass : "x-form-focus",
35341 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35342 automatic validation (defaults to "keyup").
35344 validationEvent : "keyup",
35346 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35348 validateOnBlur : true,
35350 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35352 validationDelay : 250,
35354 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35355 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35357 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35359 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35361 fieldClass : "x-form-field",
35363 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35366 ----------- ----------------------------------------------------------------------
35367 qtip Display a quick tip when the user hovers over the field
35368 title Display a default browser title attribute popup
35369 under Add a block div beneath the field containing the error text
35370 side Add an error icon to the right of the field with a popup on hover
35371 [element id] Add the error text directly to the innerHTML of the specified element
35374 msgTarget : 'qtip',
35376 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35381 * @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.
35386 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35391 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35393 inputType : undefined,
35396 * @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).
35398 tabIndex : undefined,
35401 isFormField : true,
35406 * @property {Roo.Element} fieldEl
35407 * Element Containing the rendered Field (with label etc.)
35410 * @cfg {Mixed} value A value to initialize this field with.
35415 * @cfg {String} name The field's HTML name attribute.
35418 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35422 initComponent : function(){
35423 Roo.form.Field.superclass.initComponent.call(this);
35427 * Fires when this field receives input focus.
35428 * @param {Roo.form.Field} this
35433 * Fires when this field loses input focus.
35434 * @param {Roo.form.Field} this
35438 * @event specialkey
35439 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35440 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35441 * @param {Roo.form.Field} this
35442 * @param {Roo.EventObject} e The event object
35447 * Fires just before the field blurs if the field value has changed.
35448 * @param {Roo.form.Field} this
35449 * @param {Mixed} newValue The new value
35450 * @param {Mixed} oldValue The original value
35455 * Fires after the field has been marked as invalid.
35456 * @param {Roo.form.Field} this
35457 * @param {String} msg The validation message
35462 * Fires after the field has been validated with no errors.
35463 * @param {Roo.form.Field} this
35468 * Fires after the key up
35469 * @param {Roo.form.Field} this
35470 * @param {Roo.EventObject} e The event Object
35477 * Returns the name attribute of the field if available
35478 * @return {String} name The field name
35480 getName: function(){
35481 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35485 onRender : function(ct, position){
35486 Roo.form.Field.superclass.onRender.call(this, ct, position);
35488 var cfg = this.getAutoCreate();
35490 cfg.name = this.name || this.id;
35492 if(this.inputType){
35493 cfg.type = this.inputType;
35495 this.el = ct.createChild(cfg, position);
35497 var type = this.el.dom.type;
35499 if(type == 'password'){
35502 this.el.addClass('x-form-'+type);
35505 this.el.dom.readOnly = true;
35507 if(this.tabIndex !== undefined){
35508 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35511 this.el.addClass([this.fieldClass, this.cls]);
35516 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35517 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35518 * @return {Roo.form.Field} this
35520 applyTo : function(target){
35521 this.allowDomMove = false;
35522 this.el = Roo.get(target);
35523 this.render(this.el.dom.parentNode);
35528 initValue : function(){
35529 if(this.value !== undefined){
35530 this.setValue(this.value);
35531 }else if(this.el.dom.value.length > 0){
35532 this.setValue(this.el.dom.value);
35537 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35539 isDirty : function() {
35540 if(this.disabled) {
35543 return String(this.getValue()) !== String(this.originalValue);
35547 afterRender : function(){
35548 Roo.form.Field.superclass.afterRender.call(this);
35553 fireKey : function(e){
35554 //Roo.log('field ' + e.getKey());
35555 if(e.isNavKeyPress()){
35556 this.fireEvent("specialkey", this, e);
35561 * Resets the current field value to the originally loaded value and clears any validation messages
35563 reset : function(){
35564 this.setValue(this.originalValue);
35565 this.clearInvalid();
35569 initEvents : function(){
35570 // safari killled keypress - so keydown is now used..
35571 this.el.on("keydown" , this.fireKey, this);
35572 this.el.on("focus", this.onFocus, this);
35573 this.el.on("blur", this.onBlur, this);
35574 this.el.relayEvent('keyup', this);
35576 // reference to original value for reset
35577 this.originalValue = this.getValue();
35581 onFocus : function(){
35582 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35583 this.el.addClass(this.focusClass);
35585 if(!this.hasFocus){
35586 this.hasFocus = true;
35587 this.startValue = this.getValue();
35588 this.fireEvent("focus", this);
35592 beforeBlur : Roo.emptyFn,
35595 onBlur : function(){
35597 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35598 this.el.removeClass(this.focusClass);
35600 this.hasFocus = false;
35601 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35604 var v = this.getValue();
35605 if(String(v) !== String(this.startValue)){
35606 this.fireEvent('change', this, v, this.startValue);
35608 this.fireEvent("blur", this);
35612 * Returns whether or not the field value is currently valid
35613 * @param {Boolean} preventMark True to disable marking the field invalid
35614 * @return {Boolean} True if the value is valid, else false
35616 isValid : function(preventMark){
35620 var restore = this.preventMark;
35621 this.preventMark = preventMark === true;
35622 var v = this.validateValue(this.processValue(this.getRawValue()));
35623 this.preventMark = restore;
35628 * Validates the field value
35629 * @return {Boolean} True if the value is valid, else false
35631 validate : function(){
35632 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35633 this.clearInvalid();
35639 processValue : function(value){
35644 // Subclasses should provide the validation implementation by overriding this
35645 validateValue : function(value){
35650 * Mark this field as invalid
35651 * @param {String} msg The validation message
35653 markInvalid : function(msg){
35654 if(!this.rendered || this.preventMark){ // not rendered
35657 this.el.addClass(this.invalidClass);
35658 msg = msg || this.invalidText;
35659 switch(this.msgTarget){
35661 this.el.dom.qtip = msg;
35662 this.el.dom.qclass = 'x-form-invalid-tip';
35663 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35664 Roo.QuickTips.enable();
35668 this.el.dom.title = msg;
35672 var elp = this.el.findParent('.x-form-element', 5, true);
35673 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35674 this.errorEl.setWidth(elp.getWidth(true)-20);
35676 this.errorEl.update(msg);
35677 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35680 if(!this.errorIcon){
35681 var elp = this.el.findParent('.x-form-element', 5, true);
35682 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35684 this.alignErrorIcon();
35685 this.errorIcon.dom.qtip = msg;
35686 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35687 this.errorIcon.show();
35688 this.on('resize', this.alignErrorIcon, this);
35691 var t = Roo.getDom(this.msgTarget);
35693 t.style.display = this.msgDisplay;
35696 this.fireEvent('invalid', this, msg);
35700 alignErrorIcon : function(){
35701 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35705 * Clear any invalid styles/messages for this field
35707 clearInvalid : function(){
35708 if(!this.rendered || this.preventMark){ // not rendered
35711 this.el.removeClass(this.invalidClass);
35712 switch(this.msgTarget){
35714 this.el.dom.qtip = '';
35717 this.el.dom.title = '';
35721 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35725 if(this.errorIcon){
35726 this.errorIcon.dom.qtip = '';
35727 this.errorIcon.hide();
35728 this.un('resize', this.alignErrorIcon, this);
35732 var t = Roo.getDom(this.msgTarget);
35734 t.style.display = 'none';
35737 this.fireEvent('valid', this);
35741 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35742 * @return {Mixed} value The field value
35744 getRawValue : function(){
35745 var v = this.el.getValue();
35746 if(v === this.emptyText){
35753 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35754 * @return {Mixed} value The field value
35756 getValue : function(){
35757 var v = this.el.getValue();
35758 if(v === this.emptyText || v === undefined){
35765 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35766 * @param {Mixed} value The value to set
35768 setRawValue : function(v){
35769 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35773 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35774 * @param {Mixed} value The value to set
35776 setValue : function(v){
35779 this.el.dom.value = (v === null || v === undefined ? '' : v);
35784 adjustSize : function(w, h){
35785 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35786 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35790 adjustWidth : function(tag, w){
35791 tag = tag.toLowerCase();
35792 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35793 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35794 if(tag == 'input'){
35797 if(tag = 'textarea'){
35800 }else if(Roo.isOpera){
35801 if(tag == 'input'){
35804 if(tag = 'textarea'){
35814 // anything other than normal should be considered experimental
35815 Roo.form.Field.msgFx = {
35817 show: function(msgEl, f){
35818 msgEl.setDisplayed('block');
35821 hide : function(msgEl, f){
35822 msgEl.setDisplayed(false).update('');
35827 show: function(msgEl, f){
35828 msgEl.slideIn('t', {stopFx:true});
35831 hide : function(msgEl, f){
35832 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35837 show: function(msgEl, f){
35838 msgEl.fixDisplay();
35839 msgEl.alignTo(f.el, 'tl-tr');
35840 msgEl.slideIn('l', {stopFx:true});
35843 hide : function(msgEl, f){
35844 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35849 * Ext JS Library 1.1.1
35850 * Copyright(c) 2006-2007, Ext JS, LLC.
35852 * Originally Released Under LGPL - original licence link has changed is not relivant.
35855 * <script type="text/javascript">
35860 * @class Roo.form.TextField
35861 * @extends Roo.form.Field
35862 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35863 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35865 * Creates a new TextField
35866 * @param {Object} config Configuration options
35868 Roo.form.TextField = function(config){
35869 Roo.form.TextField.superclass.constructor.call(this, config);
35873 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35874 * according to the default logic, but this event provides a hook for the developer to apply additional
35875 * logic at runtime to resize the field if needed.
35876 * @param {Roo.form.Field} this This text field
35877 * @param {Number} width The new field width
35883 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35885 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35889 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35893 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35897 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35901 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35905 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35907 disableKeyFilter : false,
35909 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35913 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35917 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35919 maxLength : Number.MAX_VALUE,
35921 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35923 minLengthText : "The minimum length for this field is {0}",
35925 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35927 maxLengthText : "The maximum length for this field is {0}",
35929 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35931 selectOnFocus : false,
35933 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35935 blankText : "This field is required",
35937 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35938 * If available, this function will be called only after the basic validators all return true, and will be passed the
35939 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35943 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35944 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35945 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35949 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35953 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35957 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35958 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35960 emptyClass : 'x-form-empty-field',
35963 initEvents : function(){
35964 Roo.form.TextField.superclass.initEvents.call(this);
35965 if(this.validationEvent == 'keyup'){
35966 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35967 this.el.on('keyup', this.filterValidation, this);
35969 else if(this.validationEvent !== false){
35970 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35972 if(this.selectOnFocus || this.emptyText){
35973 this.on("focus", this.preFocus, this);
35974 if(this.emptyText){
35975 this.on('blur', this.postBlur, this);
35976 this.applyEmptyText();
35979 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35980 this.el.on("keypress", this.filterKeys, this);
35983 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35984 this.el.on("click", this.autoSize, this);
35988 processValue : function(value){
35989 if(this.stripCharsRe){
35990 var newValue = value.replace(this.stripCharsRe, '');
35991 if(newValue !== value){
35992 this.setRawValue(newValue);
35999 filterValidation : function(e){
36000 if(!e.isNavKeyPress()){
36001 this.validationTask.delay(this.validationDelay);
36006 onKeyUp : function(e){
36007 if(!e.isNavKeyPress()){
36013 * Resets the current field value to the originally-loaded value and clears any validation messages.
36014 * Also adds emptyText and emptyClass if the original value was blank.
36016 reset : function(){
36017 Roo.form.TextField.superclass.reset.call(this);
36018 this.applyEmptyText();
36021 applyEmptyText : function(){
36022 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
36023 this.setRawValue(this.emptyText);
36024 this.el.addClass(this.emptyClass);
36029 preFocus : function(){
36030 if(this.emptyText){
36031 if(this.el.dom.value == this.emptyText){
36032 this.setRawValue('');
36034 this.el.removeClass(this.emptyClass);
36036 if(this.selectOnFocus){
36037 this.el.dom.select();
36042 postBlur : function(){
36043 this.applyEmptyText();
36047 filterKeys : function(e){
36048 var k = e.getKey();
36049 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36052 var c = e.getCharCode(), cc = String.fromCharCode(c);
36053 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36056 if(!this.maskRe.test(cc)){
36061 setValue : function(v){
36062 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
36063 this.el.removeClass(this.emptyClass);
36065 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36066 this.applyEmptyText();
36071 * Validates a value according to the field's validation rules and marks the field as invalid
36072 * if the validation fails
36073 * @param {Mixed} value The value to validate
36074 * @return {Boolean} True if the value is valid, else false
36076 validateValue : function(value){
36077 if(value.length < 1 || value === this.emptyText){ // if it's blank
36078 if(this.allowBlank){
36079 this.clearInvalid();
36082 this.markInvalid(this.blankText);
36086 if(value.length < this.minLength){
36087 this.markInvalid(String.format(this.minLengthText, this.minLength));
36090 if(value.length > this.maxLength){
36091 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36095 var vt = Roo.form.VTypes;
36096 if(!vt[this.vtype](value, this)){
36097 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36101 if(typeof this.validator == "function"){
36102 var msg = this.validator(value);
36104 this.markInvalid(msg);
36108 if(this.regex && !this.regex.test(value)){
36109 this.markInvalid(this.regexText);
36116 * Selects text in this field
36117 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36118 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36120 selectText : function(start, end){
36121 var v = this.getRawValue();
36123 start = start === undefined ? 0 : start;
36124 end = end === undefined ? v.length : end;
36125 var d = this.el.dom;
36126 if(d.setSelectionRange){
36127 d.setSelectionRange(start, end);
36128 }else if(d.createTextRange){
36129 var range = d.createTextRange();
36130 range.moveStart("character", start);
36131 range.moveEnd("character", v.length-end);
36138 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36139 * This only takes effect if grow = true, and fires the autosize event.
36141 autoSize : function(){
36142 if(!this.grow || !this.rendered){
36146 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36149 var v = el.dom.value;
36150 var d = document.createElement('div');
36151 d.appendChild(document.createTextNode(v));
36155 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36156 this.el.setWidth(w);
36157 this.fireEvent("autosize", this, w);
36161 * Ext JS Library 1.1.1
36162 * Copyright(c) 2006-2007, Ext JS, LLC.
36164 * Originally Released Under LGPL - original licence link has changed is not relivant.
36167 * <script type="text/javascript">
36171 * @class Roo.form.Hidden
36172 * @extends Roo.form.TextField
36173 * Simple Hidden element used on forms
36175 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36178 * Creates a new Hidden form element.
36179 * @param {Object} config Configuration options
36184 // easy hidden field...
36185 Roo.form.Hidden = function(config){
36186 Roo.form.Hidden.superclass.constructor.call(this, config);
36189 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36191 inputType: 'hidden',
36194 labelSeparator: '',
36196 itemCls : 'x-form-item-display-none'
36204 * Ext JS Library 1.1.1
36205 * Copyright(c) 2006-2007, Ext JS, LLC.
36207 * Originally Released Under LGPL - original licence link has changed is not relivant.
36210 * <script type="text/javascript">
36214 * @class Roo.form.TriggerField
36215 * @extends Roo.form.TextField
36216 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36217 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36218 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36219 * for which you can provide a custom implementation. For example:
36221 var trigger = new Roo.form.TriggerField();
36222 trigger.onTriggerClick = myTriggerFn;
36223 trigger.applyTo('my-field');
36226 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36227 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36228 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36229 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36231 * Create a new TriggerField.
36232 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36233 * to the base TextField)
36235 Roo.form.TriggerField = function(config){
36236 this.mimicing = false;
36237 Roo.form.TriggerField.superclass.constructor.call(this, config);
36240 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36242 * @cfg {String} triggerClass A CSS class to apply to the trigger
36245 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36246 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36248 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36250 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36254 /** @cfg {Boolean} grow @hide */
36255 /** @cfg {Number} growMin @hide */
36256 /** @cfg {Number} growMax @hide */
36262 autoSize: Roo.emptyFn,
36266 deferHeight : true,
36269 actionMode : 'wrap',
36271 onResize : function(w, h){
36272 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36273 if(typeof w == 'number'){
36274 var x = w - this.trigger.getWidth();
36275 this.el.setWidth(this.adjustWidth('input', x));
36276 this.trigger.setStyle('left', x+'px');
36281 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36284 getResizeEl : function(){
36289 getPositionEl : function(){
36294 alignErrorIcon : function(){
36295 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36299 onRender : function(ct, position){
36300 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36301 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36302 this.trigger = this.wrap.createChild(this.triggerConfig ||
36303 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36304 if(this.hideTrigger){
36305 this.trigger.setDisplayed(false);
36307 this.initTrigger();
36309 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36314 initTrigger : function(){
36315 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36316 this.trigger.addClassOnOver('x-form-trigger-over');
36317 this.trigger.addClassOnClick('x-form-trigger-click');
36321 onDestroy : function(){
36323 this.trigger.removeAllListeners();
36324 this.trigger.remove();
36327 this.wrap.remove();
36329 Roo.form.TriggerField.superclass.onDestroy.call(this);
36333 onFocus : function(){
36334 Roo.form.TriggerField.superclass.onFocus.call(this);
36335 if(!this.mimicing){
36336 this.wrap.addClass('x-trigger-wrap-focus');
36337 this.mimicing = true;
36338 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36339 if(this.monitorTab){
36340 this.el.on("keydown", this.checkTab, this);
36346 checkTab : function(e){
36347 if(e.getKey() == e.TAB){
36348 this.triggerBlur();
36353 onBlur : function(){
36358 mimicBlur : function(e, t){
36359 if(!this.wrap.contains(t) && this.validateBlur()){
36360 this.triggerBlur();
36365 triggerBlur : function(){
36366 this.mimicing = false;
36367 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36368 if(this.monitorTab){
36369 this.el.un("keydown", this.checkTab, this);
36371 this.wrap.removeClass('x-trigger-wrap-focus');
36372 Roo.form.TriggerField.superclass.onBlur.call(this);
36376 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36377 validateBlur : function(e, t){
36382 onDisable : function(){
36383 Roo.form.TriggerField.superclass.onDisable.call(this);
36385 this.wrap.addClass('x-item-disabled');
36390 onEnable : function(){
36391 Roo.form.TriggerField.superclass.onEnable.call(this);
36393 this.wrap.removeClass('x-item-disabled');
36398 onShow : function(){
36399 var ae = this.getActionEl();
36402 ae.dom.style.display = '';
36403 ae.dom.style.visibility = 'visible';
36409 onHide : function(){
36410 var ae = this.getActionEl();
36411 ae.dom.style.display = 'none';
36415 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36416 * by an implementing function.
36418 * @param {EventObject} e
36420 onTriggerClick : Roo.emptyFn
36423 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36424 // to be extended by an implementing class. For an example of implementing this class, see the custom
36425 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36426 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36427 initComponent : function(){
36428 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36430 this.triggerConfig = {
36431 tag:'span', cls:'x-form-twin-triggers', cn:[
36432 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36433 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36437 getTrigger : function(index){
36438 return this.triggers[index];
36441 initTrigger : function(){
36442 var ts = this.trigger.select('.x-form-trigger', true);
36443 this.wrap.setStyle('overflow', 'hidden');
36444 var triggerField = this;
36445 ts.each(function(t, all, index){
36446 t.hide = function(){
36447 var w = triggerField.wrap.getWidth();
36448 this.dom.style.display = 'none';
36449 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36451 t.show = function(){
36452 var w = triggerField.wrap.getWidth();
36453 this.dom.style.display = '';
36454 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36456 var triggerIndex = 'Trigger'+(index+1);
36458 if(this['hide'+triggerIndex]){
36459 t.dom.style.display = 'none';
36461 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36462 t.addClassOnOver('x-form-trigger-over');
36463 t.addClassOnClick('x-form-trigger-click');
36465 this.triggers = ts.elements;
36468 onTrigger1Click : Roo.emptyFn,
36469 onTrigger2Click : Roo.emptyFn
36472 * Ext JS Library 1.1.1
36473 * Copyright(c) 2006-2007, Ext JS, LLC.
36475 * Originally Released Under LGPL - original licence link has changed is not relivant.
36478 * <script type="text/javascript">
36482 * @class Roo.form.TextArea
36483 * @extends Roo.form.TextField
36484 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36485 * support for auto-sizing.
36487 * Creates a new TextArea
36488 * @param {Object} config Configuration options
36490 Roo.form.TextArea = function(config){
36491 Roo.form.TextArea.superclass.constructor.call(this, config);
36492 // these are provided exchanges for backwards compat
36493 // minHeight/maxHeight were replaced by growMin/growMax to be
36494 // compatible with TextField growing config values
36495 if(this.minHeight !== undefined){
36496 this.growMin = this.minHeight;
36498 if(this.maxHeight !== undefined){
36499 this.growMax = this.maxHeight;
36503 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36505 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36509 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36513 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36514 * in the field (equivalent to setting overflow: hidden, defaults to false)
36516 preventScrollbars: false,
36518 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36519 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36523 onRender : function(ct, position){
36525 this.defaultAutoCreate = {
36527 style:"width:300px;height:60px;",
36528 autocomplete: "off"
36531 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36533 this.textSizeEl = Roo.DomHelper.append(document.body, {
36534 tag: "pre", cls: "x-form-grow-sizer"
36536 if(this.preventScrollbars){
36537 this.el.setStyle("overflow", "hidden");
36539 this.el.setHeight(this.growMin);
36543 onDestroy : function(){
36544 if(this.textSizeEl){
36545 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36547 Roo.form.TextArea.superclass.onDestroy.call(this);
36551 onKeyUp : function(e){
36552 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36558 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36559 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36561 autoSize : function(){
36562 if(!this.grow || !this.textSizeEl){
36566 var v = el.dom.value;
36567 var ts = this.textSizeEl;
36570 ts.appendChild(document.createTextNode(v));
36573 Roo.fly(ts).setWidth(this.el.getWidth());
36575 v = "  ";
36578 v = v.replace(/\n/g, '<p> </p>');
36580 v += " \n ";
36583 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36584 if(h != this.lastHeight){
36585 this.lastHeight = h;
36586 this.el.setHeight(h);
36587 this.fireEvent("autosize", this, h);
36592 * Ext JS Library 1.1.1
36593 * Copyright(c) 2006-2007, Ext JS, LLC.
36595 * Originally Released Under LGPL - original licence link has changed is not relivant.
36598 * <script type="text/javascript">
36603 * @class Roo.form.NumberField
36604 * @extends Roo.form.TextField
36605 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36607 * Creates a new NumberField
36608 * @param {Object} config Configuration options
36610 Roo.form.NumberField = function(config){
36611 Roo.form.NumberField.superclass.constructor.call(this, config);
36614 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36616 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36618 fieldClass: "x-form-field x-form-num-field",
36620 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36622 allowDecimals : true,
36624 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36626 decimalSeparator : ".",
36628 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36630 decimalPrecision : 2,
36632 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36634 allowNegative : true,
36636 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36638 minValue : Number.NEGATIVE_INFINITY,
36640 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36642 maxValue : Number.MAX_VALUE,
36644 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36646 minText : "The minimum value for this field is {0}",
36648 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36650 maxText : "The maximum value for this field is {0}",
36652 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36653 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36655 nanText : "{0} is not a valid number",
36658 initEvents : function(){
36659 Roo.form.NumberField.superclass.initEvents.call(this);
36660 var allowed = "0123456789";
36661 if(this.allowDecimals){
36662 allowed += this.decimalSeparator;
36664 if(this.allowNegative){
36667 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36668 var keyPress = function(e){
36669 var k = e.getKey();
36670 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36673 var c = e.getCharCode();
36674 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36678 this.el.on("keypress", keyPress, this);
36682 validateValue : function(value){
36683 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36686 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36689 var num = this.parseValue(value);
36691 this.markInvalid(String.format(this.nanText, value));
36694 if(num < this.minValue){
36695 this.markInvalid(String.format(this.minText, this.minValue));
36698 if(num > this.maxValue){
36699 this.markInvalid(String.format(this.maxText, this.maxValue));
36705 getValue : function(){
36706 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36710 parseValue : function(value){
36711 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36712 return isNaN(value) ? '' : value;
36716 fixPrecision : function(value){
36717 var nan = isNaN(value);
36718 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36719 return nan ? '' : value;
36721 return parseFloat(value).toFixed(this.decimalPrecision);
36724 setValue : function(v){
36725 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36729 decimalPrecisionFcn : function(v){
36730 return Math.floor(v);
36733 beforeBlur : function(){
36734 var v = this.parseValue(this.getRawValue());
36736 this.setValue(this.fixPrecision(v));
36741 * Ext JS Library 1.1.1
36742 * Copyright(c) 2006-2007, Ext JS, LLC.
36744 * Originally Released Under LGPL - original licence link has changed is not relivant.
36747 * <script type="text/javascript">
36751 * @class Roo.form.DateField
36752 * @extends Roo.form.TriggerField
36753 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36755 * Create a new DateField
36756 * @param {Object} config
36758 Roo.form.DateField = function(config){
36759 Roo.form.DateField.superclass.constructor.call(this, config);
36765 * Fires when a date is selected
36766 * @param {Roo.form.DateField} combo This combo box
36767 * @param {Date} date The date selected
36774 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36775 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36776 this.ddMatch = null;
36777 if(this.disabledDates){
36778 var dd = this.disabledDates;
36780 for(var i = 0; i < dd.length; i++){
36782 if(i != dd.length-1) re += "|";
36784 this.ddMatch = new RegExp(re + ")");
36788 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36790 * @cfg {String} format
36791 * The default date format string which can be overriden for localization support. The format must be
36792 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36796 * @cfg {String} altFormats
36797 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36798 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36800 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36802 * @cfg {Array} disabledDays
36803 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36805 disabledDays : null,
36807 * @cfg {String} disabledDaysText
36808 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36810 disabledDaysText : "Disabled",
36812 * @cfg {Array} disabledDates
36813 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36814 * expression so they are very powerful. Some examples:
36816 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36817 * <li>["03/08", "09/16"] would disable those days for every year</li>
36818 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36819 * <li>["03/../2006"] would disable every day in March 2006</li>
36820 * <li>["^03"] would disable every day in every March</li>
36822 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36823 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36825 disabledDates : null,
36827 * @cfg {String} disabledDatesText
36828 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36830 disabledDatesText : "Disabled",
36832 * @cfg {Date/String} minValue
36833 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36834 * valid format (defaults to null).
36838 * @cfg {Date/String} maxValue
36839 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36840 * valid format (defaults to null).
36844 * @cfg {String} minText
36845 * The error text to display when the date in the cell is before minValue (defaults to
36846 * 'The date in this field must be after {minValue}').
36848 minText : "The date in this field must be equal to or after {0}",
36850 * @cfg {String} maxText
36851 * The error text to display when the date in the cell is after maxValue (defaults to
36852 * 'The date in this field must be before {maxValue}').
36854 maxText : "The date in this field must be equal to or before {0}",
36856 * @cfg {String} invalidText
36857 * The error text to display when the date in the field is invalid (defaults to
36858 * '{value} is not a valid date - it must be in the format {format}').
36860 invalidText : "{0} is not a valid date - it must be in the format {1}",
36862 * @cfg {String} triggerClass
36863 * An additional CSS class used to style the trigger button. The trigger will always get the
36864 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36865 * which displays a calendar icon).
36867 triggerClass : 'x-form-date-trigger',
36871 * @cfg {bool} useIso
36872 * if enabled, then the date field will use a hidden field to store the
36873 * real value as iso formated date. default (false)
36877 * @cfg {String/Object} autoCreate
36878 * A DomHelper element spec, or true for a default element spec (defaults to
36879 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36882 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36885 hiddenField: false,
36887 onRender : function(ct, position)
36889 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36891 this.el.dom.removeAttribute('name');
36892 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36894 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36895 // prevent input submission
36896 this.hiddenName = this.name;
36903 validateValue : function(value)
36905 value = this.formatDate(value);
36906 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36909 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36912 var svalue = value;
36913 value = this.parseDate(value);
36915 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36918 var time = value.getTime();
36919 if(this.minValue && time < this.minValue.getTime()){
36920 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36923 if(this.maxValue && time > this.maxValue.getTime()){
36924 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36927 if(this.disabledDays){
36928 var day = value.getDay();
36929 for(var i = 0; i < this.disabledDays.length; i++) {
36930 if(day === this.disabledDays[i]){
36931 this.markInvalid(this.disabledDaysText);
36936 var fvalue = this.formatDate(value);
36937 if(this.ddMatch && this.ddMatch.test(fvalue)){
36938 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36945 // Provides logic to override the default TriggerField.validateBlur which just returns true
36946 validateBlur : function(){
36947 return !this.menu || !this.menu.isVisible();
36951 * Returns the current date value of the date field.
36952 * @return {Date} The date value
36954 getValue : function(){
36956 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36960 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36961 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36962 * (the default format used is "m/d/y").
36965 //All of these calls set the same date value (May 4, 2006)
36967 //Pass a date object:
36968 var dt = new Date('5/4/06');
36969 dateField.setValue(dt);
36971 //Pass a date string (default format):
36972 dateField.setValue('5/4/06');
36974 //Pass a date string (custom format):
36975 dateField.format = 'Y-m-d';
36976 dateField.setValue('2006-5-4');
36978 * @param {String/Date} date The date or valid date string
36980 setValue : function(date){
36981 if (this.hiddenField) {
36982 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36984 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36988 parseDate : function(value){
36989 if(!value || value instanceof Date){
36992 var v = Date.parseDate(value, this.format);
36993 if(!v && this.altFormats){
36994 if(!this.altFormatsArray){
36995 this.altFormatsArray = this.altFormats.split("|");
36997 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36998 v = Date.parseDate(value, this.altFormatsArray[i]);
37005 formatDate : function(date, fmt){
37006 return (!date || !(date instanceof Date)) ?
37007 date : date.dateFormat(fmt || this.format);
37012 select: function(m, d){
37014 this.fireEvent('select', this, d);
37016 show : function(){ // retain focus styling
37020 this.focus.defer(10, this);
37021 var ml = this.menuListeners;
37022 this.menu.un("select", ml.select, this);
37023 this.menu.un("show", ml.show, this);
37024 this.menu.un("hide", ml.hide, this);
37029 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37030 onTriggerClick : function(){
37034 if(this.menu == null){
37035 this.menu = new Roo.menu.DateMenu();
37037 Roo.apply(this.menu.picker, {
37038 showClear: this.allowBlank,
37039 minDate : this.minValue,
37040 maxDate : this.maxValue,
37041 disabledDatesRE : this.ddMatch,
37042 disabledDatesText : this.disabledDatesText,
37043 disabledDays : this.disabledDays,
37044 disabledDaysText : this.disabledDaysText,
37045 format : this.format,
37046 minText : String.format(this.minText, this.formatDate(this.minValue)),
37047 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37049 this.menu.on(Roo.apply({}, this.menuListeners, {
37052 this.menu.picker.setValue(this.getValue() || new Date());
37053 this.menu.show(this.el, "tl-bl?");
37056 beforeBlur : function(){
37057 var v = this.parseDate(this.getRawValue());
37063 /** @cfg {Boolean} grow @hide */
37064 /** @cfg {Number} growMin @hide */
37065 /** @cfg {Number} growMax @hide */
37072 * Ext JS Library 1.1.1
37073 * Copyright(c) 2006-2007, Ext JS, LLC.
37075 * Originally Released Under LGPL - original licence link has changed is not relivant.
37078 * <script type="text/javascript">
37083 * @class Roo.form.ComboBox
37084 * @extends Roo.form.TriggerField
37085 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
37087 * Create a new ComboBox.
37088 * @param {Object} config Configuration options
37090 Roo.form.ComboBox = function(config){
37091 Roo.form.ComboBox.superclass.constructor.call(this, config);
37095 * Fires when the dropdown list is expanded
37096 * @param {Roo.form.ComboBox} combo This combo box
37101 * Fires when the dropdown list is collapsed
37102 * @param {Roo.form.ComboBox} combo This combo box
37106 * @event beforeselect
37107 * Fires before a list item is selected. Return false to cancel the selection.
37108 * @param {Roo.form.ComboBox} combo This combo box
37109 * @param {Roo.data.Record} record The data record returned from the underlying store
37110 * @param {Number} index The index of the selected item in the dropdown list
37112 'beforeselect' : true,
37115 * Fires when a list item is selected
37116 * @param {Roo.form.ComboBox} combo This combo box
37117 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37118 * @param {Number} index The index of the selected item in the dropdown list
37122 * @event beforequery
37123 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37124 * The event object passed has these properties:
37125 * @param {Roo.form.ComboBox} combo This combo box
37126 * @param {String} query The query
37127 * @param {Boolean} forceAll true to force "all" query
37128 * @param {Boolean} cancel true to cancel the query
37129 * @param {Object} e The query event object
37131 'beforequery': true,
37134 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37135 * @param {Roo.form.ComboBox} combo This combo box
37140 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37141 * @param {Roo.form.ComboBox} combo This combo box
37142 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37148 if(this.transform){
37149 this.allowDomMove = false;
37150 var s = Roo.getDom(this.transform);
37151 if(!this.hiddenName){
37152 this.hiddenName = s.name;
37155 this.mode = 'local';
37156 var d = [], opts = s.options;
37157 for(var i = 0, len = opts.length;i < len; i++){
37159 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37161 this.value = value;
37163 d.push([value, o.text]);
37165 this.store = new Roo.data.SimpleStore({
37167 fields: ['value', 'text'],
37170 this.valueField = 'value';
37171 this.displayField = 'text';
37173 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37174 if(!this.lazyRender){
37175 this.target = true;
37176 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37177 s.parentNode.removeChild(s); // remove it
37178 this.render(this.el.parentNode);
37180 s.parentNode.removeChild(s); // remove it
37185 this.store = Roo.factory(this.store, Roo.data);
37188 this.selectedIndex = -1;
37189 if(this.mode == 'local'){
37190 if(config.queryDelay === undefined){
37191 this.queryDelay = 10;
37193 if(config.minChars === undefined){
37199 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37201 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37204 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37205 * rendering into an Roo.Editor, defaults to false)
37208 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37209 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37212 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37215 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37216 * the dropdown list (defaults to undefined, with no header element)
37220 * @cfg {String/Roo.Template} tpl The template to use to render the output
37224 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37226 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37228 listWidth: undefined,
37230 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37231 * mode = 'remote' or 'text' if mode = 'local')
37233 displayField: undefined,
37235 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37236 * mode = 'remote' or 'value' if mode = 'local').
37237 * Note: use of a valueField requires the user make a selection
37238 * in order for a value to be mapped.
37240 valueField: undefined,
37242 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37243 * field's data value (defaults to the underlying DOM element's name)
37245 hiddenName: undefined,
37247 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37251 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37253 selectedClass: 'x-combo-selected',
37255 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37256 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37257 * which displays a downward arrow icon).
37259 triggerClass : 'x-form-arrow-trigger',
37261 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37265 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37266 * anchor positions (defaults to 'tl-bl')
37268 listAlign: 'tl-bl?',
37270 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37274 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37275 * query specified by the allQuery config option (defaults to 'query')
37277 triggerAction: 'query',
37279 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37280 * (defaults to 4, does not apply if editable = false)
37284 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37285 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37289 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37290 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37294 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37295 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37299 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37300 * when editable = true (defaults to false)
37302 selectOnFocus:false,
37304 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37306 queryParam: 'query',
37308 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37309 * when mode = 'remote' (defaults to 'Loading...')
37311 loadingText: 'Loading...',
37313 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37317 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37321 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37322 * traditional select (defaults to true)
37326 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37330 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37334 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37335 * listWidth has a higher value)
37339 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37340 * allow the user to set arbitrary text into the field (defaults to false)
37342 forceSelection:false,
37344 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37345 * if typeAhead = true (defaults to 250)
37347 typeAheadDelay : 250,
37349 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37350 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37352 valueNotFoundText : undefined,
37354 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37356 blockFocus : false,
37359 * @cfg {Boolean} disableClear Disable showing of clear button.
37361 disableClear : false,
37363 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37365 alwaysQuery : false,
37373 onRender : function(ct, position){
37374 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37375 if(this.hiddenName){
37376 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37378 this.hiddenField.value =
37379 this.hiddenValue !== undefined ? this.hiddenValue :
37380 this.value !== undefined ? this.value : '';
37382 // prevent input submission
37383 this.el.dom.removeAttribute('name');
37386 this.el.dom.setAttribute('autocomplete', 'off');
37389 var cls = 'x-combo-list';
37391 this.list = new Roo.Layer({
37392 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37395 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37396 this.list.setWidth(lw);
37397 this.list.swallowEvent('mousewheel');
37398 this.assetHeight = 0;
37401 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37402 this.assetHeight += this.header.getHeight();
37405 this.innerList = this.list.createChild({cls:cls+'-inner'});
37406 this.innerList.on('mouseover', this.onViewOver, this);
37407 this.innerList.on('mousemove', this.onViewMove, this);
37408 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37410 if(this.allowBlank && !this.pageSize && !this.disableClear){
37411 this.footer = this.list.createChild({cls:cls+'-ft'});
37412 this.pageTb = new Roo.Toolbar(this.footer);
37416 this.footer = this.list.createChild({cls:cls+'-ft'});
37417 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37418 {pageSize: this.pageSize});
37422 if (this.pageTb && this.allowBlank && !this.disableClear) {
37424 this.pageTb.add(new Roo.Toolbar.Fill(), {
37425 cls: 'x-btn-icon x-btn-clear',
37427 handler: function()
37430 _this.clearValue();
37431 _this.onSelect(false, -1);
37436 this.assetHeight += this.footer.getHeight();
37441 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37444 this.view = new Roo.View(this.innerList, this.tpl, {
37445 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37448 this.view.on('click', this.onViewClick, this);
37450 this.store.on('beforeload', this.onBeforeLoad, this);
37451 this.store.on('load', this.onLoad, this);
37452 this.store.on('loadexception', this.collapse, this);
37454 if(this.resizable){
37455 this.resizer = new Roo.Resizable(this.list, {
37456 pinned:true, handles:'se'
37458 this.resizer.on('resize', function(r, w, h){
37459 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37460 this.listWidth = w;
37461 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37462 this.restrictHeight();
37464 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37466 if(!this.editable){
37467 this.editable = true;
37468 this.setEditable(false);
37472 if (typeof(this.events.add.listeners) != 'undefined') {
37474 this.addicon = this.wrap.createChild(
37475 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37477 this.addicon.on('click', function(e) {
37478 this.fireEvent('add', this);
37481 if (typeof(this.events.edit.listeners) != 'undefined') {
37483 this.editicon = this.wrap.createChild(
37484 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37485 if (this.addicon) {
37486 this.editicon.setStyle('margin-left', '40px');
37488 this.editicon.on('click', function(e) {
37490 // we fire even if inothing is selected..
37491 this.fireEvent('edit', this, this.lastData );
37501 initEvents : function(){
37502 Roo.form.ComboBox.superclass.initEvents.call(this);
37504 this.keyNav = new Roo.KeyNav(this.el, {
37505 "up" : function(e){
37506 this.inKeyMode = true;
37510 "down" : function(e){
37511 if(!this.isExpanded()){
37512 this.onTriggerClick();
37514 this.inKeyMode = true;
37519 "enter" : function(e){
37520 this.onViewClick();
37524 "esc" : function(e){
37528 "tab" : function(e){
37529 this.onViewClick(false);
37535 doRelay : function(foo, bar, hname){
37536 if(hname == 'down' || this.scope.isExpanded()){
37537 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37544 this.queryDelay = Math.max(this.queryDelay || 10,
37545 this.mode == 'local' ? 10 : 250);
37546 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37547 if(this.typeAhead){
37548 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37550 if(this.editable !== false){
37551 this.el.on("keyup", this.onKeyUp, this);
37553 if(this.forceSelection){
37554 this.on('blur', this.doForce, this);
37558 onDestroy : function(){
37560 this.view.setStore(null);
37561 this.view.el.removeAllListeners();
37562 this.view.el.remove();
37563 this.view.purgeListeners();
37566 this.list.destroy();
37569 this.store.un('beforeload', this.onBeforeLoad, this);
37570 this.store.un('load', this.onLoad, this);
37571 this.store.un('loadexception', this.collapse, this);
37573 Roo.form.ComboBox.superclass.onDestroy.call(this);
37577 fireKey : function(e){
37578 if(e.isNavKeyPress() && !this.list.isVisible()){
37579 this.fireEvent("specialkey", this, e);
37584 onResize: function(w, h){
37585 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37587 if(typeof w != 'number'){
37588 // we do not handle it!?!?
37591 var tw = this.trigger.getWidth();
37592 tw += this.addicon ? this.addicon.getWidth() : 0;
37593 tw += this.editicon ? this.editicon.getWidth() : 0;
37595 this.el.setWidth( this.adjustWidth('input', x));
37597 this.trigger.setStyle('left', x+'px');
37599 if(this.list && this.listWidth === undefined){
37600 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37601 this.list.setWidth(lw);
37602 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37610 * Allow or prevent the user from directly editing the field text. If false is passed,
37611 * the user will only be able to select from the items defined in the dropdown list. This method
37612 * is the runtime equivalent of setting the 'editable' config option at config time.
37613 * @param {Boolean} value True to allow the user to directly edit the field text
37615 setEditable : function(value){
37616 if(value == this.editable){
37619 this.editable = value;
37621 this.el.dom.setAttribute('readOnly', true);
37622 this.el.on('mousedown', this.onTriggerClick, this);
37623 this.el.addClass('x-combo-noedit');
37625 this.el.dom.setAttribute('readOnly', false);
37626 this.el.un('mousedown', this.onTriggerClick, this);
37627 this.el.removeClass('x-combo-noedit');
37632 onBeforeLoad : function(){
37633 if(!this.hasFocus){
37636 this.innerList.update(this.loadingText ?
37637 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37638 this.restrictHeight();
37639 this.selectedIndex = -1;
37643 onLoad : function(){
37644 if(!this.hasFocus){
37647 if(this.store.getCount() > 0){
37649 this.restrictHeight();
37650 if(this.lastQuery == this.allQuery){
37652 this.el.dom.select();
37654 if(!this.selectByValue(this.value, true)){
37655 this.select(0, true);
37659 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37660 this.taTask.delay(this.typeAheadDelay);
37664 this.onEmptyResults();
37670 onTypeAhead : function(){
37671 if(this.store.getCount() > 0){
37672 var r = this.store.getAt(0);
37673 var newValue = r.data[this.displayField];
37674 var len = newValue.length;
37675 var selStart = this.getRawValue().length;
37676 if(selStart != len){
37677 this.setRawValue(newValue);
37678 this.selectText(selStart, newValue.length);
37684 onSelect : function(record, index){
37685 if(this.fireEvent('beforeselect', this, record, index) !== false){
37686 this.setFromData(index > -1 ? record.data : false);
37688 this.fireEvent('select', this, record, index);
37693 * Returns the currently selected field value or empty string if no value is set.
37694 * @return {String} value The selected value
37696 getValue : function(){
37697 if(this.valueField){
37698 return typeof this.value != 'undefined' ? this.value : '';
37700 return Roo.form.ComboBox.superclass.getValue.call(this);
37705 * Clears any text/value currently set in the field
37707 clearValue : function(){
37708 if(this.hiddenField){
37709 this.hiddenField.value = '';
37712 this.setRawValue('');
37713 this.lastSelectionText = '';
37714 this.applyEmptyText();
37718 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37719 * will be displayed in the field. If the value does not match the data value of an existing item,
37720 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37721 * Otherwise the field will be blank (although the value will still be set).
37722 * @param {String} value The value to match
37724 setValue : function(v){
37726 if(this.valueField){
37727 var r = this.findRecord(this.valueField, v);
37729 text = r.data[this.displayField];
37730 }else if(this.valueNotFoundText !== undefined){
37731 text = this.valueNotFoundText;
37734 this.lastSelectionText = text;
37735 if(this.hiddenField){
37736 this.hiddenField.value = v;
37738 Roo.form.ComboBox.superclass.setValue.call(this, text);
37742 * @property {Object} the last set data for the element
37747 * Sets the value of the field based on a object which is related to the record format for the store.
37748 * @param {Object} value the value to set as. or false on reset?
37750 setFromData : function(o){
37751 var dv = ''; // display value
37752 var vv = ''; // value value..
37754 if (this.displayField) {
37755 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37757 // this is an error condition!!!
37758 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
37761 if(this.valueField){
37762 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37764 if(this.hiddenField){
37765 this.hiddenField.value = vv;
37767 this.lastSelectionText = dv;
37768 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37772 // no hidden field.. - we store the value in 'value', but still display
37773 // display field!!!!
37774 this.lastSelectionText = dv;
37775 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37781 reset : function(){
37782 // overridden so that last data is reset..
37783 this.setValue(this.originalValue);
37784 this.clearInvalid();
37785 this.lastData = false;
37788 findRecord : function(prop, value){
37790 if(this.store.getCount() > 0){
37791 this.store.each(function(r){
37792 if(r.data[prop] == value){
37802 onViewMove : function(e, t){
37803 this.inKeyMode = false;
37807 onViewOver : function(e, t){
37808 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37811 var item = this.view.findItemFromChild(t);
37813 var index = this.view.indexOf(item);
37814 this.select(index, false);
37819 onViewClick : function(doFocus){
37820 var index = this.view.getSelectedIndexes()[0];
37821 var r = this.store.getAt(index);
37823 this.onSelect(r, index);
37825 if(doFocus !== false && !this.blockFocus){
37831 restrictHeight : function(){
37832 this.innerList.dom.style.height = '';
37833 var inner = this.innerList.dom;
37834 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37835 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37836 this.list.beginUpdate();
37837 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37838 this.list.alignTo(this.el, this.listAlign);
37839 this.list.endUpdate();
37843 onEmptyResults : function(){
37848 * Returns true if the dropdown list is expanded, else false.
37850 isExpanded : function(){
37851 return this.list.isVisible();
37855 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37856 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37857 * @param {String} value The data value of the item to select
37858 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37859 * selected item if it is not currently in view (defaults to true)
37860 * @return {Boolean} True if the value matched an item in the list, else false
37862 selectByValue : function(v, scrollIntoView){
37863 if(v !== undefined && v !== null){
37864 var r = this.findRecord(this.valueField || this.displayField, v);
37866 this.select(this.store.indexOf(r), scrollIntoView);
37874 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37875 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37876 * @param {Number} index The zero-based index of the list item to select
37877 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37878 * selected item if it is not currently in view (defaults to true)
37880 select : function(index, scrollIntoView){
37881 this.selectedIndex = index;
37882 this.view.select(index);
37883 if(scrollIntoView !== false){
37884 var el = this.view.getNode(index);
37886 this.innerList.scrollChildIntoView(el, false);
37892 selectNext : function(){
37893 var ct = this.store.getCount();
37895 if(this.selectedIndex == -1){
37897 }else if(this.selectedIndex < ct-1){
37898 this.select(this.selectedIndex+1);
37904 selectPrev : function(){
37905 var ct = this.store.getCount();
37907 if(this.selectedIndex == -1){
37909 }else if(this.selectedIndex != 0){
37910 this.select(this.selectedIndex-1);
37916 onKeyUp : function(e){
37917 if(this.editable !== false && !e.isSpecialKey()){
37918 this.lastKey = e.getKey();
37919 this.dqTask.delay(this.queryDelay);
37924 validateBlur : function(){
37925 return !this.list || !this.list.isVisible();
37929 initQuery : function(){
37930 this.doQuery(this.getRawValue());
37934 doForce : function(){
37935 if(this.el.dom.value.length > 0){
37936 this.el.dom.value =
37937 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37938 this.applyEmptyText();
37943 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37944 * query allowing the query action to be canceled if needed.
37945 * @param {String} query The SQL query to execute
37946 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37947 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37948 * saved in the current store (defaults to false)
37950 doQuery : function(q, forceAll){
37951 if(q === undefined || q === null){
37956 forceAll: forceAll,
37960 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37964 forceAll = qe.forceAll;
37965 if(forceAll === true || (q.length >= this.minChars)){
37966 if(this.lastQuery != q || this.alwaysQuery){
37967 this.lastQuery = q;
37968 if(this.mode == 'local'){
37969 this.selectedIndex = -1;
37971 this.store.clearFilter();
37973 this.store.filter(this.displayField, q);
37977 this.store.baseParams[this.queryParam] = q;
37979 params: this.getParams(q)
37984 this.selectedIndex = -1;
37991 getParams : function(q){
37993 //p[this.queryParam] = q;
37996 p.limit = this.pageSize;
38002 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
38004 collapse : function(){
38005 if(!this.isExpanded()){
38009 Roo.get(document).un('mousedown', this.collapseIf, this);
38010 Roo.get(document).un('mousewheel', this.collapseIf, this);
38011 if (!this.editable) {
38012 Roo.get(document).un('keydown', this.listKeyPress, this);
38014 this.fireEvent('collapse', this);
38018 collapseIf : function(e){
38019 if(!e.within(this.wrap) && !e.within(this.list)){
38025 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
38027 expand : function(){
38028 if(this.isExpanded() || !this.hasFocus){
38031 this.list.alignTo(this.el, this.listAlign);
38033 Roo.get(document).on('mousedown', this.collapseIf, this);
38034 Roo.get(document).on('mousewheel', this.collapseIf, this);
38035 if (!this.editable) {
38036 Roo.get(document).on('keydown', this.listKeyPress, this);
38039 this.fireEvent('expand', this);
38043 // Implements the default empty TriggerField.onTriggerClick function
38044 onTriggerClick : function(){
38048 if(this.isExpanded()){
38050 if (!this.blockFocus) {
38055 this.hasFocus = true;
38056 if(this.triggerAction == 'all') {
38057 this.doQuery(this.allQuery, true);
38059 this.doQuery(this.getRawValue());
38061 if (!this.blockFocus) {
38066 listKeyPress : function(e)
38068 //Roo.log('listkeypress');
38069 // scroll to first matching element based on key pres..
38070 if (e.isSpecialKey()) {
38073 var k = String.fromCharCode(e.getKey()).toUpperCase();
38076 var csel = this.view.getSelectedNodes();
38077 var cselitem = false;
38079 var ix = this.view.indexOf(csel[0]);
38080 cselitem = this.store.getAt(ix);
38081 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
38087 this.store.each(function(v) {
38089 // start at existing selection.
38090 if (cselitem.id == v.id) {
38096 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
38097 match = this.store.indexOf(v);
38102 if (match === false) {
38103 return true; // no more action?
38106 this.view.select(match);
38107 var sn = Roo.get(this.view.getSelectedNodes()[0])
38108 sn.scrollIntoView(sn.dom.parentNode, false);
38112 * @cfg {Boolean} grow
38116 * @cfg {Number} growMin
38120 * @cfg {Number} growMax
38129 * Ext JS Library 1.1.1
38130 * Copyright(c) 2006-2007, Ext JS, LLC.
38132 * Originally Released Under LGPL - original licence link has changed is not relivant.
38135 * <script type="text/javascript">
38138 * @class Roo.form.Checkbox
38139 * @extends Roo.form.Field
38140 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
38142 * Creates a new Checkbox
38143 * @param {Object} config Configuration options
38145 Roo.form.Checkbox = function(config){
38146 Roo.form.Checkbox.superclass.constructor.call(this, config);
38150 * Fires when the checkbox is checked or unchecked.
38151 * @param {Roo.form.Checkbox} this This checkbox
38152 * @param {Boolean} checked The new checked value
38158 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38160 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38162 focusClass : undefined,
38164 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38166 fieldClass: "x-form-field",
38168 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38172 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38173 * {tag: "input", type: "checkbox", autocomplete: "off"})
38175 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38177 * @cfg {String} boxLabel The text that appears beside the checkbox
38181 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38185 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38187 valueOff: '0', // value when not checked..
38189 actionMode : 'viewEl',
38192 itemCls : 'x-menu-check-item x-form-item',
38193 groupClass : 'x-menu-group-item',
38194 inputType : 'hidden',
38197 inSetChecked: false, // check that we are not calling self...
38199 inputElement: false, // real input element?
38200 basedOn: false, // ????
38202 isFormField: true, // not sure where this is needed!!!!
38204 onResize : function(){
38205 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38206 if(!this.boxLabel){
38207 this.el.alignTo(this.wrap, 'c-c');
38211 initEvents : function(){
38212 Roo.form.Checkbox.superclass.initEvents.call(this);
38213 this.el.on("click", this.onClick, this);
38214 this.el.on("change", this.onClick, this);
38218 getResizeEl : function(){
38222 getPositionEl : function(){
38227 onRender : function(ct, position){
38228 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38230 if(this.inputValue !== undefined){
38231 this.el.dom.value = this.inputValue;
38234 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38235 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38236 var viewEl = this.wrap.createChild({
38237 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38238 this.viewEl = viewEl;
38239 this.wrap.on('click', this.onClick, this);
38241 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38242 this.el.on('propertychange', this.setFromHidden, this); //ie
38247 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38248 // viewEl.on('click', this.onClick, this);
38250 //if(this.checked){
38251 this.setChecked(this.checked);
38253 //this.checked = this.el.dom;
38259 initValue : Roo.emptyFn,
38262 * Returns the checked state of the checkbox.
38263 * @return {Boolean} True if checked, else false
38265 getValue : function(){
38267 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38269 return this.valueOff;
38274 onClick : function(){
38275 this.setChecked(!this.checked);
38277 //if(this.el.dom.checked != this.checked){
38278 // this.setValue(this.el.dom.checked);
38283 * Sets the checked state of the checkbox.
38284 * On is always based on a string comparison between inputValue and the param.
38285 * @param {Boolean/String} value - the value to set
38286 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38288 setValue : function(v,suppressEvent){
38291 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38292 //if(this.el && this.el.dom){
38293 // this.el.dom.checked = this.checked;
38294 // this.el.dom.defaultChecked = this.checked;
38296 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38297 //this.fireEvent("check", this, this.checked);
38300 setChecked : function(state,suppressEvent)
38302 if (this.inSetChecked) {
38303 this.checked = state;
38309 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38311 this.checked = state;
38312 if(suppressEvent !== true){
38313 this.fireEvent('check', this, state);
38315 this.inSetChecked = true;
38316 this.el.dom.value = state ? this.inputValue : this.valueOff;
38317 this.inSetChecked = false;
38320 // handle setting of hidden value by some other method!!?!?
38321 setFromHidden: function()
38326 //console.log("SET FROM HIDDEN");
38327 //alert('setFrom hidden');
38328 this.setValue(this.el.dom.value);
38331 onDestroy : function()
38334 Roo.get(this.viewEl).remove();
38337 Roo.form.Checkbox.superclass.onDestroy.call(this);
38342 * Ext JS Library 1.1.1
38343 * Copyright(c) 2006-2007, Ext JS, LLC.
38345 * Originally Released Under LGPL - original licence link has changed is not relivant.
38348 * <script type="text/javascript">
38352 * @class Roo.form.Radio
38353 * @extends Roo.form.Checkbox
38354 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38355 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38357 * Creates a new Radio
38358 * @param {Object} config Configuration options
38360 Roo.form.Radio = function(){
38361 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38363 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38364 inputType: 'radio',
38367 * If this radio is part of a group, it will return the selected value
38370 getGroupValue : function(){
38371 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38373 });//<script type="text/javascript">
38376 * Ext JS Library 1.1.1
38377 * Copyright(c) 2006-2007, Ext JS, LLC.
38378 * licensing@extjs.com
38380 * http://www.extjs.com/license
38386 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38387 * - IE ? - no idea how much works there.
38395 * @class Ext.form.HtmlEditor
38396 * @extends Ext.form.Field
38397 * Provides a lightweight HTML Editor component.
38398 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38400 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38401 * supported by this editor.</b><br/><br/>
38402 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38403 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38405 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38407 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38411 * @cfg {String} createLinkText The default text for the create link prompt
38413 createLinkText : 'Please enter the URL for the link:',
38415 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38417 defaultLinkValue : 'http:/'+'/',
38423 // private properties
38424 validationEvent : false,
38426 initialized : false,
38428 sourceEditMode : false,
38429 onFocus : Roo.emptyFn,
38431 hideMode:'offsets',
38432 defaultAutoCreate : {
38434 style:"width:500px;height:300px;",
38435 autocomplete: "off"
38439 initComponent : function(){
38442 * @event initialize
38443 * Fires when the editor is fully initialized (including the iframe)
38444 * @param {HtmlEditor} this
38449 * Fires when the editor is first receives the focus. Any insertion must wait
38450 * until after this event.
38451 * @param {HtmlEditor} this
38455 * @event beforesync
38456 * Fires before the textarea is updated with content from the editor iframe. Return false
38457 * to cancel the sync.
38458 * @param {HtmlEditor} this
38459 * @param {String} html
38463 * @event beforepush
38464 * Fires before the iframe editor is updated with content from the textarea. Return false
38465 * to cancel the push.
38466 * @param {HtmlEditor} this
38467 * @param {String} html
38472 * Fires when the textarea is updated with content from the editor iframe.
38473 * @param {HtmlEditor} this
38474 * @param {String} html
38479 * Fires when the iframe editor is updated with content from the textarea.
38480 * @param {HtmlEditor} this
38481 * @param {String} html
38485 * @event editmodechange
38486 * Fires when the editor switches edit modes
38487 * @param {HtmlEditor} this
38488 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38490 editmodechange: true,
38492 * @event editorevent
38493 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38494 * @param {HtmlEditor} this
38501 * Protected method that will not generally be called directly. It
38502 * is called when the editor creates its toolbar. Override this method if you need to
38503 * add custom toolbar buttons.
38504 * @param {HtmlEditor} editor
38506 createToolbar : function(editor){
38507 if (!editor.toolbars || !editor.toolbars.length) {
38508 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38511 for (var i =0 ; i < editor.toolbars.length;i++) {
38512 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38513 editor.toolbars[i].init(editor);
38520 * Protected method that will not generally be called directly. It
38521 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38522 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38524 getDocMarkup : function(){
38525 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
38529 onRender : function(ct, position){
38530 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38531 this.el.dom.style.border = '0 none';
38532 this.el.dom.setAttribute('tabIndex', -1);
38533 this.el.addClass('x-hidden');
38534 if(Roo.isIE){ // fix IE 1px bogus margin
38535 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38537 this.wrap = this.el.wrap({
38538 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38541 this.frameId = Roo.id();
38542 this.createToolbar(this);
38549 var iframe = this.wrap.createChild({
38552 name: this.frameId,
38553 frameBorder : 'no',
38554 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38557 // console.log(iframe);
38558 //this.wrap.dom.appendChild(iframe);
38560 this.iframe = iframe.dom;
38562 this.assignDocWin();
38564 this.doc.designMode = 'on';
38567 this.doc.write(this.getDocMarkup());
38571 var task = { // must defer to wait for browser to be ready
38573 //console.log("run task?" + this.doc.readyState);
38574 this.assignDocWin();
38575 if(this.doc.body || this.doc.readyState == 'complete'){
38577 this.doc.designMode="on";
38581 Roo.TaskMgr.stop(task);
38582 this.initEditor.defer(10, this);
38589 Roo.TaskMgr.start(task);
38592 this.setSize(this.el.getSize());
38597 onResize : function(w, h){
38598 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38599 if(this.el && this.iframe){
38600 if(typeof w == 'number'){
38601 var aw = w - this.wrap.getFrameWidth('lr');
38602 this.el.setWidth(this.adjustWidth('textarea', aw));
38603 this.iframe.style.width = aw + 'px';
38605 if(typeof h == 'number'){
38607 for (var i =0; i < this.toolbars.length;i++) {
38608 // fixme - ask toolbars for heights?
38609 tbh += this.toolbars[i].tb.el.getHeight();
38615 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38616 this.el.setHeight(this.adjustWidth('textarea', ah));
38617 this.iframe.style.height = ah + 'px';
38619 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38626 * Toggles the editor between standard and source edit mode.
38627 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38629 toggleSourceEdit : function(sourceEditMode){
38631 this.sourceEditMode = sourceEditMode === true;
38633 if(this.sourceEditMode){
38636 this.iframe.className = 'x-hidden';
38637 this.el.removeClass('x-hidden');
38638 this.el.dom.removeAttribute('tabIndex');
38643 this.iframe.className = '';
38644 this.el.addClass('x-hidden');
38645 this.el.dom.setAttribute('tabIndex', -1);
38648 this.setSize(this.wrap.getSize());
38649 this.fireEvent('editmodechange', this, this.sourceEditMode);
38652 // private used internally
38653 createLink : function(){
38654 var url = prompt(this.createLinkText, this.defaultLinkValue);
38655 if(url && url != 'http:/'+'/'){
38656 this.relayCmd('createlink', url);
38660 // private (for BoxComponent)
38661 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38663 // private (for BoxComponent)
38664 getResizeEl : function(){
38668 // private (for BoxComponent)
38669 getPositionEl : function(){
38674 initEvents : function(){
38675 this.originalValue = this.getValue();
38679 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38682 markInvalid : Roo.emptyFn,
38684 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38687 clearInvalid : Roo.emptyFn,
38689 setValue : function(v){
38690 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38695 * Protected method that will not generally be called directly. If you need/want
38696 * custom HTML cleanup, this is the method you should override.
38697 * @param {String} html The HTML to be cleaned
38698 * return {String} The cleaned HTML
38700 cleanHtml : function(html){
38701 html = String(html);
38702 if(html.length > 5){
38703 if(Roo.isSafari){ // strip safari nonsense
38704 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38707 if(html == ' '){
38714 * Protected method that will not generally be called directly. Syncs the contents
38715 * of the editor iframe with the textarea.
38717 syncValue : function(){
38718 if(this.initialized){
38719 var bd = (this.doc.body || this.doc.documentElement);
38720 this.cleanUpPaste();
38721 var html = bd.innerHTML;
38723 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38724 var m = bs.match(/text-align:(.*?);/i);
38726 html = '<div style="'+m[0]+'">' + html + '</div>';
38729 html = this.cleanHtml(html);
38730 if(this.fireEvent('beforesync', this, html) !== false){
38731 this.el.dom.value = html;
38732 this.fireEvent('sync', this, html);
38738 * Protected method that will not generally be called directly. Pushes the value of the textarea
38739 * into the iframe editor.
38741 pushValue : function(){
38742 if(this.initialized){
38743 var v = this.el.dom.value;
38748 if(this.fireEvent('beforepush', this, v) !== false){
38749 var d = (this.doc.body || this.doc.documentElement);
38751 this.cleanUpPaste();
38752 this.el.dom.value = d.innerHTML;
38753 this.fireEvent('push', this, v);
38759 deferFocus : function(){
38760 this.focus.defer(10, this);
38764 focus : function(){
38765 if(this.win && !this.sourceEditMode){
38772 assignDocWin: function()
38774 var iframe = this.iframe;
38777 this.doc = iframe.contentWindow.document;
38778 this.win = iframe.contentWindow;
38780 if (!Roo.get(this.frameId)) {
38783 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38784 this.win = Roo.get(this.frameId).dom.contentWindow;
38789 initEditor : function(){
38790 //console.log("INIT EDITOR");
38791 this.assignDocWin();
38795 this.doc.designMode="on";
38797 this.doc.write(this.getDocMarkup());
38800 var dbody = (this.doc.body || this.doc.documentElement);
38801 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38802 // this copies styles from the containing element into thsi one..
38803 // not sure why we need all of this..
38804 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38805 ss['background-attachment'] = 'fixed'; // w3c
38806 dbody.bgProperties = 'fixed'; // ie
38807 Roo.DomHelper.applyStyles(dbody, ss);
38808 Roo.EventManager.on(this.doc, {
38809 'mousedown': this.onEditorEvent,
38810 'dblclick': this.onEditorEvent,
38811 'click': this.onEditorEvent,
38812 'keyup': this.onEditorEvent,
38817 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
38819 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38820 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38822 this.initialized = true;
38824 this.fireEvent('initialize', this);
38829 onDestroy : function(){
38835 for (var i =0; i < this.toolbars.length;i++) {
38836 // fixme - ask toolbars for heights?
38837 this.toolbars[i].onDestroy();
38840 this.wrap.dom.innerHTML = '';
38841 this.wrap.remove();
38846 onFirstFocus : function(){
38848 this.assignDocWin();
38851 this.activated = true;
38852 for (var i =0; i < this.toolbars.length;i++) {
38853 this.toolbars[i].onFirstFocus();
38856 if(Roo.isGecko){ // prevent silly gecko errors
38858 var s = this.win.getSelection();
38859 if(!s.focusNode || s.focusNode.nodeType != 3){
38860 var r = s.getRangeAt(0);
38861 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38866 this.execCmd('useCSS', true);
38867 this.execCmd('styleWithCSS', false);
38870 this.fireEvent('activate', this);
38874 adjustFont: function(btn){
38875 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38876 //if(Roo.isSafari){ // safari
38879 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38880 if(Roo.isSafari){ // safari
38881 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38882 v = (v < 10) ? 10 : v;
38883 v = (v > 48) ? 48 : v;
38884 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38889 v = Math.max(1, v+adjust);
38891 this.execCmd('FontSize', v );
38894 onEditorEvent : function(e){
38895 this.fireEvent('editorevent', this, e);
38896 // this.updateToolbar();
38900 insertTag : function(tg)
38902 // could be a bit smarter... -> wrap the current selected tRoo..
38904 this.execCmd("formatblock", tg);
38908 insertText : function(txt)
38912 range = this.createRange();
38913 range.deleteContents();
38914 //alert(Sender.getAttribute('label'));
38916 range.insertNode(this.doc.createTextNode(txt));
38920 relayBtnCmd : function(btn){
38921 this.relayCmd(btn.cmd);
38925 * Executes a Midas editor command on the editor document and performs necessary focus and
38926 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38927 * @param {String} cmd The Midas command
38928 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38930 relayCmd : function(cmd, value){
38932 this.execCmd(cmd, value);
38933 this.fireEvent('editorevent', this);
38934 //this.updateToolbar();
38939 * Executes a Midas editor command directly on the editor document.
38940 * For visual commands, you should use {@link #relayCmd} instead.
38941 * <b>This should only be called after the editor is initialized.</b>
38942 * @param {String} cmd The Midas command
38943 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38945 execCmd : function(cmd, value){
38946 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38952 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38954 * @param {String} text
38956 insertAtCursor : function(text){
38957 if(!this.activated){
38962 var r = this.doc.selection.createRange();
38969 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
38971 this.execCmd('InsertHTML', text);
38976 mozKeyPress : function(e){
38978 var c = e.getCharCode(), cmd;
38981 c = String.fromCharCode(c).toLowerCase();
38992 this.cleanUpPaste.defer(100, this);
39000 e.preventDefault();
39008 fixKeys : function(){ // load time branching for fastest keydown performance
39010 return function(e){
39011 var k = e.getKey(), r;
39014 r = this.doc.selection.createRange();
39017 r.pasteHTML('    ');
39024 r = this.doc.selection.createRange();
39026 var target = r.parentElement();
39027 if(!target || target.tagName.toLowerCase() != 'li'){
39029 r.pasteHTML('<br />');
39035 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39036 this.cleanUpPaste.defer(100, this);
39042 }else if(Roo.isOpera){
39043 return function(e){
39044 var k = e.getKey();
39048 this.execCmd('InsertHTML','    ');
39051 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39052 this.cleanUpPaste.defer(100, this);
39057 }else if(Roo.isSafari){
39058 return function(e){
39059 var k = e.getKey();
39063 this.execCmd('InsertText','\t');
39067 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39068 this.cleanUpPaste.defer(100, this);
39076 getAllAncestors: function()
39078 var p = this.getSelectedNode();
39081 a.push(p); // push blank onto stack..
39082 p = this.getParentElement();
39086 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
39090 a.push(this.doc.body);
39094 lastSelNode : false,
39097 getSelection : function()
39099 this.assignDocWin();
39100 return Roo.isIE ? this.doc.selection : this.win.getSelection();
39103 getSelectedNode: function()
39105 // this may only work on Gecko!!!
39107 // should we cache this!!!!
39112 var range = this.createRange(this.getSelection());
39115 var parent = range.parentElement();
39117 var testRange = range.duplicate();
39118 testRange.moveToElementText(parent);
39119 if (testRange.inRange(range)) {
39122 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
39125 parent = parent.parentElement;
39131 var ar = range.endContainer.childNodes;
39133 ar = range.commonAncestorContainer.childNodes;
39134 //alert(ar.length);
39137 var other_nodes = [];
39138 var has_other_nodes = false;
39139 for (var i=0;i<ar.length;i++) {
39140 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
39143 // fullly contained node.
39145 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
39150 // probably selected..
39151 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
39152 other_nodes.push(ar[i]);
39155 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39160 has_other_nodes = true;
39162 if (!nodes.length && other_nodes.length) {
39163 nodes= other_nodes;
39165 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39171 createRange: function(sel)
39173 // this has strange effects when using with
39174 // top toolbar - not sure if it's a great idea.
39175 //this.editor.contentWindow.focus();
39176 if (typeof sel != "undefined") {
39178 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39180 return this.doc.createRange();
39183 return this.doc.createRange();
39186 getParentElement: function()
39189 this.assignDocWin();
39190 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39192 var range = this.createRange(sel);
39195 var p = range.commonAncestorContainer;
39196 while (p.nodeType == 3) { // text node
39208 // BC Hacks - cause I cant work out what i was trying to do..
39209 rangeIntersectsNode : function(range, node)
39211 var nodeRange = node.ownerDocument.createRange();
39213 nodeRange.selectNode(node);
39216 nodeRange.selectNodeContents(node);
39219 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
39220 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
39222 rangeCompareNode : function(range, node) {
39223 var nodeRange = node.ownerDocument.createRange();
39225 nodeRange.selectNode(node);
39227 nodeRange.selectNodeContents(node);
39229 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
39230 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
39232 if (nodeIsBefore && !nodeIsAfter)
39234 if (!nodeIsBefore && nodeIsAfter)
39236 if (nodeIsBefore && nodeIsAfter)
39242 // private? - in a new class?
39243 cleanUpPaste : function()
39245 // cleans up the whole document..
39246 // console.log('cleanuppaste');
39247 this.cleanUpChildren(this.doc.body);
39251 cleanUpChildren : function (n)
39253 if (!n.childNodes.length) {
39256 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39257 this.cleanUpChild(n.childNodes[i]);
39264 cleanUpChild : function (node)
39266 //console.log(node);
39267 if (node.nodeName == "#text") {
39268 // clean up silly Windows -- stuff?
39271 if (node.nodeName == "#comment") {
39272 node.parentNode.removeChild(node);
39273 // clean up silly Windows -- stuff?
39277 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39279 node.parentNode.removeChild(node);
39283 if (!node.attributes || !node.attributes.length) {
39284 this.cleanUpChildren(node);
39288 function cleanAttr(n,v)
39291 if (v.match(/^\./) || v.match(/^\//)) {
39294 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39297 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39298 node.removeAttribute(n);
39302 function cleanStyle(n,v)
39304 if (v.match(/expression/)) { //XSS?? should we even bother..
39305 node.removeAttribute(n);
39310 var parts = v.split(/;/);
39311 Roo.each(parts, function(p) {
39312 p = p.replace(/\s+/g,'');
39316 var l = p.split(':').shift().replace(/\s+/g,'');
39318 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39319 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39320 node.removeAttribute(n);
39329 for (var i = node.attributes.length-1; i > -1 ; i--) {
39330 var a = node.attributes[i];
39332 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39333 node.removeAttribute(a.name);
39336 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39337 cleanAttr(a.name,a.value); // fixme..
39340 if (a.name == 'style') {
39341 cleanStyle(a.name,a.value);
39343 /// clean up MS crap..
39344 if (a.name == 'class') {
39345 if (a.value.match(/^Mso/)) {
39346 node.className = '';
39356 this.cleanUpChildren(node);
39362 // hide stuff that is not compatible
39376 * @event specialkey
39380 * @cfg {String} fieldClass @hide
39383 * @cfg {String} focusClass @hide
39386 * @cfg {String} autoCreate @hide
39389 * @cfg {String} inputType @hide
39392 * @cfg {String} invalidClass @hide
39395 * @cfg {String} invalidText @hide
39398 * @cfg {String} msgFx @hide
39401 * @cfg {String} validateOnBlur @hide
39405 Roo.form.HtmlEditor.white = [
39406 'area', 'br', 'img', 'input', 'hr', 'wbr',
39408 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39409 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39410 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39411 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39412 'table', 'ul', 'xmp',
39414 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39417 'dir', 'menu', 'ol', 'ul', 'dl',
39423 Roo.form.HtmlEditor.black = [
39424 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39426 'base', 'basefont', 'bgsound', 'blink', 'body',
39427 'frame', 'frameset', 'head', 'html', 'ilayer',
39428 'iframe', 'layer', 'link', 'meta', 'object',
39429 'script', 'style' ,'title', 'xml' // clean later..
39431 Roo.form.HtmlEditor.clean = [
39432 'script', 'style', 'title', 'xml'
39437 Roo.form.HtmlEditor.ablack = [
39441 Roo.form.HtmlEditor.aclean = [
39442 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39446 Roo.form.HtmlEditor.pwhite= [
39447 'http', 'https', 'mailto'
39450 Roo.form.HtmlEditor.cwhite= [
39455 // <script type="text/javascript">
39458 * Ext JS Library 1.1.1
39459 * Copyright(c) 2006-2007, Ext JS, LLC.
39465 * @class Roo.form.HtmlEditorToolbar1
39470 new Roo.form.HtmlEditor({
39473 new Roo.form.HtmlEditorToolbar1({
39474 disable : { fonts: 1 , format: 1, ..., ... , ...],
39480 * @cfg {Object} disable List of elements to disable..
39481 * @cfg {Array} btns List of additional buttons.
39485 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39488 Roo.form.HtmlEditor.ToolbarStandard = function(config)
39491 Roo.apply(this, config);
39492 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39493 // dont call parent... till later.
39496 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
39504 * @cfg {Object} disable List of toolbar elements to disable
39509 * @cfg {Array} fontFamilies An array of available font families
39527 // "á" , ?? a acute?
39532 "°" // , // degrees
39534 // "é" , // e ecute
39535 // "ú" , // u ecute?
39538 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
39539 "input:submit", "input:button", "select", "textarea", "label" ],
39542 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
39544 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39547 * @cfg {String} defaultFont default font to use.
39549 defaultFont: 'tahoma',
39551 fontSelect : false,
39554 formatCombo : false,
39556 init : function(editor)
39558 this.editor = editor;
39561 var fid = editor.frameId;
39563 function btn(id, toggle, handler){
39564 var xid = fid + '-'+ id ;
39568 cls : 'x-btn-icon x-edit-'+id,
39569 enableToggle:toggle !== false,
39570 scope: editor, // was editor...
39571 handler:handler||editor.relayBtnCmd,
39572 clickEvent:'mousedown',
39573 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39580 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
39582 // stop form submits
39583 tb.el.on('click', function(e){
39584 e.preventDefault(); // what does this do?
39587 if(!this.disable.font && !Roo.isSafari){
39588 /* why no safari for fonts
39589 editor.fontSelect = tb.el.createChild({
39592 cls:'x-font-select',
39593 html: editor.createFontOptions()
39595 editor.fontSelect.on('change', function(){
39596 var font = editor.fontSelect.dom.value;
39597 editor.relayCmd('fontname', font);
39598 editor.deferFocus();
39601 editor.fontSelect.dom,
39606 if(!this.disable.formats){
39607 this.formatCombo = new Roo.form.ComboBox({
39608 store: new Roo.data.SimpleStore({
39611 data : this.formats // from states.js
39614 //autoCreate : {tag: "div", size: "20"},
39615 displayField:'tag',
39619 triggerAction: 'all',
39620 emptyText:'Add tag',
39621 selectOnFocus:true,
39624 'select': function(c, r, i) {
39625 editor.insertTag(r.get('tag'));
39631 tb.addField(this.formatCombo);
39635 if(!this.disable.format){
39642 if(!this.disable.fontSize){
39647 btn('increasefontsize', false, editor.adjustFont),
39648 btn('decreasefontsize', false, editor.adjustFont)
39653 if(this.disable.colors){
39656 id:editor.frameId +'-forecolor',
39657 cls:'x-btn-icon x-edit-forecolor',
39658 clickEvent:'mousedown',
39659 tooltip: this.buttonTips['forecolor'] || undefined,
39661 menu : new Roo.menu.ColorMenu({
39662 allowReselect: true,
39663 focus: Roo.emptyFn,
39666 selectHandler: function(cp, color){
39667 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
39668 editor.deferFocus();
39671 clickEvent:'mousedown'
39674 id:editor.frameId +'backcolor',
39675 cls:'x-btn-icon x-edit-backcolor',
39676 clickEvent:'mousedown',
39677 tooltip: this.buttonTips['backcolor'] || undefined,
39679 menu : new Roo.menu.ColorMenu({
39680 focus: Roo.emptyFn,
39683 allowReselect: true,
39684 selectHandler: function(cp, color){
39686 editor.execCmd('useCSS', false);
39687 editor.execCmd('hilitecolor', color);
39688 editor.execCmd('useCSS', true);
39689 editor.deferFocus();
39691 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
39692 Roo.isSafari || Roo.isIE ? '#'+color : color);
39693 editor.deferFocus();
39697 clickEvent:'mousedown'
39702 // now add all the items...
39705 if(!this.disable.alignments){
39708 btn('justifyleft'),
39709 btn('justifycenter'),
39710 btn('justifyright')
39714 //if(!Roo.isSafari){
39715 if(!this.disable.links){
39718 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
39722 if(!this.disable.lists){
39725 btn('insertorderedlist'),
39726 btn('insertunorderedlist')
39729 if(!this.disable.sourceEdit){
39732 btn('sourceedit', true, function(btn){
39733 this.toggleSourceEdit(btn.pressed);
39740 // special menu.. - needs to be tidied up..
39741 if (!this.disable.special) {
39744 cls: 'x-edit-none',
39749 for (var i =0; i < this.specialChars.length; i++) {
39750 smenu.menu.items.push({
39752 html: this.specialChars[i],
39753 handler: function(a,b) {
39754 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
39767 for(var i =0; i< this.btns.length;i++) {
39768 var b = this.btns[i];
39769 b.cls = 'x-edit-none';
39778 // disable everything...
39780 this.tb.items.each(function(item){
39781 if(item.id != editor.frameId+ '-sourceedit'){
39785 this.rendered = true;
39787 // the all the btns;
39788 editor.on('editorevent', this.updateToolbar, this);
39789 // other toolbars need to implement this..
39790 //editor.on('editmodechange', this.updateToolbar, this);
39796 * Protected method that will not generally be called directly. It triggers
39797 * a toolbar update by reading the markup state of the current selection in the editor.
39799 updateToolbar: function(){
39801 if(!this.editor.activated){
39802 this.editor.onFirstFocus();
39806 var btns = this.tb.items.map,
39807 doc = this.editor.doc,
39808 frameId = this.editor.frameId;
39810 if(!this.disable.font && !Roo.isSafari){
39812 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39813 if(name != this.fontSelect.dom.value){
39814 this.fontSelect.dom.value = name;
39818 if(!this.disable.format){
39819 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39820 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39821 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39823 if(!this.disable.alignments){
39824 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39825 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39826 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39828 if(!Roo.isSafari && !this.disable.lists){
39829 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39830 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39833 var ans = this.editor.getAllAncestors();
39834 if (this.formatCombo) {
39837 var store = this.formatCombo.store;
39838 this.formatCombo.setValue("");
39839 for (var i =0; i < ans.length;i++) {
39840 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
39842 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39850 // hides menus... - so this cant be on a menu...
39851 Roo.menu.MenuMgr.hideAll();
39853 //this.editorsyncValue();
39857 createFontOptions : function(){
39858 var buf = [], fs = this.fontFamilies, ff, lc;
39859 for(var i = 0, len = fs.length; i< len; i++){
39861 lc = ff.toLowerCase();
39863 '<option value="',lc,'" style="font-family:',ff,';"',
39864 (this.defaultFont == lc ? ' selected="true">' : '>'),
39869 return buf.join('');
39872 toggleSourceEdit : function(sourceEditMode){
39873 if(sourceEditMode === undefined){
39874 sourceEditMode = !this.sourceEditMode;
39876 this.sourceEditMode = sourceEditMode === true;
39877 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39878 // just toggle the button?
39879 if(btn.pressed !== this.editor.sourceEditMode){
39880 btn.toggle(this.editor.sourceEditMode);
39884 if(this.sourceEditMode){
39885 this.tb.items.each(function(item){
39886 if(item.cmd != 'sourceedit'){
39892 if(this.initialized){
39893 this.tb.items.each(function(item){
39899 // tell the editor that it's been pressed..
39900 this.editor.toggleSourceEdit(sourceEditMode);
39904 * Object collection of toolbar tooltips for the buttons in the editor. The key
39905 * is the command id associated with that button and the value is a valid QuickTips object.
39910 title: 'Bold (Ctrl+B)',
39911 text: 'Make the selected text bold.',
39912 cls: 'x-html-editor-tip'
39915 title: 'Italic (Ctrl+I)',
39916 text: 'Make the selected text italic.',
39917 cls: 'x-html-editor-tip'
39925 title: 'Bold (Ctrl+B)',
39926 text: 'Make the selected text bold.',
39927 cls: 'x-html-editor-tip'
39930 title: 'Italic (Ctrl+I)',
39931 text: 'Make the selected text italic.',
39932 cls: 'x-html-editor-tip'
39935 title: 'Underline (Ctrl+U)',
39936 text: 'Underline the selected text.',
39937 cls: 'x-html-editor-tip'
39939 increasefontsize : {
39940 title: 'Grow Text',
39941 text: 'Increase the font size.',
39942 cls: 'x-html-editor-tip'
39944 decreasefontsize : {
39945 title: 'Shrink Text',
39946 text: 'Decrease the font size.',
39947 cls: 'x-html-editor-tip'
39950 title: 'Text Highlight Color',
39951 text: 'Change the background color of the selected text.',
39952 cls: 'x-html-editor-tip'
39955 title: 'Font Color',
39956 text: 'Change the color of the selected text.',
39957 cls: 'x-html-editor-tip'
39960 title: 'Align Text Left',
39961 text: 'Align text to the left.',
39962 cls: 'x-html-editor-tip'
39965 title: 'Center Text',
39966 text: 'Center text in the editor.',
39967 cls: 'x-html-editor-tip'
39970 title: 'Align Text Right',
39971 text: 'Align text to the right.',
39972 cls: 'x-html-editor-tip'
39974 insertunorderedlist : {
39975 title: 'Bullet List',
39976 text: 'Start a bulleted list.',
39977 cls: 'x-html-editor-tip'
39979 insertorderedlist : {
39980 title: 'Numbered List',
39981 text: 'Start a numbered list.',
39982 cls: 'x-html-editor-tip'
39985 title: 'Hyperlink',
39986 text: 'Make the selected text a hyperlink.',
39987 cls: 'x-html-editor-tip'
39990 title: 'Source Edit',
39991 text: 'Switch to source editing mode.',
39992 cls: 'x-html-editor-tip'
39996 onDestroy : function(){
39999 this.tb.items.each(function(item){
40001 item.menu.removeAll();
40003 item.menu.el.destroy();
40011 onFirstFocus: function() {
40012 this.tb.items.each(function(item){
40021 // <script type="text/javascript">
40024 * Ext JS Library 1.1.1
40025 * Copyright(c) 2006-2007, Ext JS, LLC.
40032 * @class Roo.form.HtmlEditor.ToolbarContext
40037 new Roo.form.HtmlEditor({
40040 new Roo.form.HtmlEditor.ToolbarStandard(),
40041 new Roo.form.HtmlEditor.ToolbarContext()
40046 * @config : {Object} disable List of elements to disable.. (not done yet.)
40051 Roo.form.HtmlEditor.ToolbarContext = function(config)
40054 Roo.apply(this, config);
40055 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
40056 // dont call parent... till later.
40058 Roo.form.HtmlEditor.ToolbarContext.types = {
40070 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
40132 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
40137 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40201 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40209 * @cfg {Object} disable List of toolbar elements to disable
40218 init : function(editor)
40220 this.editor = editor;
40223 var fid = editor.frameId;
40225 function btn(id, toggle, handler){
40226 var xid = fid + '-'+ id ;
40230 cls : 'x-btn-icon x-edit-'+id,
40231 enableToggle:toggle !== false,
40232 scope: editor, // was editor...
40233 handler:handler||editor.relayBtnCmd,
40234 clickEvent:'mousedown',
40235 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40239 // create a new element.
40240 var wdiv = editor.wrap.createChild({
40242 }, editor.wrap.dom.firstChild.nextSibling, true);
40244 // can we do this more than once??
40246 // stop form submits
40249 // disable everything...
40250 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40251 this.toolbars = {};
40253 for (var i in ty) {
40255 this.toolbars[i] = this.buildToolbar(ty[i],i);
40257 this.tb = this.toolbars.BODY;
40261 this.rendered = true;
40263 // the all the btns;
40264 editor.on('editorevent', this.updateToolbar, this);
40265 // other toolbars need to implement this..
40266 //editor.on('editmodechange', this.updateToolbar, this);
40272 * Protected method that will not generally be called directly. It triggers
40273 * a toolbar update by reading the markup state of the current selection in the editor.
40275 updateToolbar: function(){
40277 if(!this.editor.activated){
40278 this.editor.onFirstFocus();
40283 var ans = this.editor.getAllAncestors();
40286 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40287 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40288 sel = sel ? sel : this.editor.doc.body;
40289 sel = sel.tagName.length ? sel : this.editor.doc.body;
40290 var tn = sel.tagName.toUpperCase();
40291 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40292 tn = sel.tagName.toUpperCase();
40293 if (this.tb.name == tn) {
40294 return; // no change
40297 ///console.log("show: " + tn);
40298 this.tb = this.toolbars[tn];
40300 this.tb.fields.each(function(e) {
40301 e.setValue(sel.getAttribute(e.name));
40303 this.tb.selectedNode = sel;
40306 Roo.menu.MenuMgr.hideAll();
40308 //this.editorsyncValue();
40313 onDestroy : function(){
40316 this.tb.items.each(function(item){
40318 item.menu.removeAll();
40320 item.menu.el.destroy();
40328 onFirstFocus: function() {
40329 // need to do this for all the toolbars..
40330 this.tb.items.each(function(item){
40334 buildToolbar: function(tlist, nm)
40336 var editor = this.editor;
40337 // create a new element.
40338 var wdiv = editor.wrap.createChild({
40340 }, editor.wrap.dom.firstChild.nextSibling, true);
40343 var tb = new Roo.Toolbar(wdiv);
40344 tb.add(nm+ ": ");
40345 for (var i in tlist) {
40346 var item = tlist[i];
40347 tb.add(item.title + ": ");
40352 tb.addField( new Roo.form.ComboBox({
40353 store: new Roo.data.SimpleStore({
40356 data : item.opts // from states.js
40359 displayField:'val',
40363 triggerAction: 'all',
40364 emptyText:'Select',
40365 selectOnFocus:true,
40366 width: item.width ? item.width : 130,
40368 'select': function(c, r, i) {
40369 tb.selectedNode.setAttribute(c.name, r.get('val'));
40380 tb.addField( new Roo.form.TextField({
40383 //allowBlank:false,
40388 tb.addField( new Roo.form.TextField({
40394 'change' : function(f, nv, ov) {
40395 tb.selectedNode.setAttribute(f.name, nv);
40401 tb.el.on('click', function(e){
40402 e.preventDefault(); // what does this do?
40404 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40407 // dont need to disable them... as they will get hidden
40424 * Ext JS Library 1.1.1
40425 * Copyright(c) 2006-2007, Ext JS, LLC.
40427 * Originally Released Under LGPL - original licence link has changed is not relivant.
40430 * <script type="text/javascript">
40434 * @class Roo.form.BasicForm
40435 * @extends Roo.util.Observable
40436 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
40438 * @param {String/HTMLElement/Roo.Element} el The form element or its id
40439 * @param {Object} config Configuration options
40441 Roo.form.BasicForm = function(el, config){
40442 this.allItems = [];
40443 this.childForms = [];
40444 Roo.apply(this, config);
40446 * The Roo.form.Field items in this form.
40447 * @type MixedCollection
40451 this.items = new Roo.util.MixedCollection(false, function(o){
40452 return o.id || (o.id = Roo.id());
40456 * @event beforeaction
40457 * Fires before any action is performed. Return false to cancel the action.
40458 * @param {Form} this
40459 * @param {Action} action The action to be performed
40461 beforeaction: true,
40463 * @event actionfailed
40464 * Fires when an action fails.
40465 * @param {Form} this
40466 * @param {Action} action The action that failed
40468 actionfailed : true,
40470 * @event actioncomplete
40471 * Fires when an action is completed.
40472 * @param {Form} this
40473 * @param {Action} action The action that completed
40475 actioncomplete : true
40480 Roo.form.BasicForm.superclass.constructor.call(this);
40483 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
40485 * @cfg {String} method
40486 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
40489 * @cfg {DataReader} reader
40490 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
40491 * This is optional as there is built-in support for processing JSON.
40494 * @cfg {DataReader} errorReader
40495 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
40496 * This is completely optional as there is built-in support for processing JSON.
40499 * @cfg {String} url
40500 * The URL to use for form actions if one isn't supplied in the action options.
40503 * @cfg {Boolean} fileUpload
40504 * Set to true if this form is a file upload.
40508 * @cfg {Object} baseParams
40509 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
40514 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
40519 activeAction : null,
40522 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
40523 * or setValues() data instead of when the form was first created.
40525 trackResetOnLoad : false,
40529 * childForms - used for multi-tab forms
40532 childForms : false,
40535 * allItems - full list of fields.
40541 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
40542 * element by passing it or its id or mask the form itself by passing in true.
40545 waitMsgTarget : false,
40548 initEl : function(el){
40549 this.el = Roo.get(el);
40550 this.id = this.el.id || Roo.id();
40551 this.el.on('submit', this.onSubmit, this);
40552 this.el.addClass('x-form');
40556 onSubmit : function(e){
40561 * Returns true if client-side validation on the form is successful.
40564 isValid : function(){
40566 this.items.each(function(f){
40575 * Returns true if any fields in this form have changed since their original load.
40578 isDirty : function(){
40580 this.items.each(function(f){
40590 * Performs a predefined action (submit or load) or custom actions you define on this form.
40591 * @param {String} actionName The name of the action type
40592 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
40593 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
40594 * accept other config options):
40596 Property Type Description
40597 ---------------- --------------- ----------------------------------------------------------------------------------
40598 url String The url for the action (defaults to the form's url)
40599 method String The form method to use (defaults to the form's method, or POST if not defined)
40600 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
40601 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
40602 validate the form on the client (defaults to false)
40604 * @return {BasicForm} this
40606 doAction : function(action, options){
40607 if(typeof action == 'string'){
40608 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
40610 if(this.fireEvent('beforeaction', this, action) !== false){
40611 this.beforeAction(action);
40612 action.run.defer(100, action);
40618 * Shortcut to do a submit action.
40619 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40620 * @return {BasicForm} this
40622 submit : function(options){
40623 this.doAction('submit', options);
40628 * Shortcut to do a load action.
40629 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40630 * @return {BasicForm} this
40632 load : function(options){
40633 this.doAction('load', options);
40638 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
40639 * @param {Record} record The record to edit
40640 * @return {BasicForm} this
40642 updateRecord : function(record){
40643 record.beginEdit();
40644 var fs = record.fields;
40645 fs.each(function(f){
40646 var field = this.findField(f.name);
40648 record.set(f.name, field.getValue());
40656 * Loads an Roo.data.Record into this form.
40657 * @param {Record} record The record to load
40658 * @return {BasicForm} this
40660 loadRecord : function(record){
40661 this.setValues(record.data);
40666 beforeAction : function(action){
40667 var o = action.options;
40670 if(this.waitMsgTarget === true){
40671 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
40672 }else if(this.waitMsgTarget){
40673 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
40674 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
40676 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
40682 afterAction : function(action, success){
40683 this.activeAction = null;
40684 var o = action.options;
40686 if(this.waitMsgTarget === true){
40688 }else if(this.waitMsgTarget){
40689 this.waitMsgTarget.unmask();
40691 Roo.MessageBox.updateProgress(1);
40692 Roo.MessageBox.hide();
40699 Roo.callback(o.success, o.scope, [this, action]);
40700 this.fireEvent('actioncomplete', this, action);
40703 Roo.callback(o.failure, o.scope, [this, action]);
40704 // show an error message if no failed handler is set..
40705 if (!this.hasListener('actionfailed')) {
40706 Roo.MessageBox.alert("Error", "Saving Failed, please check your entries");
40709 this.fireEvent('actionfailed', this, action);
40715 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
40716 * @param {String} id The value to search for
40719 findField : function(id){
40720 var field = this.items.get(id);
40722 this.items.each(function(f){
40723 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
40729 return field || null;
40733 * Add a secondary form to this one,
40734 * Used to provide tabbed forms. One form is primary, with hidden values
40735 * which mirror the elements from the other forms.
40737 * @param {Roo.form.Form} form to add.
40740 addForm : function(form)
40743 if (this.childForms.indexOf(form) > -1) {
40747 this.childForms.push(form);
40749 Roo.each(form.allItems, function (fe) {
40751 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
40752 if (this.findField(n)) { // already added..
40755 var add = new Roo.form.Hidden({
40758 add.render(this.el);
40765 * Mark fields in this form invalid in bulk.
40766 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
40767 * @return {BasicForm} this
40769 markInvalid : function(errors){
40770 if(errors instanceof Array){
40771 for(var i = 0, len = errors.length; i < len; i++){
40772 var fieldError = errors[i];
40773 var f = this.findField(fieldError.id);
40775 f.markInvalid(fieldError.msg);
40781 if(typeof errors[id] != 'function' && (field = this.findField(id))){
40782 field.markInvalid(errors[id]);
40786 Roo.each(this.childForms || [], function (f) {
40787 f.markInvalid(errors);
40794 * Set values for fields in this form in bulk.
40795 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
40796 * @return {BasicForm} this
40798 setValues : function(values){
40799 if(values instanceof Array){ // array of objects
40800 for(var i = 0, len = values.length; i < len; i++){
40802 var f = this.findField(v.id);
40804 f.setValue(v.value);
40805 if(this.trackResetOnLoad){
40806 f.originalValue = f.getValue();
40810 }else{ // object hash
40813 if(typeof values[id] != 'function' && (field = this.findField(id))){
40815 if (field.setFromData &&
40816 field.valueField &&
40817 field.displayField &&
40818 // combos' with local stores can
40819 // be queried via setValue()
40820 // to set their value..
40821 (field.store && !field.store.isLocal)
40825 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40826 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40827 field.setFromData(sd);
40830 field.setValue(values[id]);
40834 if(this.trackResetOnLoad){
40835 field.originalValue = field.getValue();
40841 Roo.each(this.childForms || [], function (f) {
40842 f.setValues(values);
40849 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40850 * they are returned as an array.
40851 * @param {Boolean} asString
40854 getValues : function(asString){
40855 if (this.childForms) {
40856 // copy values from the child forms
40857 Roo.each(this.childForms, function (f) {
40858 this.setValues(f.getValues());
40864 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40865 if(asString === true){
40868 return Roo.urlDecode(fs);
40872 * Returns the fields in this form as an object with key/value pairs.
40873 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
40876 getFieldValues : function()
40878 if (this.childForms) {
40879 // copy values from the child forms
40880 Roo.each(this.childForms, function (f) {
40881 this.setValues(f.getValues());
40886 this.items.each(function(f){
40887 if (!f.getName()) {
40890 var v = f.getValue();
40891 if ((typeof(v) == 'object') && f.getRawValue) {
40892 v = f.getRawValue() ; // dates..
40894 ret[f.getName()] = v;
40901 * Clears all invalid messages in this form.
40902 * @return {BasicForm} this
40904 clearInvalid : function(){
40905 this.items.each(function(f){
40909 Roo.each(this.childForms || [], function (f) {
40918 * Resets this form.
40919 * @return {BasicForm} this
40921 reset : function(){
40922 this.items.each(function(f){
40926 Roo.each(this.childForms || [], function (f) {
40935 * Add Roo.form components to this form.
40936 * @param {Field} field1
40937 * @param {Field} field2 (optional)
40938 * @param {Field} etc (optional)
40939 * @return {BasicForm} this
40942 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40948 * Removes a field from the items collection (does NOT remove its markup).
40949 * @param {Field} field
40950 * @return {BasicForm} this
40952 remove : function(field){
40953 this.items.remove(field);
40958 * Looks at the fields in this form, checks them for an id attribute,
40959 * and calls applyTo on the existing dom element with that id.
40960 * @return {BasicForm} this
40962 render : function(){
40963 this.items.each(function(f){
40964 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40972 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40973 * @param {Object} values
40974 * @return {BasicForm} this
40976 applyToFields : function(o){
40977 this.items.each(function(f){
40984 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40985 * @param {Object} values
40986 * @return {BasicForm} this
40988 applyIfToFields : function(o){
40989 this.items.each(function(f){
40997 Roo.BasicForm = Roo.form.BasicForm;/*
40999 * Ext JS Library 1.1.1
41000 * Copyright(c) 2006-2007, Ext JS, LLC.
41002 * Originally Released Under LGPL - original licence link has changed is not relivant.
41005 * <script type="text/javascript">
41009 * @class Roo.form.Form
41010 * @extends Roo.form.BasicForm
41011 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
41013 * @param {Object} config Configuration options
41015 Roo.form.Form = function(config){
41017 if (config.items) {
41018 xitems = config.items;
41019 delete config.items;
41023 Roo.form.Form.superclass.constructor.call(this, null, config);
41024 this.url = this.url || this.action;
41026 this.root = new Roo.form.Layout(Roo.applyIf({
41030 this.active = this.root;
41032 * Array of all the buttons that have been added to this form via {@link addButton}
41036 this.allItems = [];
41039 * @event clientvalidation
41040 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
41041 * @param {Form} this
41042 * @param {Boolean} valid true if the form has passed client-side validation
41044 clientvalidation: true,
41047 * Fires when the form is rendered
41048 * @param {Roo.form.Form} form
41053 if (this.progressUrl) {
41054 // push a hidden field onto the list of fields..
41058 name : 'UPLOAD_IDENTIFIER'
41063 Roo.each(xitems, this.addxtype, this);
41069 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
41071 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
41074 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
41077 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
41079 buttonAlign:'center',
41082 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
41087 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
41088 * This property cascades to child containers if not set.
41093 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
41094 * fires a looping event with that state. This is required to bind buttons to the valid
41095 * state using the config value formBind:true on the button.
41097 monitorValid : false,
41100 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
41105 * @cfg {String} progressUrl - Url to return progress data
41108 progressUrl : false,
41111 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
41112 * fields are added and the column is closed. If no fields are passed the column remains open
41113 * until end() is called.
41114 * @param {Object} config The config to pass to the column
41115 * @param {Field} field1 (optional)
41116 * @param {Field} field2 (optional)
41117 * @param {Field} etc (optional)
41118 * @return Column The column container object
41120 column : function(c){
41121 var col = new Roo.form.Column(c);
41123 if(arguments.length > 1){ // duplicate code required because of Opera
41124 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41131 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
41132 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
41133 * until end() is called.
41134 * @param {Object} config The config to pass to the fieldset
41135 * @param {Field} field1 (optional)
41136 * @param {Field} field2 (optional)
41137 * @param {Field} etc (optional)
41138 * @return FieldSet The fieldset container object
41140 fieldset : function(c){
41141 var fs = new Roo.form.FieldSet(c);
41143 if(arguments.length > 1){ // duplicate code required because of Opera
41144 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41151 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
41152 * fields are added and the container is closed. If no fields are passed the container remains open
41153 * until end() is called.
41154 * @param {Object} config The config to pass to the Layout
41155 * @param {Field} field1 (optional)
41156 * @param {Field} field2 (optional)
41157 * @param {Field} etc (optional)
41158 * @return Layout The container object
41160 container : function(c){
41161 var l = new Roo.form.Layout(c);
41163 if(arguments.length > 1){ // duplicate code required because of Opera
41164 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41171 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41172 * @param {Object} container A Roo.form.Layout or subclass of Layout
41173 * @return {Form} this
41175 start : function(c){
41176 // cascade label info
41177 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
41178 this.active.stack.push(c);
41179 c.ownerCt = this.active;
41185 * Closes the current open container
41186 * @return {Form} this
41189 if(this.active == this.root){
41192 this.active = this.active.ownerCt;
41197 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
41198 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
41199 * as the label of the field.
41200 * @param {Field} field1
41201 * @param {Field} field2 (optional)
41202 * @param {Field} etc. (optional)
41203 * @return {Form} this
41206 this.active.stack.push.apply(this.active.stack, arguments);
41207 this.allItems.push.apply(this.allItems,arguments);
41209 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
41210 if(a[i].isFormField){
41215 Roo.form.Form.superclass.add.apply(this, r);
41225 * Find any element that has been added to a form, using it's ID or name
41226 * This can include framesets, columns etc. along with regular fields..
41227 * @param {String} id - id or name to find.
41229 * @return {Element} e - or false if nothing found.
41231 findbyId : function(id)
41237 Roo.each(this.allItems, function(f){
41238 if (f.id == id || f.name == id ){
41249 * Render this form into the passed container. This should only be called once!
41250 * @param {String/HTMLElement/Element} container The element this component should be rendered into
41251 * @return {Form} this
41253 render : function(ct)
41259 var o = this.autoCreate || {
41261 method : this.method || 'POST',
41262 id : this.id || Roo.id()
41264 this.initEl(ct.createChild(o));
41266 this.root.render(this.el);
41270 this.items.each(function(f){
41271 f.render('x-form-el-'+f.id);
41274 if(this.buttons.length > 0){
41275 // tables are required to maintain order and for correct IE layout
41276 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
41277 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
41278 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
41280 var tr = tb.getElementsByTagName('tr')[0];
41281 for(var i = 0, len = this.buttons.length; i < len; i++) {
41282 var b = this.buttons[i];
41283 var td = document.createElement('td');
41284 td.className = 'x-form-btn-td';
41285 b.render(tr.appendChild(td));
41288 if(this.monitorValid){ // initialize after render
41289 this.startMonitoring();
41291 this.fireEvent('rendered', this);
41296 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
41297 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
41298 * object or a valid Roo.DomHelper element config
41299 * @param {Function} handler The function called when the button is clicked
41300 * @param {Object} scope (optional) The scope of the handler function
41301 * @return {Roo.Button}
41303 addButton : function(config, handler, scope){
41307 minWidth: this.minButtonWidth,
41310 if(typeof config == "string"){
41313 Roo.apply(bc, config);
41315 var btn = new Roo.Button(null, bc);
41316 this.buttons.push(btn);
41321 * Adds a series of form elements (using the xtype property as the factory method.
41322 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41323 * @param {Object} config
41326 addxtype : function()
41328 var ar = Array.prototype.slice.call(arguments, 0);
41330 for(var i = 0; i < ar.length; i++) {
41332 continue; // skip -- if this happends something invalid got sent, we
41333 // should ignore it, as basically that interface element will not show up
41334 // and that should be pretty obvious!!
41337 if (Roo.form[ar[i].xtype]) {
41339 var fe = Roo.factory(ar[i], Roo.form);
41345 fe.store.form = this;
41350 this.allItems.push(fe);
41351 if (fe.items && fe.addxtype) {
41352 fe.addxtype.apply(fe, fe.items);
41362 // console.log('adding ' + ar[i].xtype);
41364 if (ar[i].xtype == 'Button') {
41365 //console.log('adding button');
41366 //console.log(ar[i]);
41367 this.addButton(ar[i]);
41368 this.allItems.push(fe);
41372 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
41373 alert('end is not supported on xtype any more, use items');
41375 // //console.log('adding end');
41383 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
41384 * option "monitorValid"
41386 startMonitoring : function(){
41389 Roo.TaskMgr.start({
41390 run : this.bindHandler,
41391 interval : this.monitorPoll || 200,
41398 * Stops monitoring of the valid state of this form
41400 stopMonitoring : function(){
41401 this.bound = false;
41405 bindHandler : function(){
41407 return false; // stops binding
41410 this.items.each(function(f){
41411 if(!f.isValid(true)){
41416 for(var i = 0, len = this.buttons.length; i < len; i++){
41417 var btn = this.buttons[i];
41418 if(btn.formBind === true && btn.disabled === valid){
41419 btn.setDisabled(!valid);
41422 this.fireEvent('clientvalidation', this, valid);
41436 Roo.Form = Roo.form.Form;
41439 * Ext JS Library 1.1.1
41440 * Copyright(c) 2006-2007, Ext JS, LLC.
41442 * Originally Released Under LGPL - original licence link has changed is not relivant.
41445 * <script type="text/javascript">
41449 * @class Roo.form.Action
41450 * Internal Class used to handle form actions
41452 * @param {Roo.form.BasicForm} el The form element or its id
41453 * @param {Object} config Configuration options
41457 // define the action interface
41458 Roo.form.Action = function(form, options){
41460 this.options = options || {};
41463 * Client Validation Failed
41466 Roo.form.Action.CLIENT_INVALID = 'client';
41468 * Server Validation Failed
41471 Roo.form.Action.SERVER_INVALID = 'server';
41473 * Connect to Server Failed
41476 Roo.form.Action.CONNECT_FAILURE = 'connect';
41478 * Reading Data from Server Failed
41481 Roo.form.Action.LOAD_FAILURE = 'load';
41483 Roo.form.Action.prototype = {
41485 failureType : undefined,
41486 response : undefined,
41487 result : undefined,
41489 // interface method
41490 run : function(options){
41494 // interface method
41495 success : function(response){
41499 // interface method
41500 handleResponse : function(response){
41504 // default connection failure
41505 failure : function(response){
41507 this.response = response;
41508 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41509 this.form.afterAction(this, false);
41512 processResponse : function(response){
41513 this.response = response;
41514 if(!response.responseText){
41517 this.result = this.handleResponse(response);
41518 return this.result;
41521 // utility functions used internally
41522 getUrl : function(appendParams){
41523 var url = this.options.url || this.form.url || this.form.el.dom.action;
41525 var p = this.getParams();
41527 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
41533 getMethod : function(){
41534 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
41537 getParams : function(){
41538 var bp = this.form.baseParams;
41539 var p = this.options.params;
41541 if(typeof p == "object"){
41542 p = Roo.urlEncode(Roo.applyIf(p, bp));
41543 }else if(typeof p == 'string' && bp){
41544 p += '&' + Roo.urlEncode(bp);
41547 p = Roo.urlEncode(bp);
41552 createCallback : function(){
41554 success: this.success,
41555 failure: this.failure,
41557 timeout: (this.form.timeout*1000),
41558 upload: this.form.fileUpload ? this.success : undefined
41563 Roo.form.Action.Submit = function(form, options){
41564 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
41567 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
41570 haveProgress : false,
41571 uploadComplete : false,
41573 // uploadProgress indicator.
41574 uploadProgress : function()
41576 if (!this.form.progressUrl) {
41580 if (!this.haveProgress) {
41581 Roo.MessageBox.progress("Uploading", "Uploading");
41583 if (this.uploadComplete) {
41584 Roo.MessageBox.hide();
41588 this.haveProgress = true;
41590 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
41592 var c = new Roo.data.Connection();
41594 url : this.form.progressUrl,
41599 success : function(req){
41600 //console.log(data);
41604 rdata = Roo.decode(req.responseText)
41606 Roo.log("Invalid data from server..");
41610 if (!rdata || !rdata.success) {
41614 var data = rdata.data;
41616 if (this.uploadComplete) {
41617 Roo.MessageBox.hide();
41622 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
41623 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
41626 this.uploadProgress.defer(2000,this);
41629 failure: function(data) {
41630 Roo.log('progress url failed ');
41641 // run get Values on the form, so it syncs any secondary forms.
41642 this.form.getValues();
41644 var o = this.options;
41645 var method = this.getMethod();
41646 var isPost = method == 'POST';
41647 if(o.clientValidation === false || this.form.isValid()){
41649 if (this.form.progressUrl) {
41650 this.form.findField('UPLOAD_IDENTIFIER').setValue(
41651 (new Date() * 1) + '' + Math.random());
41656 Roo.Ajax.request(Roo.apply(this.createCallback(), {
41657 form:this.form.el.dom,
41658 url:this.getUrl(!isPost),
41660 params:isPost ? this.getParams() : null,
41661 isUpload: this.form.fileUpload
41664 this.uploadProgress();
41666 }else if (o.clientValidation !== false){ // client validation failed
41667 this.failureType = Roo.form.Action.CLIENT_INVALID;
41668 this.form.afterAction(this, false);
41672 success : function(response)
41674 this.uploadComplete= true;
41675 if (this.haveProgress) {
41676 Roo.MessageBox.hide();
41680 var result = this.processResponse(response);
41681 if(result === true || result.success){
41682 this.form.afterAction(this, true);
41686 this.form.markInvalid(result.errors);
41687 this.failureType = Roo.form.Action.SERVER_INVALID;
41689 this.form.afterAction(this, false);
41691 failure : function(response)
41693 this.uploadComplete= true;
41694 if (this.haveProgress) {
41695 Roo.MessageBox.hide();
41699 this.response = response;
41700 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41701 this.form.afterAction(this, false);
41704 handleResponse : function(response){
41705 if(this.form.errorReader){
41706 var rs = this.form.errorReader.read(response);
41709 for(var i = 0, len = rs.records.length; i < len; i++) {
41710 var r = rs.records[i];
41711 errors[i] = r.data;
41714 if(errors.length < 1){
41718 success : rs.success,
41724 ret = Roo.decode(response.responseText);
41728 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
41738 Roo.form.Action.Load = function(form, options){
41739 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
41740 this.reader = this.form.reader;
41743 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
41748 Roo.Ajax.request(Roo.apply(
41749 this.createCallback(), {
41750 method:this.getMethod(),
41751 url:this.getUrl(false),
41752 params:this.getParams()
41756 success : function(response){
41758 var result = this.processResponse(response);
41759 if(result === true || !result.success || !result.data){
41760 this.failureType = Roo.form.Action.LOAD_FAILURE;
41761 this.form.afterAction(this, false);
41764 this.form.clearInvalid();
41765 this.form.setValues(result.data);
41766 this.form.afterAction(this, true);
41769 handleResponse : function(response){
41770 if(this.form.reader){
41771 var rs = this.form.reader.read(response);
41772 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
41774 success : rs.success,
41778 return Roo.decode(response.responseText);
41782 Roo.form.Action.ACTION_TYPES = {
41783 'load' : Roo.form.Action.Load,
41784 'submit' : Roo.form.Action.Submit
41787 * Ext JS Library 1.1.1
41788 * Copyright(c) 2006-2007, Ext JS, LLC.
41790 * Originally Released Under LGPL - original licence link has changed is not relivant.
41793 * <script type="text/javascript">
41797 * @class Roo.form.Layout
41798 * @extends Roo.Component
41799 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
41801 * @param {Object} config Configuration options
41803 Roo.form.Layout = function(config){
41805 if (config.items) {
41806 xitems = config.items;
41807 delete config.items;
41809 Roo.form.Layout.superclass.constructor.call(this, config);
41811 Roo.each(xitems, this.addxtype, this);
41815 Roo.extend(Roo.form.Layout, Roo.Component, {
41817 * @cfg {String/Object} autoCreate
41818 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
41821 * @cfg {String/Object/Function} style
41822 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
41823 * a function which returns such a specification.
41826 * @cfg {String} labelAlign
41827 * Valid values are "left," "top" and "right" (defaults to "left")
41830 * @cfg {Number} labelWidth
41831 * Fixed width in pixels of all field labels (defaults to undefined)
41834 * @cfg {Boolean} clear
41835 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
41839 * @cfg {String} labelSeparator
41840 * The separator to use after field labels (defaults to ':')
41842 labelSeparator : ':',
41844 * @cfg {Boolean} hideLabels
41845 * True to suppress the display of field labels in this layout (defaults to false)
41847 hideLabels : false,
41850 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
41855 onRender : function(ct, position){
41856 if(this.el){ // from markup
41857 this.el = Roo.get(this.el);
41858 }else { // generate
41859 var cfg = this.getAutoCreate();
41860 this.el = ct.createChild(cfg, position);
41863 this.el.applyStyles(this.style);
41865 if(this.labelAlign){
41866 this.el.addClass('x-form-label-'+this.labelAlign);
41868 if(this.hideLabels){
41869 this.labelStyle = "display:none";
41870 this.elementStyle = "padding-left:0;";
41872 if(typeof this.labelWidth == 'number'){
41873 this.labelStyle = "width:"+this.labelWidth+"px;";
41874 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
41876 if(this.labelAlign == 'top'){
41877 this.labelStyle = "width:auto;";
41878 this.elementStyle = "padding-left:0;";
41881 var stack = this.stack;
41882 var slen = stack.length;
41884 if(!this.fieldTpl){
41885 var t = new Roo.Template(
41886 '<div class="x-form-item {5}">',
41887 '<label for="{0}" style="{2}">{1}{4}</label>',
41888 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41890 '</div><div class="x-form-clear-left"></div>'
41892 t.disableFormats = true;
41894 Roo.form.Layout.prototype.fieldTpl = t;
41896 for(var i = 0; i < slen; i++) {
41897 if(stack[i].isFormField){
41898 this.renderField(stack[i]);
41900 this.renderComponent(stack[i]);
41905 this.el.createChild({cls:'x-form-clear'});
41910 renderField : function(f){
41911 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
41914 f.labelStyle||this.labelStyle||'', //2
41915 this.elementStyle||'', //3
41916 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
41917 f.itemCls||this.itemCls||'' //5
41918 ], true).getPrevSibling());
41922 renderComponent : function(c){
41923 c.render(c.isLayout ? this.el : this.el.createChild());
41926 * Adds a object form elements (using the xtype property as the factory method.)
41927 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
41928 * @param {Object} config
41930 addxtype : function(o)
41932 // create the lement.
41933 o.form = this.form;
41934 var fe = Roo.factory(o, Roo.form);
41935 this.form.allItems.push(fe);
41936 this.stack.push(fe);
41938 if (fe.isFormField) {
41939 this.form.items.add(fe);
41947 * @class Roo.form.Column
41948 * @extends Roo.form.Layout
41949 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
41951 * @param {Object} config Configuration options
41953 Roo.form.Column = function(config){
41954 Roo.form.Column.superclass.constructor.call(this, config);
41957 Roo.extend(Roo.form.Column, Roo.form.Layout, {
41959 * @cfg {Number/String} width
41960 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41963 * @cfg {String/Object} autoCreate
41964 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41968 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41971 onRender : function(ct, position){
41972 Roo.form.Column.superclass.onRender.call(this, ct, position);
41974 this.el.setWidth(this.width);
41981 * @class Roo.form.Row
41982 * @extends Roo.form.Layout
41983 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41985 * @param {Object} config Configuration options
41989 Roo.form.Row = function(config){
41990 Roo.form.Row.superclass.constructor.call(this, config);
41993 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41995 * @cfg {Number/String} width
41996 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41999 * @cfg {Number/String} height
42000 * The fixed height of the column in pixels or CSS value (defaults to "auto")
42002 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
42006 onRender : function(ct, position){
42007 //console.log('row render');
42009 var t = new Roo.Template(
42010 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
42011 '<label for="{0}" style="{2}">{1}{4}</label>',
42012 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
42016 t.disableFormats = true;
42018 Roo.form.Layout.prototype.rowTpl = t;
42020 this.fieldTpl = this.rowTpl;
42022 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
42023 var labelWidth = 100;
42025 if ((this.labelAlign != 'top')) {
42026 if (typeof this.labelWidth == 'number') {
42027 labelWidth = this.labelWidth
42029 this.padWidth = 20 + labelWidth;
42033 Roo.form.Column.superclass.onRender.call(this, ct, position);
42035 this.el.setWidth(this.width);
42038 this.el.setHeight(this.height);
42043 renderField : function(f){
42044 f.fieldEl = this.fieldTpl.append(this.el, [
42045 f.id, f.fieldLabel,
42046 f.labelStyle||this.labelStyle||'',
42047 this.elementStyle||'',
42048 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
42049 f.itemCls||this.itemCls||'',
42050 f.width ? f.width + this.padWidth : 160 + this.padWidth
42057 * @class Roo.form.FieldSet
42058 * @extends Roo.form.Layout
42059 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
42061 * @param {Object} config Configuration options
42063 Roo.form.FieldSet = function(config){
42064 Roo.form.FieldSet.superclass.constructor.call(this, config);
42067 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
42069 * @cfg {String} legend
42070 * The text to display as the legend for the FieldSet (defaults to '')
42073 * @cfg {String/Object} autoCreate
42074 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
42078 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
42081 onRender : function(ct, position){
42082 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
42084 this.setLegend(this.legend);
42089 setLegend : function(text){
42091 this.el.child('legend').update(text);
42096 * Ext JS Library 1.1.1
42097 * Copyright(c) 2006-2007, Ext JS, LLC.
42099 * Originally Released Under LGPL - original licence link has changed is not relivant.
42102 * <script type="text/javascript">
42105 * @class Roo.form.VTypes
42106 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
42109 Roo.form.VTypes = function(){
42110 // closure these in so they are only created once.
42111 var alpha = /^[a-zA-Z_]+$/;
42112 var alphanum = /^[a-zA-Z0-9_]+$/;
42113 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
42114 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
42116 // All these messages and functions are configurable
42119 * The function used to validate email addresses
42120 * @param {String} value The email address
42122 'email' : function(v){
42123 return email.test(v);
42126 * The error text to display when the email validation function returns false
42129 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
42131 * The keystroke filter mask to be applied on email input
42134 'emailMask' : /[a-z0-9_\.\-@]/i,
42137 * The function used to validate URLs
42138 * @param {String} value The URL
42140 'url' : function(v){
42141 return url.test(v);
42144 * The error text to display when the url validation function returns false
42147 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
42150 * The function used to validate alpha values
42151 * @param {String} value The value
42153 'alpha' : function(v){
42154 return alpha.test(v);
42157 * The error text to display when the alpha validation function returns false
42160 'alphaText' : 'This field should only contain letters and _',
42162 * The keystroke filter mask to be applied on alpha input
42165 'alphaMask' : /[a-z_]/i,
42168 * The function used to validate alphanumeric values
42169 * @param {String} value The value
42171 'alphanum' : function(v){
42172 return alphanum.test(v);
42175 * The error text to display when the alphanumeric validation function returns false
42178 'alphanumText' : 'This field should only contain letters, numbers and _',
42180 * The keystroke filter mask to be applied on alphanumeric input
42183 'alphanumMask' : /[a-z0-9_]/i
42185 }();//<script type="text/javascript">
42188 * @class Roo.form.FCKeditor
42189 * @extends Roo.form.TextArea
42190 * Wrapper around the FCKEditor http://www.fckeditor.net
42192 * Creates a new FCKeditor
42193 * @param {Object} config Configuration options
42195 Roo.form.FCKeditor = function(config){
42196 Roo.form.FCKeditor.superclass.constructor.call(this, config);
42199 * @event editorinit
42200 * Fired when the editor is initialized - you can add extra handlers here..
42201 * @param {FCKeditor} this
42202 * @param {Object} the FCK object.
42209 Roo.form.FCKeditor.editors = { };
42210 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
42212 //defaultAutoCreate : {
42213 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
42217 * @cfg {Object} fck options - see fck manual for details.
42222 * @cfg {Object} fck toolbar set (Basic or Default)
42224 toolbarSet : 'Basic',
42226 * @cfg {Object} fck BasePath
42228 basePath : '/fckeditor/',
42236 onRender : function(ct, position)
42239 this.defaultAutoCreate = {
42241 style:"width:300px;height:60px;",
42242 autocomplete: "off"
42245 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
42248 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
42249 if(this.preventScrollbars){
42250 this.el.setStyle("overflow", "hidden");
42252 this.el.setHeight(this.growMin);
42255 //console.log('onrender' + this.getId() );
42256 Roo.form.FCKeditor.editors[this.getId()] = this;
42259 this.replaceTextarea() ;
42263 getEditor : function() {
42264 return this.fckEditor;
42267 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
42268 * @param {Mixed} value The value to set
42272 setValue : function(value)
42274 //console.log('setValue: ' + value);
42276 if(typeof(value) == 'undefined') { // not sure why this is happending...
42279 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42281 //if(!this.el || !this.getEditor()) {
42282 // this.value = value;
42283 //this.setValue.defer(100,this,[value]);
42287 if(!this.getEditor()) {
42291 this.getEditor().SetData(value);
42298 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
42299 * @return {Mixed} value The field value
42301 getValue : function()
42304 if (this.frame && this.frame.dom.style.display == 'none') {
42305 return Roo.form.FCKeditor.superclass.getValue.call(this);
42308 if(!this.el || !this.getEditor()) {
42310 // this.getValue.defer(100,this);
42315 var value=this.getEditor().GetData();
42316 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42317 return Roo.form.FCKeditor.superclass.getValue.call(this);
42323 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
42324 * @return {Mixed} value The field value
42326 getRawValue : function()
42328 if (this.frame && this.frame.dom.style.display == 'none') {
42329 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42332 if(!this.el || !this.getEditor()) {
42333 //this.getRawValue.defer(100,this);
42340 var value=this.getEditor().GetData();
42341 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
42342 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42346 setSize : function(w,h) {
42350 //if (this.frame && this.frame.dom.style.display == 'none') {
42351 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42354 //if(!this.el || !this.getEditor()) {
42355 // this.setSize.defer(100,this, [w,h]);
42361 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42363 this.frame.dom.setAttribute('width', w);
42364 this.frame.dom.setAttribute('height', h);
42365 this.frame.setSize(w,h);
42369 toggleSourceEdit : function(value) {
42373 this.el.dom.style.display = value ? '' : 'none';
42374 this.frame.dom.style.display = value ? 'none' : '';
42379 focus: function(tag)
42381 if (this.frame.dom.style.display == 'none') {
42382 return Roo.form.FCKeditor.superclass.focus.call(this);
42384 if(!this.el || !this.getEditor()) {
42385 this.focus.defer(100,this, [tag]);
42392 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
42393 this.getEditor().Focus();
42395 if (!this.getEditor().Selection.GetSelection()) {
42396 this.focus.defer(100,this, [tag]);
42401 var r = this.getEditor().EditorDocument.createRange();
42402 r.setStart(tgs[0],0);
42403 r.setEnd(tgs[0],0);
42404 this.getEditor().Selection.GetSelection().removeAllRanges();
42405 this.getEditor().Selection.GetSelection().addRange(r);
42406 this.getEditor().Focus();
42413 replaceTextarea : function()
42415 if ( document.getElementById( this.getId() + '___Frame' ) )
42417 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
42419 // We must check the elements firstly using the Id and then the name.
42420 var oTextarea = document.getElementById( this.getId() );
42422 var colElementsByName = document.getElementsByName( this.getId() ) ;
42424 oTextarea.style.display = 'none' ;
42426 if ( oTextarea.tabIndex ) {
42427 this.TabIndex = oTextarea.tabIndex ;
42430 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
42431 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
42432 this.frame = Roo.get(this.getId() + '___Frame')
42435 _getConfigHtml : function()
42439 for ( var o in this.fckconfig ) {
42440 sConfig += sConfig.length > 0 ? '&' : '';
42441 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
42444 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
42448 _getIFrameHtml : function()
42450 var sFile = 'fckeditor.html' ;
42451 /* no idea what this is about..
42454 if ( (/fcksource=true/i).test( window.top.location.search ) )
42455 sFile = 'fckeditor.original.html' ;
42460 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
42461 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
42464 var html = '<iframe id="' + this.getId() +
42465 '___Frame" src="' + sLink +
42466 '" width="' + this.width +
42467 '" height="' + this.height + '"' +
42468 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
42469 ' frameborder="0" scrolling="no"></iframe>' ;
42474 _insertHtmlBefore : function( html, element )
42476 if ( element.insertAdjacentHTML ) {
42478 element.insertAdjacentHTML( 'beforeBegin', html ) ;
42480 var oRange = document.createRange() ;
42481 oRange.setStartBefore( element ) ;
42482 var oFragment = oRange.createContextualFragment( html );
42483 element.parentNode.insertBefore( oFragment, element ) ;
42496 //Roo.reg('fckeditor', Roo.form.FCKeditor);
42498 function FCKeditor_OnComplete(editorInstance){
42499 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
42500 f.fckEditor = editorInstance;
42501 //console.log("loaded");
42502 f.fireEvent('editorinit', f, editorInstance);
42522 //<script type="text/javascript">
42524 * @class Roo.form.GridField
42525 * @extends Roo.form.Field
42526 * Embed a grid (or editable grid into a form)
42529 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
42531 * xgrid.store = Roo.data.Store
42532 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
42533 * xgrid.store.reader = Roo.data.JsonReader
42537 * Creates a new GridField
42538 * @param {Object} config Configuration options
42540 Roo.form.GridField = function(config){
42541 Roo.form.GridField.superclass.constructor.call(this, config);
42545 Roo.extend(Roo.form.GridField, Roo.form.Field, {
42547 * @cfg {Number} width - used to restrict width of grid..
42551 * @cfg {Number} height - used to restrict height of grid..
42555 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
42561 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42562 * {tag: "input", type: "checkbox", autocomplete: "off"})
42564 // defaultAutoCreate : { tag: 'div' },
42565 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42567 * @cfg {String} addTitle Text to include for adding a title.
42571 onResize : function(){
42572 Roo.form.Field.superclass.onResize.apply(this, arguments);
42575 initEvents : function(){
42576 // Roo.form.Checkbox.superclass.initEvents.call(this);
42577 // has no events...
42582 getResizeEl : function(){
42586 getPositionEl : function(){
42591 onRender : function(ct, position){
42593 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
42594 var style = this.style;
42597 Roo.form.GridField.superclass.onRender.call(this, ct, position);
42598 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
42599 this.viewEl = this.wrap.createChild({ tag: 'div' });
42601 this.viewEl.applyStyles(style);
42604 this.viewEl.setWidth(this.width);
42607 this.viewEl.setHeight(this.height);
42609 //if(this.inputValue !== undefined){
42610 //this.setValue(this.value);
42613 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
42616 this.grid.render();
42617 this.grid.getDataSource().on('remove', this.refreshValue, this);
42618 this.grid.getDataSource().on('update', this.refreshValue, this);
42619 this.grid.on('afteredit', this.refreshValue, this);
42625 * Sets the value of the item.
42626 * @param {String} either an object or a string..
42628 setValue : function(v){
42630 v = v || []; // empty set..
42631 // this does not seem smart - it really only affects memoryproxy grids..
42632 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
42633 var ds = this.grid.getDataSource();
42634 // assumes a json reader..
42636 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
42637 ds.loadData( data);
42639 Roo.form.GridField.superclass.setValue.call(this, v);
42640 this.refreshValue();
42641 // should load data in the grid really....
42645 refreshValue: function() {
42647 this.grid.getDataSource().each(function(r) {
42650 this.el.dom.value = Roo.encode(val);
42658 * Ext JS Library 1.1.1
42659 * Copyright(c) 2006-2007, Ext JS, LLC.
42661 * Originally Released Under LGPL - original licence link has changed is not relivant.
42664 * <script type="text/javascript">
42667 * @class Roo.form.DisplayField
42668 * @extends Roo.form.Field
42669 * A generic Field to display non-editable data.
42671 * Creates a new Display Field item.
42672 * @param {Object} config Configuration options
42674 Roo.form.DisplayField = function(config){
42675 Roo.form.DisplayField.superclass.constructor.call(this, config);
42679 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
42680 inputType: 'hidden',
42686 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42688 focusClass : undefined,
42690 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42692 fieldClass: 'x-form-field',
42695 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
42697 valueRenderer: undefined,
42701 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42702 * {tag: "input", type: "checkbox", autocomplete: "off"})
42705 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42707 onResize : function(){
42708 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
42712 initEvents : function(){
42713 // Roo.form.Checkbox.superclass.initEvents.call(this);
42714 // has no events...
42719 getResizeEl : function(){
42723 getPositionEl : function(){
42728 onRender : function(ct, position){
42730 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
42731 //if(this.inputValue !== undefined){
42732 this.wrap = this.el.wrap();
42734 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
42736 if (this.bodyStyle) {
42737 this.viewEl.applyStyles(this.bodyStyle);
42739 //this.viewEl.setStyle('padding', '2px');
42741 this.setValue(this.value);
42746 initValue : Roo.emptyFn,
42751 onClick : function(){
42756 * Sets the checked state of the checkbox.
42757 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
42759 setValue : function(v){
42761 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
42762 // this might be called before we have a dom element..
42763 if (!this.viewEl) {
42766 this.viewEl.dom.innerHTML = html;
42767 Roo.form.DisplayField.superclass.setValue.call(this, v);
42777 * @class Roo.form.DayPicker
42778 * @extends Roo.form.Field
42779 * A Day picker show [M] [T] [W] ....
42781 * Creates a new Day Picker
42782 * @param {Object} config Configuration options
42784 Roo.form.DayPicker= function(config){
42785 Roo.form.DayPicker.superclass.constructor.call(this, config);
42789 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
42791 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42793 focusClass : undefined,
42795 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42797 fieldClass: "x-form-field",
42800 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42801 * {tag: "input", type: "checkbox", autocomplete: "off"})
42803 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42806 actionMode : 'viewEl',
42810 inputType : 'hidden',
42813 inputElement: false, // real input element?
42814 basedOn: false, // ????
42816 isFormField: true, // not sure where this is needed!!!!
42818 onResize : function(){
42819 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42820 if(!this.boxLabel){
42821 this.el.alignTo(this.wrap, 'c-c');
42825 initEvents : function(){
42826 Roo.form.Checkbox.superclass.initEvents.call(this);
42827 this.el.on("click", this.onClick, this);
42828 this.el.on("change", this.onClick, this);
42832 getResizeEl : function(){
42836 getPositionEl : function(){
42842 onRender : function(ct, position){
42843 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42845 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
42847 var r1 = '<table><tr>';
42848 var r2 = '<tr class="x-form-daypick-icons">';
42849 for (var i=0; i < 7; i++) {
42850 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
42851 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
42854 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
42855 viewEl.select('img').on('click', this.onClick, this);
42856 this.viewEl = viewEl;
42859 // this will not work on Chrome!!!
42860 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42861 this.el.on('propertychange', this.setFromHidden, this); //ie
42869 initValue : Roo.emptyFn,
42872 * Returns the checked state of the checkbox.
42873 * @return {Boolean} True if checked, else false
42875 getValue : function(){
42876 return this.el.dom.value;
42881 onClick : function(e){
42882 //this.setChecked(!this.checked);
42883 Roo.get(e.target).toggleClass('x-menu-item-checked');
42884 this.refreshValue();
42885 //if(this.el.dom.checked != this.checked){
42886 // this.setValue(this.el.dom.checked);
42891 refreshValue : function()
42894 this.viewEl.select('img',true).each(function(e,i,n) {
42895 val += e.is(".x-menu-item-checked") ? String(n) : '';
42897 this.setValue(val, true);
42901 * Sets the checked state of the checkbox.
42902 * On is always based on a string comparison between inputValue and the param.
42903 * @param {Boolean/String} value - the value to set
42904 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42906 setValue : function(v,suppressEvent){
42907 if (!this.el.dom) {
42910 var old = this.el.dom.value ;
42911 this.el.dom.value = v;
42912 if (suppressEvent) {
42916 // update display..
42917 this.viewEl.select('img',true).each(function(e,i,n) {
42919 var on = e.is(".x-menu-item-checked");
42920 var newv = v.indexOf(String(n)) > -1;
42922 e.toggleClass('x-menu-item-checked');
42928 this.fireEvent('change', this, v, old);
42933 // handle setting of hidden value by some other method!!?!?
42934 setFromHidden: function()
42939 //console.log("SET FROM HIDDEN");
42940 //alert('setFrom hidden');
42941 this.setValue(this.el.dom.value);
42944 onDestroy : function()
42947 Roo.get(this.viewEl).remove();
42950 Roo.form.DayPicker.superclass.onDestroy.call(this);
42953 });//<script type="text/javasscript">
42957 * @class Roo.DDView
42958 * A DnD enabled version of Roo.View.
42959 * @param {Element/String} container The Element in which to create the View.
42960 * @param {String} tpl The template string used to create the markup for each element of the View
42961 * @param {Object} config The configuration properties. These include all the config options of
42962 * {@link Roo.View} plus some specific to this class.<br>
42964 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
42965 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
42967 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
42968 .x-view-drag-insert-above {
42969 border-top:1px dotted #3366cc;
42971 .x-view-drag-insert-below {
42972 border-bottom:1px dotted #3366cc;
42978 Roo.DDView = function(container, tpl, config) {
42979 Roo.DDView.superclass.constructor.apply(this, arguments);
42980 this.getEl().setStyle("outline", "0px none");
42981 this.getEl().unselectable();
42982 if (this.dragGroup) {
42983 this.setDraggable(this.dragGroup.split(","));
42985 if (this.dropGroup) {
42986 this.setDroppable(this.dropGroup.split(","));
42988 if (this.deletable) {
42989 this.setDeletable();
42991 this.isDirtyFlag = false;
42997 Roo.extend(Roo.DDView, Roo.View, {
42998 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
42999 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
43000 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
43001 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
43005 reset: Roo.emptyFn,
43007 clearInvalid: Roo.form.Field.prototype.clearInvalid,
43009 validate: function() {
43013 destroy: function() {
43014 this.purgeListeners();
43015 this.getEl.removeAllListeners();
43016 this.getEl().remove();
43017 if (this.dragZone) {
43018 if (this.dragZone.destroy) {
43019 this.dragZone.destroy();
43022 if (this.dropZone) {
43023 if (this.dropZone.destroy) {
43024 this.dropZone.destroy();
43029 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
43030 getName: function() {
43034 /** Loads the View from a JSON string representing the Records to put into the Store. */
43035 setValue: function(v) {
43037 throw "DDView.setValue(). DDView must be constructed with a valid Store";
43040 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
43041 this.store.proxy = new Roo.data.MemoryProxy(data);
43045 /** @return {String} a parenthesised list of the ids of the Records in the View. */
43046 getValue: function() {
43048 this.store.each(function(rec) {
43049 result += rec.id + ',';
43051 return result.substr(0, result.length - 1) + ')';
43054 getIds: function() {
43055 var i = 0, result = new Array(this.store.getCount());
43056 this.store.each(function(rec) {
43057 result[i++] = rec.id;
43062 isDirty: function() {
43063 return this.isDirtyFlag;
43067 * Part of the Roo.dd.DropZone interface. If no target node is found, the
43068 * whole Element becomes the target, and this causes the drop gesture to append.
43070 getTargetFromEvent : function(e) {
43071 var target = e.getTarget();
43072 while ((target !== null) && (target.parentNode != this.el.dom)) {
43073 target = target.parentNode;
43076 target = this.el.dom.lastChild || this.el.dom;
43082 * Create the drag data which consists of an object which has the property "ddel" as
43083 * the drag proxy element.
43085 getDragData : function(e) {
43086 var target = this.findItemFromChild(e.getTarget());
43088 this.handleSelection(e);
43089 var selNodes = this.getSelectedNodes();
43092 copy: this.copy || (this.allowCopy && e.ctrlKey),
43096 var selectedIndices = this.getSelectedIndexes();
43097 for (var i = 0; i < selectedIndices.length; i++) {
43098 dragData.records.push(this.store.getAt(selectedIndices[i]));
43100 if (selNodes.length == 1) {
43101 dragData.ddel = target.cloneNode(true); // the div element
43103 var div = document.createElement('div'); // create the multi element drag "ghost"
43104 div.className = 'multi-proxy';
43105 for (var i = 0, len = selNodes.length; i < len; i++) {
43106 div.appendChild(selNodes[i].cloneNode(true));
43108 dragData.ddel = div;
43110 //console.log(dragData)
43111 //console.log(dragData.ddel.innerHTML)
43114 //console.log('nodragData')
43118 /** Specify to which ddGroup items in this DDView may be dragged. */
43119 setDraggable: function(ddGroup) {
43120 if (ddGroup instanceof Array) {
43121 Roo.each(ddGroup, this.setDraggable, this);
43124 if (this.dragZone) {
43125 this.dragZone.addToGroup(ddGroup);
43127 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
43128 containerScroll: true,
43132 // Draggability implies selection. DragZone's mousedown selects the element.
43133 if (!this.multiSelect) { this.singleSelect = true; }
43135 // Wire the DragZone's handlers up to methods in *this*
43136 this.dragZone.getDragData = this.getDragData.createDelegate(this);
43140 /** Specify from which ddGroup this DDView accepts drops. */
43141 setDroppable: function(ddGroup) {
43142 if (ddGroup instanceof Array) {
43143 Roo.each(ddGroup, this.setDroppable, this);
43146 if (this.dropZone) {
43147 this.dropZone.addToGroup(ddGroup);
43149 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
43150 containerScroll: true,
43154 // Wire the DropZone's handlers up to methods in *this*
43155 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
43156 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
43157 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
43158 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
43159 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
43163 /** Decide whether to drop above or below a View node. */
43164 getDropPoint : function(e, n, dd){
43165 if (n == this.el.dom) { return "above"; }
43166 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
43167 var c = t + (b - t) / 2;
43168 var y = Roo.lib.Event.getPageY(e);
43176 onNodeEnter : function(n, dd, e, data){
43180 onNodeOver : function(n, dd, e, data){
43181 var pt = this.getDropPoint(e, n, dd);
43182 // set the insert point style on the target node
43183 var dragElClass = this.dropNotAllowed;
43186 if (pt == "above"){
43187 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
43188 targetElClass = "x-view-drag-insert-above";
43190 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
43191 targetElClass = "x-view-drag-insert-below";
43193 if (this.lastInsertClass != targetElClass){
43194 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
43195 this.lastInsertClass = targetElClass;
43198 return dragElClass;
43201 onNodeOut : function(n, dd, e, data){
43202 this.removeDropIndicators(n);
43205 onNodeDrop : function(n, dd, e, data){
43206 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
43209 var pt = this.getDropPoint(e, n, dd);
43210 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
43211 if (pt == "below") { insertAt++; }
43212 for (var i = 0; i < data.records.length; i++) {
43213 var r = data.records[i];
43214 var dup = this.store.getById(r.id);
43215 if (dup && (dd != this.dragZone)) {
43216 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
43219 this.store.insert(insertAt++, r.copy());
43221 data.source.isDirtyFlag = true;
43223 this.store.insert(insertAt++, r);
43225 this.isDirtyFlag = true;
43228 this.dragZone.cachedTarget = null;
43232 removeDropIndicators : function(n){
43234 Roo.fly(n).removeClass([
43235 "x-view-drag-insert-above",
43236 "x-view-drag-insert-below"]);
43237 this.lastInsertClass = "_noclass";
43242 * Utility method. Add a delete option to the DDView's context menu.
43243 * @param {String} imageUrl The URL of the "delete" icon image.
43245 setDeletable: function(imageUrl) {
43246 if (!this.singleSelect && !this.multiSelect) {
43247 this.singleSelect = true;
43249 var c = this.getContextMenu();
43250 this.contextMenu.on("itemclick", function(item) {
43253 this.remove(this.getSelectedIndexes());
43257 this.contextMenu.add({
43264 /** Return the context menu for this DDView. */
43265 getContextMenu: function() {
43266 if (!this.contextMenu) {
43267 // Create the View's context menu
43268 this.contextMenu = new Roo.menu.Menu({
43269 id: this.id + "-contextmenu"
43271 this.el.on("contextmenu", this.showContextMenu, this);
43273 return this.contextMenu;
43276 disableContextMenu: function() {
43277 if (this.contextMenu) {
43278 this.el.un("contextmenu", this.showContextMenu, this);
43282 showContextMenu: function(e, item) {
43283 item = this.findItemFromChild(e.getTarget());
43286 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
43287 this.contextMenu.showAt(e.getXY());
43292 * Remove {@link Roo.data.Record}s at the specified indices.
43293 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
43295 remove: function(selectedIndices) {
43296 selectedIndices = [].concat(selectedIndices);
43297 for (var i = 0; i < selectedIndices.length; i++) {
43298 var rec = this.store.getAt(selectedIndices[i]);
43299 this.store.remove(rec);
43304 * Double click fires the event, but also, if this is draggable, and there is only one other
43305 * related DropZone, it transfers the selected node.
43307 onDblClick : function(e){
43308 var item = this.findItemFromChild(e.getTarget());
43310 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
43313 if (this.dragGroup) {
43314 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
43315 while (targets.indexOf(this.dropZone) > -1) {
43316 targets.remove(this.dropZone);
43318 if (targets.length == 1) {
43319 this.dragZone.cachedTarget = null;
43320 var el = Roo.get(targets[0].getEl());
43321 var box = el.getBox(true);
43322 targets[0].onNodeDrop(el.dom, {
43324 xy: [box.x, box.y + box.height - 1]
43325 }, null, this.getDragData(e));
43331 handleSelection: function(e) {
43332 this.dragZone.cachedTarget = null;
43333 var item = this.findItemFromChild(e.getTarget());
43335 this.clearSelections(true);
43338 if (item && (this.multiSelect || this.singleSelect)){
43339 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
43340 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
43341 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
43342 this.unselect(item);
43344 this.select(item, this.multiSelect && e.ctrlKey);
43345 this.lastSelection = item;
43350 onItemClick : function(item, index, e){
43351 if(this.fireEvent("beforeclick", this, index, item, e) === false){
43357 unselect : function(nodeInfo, suppressEvent){
43358 var node = this.getNode(nodeInfo);
43359 if(node && this.isSelected(node)){
43360 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
43361 Roo.fly(node).removeClass(this.selectedClass);
43362 this.selections.remove(node);
43363 if(!suppressEvent){
43364 this.fireEvent("selectionchange", this, this.selections);
43372 * Ext JS Library 1.1.1
43373 * Copyright(c) 2006-2007, Ext JS, LLC.
43375 * Originally Released Under LGPL - original licence link has changed is not relivant.
43378 * <script type="text/javascript">
43382 * @class Roo.LayoutManager
43383 * @extends Roo.util.Observable
43384 * Base class for layout managers.
43386 Roo.LayoutManager = function(container, config){
43387 Roo.LayoutManager.superclass.constructor.call(this);
43388 this.el = Roo.get(container);
43389 // ie scrollbar fix
43390 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
43391 document.body.scroll = "no";
43392 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
43393 this.el.position('relative');
43395 this.id = this.el.id;
43396 this.el.addClass("x-layout-container");
43397 /** false to disable window resize monitoring @type Boolean */
43398 this.monitorWindowResize = true;
43403 * Fires when a layout is performed.
43404 * @param {Roo.LayoutManager} this
43408 * @event regionresized
43409 * Fires when the user resizes a region.
43410 * @param {Roo.LayoutRegion} region The resized region
43411 * @param {Number} newSize The new size (width for east/west, height for north/south)
43413 "regionresized" : true,
43415 * @event regioncollapsed
43416 * Fires when a region is collapsed.
43417 * @param {Roo.LayoutRegion} region The collapsed region
43419 "regioncollapsed" : true,
43421 * @event regionexpanded
43422 * Fires when a region is expanded.
43423 * @param {Roo.LayoutRegion} region The expanded region
43425 "regionexpanded" : true
43427 this.updating = false;
43428 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
43431 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
43433 * Returns true if this layout is currently being updated
43434 * @return {Boolean}
43436 isUpdating : function(){
43437 return this.updating;
43441 * Suspend the LayoutManager from doing auto-layouts while
43442 * making multiple add or remove calls
43444 beginUpdate : function(){
43445 this.updating = true;
43449 * Restore auto-layouts and optionally disable the manager from performing a layout
43450 * @param {Boolean} noLayout true to disable a layout update
43452 endUpdate : function(noLayout){
43453 this.updating = false;
43459 layout: function(){
43463 onRegionResized : function(region, newSize){
43464 this.fireEvent("regionresized", region, newSize);
43468 onRegionCollapsed : function(region){
43469 this.fireEvent("regioncollapsed", region);
43472 onRegionExpanded : function(region){
43473 this.fireEvent("regionexpanded", region);
43477 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
43478 * performs box-model adjustments.
43479 * @return {Object} The size as an object {width: (the width), height: (the height)}
43481 getViewSize : function(){
43483 if(this.el.dom != document.body){
43484 size = this.el.getSize();
43486 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
43488 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
43489 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
43494 * Returns the Element this layout is bound to.
43495 * @return {Roo.Element}
43497 getEl : function(){
43502 * Returns the specified region.
43503 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
43504 * @return {Roo.LayoutRegion}
43506 getRegion : function(target){
43507 return this.regions[target.toLowerCase()];
43510 onWindowResize : function(){
43511 if(this.monitorWindowResize){
43517 * Ext JS Library 1.1.1
43518 * Copyright(c) 2006-2007, Ext JS, LLC.
43520 * Originally Released Under LGPL - original licence link has changed is not relivant.
43523 * <script type="text/javascript">
43526 * @class Roo.BorderLayout
43527 * @extends Roo.LayoutManager
43528 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
43529 * please see: <br><br>
43530 * <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>
43531 * <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>
43534 var layout = new Roo.BorderLayout(document.body, {
43568 preferredTabWidth: 150
43573 var CP = Roo.ContentPanel;
43575 layout.beginUpdate();
43576 layout.add("north", new CP("north", "North"));
43577 layout.add("south", new CP("south", {title: "South", closable: true}));
43578 layout.add("west", new CP("west", {title: "West"}));
43579 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
43580 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
43581 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
43582 layout.getRegion("center").showPanel("center1");
43583 layout.endUpdate();
43586 <b>The container the layout is rendered into can be either the body element or any other element.
43587 If it is not the body element, the container needs to either be an absolute positioned element,
43588 or you will need to add "position:relative" to the css of the container. You will also need to specify
43589 the container size if it is not the body element.</b>
43592 * Create a new BorderLayout
43593 * @param {String/HTMLElement/Element} container The container this layout is bound to
43594 * @param {Object} config Configuration options
43596 Roo.BorderLayout = function(container, config){
43597 config = config || {};
43598 Roo.BorderLayout.superclass.constructor.call(this, container, config);
43599 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
43600 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
43601 var target = this.factory.validRegions[i];
43602 if(config[target]){
43603 this.addRegion(target, config[target]);
43608 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
43610 * Creates and adds a new region if it doesn't already exist.
43611 * @param {String} target The target region key (north, south, east, west or center).
43612 * @param {Object} config The regions config object
43613 * @return {BorderLayoutRegion} The new region
43615 addRegion : function(target, config){
43616 if(!this.regions[target]){
43617 var r = this.factory.create(target, this, config);
43618 this.bindRegion(target, r);
43620 return this.regions[target];
43624 bindRegion : function(name, r){
43625 this.regions[name] = r;
43626 r.on("visibilitychange", this.layout, this);
43627 r.on("paneladded", this.layout, this);
43628 r.on("panelremoved", this.layout, this);
43629 r.on("invalidated", this.layout, this);
43630 r.on("resized", this.onRegionResized, this);
43631 r.on("collapsed", this.onRegionCollapsed, this);
43632 r.on("expanded", this.onRegionExpanded, this);
43636 * Performs a layout update.
43638 layout : function(){
43639 if(this.updating) return;
43640 var size = this.getViewSize();
43641 var w = size.width;
43642 var h = size.height;
43647 //var x = 0, y = 0;
43649 var rs = this.regions;
43650 var north = rs["north"];
43651 var south = rs["south"];
43652 var west = rs["west"];
43653 var east = rs["east"];
43654 var center = rs["center"];
43655 //if(this.hideOnLayout){ // not supported anymore
43656 //c.el.setStyle("display", "none");
43658 if(north && north.isVisible()){
43659 var b = north.getBox();
43660 var m = north.getMargins();
43661 b.width = w - (m.left+m.right);
43664 centerY = b.height + b.y + m.bottom;
43665 centerH -= centerY;
43666 north.updateBox(this.safeBox(b));
43668 if(south && south.isVisible()){
43669 var b = south.getBox();
43670 var m = south.getMargins();
43671 b.width = w - (m.left+m.right);
43673 var totalHeight = (b.height + m.top + m.bottom);
43674 b.y = h - totalHeight + m.top;
43675 centerH -= totalHeight;
43676 south.updateBox(this.safeBox(b));
43678 if(west && west.isVisible()){
43679 var b = west.getBox();
43680 var m = west.getMargins();
43681 b.height = centerH - (m.top+m.bottom);
43683 b.y = centerY + m.top;
43684 var totalWidth = (b.width + m.left + m.right);
43685 centerX += totalWidth;
43686 centerW -= totalWidth;
43687 west.updateBox(this.safeBox(b));
43689 if(east && east.isVisible()){
43690 var b = east.getBox();
43691 var m = east.getMargins();
43692 b.height = centerH - (m.top+m.bottom);
43693 var totalWidth = (b.width + m.left + m.right);
43694 b.x = w - totalWidth + m.left;
43695 b.y = centerY + m.top;
43696 centerW -= totalWidth;
43697 east.updateBox(this.safeBox(b));
43700 var m = center.getMargins();
43702 x: centerX + m.left,
43703 y: centerY + m.top,
43704 width: centerW - (m.left+m.right),
43705 height: centerH - (m.top+m.bottom)
43707 //if(this.hideOnLayout){
43708 //center.el.setStyle("display", "block");
43710 center.updateBox(this.safeBox(centerBox));
43713 this.fireEvent("layout", this);
43717 safeBox : function(box){
43718 box.width = Math.max(0, box.width);
43719 box.height = Math.max(0, box.height);
43724 * Adds a ContentPanel (or subclass) to this layout.
43725 * @param {String} target The target region key (north, south, east, west or center).
43726 * @param {Roo.ContentPanel} panel The panel to add
43727 * @return {Roo.ContentPanel} The added panel
43729 add : function(target, panel){
43731 target = target.toLowerCase();
43732 return this.regions[target].add(panel);
43736 * Remove a ContentPanel (or subclass) to this layout.
43737 * @param {String} target The target region key (north, south, east, west or center).
43738 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
43739 * @return {Roo.ContentPanel} The removed panel
43741 remove : function(target, panel){
43742 target = target.toLowerCase();
43743 return this.regions[target].remove(panel);
43747 * Searches all regions for a panel with the specified id
43748 * @param {String} panelId
43749 * @return {Roo.ContentPanel} The panel or null if it wasn't found
43751 findPanel : function(panelId){
43752 var rs = this.regions;
43753 for(var target in rs){
43754 if(typeof rs[target] != "function"){
43755 var p = rs[target].getPanel(panelId);
43765 * Searches all regions for a panel with the specified id and activates (shows) it.
43766 * @param {String/ContentPanel} panelId The panels id or the panel itself
43767 * @return {Roo.ContentPanel} The shown panel or null
43769 showPanel : function(panelId) {
43770 var rs = this.regions;
43771 for(var target in rs){
43772 var r = rs[target];
43773 if(typeof r != "function"){
43774 if(r.hasPanel(panelId)){
43775 return r.showPanel(panelId);
43783 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
43784 * @param {Roo.state.Provider} provider (optional) An alternate state provider
43786 restoreState : function(provider){
43788 provider = Roo.state.Manager;
43790 var sm = new Roo.LayoutStateManager();
43791 sm.init(this, provider);
43795 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
43796 * object should contain properties for each region to add ContentPanels to, and each property's value should be
43797 * a valid ContentPanel config object. Example:
43799 // Create the main layout
43800 var layout = new Roo.BorderLayout('main-ct', {
43811 // Create and add multiple ContentPanels at once via configs
43814 id: 'source-files',
43816 title:'Ext Source Files',
43829 * @param {Object} regions An object containing ContentPanel configs by region name
43831 batchAdd : function(regions){
43832 this.beginUpdate();
43833 for(var rname in regions){
43834 var lr = this.regions[rname];
43836 this.addTypedPanels(lr, regions[rname]);
43843 addTypedPanels : function(lr, ps){
43844 if(typeof ps == 'string'){
43845 lr.add(new Roo.ContentPanel(ps));
43847 else if(ps instanceof Array){
43848 for(var i =0, len = ps.length; i < len; i++){
43849 this.addTypedPanels(lr, ps[i]);
43852 else if(!ps.events){ // raw config?
43854 delete ps.el; // prevent conflict
43855 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
43857 else { // panel object assumed!
43862 * Adds a xtype elements to the layout.
43866 xtype : 'ContentPanel',
43873 xtype : 'NestedLayoutPanel',
43879 items : [ ... list of content panels or nested layout panels.. ]
43883 * @param {Object} cfg Xtype definition of item to add.
43885 addxtype : function(cfg)
43887 // basically accepts a pannel...
43888 // can accept a layout region..!?!?
43889 // console.log('BorderLayout add ' + cfg.xtype)
43891 if (!cfg.xtype.match(/Panel$/)) {
43895 var region = cfg.region;
43901 xitems = cfg.items;
43908 case 'ContentPanel': // ContentPanel (el, cfg)
43909 case 'ScrollPanel': // ContentPanel (el, cfg)
43910 if(cfg.autoCreate) {
43911 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43913 var el = this.el.createChild();
43914 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
43917 this.add(region, ret);
43921 case 'TreePanel': // our new panel!
43922 cfg.el = this.el.createChild();
43923 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43924 this.add(region, ret);
43927 case 'NestedLayoutPanel':
43928 // create a new Layout (which is a Border Layout...
43929 var el = this.el.createChild();
43930 var clayout = cfg.layout;
43932 clayout.items = clayout.items || [];
43933 // replace this exitems with the clayout ones..
43934 xitems = clayout.items;
43937 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
43938 cfg.background = false;
43940 var layout = new Roo.BorderLayout(el, clayout);
43942 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
43943 //console.log('adding nested layout panel ' + cfg.toSource());
43944 this.add(region, ret);
43950 // needs grid and region
43952 //var el = this.getRegion(region).el.createChild();
43953 var el = this.el.createChild();
43954 // create the grid first...
43956 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
43958 if (region == 'center' && this.active ) {
43959 cfg.background = false;
43961 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
43963 this.add(region, ret);
43964 if (cfg.background) {
43965 ret.on('activate', function(gp) {
43966 if (!gp.grid.rendered) {
43979 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
43981 // GridPanel (grid, cfg)
43984 this.beginUpdate();
43986 Roo.each(xitems, function(i) {
43996 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
43997 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
43998 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
43999 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
44002 var CP = Roo.ContentPanel;
44004 var layout = Roo.BorderLayout.create({
44008 panels: [new CP("north", "North")]
44017 panels: [new CP("west", {title: "West"})]
44026 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
44035 panels: [new CP("south", {title: "South", closable: true})]
44042 preferredTabWidth: 150,
44044 new CP("center1", {title: "Close Me", closable: true}),
44045 new CP("center2", {title: "Center Panel", closable: false})
44050 layout.getRegion("center").showPanel("center1");
44055 Roo.BorderLayout.create = function(config, targetEl){
44056 var layout = new Roo.BorderLayout(targetEl || document.body, config);
44057 layout.beginUpdate();
44058 var regions = Roo.BorderLayout.RegionFactory.validRegions;
44059 for(var j = 0, jlen = regions.length; j < jlen; j++){
44060 var lr = regions[j];
44061 if(layout.regions[lr] && config[lr].panels){
44062 var r = layout.regions[lr];
44063 var ps = config[lr].panels;
44064 layout.addTypedPanels(r, ps);
44067 layout.endUpdate();
44072 Roo.BorderLayout.RegionFactory = {
44074 validRegions : ["north","south","east","west","center"],
44077 create : function(target, mgr, config){
44078 target = target.toLowerCase();
44079 if(config.lightweight || config.basic){
44080 return new Roo.BasicLayoutRegion(mgr, config, target);
44084 return new Roo.NorthLayoutRegion(mgr, config);
44086 return new Roo.SouthLayoutRegion(mgr, config);
44088 return new Roo.EastLayoutRegion(mgr, config);
44090 return new Roo.WestLayoutRegion(mgr, config);
44092 return new Roo.CenterLayoutRegion(mgr, config);
44094 throw 'Layout region "'+target+'" not supported.';
44098 * Ext JS Library 1.1.1
44099 * Copyright(c) 2006-2007, Ext JS, LLC.
44101 * Originally Released Under LGPL - original licence link has changed is not relivant.
44104 * <script type="text/javascript">
44108 * @class Roo.BasicLayoutRegion
44109 * @extends Roo.util.Observable
44110 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
44111 * and does not have a titlebar, tabs or any other features. All it does is size and position
44112 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
44114 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
44116 this.position = pos;
44119 * @scope Roo.BasicLayoutRegion
44123 * @event beforeremove
44124 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
44125 * @param {Roo.LayoutRegion} this
44126 * @param {Roo.ContentPanel} panel The panel
44127 * @param {Object} e The cancel event object
44129 "beforeremove" : true,
44131 * @event invalidated
44132 * Fires when the layout for this region is changed.
44133 * @param {Roo.LayoutRegion} this
44135 "invalidated" : true,
44137 * @event visibilitychange
44138 * Fires when this region is shown or hidden
44139 * @param {Roo.LayoutRegion} this
44140 * @param {Boolean} visibility true or false
44142 "visibilitychange" : true,
44144 * @event paneladded
44145 * Fires when a panel is added.
44146 * @param {Roo.LayoutRegion} this
44147 * @param {Roo.ContentPanel} panel The panel
44149 "paneladded" : true,
44151 * @event panelremoved
44152 * Fires when a panel is removed.
44153 * @param {Roo.LayoutRegion} this
44154 * @param {Roo.ContentPanel} panel The panel
44156 "panelremoved" : true,
44159 * Fires when this region is collapsed.
44160 * @param {Roo.LayoutRegion} this
44162 "collapsed" : true,
44165 * Fires when this region is expanded.
44166 * @param {Roo.LayoutRegion} this
44171 * Fires when this region is slid into view.
44172 * @param {Roo.LayoutRegion} this
44174 "slideshow" : true,
44177 * Fires when this region slides out of view.
44178 * @param {Roo.LayoutRegion} this
44180 "slidehide" : true,
44182 * @event panelactivated
44183 * Fires when a panel is activated.
44184 * @param {Roo.LayoutRegion} this
44185 * @param {Roo.ContentPanel} panel The activated panel
44187 "panelactivated" : true,
44190 * Fires when the user resizes this region.
44191 * @param {Roo.LayoutRegion} this
44192 * @param {Number} newSize The new size (width for east/west, height for north/south)
44196 /** A collection of panels in this region. @type Roo.util.MixedCollection */
44197 this.panels = new Roo.util.MixedCollection();
44198 this.panels.getKey = this.getPanelId.createDelegate(this);
44200 this.activePanel = null;
44201 // ensure listeners are added...
44203 if (config.listeners || config.events) {
44204 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
44205 listeners : config.listeners || {},
44206 events : config.events || {}
44210 if(skipConfig !== true){
44211 this.applyConfig(config);
44215 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
44216 getPanelId : function(p){
44220 applyConfig : function(config){
44221 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44222 this.config = config;
44227 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
44228 * the width, for horizontal (north, south) the height.
44229 * @param {Number} newSize The new width or height
44231 resizeTo : function(newSize){
44232 var el = this.el ? this.el :
44233 (this.activePanel ? this.activePanel.getEl() : null);
44235 switch(this.position){
44238 el.setWidth(newSize);
44239 this.fireEvent("resized", this, newSize);
44243 el.setHeight(newSize);
44244 this.fireEvent("resized", this, newSize);
44250 getBox : function(){
44251 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
44254 getMargins : function(){
44255 return this.margins;
44258 updateBox : function(box){
44260 var el = this.activePanel.getEl();
44261 el.dom.style.left = box.x + "px";
44262 el.dom.style.top = box.y + "px";
44263 this.activePanel.setSize(box.width, box.height);
44267 * Returns the container element for this region.
44268 * @return {Roo.Element}
44270 getEl : function(){
44271 return this.activePanel;
44275 * Returns true if this region is currently visible.
44276 * @return {Boolean}
44278 isVisible : function(){
44279 return this.activePanel ? true : false;
44282 setActivePanel : function(panel){
44283 panel = this.getPanel(panel);
44284 if(this.activePanel && this.activePanel != panel){
44285 this.activePanel.setActiveState(false);
44286 this.activePanel.getEl().setLeftTop(-10000,-10000);
44288 this.activePanel = panel;
44289 panel.setActiveState(true);
44291 panel.setSize(this.box.width, this.box.height);
44293 this.fireEvent("panelactivated", this, panel);
44294 this.fireEvent("invalidated");
44298 * Show the specified panel.
44299 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
44300 * @return {Roo.ContentPanel} The shown panel or null
44302 showPanel : function(panel){
44303 if(panel = this.getPanel(panel)){
44304 this.setActivePanel(panel);
44310 * Get the active panel for this region.
44311 * @return {Roo.ContentPanel} The active panel or null
44313 getActivePanel : function(){
44314 return this.activePanel;
44318 * Add the passed ContentPanel(s)
44319 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44320 * @return {Roo.ContentPanel} The panel added (if only one was added)
44322 add : function(panel){
44323 if(arguments.length > 1){
44324 for(var i = 0, len = arguments.length; i < len; i++) {
44325 this.add(arguments[i]);
44329 if(this.hasPanel(panel)){
44330 this.showPanel(panel);
44333 var el = panel.getEl();
44334 if(el.dom.parentNode != this.mgr.el.dom){
44335 this.mgr.el.dom.appendChild(el.dom);
44337 if(panel.setRegion){
44338 panel.setRegion(this);
44340 this.panels.add(panel);
44341 el.setStyle("position", "absolute");
44342 if(!panel.background){
44343 this.setActivePanel(panel);
44344 if(this.config.initialSize && this.panels.getCount()==1){
44345 this.resizeTo(this.config.initialSize);
44348 this.fireEvent("paneladded", this, panel);
44353 * Returns true if the panel is in this region.
44354 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44355 * @return {Boolean}
44357 hasPanel : function(panel){
44358 if(typeof panel == "object"){ // must be panel obj
44359 panel = panel.getId();
44361 return this.getPanel(panel) ? true : false;
44365 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44366 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44367 * @param {Boolean} preservePanel Overrides the config preservePanel option
44368 * @return {Roo.ContentPanel} The panel that was removed
44370 remove : function(panel, preservePanel){
44371 panel = this.getPanel(panel);
44376 this.fireEvent("beforeremove", this, panel, e);
44377 if(e.cancel === true){
44380 var panelId = panel.getId();
44381 this.panels.removeKey(panelId);
44386 * Returns the panel specified or null if it's not in this region.
44387 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44388 * @return {Roo.ContentPanel}
44390 getPanel : function(id){
44391 if(typeof id == "object"){ // must be panel obj
44394 return this.panels.get(id);
44398 * Returns this regions position (north/south/east/west/center).
44401 getPosition: function(){
44402 return this.position;
44406 * Ext JS Library 1.1.1
44407 * Copyright(c) 2006-2007, Ext JS, LLC.
44409 * Originally Released Under LGPL - original licence link has changed is not relivant.
44412 * <script type="text/javascript">
44416 * @class Roo.LayoutRegion
44417 * @extends Roo.BasicLayoutRegion
44418 * This class represents a region in a layout manager.
44419 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
44420 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
44421 * @cfg {Boolean} floatable False to disable floating (defaults to true)
44422 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
44423 * @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})
44424 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
44425 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
44426 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
44427 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
44428 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
44429 * @cfg {String} title The title for the region (overrides panel titles)
44430 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
44431 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
44432 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
44433 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
44434 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
44435 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
44436 * the space available, similar to FireFox 1.5 tabs (defaults to false)
44437 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
44438 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
44439 * @cfg {Boolean} showPin True to show a pin button
44440 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
44441 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
44442 * @cfg {Boolean} disableTabTips True to disable tab tooltips
44443 * @cfg {Number} width For East/West panels
44444 * @cfg {Number} height For North/South panels
44445 * @cfg {Boolean} split To show the splitter
44446 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
44448 Roo.LayoutRegion = function(mgr, config, pos){
44449 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
44450 var dh = Roo.DomHelper;
44451 /** This region's container element
44452 * @type Roo.Element */
44453 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
44454 /** This region's title element
44455 * @type Roo.Element */
44457 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
44458 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
44459 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
44461 this.titleEl.enableDisplayMode();
44462 /** This region's title text element
44463 * @type HTMLElement */
44464 this.titleTextEl = this.titleEl.dom.firstChild;
44465 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
44466 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
44467 this.closeBtn.enableDisplayMode();
44468 this.closeBtn.on("click", this.closeClicked, this);
44469 this.closeBtn.hide();
44471 this.createBody(config);
44472 this.visible = true;
44473 this.collapsed = false;
44475 if(config.hideWhenEmpty){
44477 this.on("paneladded", this.validateVisibility, this);
44478 this.on("panelremoved", this.validateVisibility, this);
44480 this.applyConfig(config);
44483 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
44485 createBody : function(){
44486 /** This region's body element
44487 * @type Roo.Element */
44488 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
44491 applyConfig : function(c){
44492 if(c.collapsible && this.position != "center" && !this.collapsedEl){
44493 var dh = Roo.DomHelper;
44494 if(c.titlebar !== false){
44495 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
44496 this.collapseBtn.on("click", this.collapse, this);
44497 this.collapseBtn.enableDisplayMode();
44499 if(c.showPin === true || this.showPin){
44500 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
44501 this.stickBtn.enableDisplayMode();
44502 this.stickBtn.on("click", this.expand, this);
44503 this.stickBtn.hide();
44506 /** This region's collapsed element
44507 * @type Roo.Element */
44508 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
44509 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
44511 if(c.floatable !== false){
44512 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
44513 this.collapsedEl.on("click", this.collapseClick, this);
44516 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
44517 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
44518 id: "message", unselectable: "on", style:{"float":"left"}});
44519 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
44521 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
44522 this.expandBtn.on("click", this.expand, this);
44524 if(this.collapseBtn){
44525 this.collapseBtn.setVisible(c.collapsible == true);
44527 this.cmargins = c.cmargins || this.cmargins ||
44528 (this.position == "west" || this.position == "east" ?
44529 {top: 0, left: 2, right:2, bottom: 0} :
44530 {top: 2, left: 0, right:0, bottom: 2});
44531 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44532 this.bottomTabs = c.tabPosition != "top";
44533 this.autoScroll = c.autoScroll || false;
44534 if(this.autoScroll){
44535 this.bodyEl.setStyle("overflow", "auto");
44537 this.bodyEl.setStyle("overflow", "hidden");
44539 //if(c.titlebar !== false){
44540 if((!c.titlebar && !c.title) || c.titlebar === false){
44541 this.titleEl.hide();
44543 this.titleEl.show();
44545 this.titleTextEl.innerHTML = c.title;
44549 this.duration = c.duration || .30;
44550 this.slideDuration = c.slideDuration || .45;
44553 this.collapse(true);
44560 * Returns true if this region is currently visible.
44561 * @return {Boolean}
44563 isVisible : function(){
44564 return this.visible;
44568 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
44569 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
44571 setCollapsedTitle : function(title){
44572 title = title || " ";
44573 if(this.collapsedTitleTextEl){
44574 this.collapsedTitleTextEl.innerHTML = title;
44578 getBox : function(){
44580 if(!this.collapsed){
44581 b = this.el.getBox(false, true);
44583 b = this.collapsedEl.getBox(false, true);
44588 getMargins : function(){
44589 return this.collapsed ? this.cmargins : this.margins;
44592 highlight : function(){
44593 this.el.addClass("x-layout-panel-dragover");
44596 unhighlight : function(){
44597 this.el.removeClass("x-layout-panel-dragover");
44600 updateBox : function(box){
44602 if(!this.collapsed){
44603 this.el.dom.style.left = box.x + "px";
44604 this.el.dom.style.top = box.y + "px";
44605 this.updateBody(box.width, box.height);
44607 this.collapsedEl.dom.style.left = box.x + "px";
44608 this.collapsedEl.dom.style.top = box.y + "px";
44609 this.collapsedEl.setSize(box.width, box.height);
44612 this.tabs.autoSizeTabs();
44616 updateBody : function(w, h){
44618 this.el.setWidth(w);
44619 w -= this.el.getBorderWidth("rl");
44620 if(this.config.adjustments){
44621 w += this.config.adjustments[0];
44625 this.el.setHeight(h);
44626 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
44627 h -= this.el.getBorderWidth("tb");
44628 if(this.config.adjustments){
44629 h += this.config.adjustments[1];
44631 this.bodyEl.setHeight(h);
44633 h = this.tabs.syncHeight(h);
44636 if(this.panelSize){
44637 w = w !== null ? w : this.panelSize.width;
44638 h = h !== null ? h : this.panelSize.height;
44640 if(this.activePanel){
44641 var el = this.activePanel.getEl();
44642 w = w !== null ? w : el.getWidth();
44643 h = h !== null ? h : el.getHeight();
44644 this.panelSize = {width: w, height: h};
44645 this.activePanel.setSize(w, h);
44647 if(Roo.isIE && this.tabs){
44648 this.tabs.el.repaint();
44653 * Returns the container element for this region.
44654 * @return {Roo.Element}
44656 getEl : function(){
44661 * Hides this region.
44664 if(!this.collapsed){
44665 this.el.dom.style.left = "-2000px";
44668 this.collapsedEl.dom.style.left = "-2000px";
44669 this.collapsedEl.hide();
44671 this.visible = false;
44672 this.fireEvent("visibilitychange", this, false);
44676 * Shows this region if it was previously hidden.
44679 if(!this.collapsed){
44682 this.collapsedEl.show();
44684 this.visible = true;
44685 this.fireEvent("visibilitychange", this, true);
44688 closeClicked : function(){
44689 if(this.activePanel){
44690 this.remove(this.activePanel);
44694 collapseClick : function(e){
44696 e.stopPropagation();
44699 e.stopPropagation();
44705 * Collapses this region.
44706 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
44708 collapse : function(skipAnim){
44709 if(this.collapsed) return;
44710 this.collapsed = true;
44712 this.split.el.hide();
44714 if(this.config.animate && skipAnim !== true){
44715 this.fireEvent("invalidated", this);
44716 this.animateCollapse();
44718 this.el.setLocation(-20000,-20000);
44720 this.collapsedEl.show();
44721 this.fireEvent("collapsed", this);
44722 this.fireEvent("invalidated", this);
44726 animateCollapse : function(){
44731 * Expands this region if it was previously collapsed.
44732 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
44733 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
44735 expand : function(e, skipAnim){
44736 if(e) e.stopPropagation();
44737 if(!this.collapsed || this.el.hasActiveFx()) return;
44739 this.afterSlideIn();
44742 this.collapsed = false;
44743 if(this.config.animate && skipAnim !== true){
44744 this.animateExpand();
44748 this.split.el.show();
44750 this.collapsedEl.setLocation(-2000,-2000);
44751 this.collapsedEl.hide();
44752 this.fireEvent("invalidated", this);
44753 this.fireEvent("expanded", this);
44757 animateExpand : function(){
44761 initTabs : function()
44763 this.bodyEl.setStyle("overflow", "hidden");
44764 var ts = new Roo.TabPanel(
44767 tabPosition: this.bottomTabs ? 'bottom' : 'top',
44768 disableTooltips: this.config.disableTabTips,
44769 toolbar : this.config.toolbar
44772 if(this.config.hideTabs){
44773 ts.stripWrap.setDisplayed(false);
44776 ts.resizeTabs = this.config.resizeTabs === true;
44777 ts.minTabWidth = this.config.minTabWidth || 40;
44778 ts.maxTabWidth = this.config.maxTabWidth || 250;
44779 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
44780 ts.monitorResize = false;
44781 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44782 ts.bodyEl.addClass('x-layout-tabs-body');
44783 this.panels.each(this.initPanelAsTab, this);
44786 initPanelAsTab : function(panel){
44787 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
44788 this.config.closeOnTab && panel.isClosable());
44789 if(panel.tabTip !== undefined){
44790 ti.setTooltip(panel.tabTip);
44792 ti.on("activate", function(){
44793 this.setActivePanel(panel);
44795 if(this.config.closeOnTab){
44796 ti.on("beforeclose", function(t, e){
44798 this.remove(panel);
44804 updatePanelTitle : function(panel, title){
44805 if(this.activePanel == panel){
44806 this.updateTitle(title);
44809 var ti = this.tabs.getTab(panel.getEl().id);
44811 if(panel.tabTip !== undefined){
44812 ti.setTooltip(panel.tabTip);
44817 updateTitle : function(title){
44818 if(this.titleTextEl && !this.config.title){
44819 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
44823 setActivePanel : function(panel){
44824 panel = this.getPanel(panel);
44825 if(this.activePanel && this.activePanel != panel){
44826 this.activePanel.setActiveState(false);
44828 this.activePanel = panel;
44829 panel.setActiveState(true);
44830 if(this.panelSize){
44831 panel.setSize(this.panelSize.width, this.panelSize.height);
44834 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
44836 this.updateTitle(panel.getTitle());
44838 this.fireEvent("invalidated", this);
44840 this.fireEvent("panelactivated", this, panel);
44844 * Shows the specified panel.
44845 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
44846 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
44848 showPanel : function(panel){
44849 if(panel = this.getPanel(panel)){
44851 var tab = this.tabs.getTab(panel.getEl().id);
44852 if(tab.isHidden()){
44853 this.tabs.unhideTab(tab.id);
44857 this.setActivePanel(panel);
44864 * Get the active panel for this region.
44865 * @return {Roo.ContentPanel} The active panel or null
44867 getActivePanel : function(){
44868 return this.activePanel;
44871 validateVisibility : function(){
44872 if(this.panels.getCount() < 1){
44873 this.updateTitle(" ");
44874 this.closeBtn.hide();
44877 if(!this.isVisible()){
44884 * Adds the passed ContentPanel(s) to this region.
44885 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44886 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
44888 add : function(panel){
44889 if(arguments.length > 1){
44890 for(var i = 0, len = arguments.length; i < len; i++) {
44891 this.add(arguments[i]);
44895 if(this.hasPanel(panel)){
44896 this.showPanel(panel);
44899 panel.setRegion(this);
44900 this.panels.add(panel);
44901 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
44902 this.bodyEl.dom.appendChild(panel.getEl().dom);
44903 if(panel.background !== true){
44904 this.setActivePanel(panel);
44906 this.fireEvent("paneladded", this, panel);
44912 this.initPanelAsTab(panel);
44914 if(panel.background !== true){
44915 this.tabs.activate(panel.getEl().id);
44917 this.fireEvent("paneladded", this, panel);
44922 * Hides the tab for the specified panel.
44923 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44925 hidePanel : function(panel){
44926 if(this.tabs && (panel = this.getPanel(panel))){
44927 this.tabs.hideTab(panel.getEl().id);
44932 * Unhides the tab for a previously hidden panel.
44933 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44935 unhidePanel : function(panel){
44936 if(this.tabs && (panel = this.getPanel(panel))){
44937 this.tabs.unhideTab(panel.getEl().id);
44941 clearPanels : function(){
44942 while(this.panels.getCount() > 0){
44943 this.remove(this.panels.first());
44948 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44949 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44950 * @param {Boolean} preservePanel Overrides the config preservePanel option
44951 * @return {Roo.ContentPanel} The panel that was removed
44953 remove : function(panel, preservePanel){
44954 panel = this.getPanel(panel);
44959 this.fireEvent("beforeremove", this, panel, e);
44960 if(e.cancel === true){
44963 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
44964 var panelId = panel.getId();
44965 this.panels.removeKey(panelId);
44967 document.body.appendChild(panel.getEl().dom);
44970 this.tabs.removeTab(panel.getEl().id);
44971 }else if (!preservePanel){
44972 this.bodyEl.dom.removeChild(panel.getEl().dom);
44974 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
44975 var p = this.panels.first();
44976 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
44977 tempEl.appendChild(p.getEl().dom);
44978 this.bodyEl.update("");
44979 this.bodyEl.dom.appendChild(p.getEl().dom);
44981 this.updateTitle(p.getTitle());
44983 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44984 this.setActivePanel(p);
44986 panel.setRegion(null);
44987 if(this.activePanel == panel){
44988 this.activePanel = null;
44990 if(this.config.autoDestroy !== false && preservePanel !== true){
44991 try{panel.destroy();}catch(e){}
44993 this.fireEvent("panelremoved", this, panel);
44998 * Returns the TabPanel component used by this region
44999 * @return {Roo.TabPanel}
45001 getTabs : function(){
45005 createTool : function(parentEl, className){
45006 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
45007 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
45008 btn.addClassOnOver("x-layout-tools-button-over");
45013 * Ext JS Library 1.1.1
45014 * Copyright(c) 2006-2007, Ext JS, LLC.
45016 * Originally Released Under LGPL - original licence link has changed is not relivant.
45019 * <script type="text/javascript">
45025 * @class Roo.SplitLayoutRegion
45026 * @extends Roo.LayoutRegion
45027 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
45029 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
45030 this.cursor = cursor;
45031 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
45034 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
45035 splitTip : "Drag to resize.",
45036 collapsibleSplitTip : "Drag to resize. Double click to hide.",
45037 useSplitTips : false,
45039 applyConfig : function(config){
45040 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
45043 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
45044 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
45045 /** The SplitBar for this region
45046 * @type Roo.SplitBar */
45047 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
45048 this.split.on("moved", this.onSplitMove, this);
45049 this.split.useShim = config.useShim === true;
45050 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
45051 if(this.useSplitTips){
45052 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
45054 if(config.collapsible){
45055 this.split.el.on("dblclick", this.collapse, this);
45058 if(typeof config.minSize != "undefined"){
45059 this.split.minSize = config.minSize;
45061 if(typeof config.maxSize != "undefined"){
45062 this.split.maxSize = config.maxSize;
45064 if(config.hideWhenEmpty || config.hidden || config.collapsed){
45065 this.hideSplitter();
45070 getHMaxSize : function(){
45071 var cmax = this.config.maxSize || 10000;
45072 var center = this.mgr.getRegion("center");
45073 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
45076 getVMaxSize : function(){
45077 var cmax = this.config.maxSize || 10000;
45078 var center = this.mgr.getRegion("center");
45079 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
45082 onSplitMove : function(split, newSize){
45083 this.fireEvent("resized", this, newSize);
45087 * Returns the {@link Roo.SplitBar} for this region.
45088 * @return {Roo.SplitBar}
45090 getSplitBar : function(){
45095 this.hideSplitter();
45096 Roo.SplitLayoutRegion.superclass.hide.call(this);
45099 hideSplitter : function(){
45101 this.split.el.setLocation(-2000,-2000);
45102 this.split.el.hide();
45108 this.split.el.show();
45110 Roo.SplitLayoutRegion.superclass.show.call(this);
45113 beforeSlide: function(){
45114 if(Roo.isGecko){// firefox overflow auto bug workaround
45115 this.bodyEl.clip();
45116 if(this.tabs) this.tabs.bodyEl.clip();
45117 if(this.activePanel){
45118 this.activePanel.getEl().clip();
45120 if(this.activePanel.beforeSlide){
45121 this.activePanel.beforeSlide();
45127 afterSlide : function(){
45128 if(Roo.isGecko){// firefox overflow auto bug workaround
45129 this.bodyEl.unclip();
45130 if(this.tabs) this.tabs.bodyEl.unclip();
45131 if(this.activePanel){
45132 this.activePanel.getEl().unclip();
45133 if(this.activePanel.afterSlide){
45134 this.activePanel.afterSlide();
45140 initAutoHide : function(){
45141 if(this.autoHide !== false){
45142 if(!this.autoHideHd){
45143 var st = new Roo.util.DelayedTask(this.slideIn, this);
45144 this.autoHideHd = {
45145 "mouseout": function(e){
45146 if(!e.within(this.el, true)){
45150 "mouseover" : function(e){
45156 this.el.on(this.autoHideHd);
45160 clearAutoHide : function(){
45161 if(this.autoHide !== false){
45162 this.el.un("mouseout", this.autoHideHd.mouseout);
45163 this.el.un("mouseover", this.autoHideHd.mouseover);
45167 clearMonitor : function(){
45168 Roo.get(document).un("click", this.slideInIf, this);
45171 // these names are backwards but not changed for compat
45172 slideOut : function(){
45173 if(this.isSlid || this.el.hasActiveFx()){
45176 this.isSlid = true;
45177 if(this.collapseBtn){
45178 this.collapseBtn.hide();
45180 this.closeBtnState = this.closeBtn.getStyle('display');
45181 this.closeBtn.hide();
45183 this.stickBtn.show();
45186 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
45187 this.beforeSlide();
45188 this.el.setStyle("z-index", 10001);
45189 this.el.slideIn(this.getSlideAnchor(), {
45190 callback: function(){
45192 this.initAutoHide();
45193 Roo.get(document).on("click", this.slideInIf, this);
45194 this.fireEvent("slideshow", this);
45201 afterSlideIn : function(){
45202 this.clearAutoHide();
45203 this.isSlid = false;
45204 this.clearMonitor();
45205 this.el.setStyle("z-index", "");
45206 if(this.collapseBtn){
45207 this.collapseBtn.show();
45209 this.closeBtn.setStyle('display', this.closeBtnState);
45211 this.stickBtn.hide();
45213 this.fireEvent("slidehide", this);
45216 slideIn : function(cb){
45217 if(!this.isSlid || this.el.hasActiveFx()){
45221 this.isSlid = false;
45222 this.beforeSlide();
45223 this.el.slideOut(this.getSlideAnchor(), {
45224 callback: function(){
45225 this.el.setLeftTop(-10000, -10000);
45227 this.afterSlideIn();
45235 slideInIf : function(e){
45236 if(!e.within(this.el)){
45241 animateCollapse : function(){
45242 this.beforeSlide();
45243 this.el.setStyle("z-index", 20000);
45244 var anchor = this.getSlideAnchor();
45245 this.el.slideOut(anchor, {
45246 callback : function(){
45247 this.el.setStyle("z-index", "");
45248 this.collapsedEl.slideIn(anchor, {duration:.3});
45250 this.el.setLocation(-10000,-10000);
45252 this.fireEvent("collapsed", this);
45259 animateExpand : function(){
45260 this.beforeSlide();
45261 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
45262 this.el.setStyle("z-index", 20000);
45263 this.collapsedEl.hide({
45266 this.el.slideIn(this.getSlideAnchor(), {
45267 callback : function(){
45268 this.el.setStyle("z-index", "");
45271 this.split.el.show();
45273 this.fireEvent("invalidated", this);
45274 this.fireEvent("expanded", this);
45302 getAnchor : function(){
45303 return this.anchors[this.position];
45306 getCollapseAnchor : function(){
45307 return this.canchors[this.position];
45310 getSlideAnchor : function(){
45311 return this.sanchors[this.position];
45314 getAlignAdj : function(){
45315 var cm = this.cmargins;
45316 switch(this.position){
45332 getExpandAdj : function(){
45333 var c = this.collapsedEl, cm = this.cmargins;
45334 switch(this.position){
45336 return [-(cm.right+c.getWidth()+cm.left), 0];
45339 return [cm.right+c.getWidth()+cm.left, 0];
45342 return [0, -(cm.top+cm.bottom+c.getHeight())];
45345 return [0, cm.top+cm.bottom+c.getHeight()];
45351 * Ext JS Library 1.1.1
45352 * Copyright(c) 2006-2007, Ext JS, LLC.
45354 * Originally Released Under LGPL - original licence link has changed is not relivant.
45357 * <script type="text/javascript">
45360 * These classes are private internal classes
45362 Roo.CenterLayoutRegion = function(mgr, config){
45363 Roo.LayoutRegion.call(this, mgr, config, "center");
45364 this.visible = true;
45365 this.minWidth = config.minWidth || 20;
45366 this.minHeight = config.minHeight || 20;
45369 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
45371 // center panel can't be hidden
45375 // center panel can't be hidden
45378 getMinWidth: function(){
45379 return this.minWidth;
45382 getMinHeight: function(){
45383 return this.minHeight;
45388 Roo.NorthLayoutRegion = function(mgr, config){
45389 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
45391 this.split.placement = Roo.SplitBar.TOP;
45392 this.split.orientation = Roo.SplitBar.VERTICAL;
45393 this.split.el.addClass("x-layout-split-v");
45395 var size = config.initialSize || config.height;
45396 if(typeof size != "undefined"){
45397 this.el.setHeight(size);
45400 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
45401 orientation: Roo.SplitBar.VERTICAL,
45402 getBox : function(){
45403 if(this.collapsed){
45404 return this.collapsedEl.getBox();
45406 var box = this.el.getBox();
45408 box.height += this.split.el.getHeight();
45413 updateBox : function(box){
45414 if(this.split && !this.collapsed){
45415 box.height -= this.split.el.getHeight();
45416 this.split.el.setLeft(box.x);
45417 this.split.el.setTop(box.y+box.height);
45418 this.split.el.setWidth(box.width);
45420 if(this.collapsed){
45421 this.updateBody(box.width, null);
45423 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45427 Roo.SouthLayoutRegion = function(mgr, config){
45428 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
45430 this.split.placement = Roo.SplitBar.BOTTOM;
45431 this.split.orientation = Roo.SplitBar.VERTICAL;
45432 this.split.el.addClass("x-layout-split-v");
45434 var size = config.initialSize || config.height;
45435 if(typeof size != "undefined"){
45436 this.el.setHeight(size);
45439 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
45440 orientation: Roo.SplitBar.VERTICAL,
45441 getBox : function(){
45442 if(this.collapsed){
45443 return this.collapsedEl.getBox();
45445 var box = this.el.getBox();
45447 var sh = this.split.el.getHeight();
45454 updateBox : function(box){
45455 if(this.split && !this.collapsed){
45456 var sh = this.split.el.getHeight();
45459 this.split.el.setLeft(box.x);
45460 this.split.el.setTop(box.y-sh);
45461 this.split.el.setWidth(box.width);
45463 if(this.collapsed){
45464 this.updateBody(box.width, null);
45466 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45470 Roo.EastLayoutRegion = function(mgr, config){
45471 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
45473 this.split.placement = Roo.SplitBar.RIGHT;
45474 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45475 this.split.el.addClass("x-layout-split-h");
45477 var size = config.initialSize || config.width;
45478 if(typeof size != "undefined"){
45479 this.el.setWidth(size);
45482 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
45483 orientation: Roo.SplitBar.HORIZONTAL,
45484 getBox : function(){
45485 if(this.collapsed){
45486 return this.collapsedEl.getBox();
45488 var box = this.el.getBox();
45490 var sw = this.split.el.getWidth();
45497 updateBox : function(box){
45498 if(this.split && !this.collapsed){
45499 var sw = this.split.el.getWidth();
45501 this.split.el.setLeft(box.x);
45502 this.split.el.setTop(box.y);
45503 this.split.el.setHeight(box.height);
45506 if(this.collapsed){
45507 this.updateBody(null, box.height);
45509 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45513 Roo.WestLayoutRegion = function(mgr, config){
45514 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
45516 this.split.placement = Roo.SplitBar.LEFT;
45517 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45518 this.split.el.addClass("x-layout-split-h");
45520 var size = config.initialSize || config.width;
45521 if(typeof size != "undefined"){
45522 this.el.setWidth(size);
45525 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
45526 orientation: Roo.SplitBar.HORIZONTAL,
45527 getBox : function(){
45528 if(this.collapsed){
45529 return this.collapsedEl.getBox();
45531 var box = this.el.getBox();
45533 box.width += this.split.el.getWidth();
45538 updateBox : function(box){
45539 if(this.split && !this.collapsed){
45540 var sw = this.split.el.getWidth();
45542 this.split.el.setLeft(box.x+box.width);
45543 this.split.el.setTop(box.y);
45544 this.split.el.setHeight(box.height);
45546 if(this.collapsed){
45547 this.updateBody(null, box.height);
45549 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45554 * Ext JS Library 1.1.1
45555 * Copyright(c) 2006-2007, Ext JS, LLC.
45557 * Originally Released Under LGPL - original licence link has changed is not relivant.
45560 * <script type="text/javascript">
45565 * Private internal class for reading and applying state
45567 Roo.LayoutStateManager = function(layout){
45568 // default empty state
45577 Roo.LayoutStateManager.prototype = {
45578 init : function(layout, provider){
45579 this.provider = provider;
45580 var state = provider.get(layout.id+"-layout-state");
45582 var wasUpdating = layout.isUpdating();
45584 layout.beginUpdate();
45586 for(var key in state){
45587 if(typeof state[key] != "function"){
45588 var rstate = state[key];
45589 var r = layout.getRegion(key);
45592 r.resizeTo(rstate.size);
45594 if(rstate.collapsed == true){
45597 r.expand(null, true);
45603 layout.endUpdate();
45605 this.state = state;
45607 this.layout = layout;
45608 layout.on("regionresized", this.onRegionResized, this);
45609 layout.on("regioncollapsed", this.onRegionCollapsed, this);
45610 layout.on("regionexpanded", this.onRegionExpanded, this);
45613 storeState : function(){
45614 this.provider.set(this.layout.id+"-layout-state", this.state);
45617 onRegionResized : function(region, newSize){
45618 this.state[region.getPosition()].size = newSize;
45622 onRegionCollapsed : function(region){
45623 this.state[region.getPosition()].collapsed = true;
45627 onRegionExpanded : function(region){
45628 this.state[region.getPosition()].collapsed = false;
45633 * Ext JS Library 1.1.1
45634 * Copyright(c) 2006-2007, Ext JS, LLC.
45636 * Originally Released Under LGPL - original licence link has changed is not relivant.
45639 * <script type="text/javascript">
45642 * @class Roo.ContentPanel
45643 * @extends Roo.util.Observable
45644 * A basic ContentPanel element.
45645 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
45646 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
45647 * @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
45648 * @cfg {Boolean} closable True if the panel can be closed/removed
45649 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
45650 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
45651 * @cfg {Toolbar} toolbar A toolbar for this panel
45652 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
45653 * @cfg {String} title The title for this panel
45654 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
45655 * @cfg {String} url Calls {@link #setUrl} with this value
45656 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
45657 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
45658 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
45659 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
45662 * Create a new ContentPanel.
45663 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
45664 * @param {String/Object} config A string to set only the title or a config object
45665 * @param {String} content (optional) Set the HTML content for this panel
45666 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
45668 Roo.ContentPanel = function(el, config, content){
45672 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
45676 if (config && config.parentLayout) {
45677 el = config.parentLayout.el.createChild();
45680 if(el.autoCreate){ // xtype is available if this is called from factory
45684 this.el = Roo.get(el);
45685 if(!this.el && config && config.autoCreate){
45686 if(typeof config.autoCreate == "object"){
45687 if(!config.autoCreate.id){
45688 config.autoCreate.id = config.id||el;
45690 this.el = Roo.DomHelper.append(document.body,
45691 config.autoCreate, true);
45693 this.el = Roo.DomHelper.append(document.body,
45694 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
45697 this.closable = false;
45698 this.loaded = false;
45699 this.active = false;
45700 if(typeof config == "string"){
45701 this.title = config;
45703 Roo.apply(this, config);
45706 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
45707 this.wrapEl = this.el.wrap();
45708 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
45715 this.resizeEl = Roo.get(this.resizeEl, true);
45717 this.resizeEl = this.el;
45722 * Fires when this panel is activated.
45723 * @param {Roo.ContentPanel} this
45727 * @event deactivate
45728 * Fires when this panel is activated.
45729 * @param {Roo.ContentPanel} this
45731 "deactivate" : true,
45735 * Fires when this panel is resized if fitToFrame is true.
45736 * @param {Roo.ContentPanel} this
45737 * @param {Number} width The width after any component adjustments
45738 * @param {Number} height The height after any component adjustments
45742 if(this.autoScroll){
45743 this.resizeEl.setStyle("overflow", "auto");
45745 // fix randome scrolling
45746 this.el.on('scroll', function() {
45747 Roo.log('fix random scolling');
45748 this.scrollTo('top',0);
45751 content = content || this.content;
45753 this.setContent(content);
45755 if(config && config.url){
45756 this.setUrl(this.url, this.params, this.loadOnce);
45761 Roo.ContentPanel.superclass.constructor.call(this);
45764 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
45766 setRegion : function(region){
45767 this.region = region;
45769 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
45771 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
45776 * Returns the toolbar for this Panel if one was configured.
45777 * @return {Roo.Toolbar}
45779 getToolbar : function(){
45780 return this.toolbar;
45783 setActiveState : function(active){
45784 this.active = active;
45786 this.fireEvent("deactivate", this);
45788 this.fireEvent("activate", this);
45792 * Updates this panel's element
45793 * @param {String} content The new content
45794 * @param {Boolean} loadScripts (optional) true to look for and process scripts
45796 setContent : function(content, loadScripts){
45797 this.el.update(content, loadScripts);
45800 ignoreResize : function(w, h){
45801 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
45804 this.lastSize = {width: w, height: h};
45809 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
45810 * @return {Roo.UpdateManager} The UpdateManager
45812 getUpdateManager : function(){
45813 return this.el.getUpdateManager();
45816 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
45817 * @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:
45820 url: "your-url.php",
45821 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
45822 callback: yourFunction,
45823 scope: yourObject, //(optional scope)
45826 text: "Loading...",
45831 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
45832 * 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.
45833 * @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}
45834 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
45835 * @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.
45836 * @return {Roo.ContentPanel} this
45839 var um = this.el.getUpdateManager();
45840 um.update.apply(um, arguments);
45846 * 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.
45847 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
45848 * @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)
45849 * @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)
45850 * @return {Roo.UpdateManager} The UpdateManager
45852 setUrl : function(url, params, loadOnce){
45853 if(this.refreshDelegate){
45854 this.removeListener("activate", this.refreshDelegate);
45856 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
45857 this.on("activate", this.refreshDelegate);
45858 return this.el.getUpdateManager();
45861 _handleRefresh : function(url, params, loadOnce){
45862 if(!loadOnce || !this.loaded){
45863 var updater = this.el.getUpdateManager();
45864 updater.update(url, params, this._setLoaded.createDelegate(this));
45868 _setLoaded : function(){
45869 this.loaded = true;
45873 * Returns this panel's id
45876 getId : function(){
45881 * Returns this panel's element - used by regiosn to add.
45882 * @return {Roo.Element}
45884 getEl : function(){
45885 return this.wrapEl || this.el;
45888 adjustForComponents : function(width, height){
45889 if(this.resizeEl != this.el){
45890 width -= this.el.getFrameWidth('lr');
45891 height -= this.el.getFrameWidth('tb');
45894 var te = this.toolbar.getEl();
45895 height -= te.getHeight();
45896 te.setWidth(width);
45898 if(this.adjustments){
45899 width += this.adjustments[0];
45900 height += this.adjustments[1];
45902 return {"width": width, "height": height};
45905 setSize : function(width, height){
45906 if(this.fitToFrame && !this.ignoreResize(width, height)){
45907 if(this.fitContainer && this.resizeEl != this.el){
45908 this.el.setSize(width, height);
45910 var size = this.adjustForComponents(width, height);
45911 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
45912 this.fireEvent('resize', this, size.width, size.height);
45917 * Returns this panel's title
45920 getTitle : function(){
45925 * Set this panel's title
45926 * @param {String} title
45928 setTitle : function(title){
45929 this.title = title;
45931 this.region.updatePanelTitle(this, title);
45936 * Returns true is this panel was configured to be closable
45937 * @return {Boolean}
45939 isClosable : function(){
45940 return this.closable;
45943 beforeSlide : function(){
45945 this.resizeEl.clip();
45948 afterSlide : function(){
45950 this.resizeEl.unclip();
45954 * Force a content refresh from the URL specified in the {@link #setUrl} method.
45955 * Will fail silently if the {@link #setUrl} method has not been called.
45956 * This does not activate the panel, just updates its content.
45958 refresh : function(){
45959 if(this.refreshDelegate){
45960 this.loaded = false;
45961 this.refreshDelegate();
45966 * Destroys this panel
45968 destroy : function(){
45969 this.el.removeAllListeners();
45970 var tempEl = document.createElement("span");
45971 tempEl.appendChild(this.el.dom);
45972 tempEl.innerHTML = "";
45978 * form - if the content panel contains a form - this is a reference to it.
45979 * @type {Roo.form.Form}
45983 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
45984 * This contains a reference to it.
45990 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
46000 * @param {Object} cfg Xtype definition of item to add.
46003 addxtype : function(cfg) {
46005 if (cfg.xtype.match(/^Form$/)) {
46006 var el = this.el.createChild();
46008 this.form = new Roo.form.Form(cfg);
46011 if ( this.form.allItems.length) this.form.render(el.dom);
46014 // should only have one of theses..
46015 if (['View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
46017 cfg.el = this.el.appendChild(document.createElement("div"));
46019 var ret = new Roo[cfg.xtype](cfg);
46020 ret.render && ret.render(false, ''); // render blank..
46029 * @class Roo.GridPanel
46030 * @extends Roo.ContentPanel
46032 * Create a new GridPanel.
46033 * @param {Roo.grid.Grid} grid The grid for this panel
46034 * @param {String/Object} config A string to set only the panel's title, or a config object
46036 Roo.GridPanel = function(grid, config){
46039 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
46040 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
46042 this.wrapper.dom.appendChild(grid.getGridEl().dom);
46044 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
46047 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
46049 // xtype created footer. - not sure if will work as we normally have to render first..
46050 if (this.footer && !this.footer.el && this.footer.xtype) {
46052 this.footer.container = this.grid.getView().getFooterPanel(true);
46053 this.footer.dataSource = this.grid.dataSource;
46054 this.footer = Roo.factory(this.footer, Roo);
46058 grid.monitorWindowResize = false; // turn off autosizing
46059 grid.autoHeight = false;
46060 grid.autoWidth = false;
46062 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
46065 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
46066 getId : function(){
46067 return this.grid.id;
46071 * Returns the grid for this panel
46072 * @return {Roo.grid.Grid}
46074 getGrid : function(){
46078 setSize : function(width, height){
46079 if(!this.ignoreResize(width, height)){
46080 var grid = this.grid;
46081 var size = this.adjustForComponents(width, height);
46082 grid.getGridEl().setSize(size.width, size.height);
46087 beforeSlide : function(){
46088 this.grid.getView().scroller.clip();
46091 afterSlide : function(){
46092 this.grid.getView().scroller.unclip();
46095 destroy : function(){
46096 this.grid.destroy();
46098 Roo.GridPanel.superclass.destroy.call(this);
46104 * @class Roo.NestedLayoutPanel
46105 * @extends Roo.ContentPanel
46107 * Create a new NestedLayoutPanel.
46110 * @param {Roo.BorderLayout} layout The layout for this panel
46111 * @param {String/Object} config A string to set only the title or a config object
46113 Roo.NestedLayoutPanel = function(layout, config)
46115 // construct with only one argument..
46116 /* FIXME - implement nicer consturctors
46117 if (layout.layout) {
46119 layout = config.layout;
46120 delete config.layout;
46122 if (layout.xtype && !layout.getEl) {
46123 // then layout needs constructing..
46124 layout = Roo.factory(layout, Roo);
46129 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
46131 layout.monitorWindowResize = false; // turn off autosizing
46132 this.layout = layout;
46133 this.layout.getEl().addClass("x-layout-nested-layout");
46140 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
46142 setSize : function(width, height){
46143 if(!this.ignoreResize(width, height)){
46144 var size = this.adjustForComponents(width, height);
46145 var el = this.layout.getEl();
46146 el.setSize(size.width, size.height);
46147 var touch = el.dom.offsetWidth;
46148 this.layout.layout();
46149 // ie requires a double layout on the first pass
46150 if(Roo.isIE && !this.initialized){
46151 this.initialized = true;
46152 this.layout.layout();
46157 // activate all subpanels if not currently active..
46159 setActiveState : function(active){
46160 this.active = active;
46162 this.fireEvent("deactivate", this);
46166 this.fireEvent("activate", this);
46167 // not sure if this should happen before or after..
46168 if (!this.layout) {
46169 return; // should not happen..
46172 for (var r in this.layout.regions) {
46173 reg = this.layout.getRegion(r);
46174 if (reg.getActivePanel()) {
46175 //reg.showPanel(reg.getActivePanel()); // force it to activate..
46176 reg.setActivePanel(reg.getActivePanel());
46179 if (!reg.panels.length) {
46182 reg.showPanel(reg.getPanel(0));
46191 * Returns the nested BorderLayout for this panel
46192 * @return {Roo.BorderLayout}
46194 getLayout : function(){
46195 return this.layout;
46199 * Adds a xtype elements to the layout of the nested panel
46203 xtype : 'ContentPanel',
46210 xtype : 'NestedLayoutPanel',
46216 items : [ ... list of content panels or nested layout panels.. ]
46220 * @param {Object} cfg Xtype definition of item to add.
46222 addxtype : function(cfg) {
46223 return this.layout.addxtype(cfg);
46228 Roo.ScrollPanel = function(el, config, content){
46229 config = config || {};
46230 config.fitToFrame = true;
46231 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
46233 this.el.dom.style.overflow = "hidden";
46234 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
46235 this.el.removeClass("x-layout-inactive-content");
46236 this.el.on("mousewheel", this.onWheel, this);
46238 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
46239 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
46240 up.unselectable(); down.unselectable();
46241 up.on("click", this.scrollUp, this);
46242 down.on("click", this.scrollDown, this);
46243 up.addClassOnOver("x-scroller-btn-over");
46244 down.addClassOnOver("x-scroller-btn-over");
46245 up.addClassOnClick("x-scroller-btn-click");
46246 down.addClassOnClick("x-scroller-btn-click");
46247 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
46249 this.resizeEl = this.el;
46250 this.el = wrap; this.up = up; this.down = down;
46253 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
46255 wheelIncrement : 5,
46256 scrollUp : function(){
46257 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
46260 scrollDown : function(){
46261 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
46264 afterScroll : function(){
46265 var el = this.resizeEl;
46266 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
46267 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
46268 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
46271 setSize : function(){
46272 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
46273 this.afterScroll();
46276 onWheel : function(e){
46277 var d = e.getWheelDelta();
46278 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
46279 this.afterScroll();
46283 setContent : function(content, loadScripts){
46284 this.resizeEl.update(content, loadScripts);
46298 * @class Roo.TreePanel
46299 * @extends Roo.ContentPanel
46301 * Create a new TreePanel. - defaults to fit/scoll contents.
46302 * @param {String/Object} config A string to set only the panel's title, or a config object
46303 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
46305 Roo.TreePanel = function(config){
46306 var el = config.el;
46307 var tree = config.tree;
46308 delete config.tree;
46309 delete config.el; // hopefull!
46311 // wrapper for IE7 strict & safari scroll issue
46313 var treeEl = el.createChild();
46314 config.resizeEl = treeEl;
46318 Roo.TreePanel.superclass.constructor.call(this, el, config);
46321 this.tree = new Roo.tree.TreePanel(treeEl , tree);
46322 //console.log(tree);
46323 this.on('activate', function()
46325 if (this.tree.rendered) {
46328 //console.log('render tree');
46329 this.tree.render();
46332 this.on('resize', function (cp, w, h) {
46333 this.tree.innerCt.setWidth(w);
46334 this.tree.innerCt.setHeight(h);
46335 this.tree.innerCt.setStyle('overflow-y', 'auto');
46342 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
46359 * Ext JS Library 1.1.1
46360 * Copyright(c) 2006-2007, Ext JS, LLC.
46362 * Originally Released Under LGPL - original licence link has changed is not relivant.
46365 * <script type="text/javascript">
46370 * @class Roo.ReaderLayout
46371 * @extends Roo.BorderLayout
46372 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
46373 * center region containing two nested regions (a top one for a list view and one for item preview below),
46374 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
46375 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
46376 * expedites the setup of the overall layout and regions for this common application style.
46379 var reader = new Roo.ReaderLayout();
46380 var CP = Roo.ContentPanel; // shortcut for adding
46382 reader.beginUpdate();
46383 reader.add("north", new CP("north", "North"));
46384 reader.add("west", new CP("west", {title: "West"}));
46385 reader.add("east", new CP("east", {title: "East"}));
46387 reader.regions.listView.add(new CP("listView", "List"));
46388 reader.regions.preview.add(new CP("preview", "Preview"));
46389 reader.endUpdate();
46392 * Create a new ReaderLayout
46393 * @param {Object} config Configuration options
46394 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
46395 * document.body if omitted)
46397 Roo.ReaderLayout = function(config, renderTo){
46398 var c = config || {size:{}};
46399 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
46400 north: c.north !== false ? Roo.apply({
46404 }, c.north) : false,
46405 west: c.west !== false ? Roo.apply({
46413 margins:{left:5,right:0,bottom:5,top:5},
46414 cmargins:{left:5,right:5,bottom:5,top:5}
46415 }, c.west) : false,
46416 east: c.east !== false ? Roo.apply({
46424 margins:{left:0,right:5,bottom:5,top:5},
46425 cmargins:{left:5,right:5,bottom:5,top:5}
46426 }, c.east) : false,
46427 center: Roo.apply({
46428 tabPosition: 'top',
46432 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
46436 this.el.addClass('x-reader');
46438 this.beginUpdate();
46440 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
46441 south: c.preview !== false ? Roo.apply({
46448 cmargins:{top:5,left:0, right:0, bottom:0}
46449 }, c.preview) : false,
46450 center: Roo.apply({
46456 this.add('center', new Roo.NestedLayoutPanel(inner,
46457 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
46461 this.regions.preview = inner.getRegion('south');
46462 this.regions.listView = inner.getRegion('center');
46465 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
46467 * Ext JS Library 1.1.1
46468 * Copyright(c) 2006-2007, Ext JS, LLC.
46470 * Originally Released Under LGPL - original licence link has changed is not relivant.
46473 * <script type="text/javascript">
46477 * @class Roo.grid.Grid
46478 * @extends Roo.util.Observable
46479 * This class represents the primary interface of a component based grid control.
46480 * <br><br>Usage:<pre><code>
46481 var grid = new Roo.grid.Grid("my-container-id", {
46484 selModel: mySelectionModel,
46485 autoSizeColumns: true,
46486 monitorWindowResize: false,
46487 trackMouseOver: true
46492 * <b>Common Problems:</b><br/>
46493 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
46494 * element will correct this<br/>
46495 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
46496 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
46497 * are unpredictable.<br/>
46498 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
46499 * grid to calculate dimensions/offsets.<br/>
46501 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
46502 * The container MUST have some type of size defined for the grid to fill. The container will be
46503 * automatically set to position relative if it isn't already.
46504 * @param {Object} config A config object that sets properties on this grid.
46506 Roo.grid.Grid = function(container, config){
46507 // initialize the container
46508 this.container = Roo.get(container);
46509 this.container.update("");
46510 this.container.setStyle("overflow", "hidden");
46511 this.container.addClass('x-grid-container');
46513 this.id = this.container.id;
46515 Roo.apply(this, config);
46516 // check and correct shorthanded configs
46518 this.dataSource = this.ds;
46522 this.colModel = this.cm;
46526 this.selModel = this.sm;
46530 if (this.selModel) {
46531 this.selModel = Roo.factory(this.selModel, Roo.grid);
46532 this.sm = this.selModel;
46533 this.sm.xmodule = this.xmodule || false;
46535 if (typeof(this.colModel.config) == 'undefined') {
46536 this.colModel = new Roo.grid.ColumnModel(this.colModel);
46537 this.cm = this.colModel;
46538 this.cm.xmodule = this.xmodule || false;
46540 if (this.dataSource) {
46541 this.dataSource= Roo.factory(this.dataSource, Roo.data);
46542 this.ds = this.dataSource;
46543 this.ds.xmodule = this.xmodule || false;
46550 this.container.setWidth(this.width);
46554 this.container.setHeight(this.height);
46561 * The raw click event for the entire grid.
46562 * @param {Roo.EventObject} e
46567 * The raw dblclick event for the entire grid.
46568 * @param {Roo.EventObject} e
46572 * @event contextmenu
46573 * The raw contextmenu event for the entire grid.
46574 * @param {Roo.EventObject} e
46576 "contextmenu" : true,
46579 * The raw mousedown event for the entire grid.
46580 * @param {Roo.EventObject} e
46582 "mousedown" : true,
46585 * The raw mouseup event for the entire grid.
46586 * @param {Roo.EventObject} e
46591 * The raw mouseover event for the entire grid.
46592 * @param {Roo.EventObject} e
46594 "mouseover" : true,
46597 * The raw mouseout event for the entire grid.
46598 * @param {Roo.EventObject} e
46603 * The raw keypress event for the entire grid.
46604 * @param {Roo.EventObject} e
46609 * The raw keydown event for the entire grid.
46610 * @param {Roo.EventObject} e
46618 * Fires when a cell is clicked
46619 * @param {Grid} this
46620 * @param {Number} rowIndex
46621 * @param {Number} columnIndex
46622 * @param {Roo.EventObject} e
46624 "cellclick" : true,
46626 * @event celldblclick
46627 * Fires when a cell is double clicked
46628 * @param {Grid} this
46629 * @param {Number} rowIndex
46630 * @param {Number} columnIndex
46631 * @param {Roo.EventObject} e
46633 "celldblclick" : true,
46636 * Fires when a row is clicked
46637 * @param {Grid} this
46638 * @param {Number} rowIndex
46639 * @param {Roo.EventObject} e
46643 * @event rowdblclick
46644 * Fires when a row is double clicked
46645 * @param {Grid} this
46646 * @param {Number} rowIndex
46647 * @param {Roo.EventObject} e
46649 "rowdblclick" : true,
46651 * @event headerclick
46652 * Fires when a header is clicked
46653 * @param {Grid} this
46654 * @param {Number} columnIndex
46655 * @param {Roo.EventObject} e
46657 "headerclick" : true,
46659 * @event headerdblclick
46660 * Fires when a header cell is double clicked
46661 * @param {Grid} this
46662 * @param {Number} columnIndex
46663 * @param {Roo.EventObject} e
46665 "headerdblclick" : true,
46667 * @event rowcontextmenu
46668 * Fires when a row is right clicked
46669 * @param {Grid} this
46670 * @param {Number} rowIndex
46671 * @param {Roo.EventObject} e
46673 "rowcontextmenu" : true,
46675 * @event cellcontextmenu
46676 * Fires when a cell is right clicked
46677 * @param {Grid} this
46678 * @param {Number} rowIndex
46679 * @param {Number} cellIndex
46680 * @param {Roo.EventObject} e
46682 "cellcontextmenu" : true,
46684 * @event headercontextmenu
46685 * Fires when a header is right clicked
46686 * @param {Grid} this
46687 * @param {Number} columnIndex
46688 * @param {Roo.EventObject} e
46690 "headercontextmenu" : true,
46692 * @event bodyscroll
46693 * Fires when the body element is scrolled
46694 * @param {Number} scrollLeft
46695 * @param {Number} scrollTop
46697 "bodyscroll" : true,
46699 * @event columnresize
46700 * Fires when the user resizes a column
46701 * @param {Number} columnIndex
46702 * @param {Number} newSize
46704 "columnresize" : true,
46706 * @event columnmove
46707 * Fires when the user moves a column
46708 * @param {Number} oldIndex
46709 * @param {Number} newIndex
46711 "columnmove" : true,
46714 * Fires when row(s) start being dragged
46715 * @param {Grid} this
46716 * @param {Roo.GridDD} dd The drag drop object
46717 * @param {event} e The raw browser event
46719 "startdrag" : true,
46722 * Fires when a drag operation is complete
46723 * @param {Grid} this
46724 * @param {Roo.GridDD} dd The drag drop object
46725 * @param {event} e The raw browser event
46730 * Fires when dragged row(s) are dropped on a valid DD target
46731 * @param {Grid} this
46732 * @param {Roo.GridDD} dd The drag drop object
46733 * @param {String} targetId The target drag drop object
46734 * @param {event} e The raw browser event
46739 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
46740 * @param {Grid} this
46741 * @param {Roo.GridDD} dd The drag drop object
46742 * @param {String} targetId The target drag drop object
46743 * @param {event} e The raw browser event
46748 * Fires when the dragged row(s) first cross another DD target while being dragged
46749 * @param {Grid} this
46750 * @param {Roo.GridDD} dd The drag drop object
46751 * @param {String} targetId The target drag drop object
46752 * @param {event} e The raw browser event
46754 "dragenter" : true,
46757 * Fires when the dragged row(s) leave another DD target while being dragged
46758 * @param {Grid} this
46759 * @param {Roo.GridDD} dd The drag drop object
46760 * @param {String} targetId The target drag drop object
46761 * @param {event} e The raw browser event
46766 * Fires when a row is rendered, so you can change add a style to it.
46767 * @param {GridView} gridview The grid view
46768 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
46774 * Fires when the grid is rendered
46775 * @param {Grid} grid
46780 Roo.grid.Grid.superclass.constructor.call(this);
46782 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
46785 * @cfg {String} ddGroup - drag drop group.
46789 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
46791 minColumnWidth : 25,
46794 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
46795 * <b>on initial render.</b> It is more efficient to explicitly size the columns
46796 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
46798 autoSizeColumns : false,
46801 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
46803 autoSizeHeaders : true,
46806 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
46808 monitorWindowResize : true,
46811 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
46812 * rows measured to get a columns size. Default is 0 (all rows).
46814 maxRowsToMeasure : 0,
46817 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
46819 trackMouseOver : true,
46822 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
46826 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
46828 enableDragDrop : false,
46831 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
46833 enableColumnMove : true,
46836 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
46838 enableColumnHide : true,
46841 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
46843 enableRowHeightSync : false,
46846 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
46851 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
46853 autoHeight : false,
46856 * @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.
46858 autoExpandColumn : false,
46861 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
46864 autoExpandMin : 50,
46867 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
46869 autoExpandMax : 1000,
46872 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
46877 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
46881 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
46891 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
46892 * of a fixed width. Default is false.
46895 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
46898 * Called once after all setup has been completed and the grid is ready to be rendered.
46899 * @return {Roo.grid.Grid} this
46901 render : function()
46903 var c = this.container;
46904 // try to detect autoHeight/width mode
46905 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
46906 this.autoHeight = true;
46908 var view = this.getView();
46911 c.on("click", this.onClick, this);
46912 c.on("dblclick", this.onDblClick, this);
46913 c.on("contextmenu", this.onContextMenu, this);
46914 c.on("keydown", this.onKeyDown, this);
46916 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
46918 this.getSelectionModel().init(this);
46923 this.loadMask = new Roo.LoadMask(this.container,
46924 Roo.apply({store:this.dataSource}, this.loadMask));
46928 if (this.toolbar && this.toolbar.xtype) {
46929 this.toolbar.container = this.getView().getHeaderPanel(true);
46930 this.toolbar = new Roo.Toolbar(this.toolbar);
46932 if (this.footer && this.footer.xtype) {
46933 this.footer.dataSource = this.getDataSource();
46934 this.footer.container = this.getView().getFooterPanel(true);
46935 this.footer = Roo.factory(this.footer, Roo);
46937 if (this.dropTarget && this.dropTarget.xtype) {
46938 delete this.dropTarget.xtype;
46939 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
46943 this.rendered = true;
46944 this.fireEvent('render', this);
46949 * Reconfigures the grid to use a different Store and Column Model.
46950 * The View will be bound to the new objects and refreshed.
46951 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
46952 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
46954 reconfigure : function(dataSource, colModel){
46956 this.loadMask.destroy();
46957 this.loadMask = new Roo.LoadMask(this.container,
46958 Roo.apply({store:dataSource}, this.loadMask));
46960 this.view.bind(dataSource, colModel);
46961 this.dataSource = dataSource;
46962 this.colModel = colModel;
46963 this.view.refresh(true);
46967 onKeyDown : function(e){
46968 this.fireEvent("keydown", e);
46972 * Destroy this grid.
46973 * @param {Boolean} removeEl True to remove the element
46975 destroy : function(removeEl, keepListeners){
46977 this.loadMask.destroy();
46979 var c = this.container;
46980 c.removeAllListeners();
46981 this.view.destroy();
46982 this.colModel.purgeListeners();
46983 if(!keepListeners){
46984 this.purgeListeners();
46987 if(removeEl === true){
46993 processEvent : function(name, e){
46994 this.fireEvent(name, e);
46995 var t = e.getTarget();
46997 var header = v.findHeaderIndex(t);
46998 if(header !== false){
46999 this.fireEvent("header" + name, this, header, e);
47001 var row = v.findRowIndex(t);
47002 var cell = v.findCellIndex(t);
47004 this.fireEvent("row" + name, this, row, e);
47005 if(cell !== false){
47006 this.fireEvent("cell" + name, this, row, cell, e);
47013 onClick : function(e){
47014 this.processEvent("click", e);
47018 onContextMenu : function(e, t){
47019 this.processEvent("contextmenu", e);
47023 onDblClick : function(e){
47024 this.processEvent("dblclick", e);
47028 walkCells : function(row, col, step, fn, scope){
47029 var cm = this.colModel, clen = cm.getColumnCount();
47030 var ds = this.dataSource, rlen = ds.getCount(), first = true;
47042 if(fn.call(scope || this, row, col, cm) === true){
47060 if(fn.call(scope || this, row, col, cm) === true){
47072 getSelections : function(){
47073 return this.selModel.getSelections();
47077 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
47078 * but if manual update is required this method will initiate it.
47080 autoSize : function(){
47082 this.view.layout();
47083 if(this.view.adjustForScroll){
47084 this.view.adjustForScroll();
47090 * Returns the grid's underlying element.
47091 * @return {Element} The element
47093 getGridEl : function(){
47094 return this.container;
47097 // private for compatibility, overridden by editor grid
47098 stopEditing : function(){},
47101 * Returns the grid's SelectionModel.
47102 * @return {SelectionModel}
47104 getSelectionModel : function(){
47105 if(!this.selModel){
47106 this.selModel = new Roo.grid.RowSelectionModel();
47108 return this.selModel;
47112 * Returns the grid's DataSource.
47113 * @return {DataSource}
47115 getDataSource : function(){
47116 return this.dataSource;
47120 * Returns the grid's ColumnModel.
47121 * @return {ColumnModel}
47123 getColumnModel : function(){
47124 return this.colModel;
47128 * Returns the grid's GridView object.
47129 * @return {GridView}
47131 getView : function(){
47133 this.view = new Roo.grid.GridView(this.viewConfig);
47138 * Called to get grid's drag proxy text, by default returns this.ddText.
47141 getDragDropText : function(){
47142 var count = this.selModel.getCount();
47143 return String.format(this.ddText, count, count == 1 ? '' : 's');
47147 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
47148 * %0 is replaced with the number of selected rows.
47151 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
47153 * Ext JS Library 1.1.1
47154 * Copyright(c) 2006-2007, Ext JS, LLC.
47156 * Originally Released Under LGPL - original licence link has changed is not relivant.
47159 * <script type="text/javascript">
47162 Roo.grid.AbstractGridView = function(){
47166 "beforerowremoved" : true,
47167 "beforerowsinserted" : true,
47168 "beforerefresh" : true,
47169 "rowremoved" : true,
47170 "rowsinserted" : true,
47171 "rowupdated" : true,
47174 Roo.grid.AbstractGridView.superclass.constructor.call(this);
47177 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
47178 rowClass : "x-grid-row",
47179 cellClass : "x-grid-cell",
47180 tdClass : "x-grid-td",
47181 hdClass : "x-grid-hd",
47182 splitClass : "x-grid-hd-split",
47184 init: function(grid){
47186 var cid = this.grid.getGridEl().id;
47187 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
47188 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
47189 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
47190 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
47193 getColumnRenderers : function(){
47194 var renderers = [];
47195 var cm = this.grid.colModel;
47196 var colCount = cm.getColumnCount();
47197 for(var i = 0; i < colCount; i++){
47198 renderers[i] = cm.getRenderer(i);
47203 getColumnIds : function(){
47205 var cm = this.grid.colModel;
47206 var colCount = cm.getColumnCount();
47207 for(var i = 0; i < colCount; i++){
47208 ids[i] = cm.getColumnId(i);
47213 getDataIndexes : function(){
47214 if(!this.indexMap){
47215 this.indexMap = this.buildIndexMap();
47217 return this.indexMap.colToData;
47220 getColumnIndexByDataIndex : function(dataIndex){
47221 if(!this.indexMap){
47222 this.indexMap = this.buildIndexMap();
47224 return this.indexMap.dataToCol[dataIndex];
47228 * Set a css style for a column dynamically.
47229 * @param {Number} colIndex The index of the column
47230 * @param {String} name The css property name
47231 * @param {String} value The css value
47233 setCSSStyle : function(colIndex, name, value){
47234 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
47235 Roo.util.CSS.updateRule(selector, name, value);
47238 generateRules : function(cm){
47239 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
47240 Roo.util.CSS.removeStyleSheet(rulesId);
47241 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47242 var cid = cm.getColumnId(i);
47243 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
47244 this.tdSelector, cid, " {\n}\n",
47245 this.hdSelector, cid, " {\n}\n",
47246 this.splitSelector, cid, " {\n}\n");
47248 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
47252 * Ext JS Library 1.1.1
47253 * Copyright(c) 2006-2007, Ext JS, LLC.
47255 * Originally Released Under LGPL - original licence link has changed is not relivant.
47258 * <script type="text/javascript">
47262 // This is a support class used internally by the Grid components
47263 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
47265 this.view = grid.getView();
47266 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
47267 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
47269 this.setHandleElId(Roo.id(hd));
47270 this.setOuterHandleElId(Roo.id(hd2));
47272 this.scroll = false;
47274 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
47276 getDragData : function(e){
47277 var t = Roo.lib.Event.getTarget(e);
47278 var h = this.view.findHeaderCell(t);
47280 return {ddel: h.firstChild, header:h};
47285 onInitDrag : function(e){
47286 this.view.headersDisabled = true;
47287 var clone = this.dragData.ddel.cloneNode(true);
47288 clone.id = Roo.id();
47289 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
47290 this.proxy.update(clone);
47294 afterValidDrop : function(){
47296 setTimeout(function(){
47297 v.headersDisabled = false;
47301 afterInvalidDrop : function(){
47303 setTimeout(function(){
47304 v.headersDisabled = false;
47310 * Ext JS Library 1.1.1
47311 * Copyright(c) 2006-2007, Ext JS, LLC.
47313 * Originally Released Under LGPL - original licence link has changed is not relivant.
47316 * <script type="text/javascript">
47319 // This is a support class used internally by the Grid components
47320 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
47322 this.view = grid.getView();
47323 // split the proxies so they don't interfere with mouse events
47324 this.proxyTop = Roo.DomHelper.append(document.body, {
47325 cls:"col-move-top", html:" "
47327 this.proxyBottom = Roo.DomHelper.append(document.body, {
47328 cls:"col-move-bottom", html:" "
47330 this.proxyTop.hide = this.proxyBottom.hide = function(){
47331 this.setLeftTop(-100,-100);
47332 this.setStyle("visibility", "hidden");
47334 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
47335 // temporarily disabled
47336 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
47337 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
47339 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
47340 proxyOffsets : [-4, -9],
47341 fly: Roo.Element.fly,
47343 getTargetFromEvent : function(e){
47344 var t = Roo.lib.Event.getTarget(e);
47345 var cindex = this.view.findCellIndex(t);
47346 if(cindex !== false){
47347 return this.view.getHeaderCell(cindex);
47352 nextVisible : function(h){
47353 var v = this.view, cm = this.grid.colModel;
47356 if(!cm.isHidden(v.getCellIndex(h))){
47364 prevVisible : function(h){
47365 var v = this.view, cm = this.grid.colModel;
47368 if(!cm.isHidden(v.getCellIndex(h))){
47376 positionIndicator : function(h, n, e){
47377 var x = Roo.lib.Event.getPageX(e);
47378 var r = Roo.lib.Dom.getRegion(n.firstChild);
47379 var px, pt, py = r.top + this.proxyOffsets[1];
47380 if((r.right - x) <= (r.right-r.left)/2){
47381 px = r.right+this.view.borderWidth;
47387 var oldIndex = this.view.getCellIndex(h);
47388 var newIndex = this.view.getCellIndex(n);
47390 if(this.grid.colModel.isFixed(newIndex)){
47394 var locked = this.grid.colModel.isLocked(newIndex);
47399 if(oldIndex < newIndex){
47402 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
47405 px += this.proxyOffsets[0];
47406 this.proxyTop.setLeftTop(px, py);
47407 this.proxyTop.show();
47408 if(!this.bottomOffset){
47409 this.bottomOffset = this.view.mainHd.getHeight();
47411 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
47412 this.proxyBottom.show();
47416 onNodeEnter : function(n, dd, e, data){
47417 if(data.header != n){
47418 this.positionIndicator(data.header, n, e);
47422 onNodeOver : function(n, dd, e, data){
47423 var result = false;
47424 if(data.header != n){
47425 result = this.positionIndicator(data.header, n, e);
47428 this.proxyTop.hide();
47429 this.proxyBottom.hide();
47431 return result ? this.dropAllowed : this.dropNotAllowed;
47434 onNodeOut : function(n, dd, e, data){
47435 this.proxyTop.hide();
47436 this.proxyBottom.hide();
47439 onNodeDrop : function(n, dd, e, data){
47440 var h = data.header;
47442 var cm = this.grid.colModel;
47443 var x = Roo.lib.Event.getPageX(e);
47444 var r = Roo.lib.Dom.getRegion(n.firstChild);
47445 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
47446 var oldIndex = this.view.getCellIndex(h);
47447 var newIndex = this.view.getCellIndex(n);
47448 var locked = cm.isLocked(newIndex);
47452 if(oldIndex < newIndex){
47455 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
47458 cm.setLocked(oldIndex, locked, true);
47459 cm.moveColumn(oldIndex, newIndex);
47460 this.grid.fireEvent("columnmove", oldIndex, newIndex);
47468 * Ext JS Library 1.1.1
47469 * Copyright(c) 2006-2007, Ext JS, LLC.
47471 * Originally Released Under LGPL - original licence link has changed is not relivant.
47474 * <script type="text/javascript">
47478 * @class Roo.grid.GridView
47479 * @extends Roo.util.Observable
47482 * @param {Object} config
47484 Roo.grid.GridView = function(config){
47485 Roo.grid.GridView.superclass.constructor.call(this);
47488 Roo.apply(this, config);
47491 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
47494 * Override this function to apply custom css classes to rows during rendering
47495 * @param {Record} record The record
47496 * @param {Number} index
47497 * @method getRowClass
47499 rowClass : "x-grid-row",
47501 cellClass : "x-grid-col",
47503 tdClass : "x-grid-td",
47505 hdClass : "x-grid-hd",
47507 splitClass : "x-grid-split",
47509 sortClasses : ["sort-asc", "sort-desc"],
47511 enableMoveAnim : false,
47515 dh : Roo.DomHelper,
47517 fly : Roo.Element.fly,
47519 css : Roo.util.CSS,
47525 scrollIncrement : 22,
47527 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
47529 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
47531 bind : function(ds, cm){
47533 this.ds.un("load", this.onLoad, this);
47534 this.ds.un("datachanged", this.onDataChange, this);
47535 this.ds.un("add", this.onAdd, this);
47536 this.ds.un("remove", this.onRemove, this);
47537 this.ds.un("update", this.onUpdate, this);
47538 this.ds.un("clear", this.onClear, this);
47541 ds.on("load", this.onLoad, this);
47542 ds.on("datachanged", this.onDataChange, this);
47543 ds.on("add", this.onAdd, this);
47544 ds.on("remove", this.onRemove, this);
47545 ds.on("update", this.onUpdate, this);
47546 ds.on("clear", this.onClear, this);
47551 this.cm.un("widthchange", this.onColWidthChange, this);
47552 this.cm.un("headerchange", this.onHeaderChange, this);
47553 this.cm.un("hiddenchange", this.onHiddenChange, this);
47554 this.cm.un("columnmoved", this.onColumnMove, this);
47555 this.cm.un("columnlockchange", this.onColumnLock, this);
47558 this.generateRules(cm);
47559 cm.on("widthchange", this.onColWidthChange, this);
47560 cm.on("headerchange", this.onHeaderChange, this);
47561 cm.on("hiddenchange", this.onHiddenChange, this);
47562 cm.on("columnmoved", this.onColumnMove, this);
47563 cm.on("columnlockchange", this.onColumnLock, this);
47568 init: function(grid){
47569 Roo.grid.GridView.superclass.init.call(this, grid);
47571 this.bind(grid.dataSource, grid.colModel);
47573 grid.on("headerclick", this.handleHeaderClick, this);
47575 if(grid.trackMouseOver){
47576 grid.on("mouseover", this.onRowOver, this);
47577 grid.on("mouseout", this.onRowOut, this);
47579 grid.cancelTextSelection = function(){};
47580 this.gridId = grid.id;
47582 var tpls = this.templates || {};
47585 tpls.master = new Roo.Template(
47586 '<div class="x-grid" hidefocus="true">',
47587 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
47588 '<div class="x-grid-topbar"></div>',
47589 '<div class="x-grid-scroller"><div></div></div>',
47590 '<div class="x-grid-locked">',
47591 '<div class="x-grid-header">{lockedHeader}</div>',
47592 '<div class="x-grid-body">{lockedBody}</div>',
47594 '<div class="x-grid-viewport">',
47595 '<div class="x-grid-header">{header}</div>',
47596 '<div class="x-grid-body">{body}</div>',
47598 '<div class="x-grid-bottombar"></div>',
47600 '<div class="x-grid-resize-proxy"> </div>',
47603 tpls.master.disableformats = true;
47607 tpls.header = new Roo.Template(
47608 '<table border="0" cellspacing="0" cellpadding="0">',
47609 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
47612 tpls.header.disableformats = true;
47614 tpls.header.compile();
47617 tpls.hcell = new Roo.Template(
47618 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
47619 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
47622 tpls.hcell.disableFormats = true;
47624 tpls.hcell.compile();
47627 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
47628 tpls.hsplit.disableFormats = true;
47630 tpls.hsplit.compile();
47633 tpls.body = new Roo.Template(
47634 '<table border="0" cellspacing="0" cellpadding="0">',
47635 "<tbody>{rows}</tbody>",
47638 tpls.body.disableFormats = true;
47640 tpls.body.compile();
47643 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
47644 tpls.row.disableFormats = true;
47646 tpls.row.compile();
47649 tpls.cell = new Roo.Template(
47650 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
47651 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
47654 tpls.cell.disableFormats = true;
47656 tpls.cell.compile();
47658 this.templates = tpls;
47661 // remap these for backwards compat
47662 onColWidthChange : function(){
47663 this.updateColumns.apply(this, arguments);
47665 onHeaderChange : function(){
47666 this.updateHeaders.apply(this, arguments);
47668 onHiddenChange : function(){
47669 this.handleHiddenChange.apply(this, arguments);
47671 onColumnMove : function(){
47672 this.handleColumnMove.apply(this, arguments);
47674 onColumnLock : function(){
47675 this.handleLockChange.apply(this, arguments);
47678 onDataChange : function(){
47680 this.updateHeaderSortState();
47683 onClear : function(){
47687 onUpdate : function(ds, record){
47688 this.refreshRow(record);
47691 refreshRow : function(record){
47692 var ds = this.ds, index;
47693 if(typeof record == 'number'){
47695 record = ds.getAt(index);
47697 index = ds.indexOf(record);
47699 this.insertRows(ds, index, index, true);
47700 this.onRemove(ds, record, index+1, true);
47701 this.syncRowHeights(index, index);
47703 this.fireEvent("rowupdated", this, index, record);
47706 onAdd : function(ds, records, index){
47707 this.insertRows(ds, index, index + (records.length-1));
47710 onRemove : function(ds, record, index, isUpdate){
47711 if(isUpdate !== true){
47712 this.fireEvent("beforerowremoved", this, index, record);
47714 var bt = this.getBodyTable(), lt = this.getLockedTable();
47715 if(bt.rows[index]){
47716 bt.firstChild.removeChild(bt.rows[index]);
47718 if(lt.rows[index]){
47719 lt.firstChild.removeChild(lt.rows[index]);
47721 if(isUpdate !== true){
47722 this.stripeRows(index);
47723 this.syncRowHeights(index, index);
47725 this.fireEvent("rowremoved", this, index, record);
47729 onLoad : function(){
47730 this.scrollToTop();
47734 * Scrolls the grid to the top
47736 scrollToTop : function(){
47738 this.scroller.dom.scrollTop = 0;
47744 * Gets a panel in the header of the grid that can be used for toolbars etc.
47745 * After modifying the contents of this panel a call to grid.autoSize() may be
47746 * required to register any changes in size.
47747 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
47748 * @return Roo.Element
47750 getHeaderPanel : function(doShow){
47752 this.headerPanel.show();
47754 return this.headerPanel;
47758 * Gets a panel in the footer of the grid that can be used for toolbars etc.
47759 * After modifying the contents of this panel a call to grid.autoSize() may be
47760 * required to register any changes in size.
47761 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
47762 * @return Roo.Element
47764 getFooterPanel : function(doShow){
47766 this.footerPanel.show();
47768 return this.footerPanel;
47771 initElements : function(){
47772 var E = Roo.Element;
47773 var el = this.grid.getGridEl().dom.firstChild;
47774 var cs = el.childNodes;
47776 this.el = new E(el);
47778 this.focusEl = new E(el.firstChild);
47779 this.focusEl.swallowEvent("click", true);
47781 this.headerPanel = new E(cs[1]);
47782 this.headerPanel.enableDisplayMode("block");
47784 this.scroller = new E(cs[2]);
47785 this.scrollSizer = new E(this.scroller.dom.firstChild);
47787 this.lockedWrap = new E(cs[3]);
47788 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
47789 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
47791 this.mainWrap = new E(cs[4]);
47792 this.mainHd = new E(this.mainWrap.dom.firstChild);
47793 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
47795 this.footerPanel = new E(cs[5]);
47796 this.footerPanel.enableDisplayMode("block");
47798 this.resizeProxy = new E(cs[6]);
47800 this.headerSelector = String.format(
47801 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
47802 this.lockedHd.id, this.mainHd.id
47805 this.splitterSelector = String.format(
47806 '#{0} div.x-grid-split, #{1} div.x-grid-split',
47807 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
47810 idToCssName : function(s)
47812 return s.replace(/[^a-z0-9]+/ig, '-');
47815 getHeaderCell : function(index){
47816 return Roo.DomQuery.select(this.headerSelector)[index];
47819 getHeaderCellMeasure : function(index){
47820 return this.getHeaderCell(index).firstChild;
47823 getHeaderCellText : function(index){
47824 return this.getHeaderCell(index).firstChild.firstChild;
47827 getLockedTable : function(){
47828 return this.lockedBody.dom.firstChild;
47831 getBodyTable : function(){
47832 return this.mainBody.dom.firstChild;
47835 getLockedRow : function(index){
47836 return this.getLockedTable().rows[index];
47839 getRow : function(index){
47840 return this.getBodyTable().rows[index];
47843 getRowComposite : function(index){
47845 this.rowEl = new Roo.CompositeElementLite();
47847 var els = [], lrow, mrow;
47848 if(lrow = this.getLockedRow(index)){
47851 if(mrow = this.getRow(index)){
47854 this.rowEl.elements = els;
47858 getCell : function(rowIndex, colIndex){
47859 var locked = this.cm.getLockedCount();
47861 if(colIndex < locked){
47862 source = this.lockedBody.dom.firstChild;
47864 source = this.mainBody.dom.firstChild;
47865 colIndex -= locked;
47867 return source.rows[rowIndex].childNodes[colIndex];
47870 getCellText : function(rowIndex, colIndex){
47871 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
47874 getCellBox : function(cell){
47875 var b = this.fly(cell).getBox();
47876 if(Roo.isOpera){ // opera fails to report the Y
47877 b.y = cell.offsetTop + this.mainBody.getY();
47882 getCellIndex : function(cell){
47883 var id = String(cell.className).match(this.cellRE);
47885 return parseInt(id[1], 10);
47890 findHeaderIndex : function(n){
47891 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47892 return r ? this.getCellIndex(r) : false;
47895 findHeaderCell : function(n){
47896 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47897 return r ? r : false;
47900 findRowIndex : function(n){
47904 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
47905 return r ? r.rowIndex : false;
47908 findCellIndex : function(node){
47909 var stop = this.el.dom;
47910 while(node && node != stop){
47911 if(this.findRE.test(node.className)){
47912 return this.getCellIndex(node);
47914 node = node.parentNode;
47919 getColumnId : function(index){
47920 return this.cm.getColumnId(index);
47923 getSplitters : function()
47925 if(this.splitterSelector){
47926 return Roo.DomQuery.select(this.splitterSelector);
47932 getSplitter : function(index){
47933 return this.getSplitters()[index];
47936 onRowOver : function(e, t){
47938 if((row = this.findRowIndex(t)) !== false){
47939 this.getRowComposite(row).addClass("x-grid-row-over");
47943 onRowOut : function(e, t){
47945 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
47946 this.getRowComposite(row).removeClass("x-grid-row-over");
47950 renderHeaders : function(){
47952 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
47953 var cb = [], lb = [], sb = [], lsb = [], p = {};
47954 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47955 p.cellId = "x-grid-hd-0-" + i;
47956 p.splitId = "x-grid-csplit-0-" + i;
47957 p.id = cm.getColumnId(i);
47958 p.title = cm.getColumnTooltip(i) || "";
47959 p.value = cm.getColumnHeader(i) || "";
47960 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
47961 if(!cm.isLocked(i)){
47962 cb[cb.length] = ct.apply(p);
47963 sb[sb.length] = st.apply(p);
47965 lb[lb.length] = ct.apply(p);
47966 lsb[lsb.length] = st.apply(p);
47969 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
47970 ht.apply({cells: cb.join(""), splits:sb.join("")})];
47973 updateHeaders : function(){
47974 var html = this.renderHeaders();
47975 this.lockedHd.update(html[0]);
47976 this.mainHd.update(html[1]);
47980 * Focuses the specified row.
47981 * @param {Number} row The row index
47983 focusRow : function(row)
47985 //Roo.log('GridView.focusRow');
47986 var x = this.scroller.dom.scrollLeft;
47987 this.focusCell(row, 0, false);
47988 this.scroller.dom.scrollLeft = x;
47992 * Focuses the specified cell.
47993 * @param {Number} row The row index
47994 * @param {Number} col The column index
47995 * @param {Boolean} hscroll false to disable horizontal scrolling
47997 focusCell : function(row, col, hscroll)
47999 //Roo.log('GridView.focusCell');
48000 var el = this.ensureVisible(row, col, hscroll);
48001 this.focusEl.alignTo(el, "tl-tl");
48003 this.focusEl.focus();
48005 this.focusEl.focus.defer(1, this.focusEl);
48010 * Scrolls the specified cell into view
48011 * @param {Number} row The row index
48012 * @param {Number} col The column index
48013 * @param {Boolean} hscroll false to disable horizontal scrolling
48015 ensureVisible : function(row, col, hscroll)
48017 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
48018 //return null; //disable for testing.
48019 if(typeof row != "number"){
48020 row = row.rowIndex;
48022 if(row < 0 && row >= this.ds.getCount()){
48025 col = (col !== undefined ? col : 0);
48026 var cm = this.grid.colModel;
48027 while(cm.isHidden(col)){
48031 var el = this.getCell(row, col);
48035 var c = this.scroller.dom;
48037 var ctop = parseInt(el.offsetTop, 10);
48038 var cleft = parseInt(el.offsetLeft, 10);
48039 var cbot = ctop + el.offsetHeight;
48040 var cright = cleft + el.offsetWidth;
48042 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
48043 var stop = parseInt(c.scrollTop, 10);
48044 var sleft = parseInt(c.scrollLeft, 10);
48045 var sbot = stop + ch;
48046 var sright = sleft + c.clientWidth;
48048 Roo.log('GridView.ensureVisible:' +
48050 ' c.clientHeight:' + c.clientHeight +
48051 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
48059 c.scrollTop = ctop;
48060 //Roo.log("set scrolltop to ctop DISABLE?");
48061 }else if(cbot > sbot){
48062 //Roo.log("set scrolltop to cbot-ch");
48063 c.scrollTop = cbot-ch;
48066 if(hscroll !== false){
48068 c.scrollLeft = cleft;
48069 }else if(cright > sright){
48070 c.scrollLeft = cright-c.clientWidth;
48077 updateColumns : function(){
48078 this.grid.stopEditing();
48079 var cm = this.grid.colModel, colIds = this.getColumnIds();
48080 //var totalWidth = cm.getTotalWidth();
48082 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48083 //if(cm.isHidden(i)) continue;
48084 var w = cm.getColumnWidth(i);
48085 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48086 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48088 this.updateSplitters();
48091 generateRules : function(cm){
48092 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
48093 Roo.util.CSS.removeStyleSheet(rulesId);
48094 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48095 var cid = cm.getColumnId(i);
48097 if(cm.config[i].align){
48098 align = 'text-align:'+cm.config[i].align+';';
48101 if(cm.isHidden(i)){
48102 hidden = 'display:none;';
48104 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
48106 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
48107 this.hdSelector, cid, " {\n", align, width, "}\n",
48108 this.tdSelector, cid, " {\n",hidden,"\n}\n",
48109 this.splitSelector, cid, " {\n", hidden , "\n}\n");
48111 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
48114 updateSplitters : function(){
48115 var cm = this.cm, s = this.getSplitters();
48116 if(s){ // splitters not created yet
48117 var pos = 0, locked = true;
48118 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48119 if(cm.isHidden(i)) continue;
48120 var w = cm.getColumnWidth(i); // make sure it's a number
48121 if(!cm.isLocked(i) && locked){
48126 s[i].style.left = (pos-this.splitOffset) + "px";
48131 handleHiddenChange : function(colModel, colIndex, hidden){
48133 this.hideColumn(colIndex);
48135 this.unhideColumn(colIndex);
48139 hideColumn : function(colIndex){
48140 var cid = this.getColumnId(colIndex);
48141 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
48142 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
48144 this.updateHeaders();
48146 this.updateSplitters();
48150 unhideColumn : function(colIndex){
48151 var cid = this.getColumnId(colIndex);
48152 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
48153 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
48156 this.updateHeaders();
48158 this.updateSplitters();
48162 insertRows : function(dm, firstRow, lastRow, isUpdate){
48163 if(firstRow == 0 && lastRow == dm.getCount()-1){
48167 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
48169 var s = this.getScrollState();
48170 var markup = this.renderRows(firstRow, lastRow);
48171 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
48172 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
48173 this.restoreScroll(s);
48175 this.fireEvent("rowsinserted", this, firstRow, lastRow);
48176 this.syncRowHeights(firstRow, lastRow);
48177 this.stripeRows(firstRow);
48183 bufferRows : function(markup, target, index){
48184 var before = null, trows = target.rows, tbody = target.tBodies[0];
48185 if(index < trows.length){
48186 before = trows[index];
48188 var b = document.createElement("div");
48189 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
48190 var rows = b.firstChild.rows;
48191 for(var i = 0, len = rows.length; i < len; i++){
48193 tbody.insertBefore(rows[0], before);
48195 tbody.appendChild(rows[0]);
48202 deleteRows : function(dm, firstRow, lastRow){
48203 if(dm.getRowCount()<1){
48204 this.fireEvent("beforerefresh", this);
48205 this.mainBody.update("");
48206 this.lockedBody.update("");
48207 this.fireEvent("refresh", this);
48209 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
48210 var bt = this.getBodyTable();
48211 var tbody = bt.firstChild;
48212 var rows = bt.rows;
48213 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
48214 tbody.removeChild(rows[firstRow]);
48216 this.stripeRows(firstRow);
48217 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
48221 updateRows : function(dataSource, firstRow, lastRow){
48222 var s = this.getScrollState();
48224 this.restoreScroll(s);
48227 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
48231 this.updateHeaderSortState();
48234 getScrollState : function(){
48236 var sb = this.scroller.dom;
48237 return {left: sb.scrollLeft, top: sb.scrollTop};
48240 stripeRows : function(startRow){
48241 if(!this.grid.stripeRows || this.ds.getCount() < 1){
48244 startRow = startRow || 0;
48245 var rows = this.getBodyTable().rows;
48246 var lrows = this.getLockedTable().rows;
48247 var cls = ' x-grid-row-alt ';
48248 for(var i = startRow, len = rows.length; i < len; i++){
48249 var row = rows[i], lrow = lrows[i];
48250 var isAlt = ((i+1) % 2 == 0);
48251 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
48252 if(isAlt == hasAlt){
48256 row.className += " x-grid-row-alt";
48258 row.className = row.className.replace("x-grid-row-alt", "");
48261 lrow.className = row.className;
48266 restoreScroll : function(state){
48267 //Roo.log('GridView.restoreScroll');
48268 var sb = this.scroller.dom;
48269 sb.scrollLeft = state.left;
48270 sb.scrollTop = state.top;
48274 syncScroll : function(){
48275 //Roo.log('GridView.syncScroll');
48276 var sb = this.scroller.dom;
48277 var sh = this.mainHd.dom;
48278 var bs = this.mainBody.dom;
48279 var lv = this.lockedBody.dom;
48280 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
48281 lv.scrollTop = bs.scrollTop = sb.scrollTop;
48284 handleScroll : function(e){
48286 var sb = this.scroller.dom;
48287 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
48291 handleWheel : function(e){
48292 var d = e.getWheelDelta();
48293 this.scroller.dom.scrollTop -= d*22;
48294 // set this here to prevent jumpy scrolling on large tables
48295 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
48299 renderRows : function(startRow, endRow){
48300 // pull in all the crap needed to render rows
48301 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
48302 var colCount = cm.getColumnCount();
48304 if(ds.getCount() < 1){
48308 // build a map for all the columns
48310 for(var i = 0; i < colCount; i++){
48311 var name = cm.getDataIndex(i);
48313 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
48314 renderer : cm.getRenderer(i),
48315 id : cm.getColumnId(i),
48316 locked : cm.isLocked(i)
48320 startRow = startRow || 0;
48321 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
48323 // records to render
48324 var rs = ds.getRange(startRow, endRow);
48326 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
48329 // As much as I hate to duplicate code, this was branched because FireFox really hates
48330 // [].join("") on strings. The performance difference was substantial enough to
48331 // branch this function
48332 doRender : Roo.isGecko ?
48333 function(cs, rs, ds, startRow, colCount, stripe){
48334 var ts = this.templates, ct = ts.cell, rt = ts.row;
48336 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
48338 var hasListener = this.grid.hasListener('rowclass');
48340 for(var j = 0, len = rs.length; j < len; j++){
48341 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
48342 for(var i = 0; i < colCount; i++){
48344 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
48346 p.css = p.attr = "";
48347 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
48348 if(p.value == undefined || p.value === "") p.value = " ";
48349 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
48350 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
48352 var markup = ct.apply(p);
48360 if(stripe && ((rowIndex+1) % 2 == 0)){
48361 alt.push("x-grid-row-alt")
48364 alt.push( " x-grid-dirty-row");
48367 if(this.getRowClass){
48368 alt.push(this.getRowClass(r, rowIndex));
48374 rowIndex : rowIndex,
48377 this.grid.fireEvent('rowclass', this, rowcfg);
48378 alt.push(rowcfg.rowClass);
48380 rp.alt = alt.join(" ");
48381 lbuf+= rt.apply(rp);
48383 buf+= rt.apply(rp);
48385 return [lbuf, buf];
48387 function(cs, rs, ds, startRow, colCount, stripe){
48388 var ts = this.templates, ct = ts.cell, rt = ts.row;
48390 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
48391 var hasListener = this.grid.hasListener('rowclass');
48393 for(var j = 0, len = rs.length; j < len; j++){
48394 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
48395 for(var i = 0; i < colCount; i++){
48397 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
48399 p.css = p.attr = "";
48400 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
48401 if(p.value == undefined || p.value === "") p.value = " ";
48402 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
48403 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
48405 var markup = ct.apply(p);
48407 cb[cb.length] = markup;
48409 lcb[lcb.length] = markup;
48413 if(stripe && ((rowIndex+1) % 2 == 0)){
48414 alt.push( "x-grid-row-alt");
48417 alt.push(" x-grid-dirty-row");
48420 if(this.getRowClass){
48421 alt.push( this.getRowClass(r, rowIndex));
48427 rowIndex : rowIndex,
48430 this.grid.fireEvent('rowclass', this, rowcfg);
48431 alt.push(rowcfg.rowClass);
48433 rp.alt = alt.join(" ");
48434 rp.cells = lcb.join("");
48435 lbuf[lbuf.length] = rt.apply(rp);
48436 rp.cells = cb.join("");
48437 buf[buf.length] = rt.apply(rp);
48439 return [lbuf.join(""), buf.join("")];
48442 renderBody : function(){
48443 var markup = this.renderRows();
48444 var bt = this.templates.body;
48445 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
48449 * Refreshes the grid
48450 * @param {Boolean} headersToo
48452 refresh : function(headersToo){
48453 this.fireEvent("beforerefresh", this);
48454 this.grid.stopEditing();
48455 var result = this.renderBody();
48456 this.lockedBody.update(result[0]);
48457 this.mainBody.update(result[1]);
48458 if(headersToo === true){
48459 this.updateHeaders();
48460 this.updateColumns();
48461 this.updateSplitters();
48462 this.updateHeaderSortState();
48464 this.syncRowHeights();
48466 this.fireEvent("refresh", this);
48469 handleColumnMove : function(cm, oldIndex, newIndex){
48470 this.indexMap = null;
48471 var s = this.getScrollState();
48472 this.refresh(true);
48473 this.restoreScroll(s);
48474 this.afterMove(newIndex);
48477 afterMove : function(colIndex){
48478 if(this.enableMoveAnim && Roo.enableFx){
48479 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
48481 // if multisort - fix sortOrder, and reload..
48482 if (this.grid.dataSource.multiSort) {
48483 // the we can call sort again..
48484 var dm = this.grid.dataSource;
48485 var cm = this.grid.colModel;
48487 for(var i = 0; i < cm.config.length; i++ ) {
48489 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
48490 continue; // dont' bother, it's not in sort list or being set.
48493 so.push(cm.config[i].dataIndex);
48496 dm.load(dm.lastOptions);
48503 updateCell : function(dm, rowIndex, dataIndex){
48504 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
48505 if(typeof colIndex == "undefined"){ // not present in grid
48508 var cm = this.grid.colModel;
48509 var cell = this.getCell(rowIndex, colIndex);
48510 var cellText = this.getCellText(rowIndex, colIndex);
48513 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
48514 id : cm.getColumnId(colIndex),
48515 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
48517 var renderer = cm.getRenderer(colIndex);
48518 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
48519 if(typeof val == "undefined" || val === "") val = " ";
48520 cellText.innerHTML = val;
48521 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
48522 this.syncRowHeights(rowIndex, rowIndex);
48525 calcColumnWidth : function(colIndex, maxRowsToMeasure){
48527 if(this.grid.autoSizeHeaders){
48528 var h = this.getHeaderCellMeasure(colIndex);
48529 maxWidth = Math.max(maxWidth, h.scrollWidth);
48532 if(this.cm.isLocked(colIndex)){
48533 tb = this.getLockedTable();
48536 tb = this.getBodyTable();
48537 index = colIndex - this.cm.getLockedCount();
48540 var rows = tb.rows;
48541 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
48542 for(var i = 0; i < stopIndex; i++){
48543 var cell = rows[i].childNodes[index].firstChild;
48544 maxWidth = Math.max(maxWidth, cell.scrollWidth);
48547 return maxWidth + /*margin for error in IE*/ 5;
48550 * Autofit a column to its content.
48551 * @param {Number} colIndex
48552 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
48554 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
48555 if(this.cm.isHidden(colIndex)){
48556 return; // can't calc a hidden column
48559 var cid = this.cm.getColumnId(colIndex);
48560 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
48561 if(this.grid.autoSizeHeaders){
48562 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
48565 var newWidth = this.calcColumnWidth(colIndex);
48566 this.cm.setColumnWidth(colIndex,
48567 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
48568 if(!suppressEvent){
48569 this.grid.fireEvent("columnresize", colIndex, newWidth);
48574 * Autofits all columns to their content and then expands to fit any extra space in the grid
48576 autoSizeColumns : function(){
48577 var cm = this.grid.colModel;
48578 var colCount = cm.getColumnCount();
48579 for(var i = 0; i < colCount; i++){
48580 this.autoSizeColumn(i, true, true);
48582 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
48585 this.updateColumns();
48591 * Autofits all columns to the grid's width proportionate with their current size
48592 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
48594 fitColumns : function(reserveScrollSpace){
48595 var cm = this.grid.colModel;
48596 var colCount = cm.getColumnCount();
48600 for (i = 0; i < colCount; i++){
48601 if(!cm.isHidden(i) && !cm.isFixed(i)){
48602 w = cm.getColumnWidth(i);
48608 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
48609 if(reserveScrollSpace){
48612 var frac = (avail - cm.getTotalWidth())/width;
48613 while (cols.length){
48616 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
48618 this.updateColumns();
48622 onRowSelect : function(rowIndex){
48623 var row = this.getRowComposite(rowIndex);
48624 row.addClass("x-grid-row-selected");
48627 onRowDeselect : function(rowIndex){
48628 var row = this.getRowComposite(rowIndex);
48629 row.removeClass("x-grid-row-selected");
48632 onCellSelect : function(row, col){
48633 var cell = this.getCell(row, col);
48635 Roo.fly(cell).addClass("x-grid-cell-selected");
48639 onCellDeselect : function(row, col){
48640 var cell = this.getCell(row, col);
48642 Roo.fly(cell).removeClass("x-grid-cell-selected");
48646 updateHeaderSortState : function(){
48648 // sort state can be single { field: xxx, direction : yyy}
48649 // or { xxx=>ASC , yyy : DESC ..... }
48652 if (!this.ds.multiSort) {
48653 var state = this.ds.getSortState();
48657 mstate[state.field] = state.direction;
48658 // FIXME... - this is not used here.. but might be elsewhere..
48659 this.sortState = state;
48662 mstate = this.ds.sortToggle;
48664 //remove existing sort classes..
48666 var sc = this.sortClasses;
48667 var hds = this.el.select(this.headerSelector).removeClass(sc);
48669 for(var f in mstate) {
48671 var sortColumn = this.cm.findColumnIndex(f);
48673 if(sortColumn != -1){
48674 var sortDir = mstate[f];
48675 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
48684 handleHeaderClick : function(g, index){
48685 if(this.headersDisabled){
48688 var dm = g.dataSource, cm = g.colModel;
48689 if(!cm.isSortable(index)){
48694 if (dm.multiSort) {
48695 // update the sortOrder
48697 for(var i = 0; i < cm.config.length; i++ ) {
48699 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
48700 continue; // dont' bother, it's not in sort list or being set.
48703 so.push(cm.config[i].dataIndex);
48709 dm.sort(cm.getDataIndex(index));
48713 destroy : function(){
48715 this.colMenu.removeAll();
48716 Roo.menu.MenuMgr.unregister(this.colMenu);
48717 this.colMenu.getEl().remove();
48718 delete this.colMenu;
48721 this.hmenu.removeAll();
48722 Roo.menu.MenuMgr.unregister(this.hmenu);
48723 this.hmenu.getEl().remove();
48726 if(this.grid.enableColumnMove){
48727 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48729 for(var dd in dds){
48730 if(!dds[dd].config.isTarget && dds[dd].dragElId){
48731 var elid = dds[dd].dragElId;
48733 Roo.get(elid).remove();
48734 } else if(dds[dd].config.isTarget){
48735 dds[dd].proxyTop.remove();
48736 dds[dd].proxyBottom.remove();
48739 if(Roo.dd.DDM.locationCache[dd]){
48740 delete Roo.dd.DDM.locationCache[dd];
48743 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48746 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
48747 this.bind(null, null);
48748 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
48751 handleLockChange : function(){
48752 this.refresh(true);
48755 onDenyColumnLock : function(){
48759 onDenyColumnHide : function(){
48763 handleHdMenuClick : function(item){
48764 var index = this.hdCtxIndex;
48765 var cm = this.cm, ds = this.ds;
48768 ds.sort(cm.getDataIndex(index), "ASC");
48771 ds.sort(cm.getDataIndex(index), "DESC");
48774 var lc = cm.getLockedCount();
48775 if(cm.getColumnCount(true) <= lc+1){
48776 this.onDenyColumnLock();
48780 cm.setLocked(index, true, true);
48781 cm.moveColumn(index, lc);
48782 this.grid.fireEvent("columnmove", index, lc);
48784 cm.setLocked(index, true);
48788 var lc = cm.getLockedCount();
48789 if((lc-1) != index){
48790 cm.setLocked(index, false, true);
48791 cm.moveColumn(index, lc-1);
48792 this.grid.fireEvent("columnmove", index, lc-1);
48794 cm.setLocked(index, false);
48798 index = cm.getIndexById(item.id.substr(4));
48800 if(item.checked && cm.getColumnCount(true) <= 1){
48801 this.onDenyColumnHide();
48804 cm.setHidden(index, item.checked);
48810 beforeColMenuShow : function(){
48811 var cm = this.cm, colCount = cm.getColumnCount();
48812 this.colMenu.removeAll();
48813 for(var i = 0; i < colCount; i++){
48814 this.colMenu.add(new Roo.menu.CheckItem({
48815 id: "col-"+cm.getColumnId(i),
48816 text: cm.getColumnHeader(i),
48817 checked: !cm.isHidden(i),
48823 handleHdCtx : function(g, index, e){
48825 var hd = this.getHeaderCell(index);
48826 this.hdCtxIndex = index;
48827 var ms = this.hmenu.items, cm = this.cm;
48828 ms.get("asc").setDisabled(!cm.isSortable(index));
48829 ms.get("desc").setDisabled(!cm.isSortable(index));
48830 if(this.grid.enableColLock !== false){
48831 ms.get("lock").setDisabled(cm.isLocked(index));
48832 ms.get("unlock").setDisabled(!cm.isLocked(index));
48834 this.hmenu.show(hd, "tl-bl");
48837 handleHdOver : function(e){
48838 var hd = this.findHeaderCell(e.getTarget());
48839 if(hd && !this.headersDisabled){
48840 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
48841 this.fly(hd).addClass("x-grid-hd-over");
48846 handleHdOut : function(e){
48847 var hd = this.findHeaderCell(e.getTarget());
48849 this.fly(hd).removeClass("x-grid-hd-over");
48853 handleSplitDblClick : function(e, t){
48854 var i = this.getCellIndex(t);
48855 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
48856 this.autoSizeColumn(i, true);
48861 render : function(){
48864 var colCount = cm.getColumnCount();
48866 if(this.grid.monitorWindowResize === true){
48867 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48869 var header = this.renderHeaders();
48870 var body = this.templates.body.apply({rows:""});
48871 var html = this.templates.master.apply({
48874 lockedHeader: header[0],
48878 //this.updateColumns();
48880 this.grid.getGridEl().dom.innerHTML = html;
48882 this.initElements();
48884 // a kludge to fix the random scolling effect in webkit
48885 this.el.on("scroll", function() {
48886 this.el.dom.scrollTop=0; // hopefully not recursive..
48889 this.scroller.on("scroll", this.handleScroll, this);
48890 this.lockedBody.on("mousewheel", this.handleWheel, this);
48891 this.mainBody.on("mousewheel", this.handleWheel, this);
48893 this.mainHd.on("mouseover", this.handleHdOver, this);
48894 this.mainHd.on("mouseout", this.handleHdOut, this);
48895 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
48896 {delegate: "."+this.splitClass});
48898 this.lockedHd.on("mouseover", this.handleHdOver, this);
48899 this.lockedHd.on("mouseout", this.handleHdOut, this);
48900 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
48901 {delegate: "."+this.splitClass});
48903 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
48904 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48907 this.updateSplitters();
48909 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
48910 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48911 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48914 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
48915 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
48917 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
48918 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
48920 if(this.grid.enableColLock !== false){
48921 this.hmenu.add('-',
48922 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
48923 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
48926 if(this.grid.enableColumnHide !== false){
48928 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
48929 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
48930 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
48932 this.hmenu.add('-',
48933 {id:"columns", text: this.columnsText, menu: this.colMenu}
48936 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
48938 this.grid.on("headercontextmenu", this.handleHdCtx, this);
48941 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
48942 this.dd = new Roo.grid.GridDragZone(this.grid, {
48943 ddGroup : this.grid.ddGroup || 'GridDD'
48948 for(var i = 0; i < colCount; i++){
48949 if(cm.isHidden(i)){
48950 this.hideColumn(i);
48952 if(cm.config[i].align){
48953 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
48954 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
48958 this.updateHeaderSortState();
48960 this.beforeInitialResize();
48963 // two part rendering gives faster view to the user
48964 this.renderPhase2.defer(1, this);
48967 renderPhase2 : function(){
48968 // render the rows now
48970 if(this.grid.autoSizeColumns){
48971 this.autoSizeColumns();
48975 beforeInitialResize : function(){
48979 onColumnSplitterMoved : function(i, w){
48980 this.userResized = true;
48981 var cm = this.grid.colModel;
48982 cm.setColumnWidth(i, w, true);
48983 var cid = cm.getColumnId(i);
48984 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48985 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48986 this.updateSplitters();
48988 this.grid.fireEvent("columnresize", i, w);
48991 syncRowHeights : function(startIndex, endIndex){
48992 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
48993 startIndex = startIndex || 0;
48994 var mrows = this.getBodyTable().rows;
48995 var lrows = this.getLockedTable().rows;
48996 var len = mrows.length-1;
48997 endIndex = Math.min(endIndex || len, len);
48998 for(var i = startIndex; i <= endIndex; i++){
48999 var m = mrows[i], l = lrows[i];
49000 var h = Math.max(m.offsetHeight, l.offsetHeight);
49001 m.style.height = l.style.height = h + "px";
49006 layout : function(initialRender, is2ndPass){
49008 var auto = g.autoHeight;
49009 var scrollOffset = 16;
49010 var c = g.getGridEl(), cm = this.cm,
49011 expandCol = g.autoExpandColumn,
49013 //c.beginMeasure();
49015 if(!c.dom.offsetWidth){ // display:none?
49017 this.lockedWrap.show();
49018 this.mainWrap.show();
49023 var hasLock = this.cm.isLocked(0);
49025 var tbh = this.headerPanel.getHeight();
49026 var bbh = this.footerPanel.getHeight();
49029 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
49030 var newHeight = ch + c.getBorderWidth("tb");
49032 newHeight = Math.min(g.maxHeight, newHeight);
49034 c.setHeight(newHeight);
49038 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
49041 var s = this.scroller;
49043 var csize = c.getSize(true);
49045 this.el.setSize(csize.width, csize.height);
49047 this.headerPanel.setWidth(csize.width);
49048 this.footerPanel.setWidth(csize.width);
49050 var hdHeight = this.mainHd.getHeight();
49051 var vw = csize.width;
49052 var vh = csize.height - (tbh + bbh);
49056 var bt = this.getBodyTable();
49057 var ltWidth = hasLock ?
49058 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
49060 var scrollHeight = bt.offsetHeight;
49061 var scrollWidth = ltWidth + bt.offsetWidth;
49062 var vscroll = false, hscroll = false;
49064 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
49066 var lw = this.lockedWrap, mw = this.mainWrap;
49067 var lb = this.lockedBody, mb = this.mainBody;
49069 setTimeout(function(){
49070 var t = s.dom.offsetTop;
49071 var w = s.dom.clientWidth,
49072 h = s.dom.clientHeight;
49075 lw.setSize(ltWidth, h);
49077 mw.setLeftTop(ltWidth, t);
49078 mw.setSize(w-ltWidth, h);
49080 lb.setHeight(h-hdHeight);
49081 mb.setHeight(h-hdHeight);
49083 if(is2ndPass !== true && !gv.userResized && expandCol){
49084 // high speed resize without full column calculation
49086 var ci = cm.getIndexById(expandCol);
49088 ci = cm.findColumnIndex(expandCol);
49090 ci = Math.max(0, ci); // make sure it's got at least the first col.
49091 var expandId = cm.getColumnId(ci);
49092 var tw = cm.getTotalWidth(false);
49093 var currentWidth = cm.getColumnWidth(ci);
49094 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
49095 if(currentWidth != cw){
49096 cm.setColumnWidth(ci, cw, true);
49097 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
49098 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
49099 gv.updateSplitters();
49100 gv.layout(false, true);
49112 onWindowResize : function(){
49113 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
49119 appendFooter : function(parentEl){
49123 sortAscText : "Sort Ascending",
49124 sortDescText : "Sort Descending",
49125 lockText : "Lock Column",
49126 unlockText : "Unlock Column",
49127 columnsText : "Columns"
49131 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
49132 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
49133 this.proxy.el.addClass('x-grid3-col-dd');
49136 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
49137 handleMouseDown : function(e){
49141 callHandleMouseDown : function(e){
49142 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
49147 * Ext JS Library 1.1.1
49148 * Copyright(c) 2006-2007, Ext JS, LLC.
49150 * Originally Released Under LGPL - original licence link has changed is not relivant.
49153 * <script type="text/javascript">
49157 // This is a support class used internally by the Grid components
49158 Roo.grid.SplitDragZone = function(grid, hd, hd2){
49160 this.view = grid.getView();
49161 this.proxy = this.view.resizeProxy;
49162 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
49163 "gridSplitters" + this.grid.getGridEl().id, {
49164 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
49166 this.setHandleElId(Roo.id(hd));
49167 this.setOuterHandleElId(Roo.id(hd2));
49168 this.scroll = false;
49170 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
49171 fly: Roo.Element.fly,
49173 b4StartDrag : function(x, y){
49174 this.view.headersDisabled = true;
49175 this.proxy.setHeight(this.view.mainWrap.getHeight());
49176 var w = this.cm.getColumnWidth(this.cellIndex);
49177 var minw = Math.max(w-this.grid.minColumnWidth, 0);
49178 this.resetConstraints();
49179 this.setXConstraint(minw, 1000);
49180 this.setYConstraint(0, 0);
49181 this.minX = x - minw;
49182 this.maxX = x + 1000;
49184 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
49188 handleMouseDown : function(e){
49189 ev = Roo.EventObject.setEvent(e);
49190 var t = this.fly(ev.getTarget());
49191 if(t.hasClass("x-grid-split")){
49192 this.cellIndex = this.view.getCellIndex(t.dom);
49193 this.split = t.dom;
49194 this.cm = this.grid.colModel;
49195 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
49196 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
49201 endDrag : function(e){
49202 this.view.headersDisabled = false;
49203 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
49204 var diff = endX - this.startPos;
49205 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
49208 autoOffset : function(){
49209 this.setDelta(0,0);
49213 * Ext JS Library 1.1.1
49214 * Copyright(c) 2006-2007, Ext JS, LLC.
49216 * Originally Released Under LGPL - original licence link has changed is not relivant.
49219 * <script type="text/javascript">
49223 // This is a support class used internally by the Grid components
49224 Roo.grid.GridDragZone = function(grid, config){
49225 this.view = grid.getView();
49226 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
49227 if(this.view.lockedBody){
49228 this.setHandleElId(Roo.id(this.view.mainBody.dom));
49229 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
49231 this.scroll = false;
49233 this.ddel = document.createElement('div');
49234 this.ddel.className = 'x-grid-dd-wrap';
49237 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
49238 ddGroup : "GridDD",
49240 getDragData : function(e){
49241 var t = Roo.lib.Event.getTarget(e);
49242 var rowIndex = this.view.findRowIndex(t);
49243 if(rowIndex !== false){
49244 var sm = this.grid.selModel;
49245 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
49246 // sm.mouseDown(e, t);
49248 if (e.hasModifier()){
49249 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
49251 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
49256 onInitDrag : function(e){
49257 var data = this.dragData;
49258 this.ddel.innerHTML = this.grid.getDragDropText();
49259 this.proxy.update(this.ddel);
49260 // fire start drag?
49263 afterRepair : function(){
49264 this.dragging = false;
49267 getRepairXY : function(e, data){
49271 onEndDrag : function(data, e){
49275 onValidDrop : function(dd, e, id){
49280 beforeInvalidDrop : function(e, id){
49285 * Ext JS Library 1.1.1
49286 * Copyright(c) 2006-2007, Ext JS, LLC.
49288 * Originally Released Under LGPL - original licence link has changed is not relivant.
49291 * <script type="text/javascript">
49296 * @class Roo.grid.ColumnModel
49297 * @extends Roo.util.Observable
49298 * This is the default implementation of a ColumnModel used by the Grid. It defines
49299 * the columns in the grid.
49302 var colModel = new Roo.grid.ColumnModel([
49303 {header: "Ticker", width: 60, sortable: true, locked: true},
49304 {header: "Company Name", width: 150, sortable: true},
49305 {header: "Market Cap.", width: 100, sortable: true},
49306 {header: "$ Sales", width: 100, sortable: true, renderer: money},
49307 {header: "Employees", width: 100, sortable: true, resizable: false}
49312 * The config options listed for this class are options which may appear in each
49313 * individual column definition.
49314 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
49316 * @param {Object} config An Array of column config objects. See this class's
49317 * config objects for details.
49319 Roo.grid.ColumnModel = function(config){
49321 * The config passed into the constructor
49323 this.config = config;
49326 // if no id, create one
49327 // if the column does not have a dataIndex mapping,
49328 // map it to the order it is in the config
49329 for(var i = 0, len = config.length; i < len; i++){
49331 if(typeof c.dataIndex == "undefined"){
49334 if(typeof c.renderer == "string"){
49335 c.renderer = Roo.util.Format[c.renderer];
49337 if(typeof c.id == "undefined"){
49340 if(c.editor && c.editor.xtype){
49341 c.editor = Roo.factory(c.editor, Roo.grid);
49343 if(c.editor && c.editor.isFormField){
49344 c.editor = new Roo.grid.GridEditor(c.editor);
49346 this.lookup[c.id] = c;
49350 * The width of columns which have no width specified (defaults to 100)
49353 this.defaultWidth = 100;
49356 * Default sortable of columns which have no sortable specified (defaults to false)
49359 this.defaultSortable = false;
49363 * @event widthchange
49364 * Fires when the width of a column changes.
49365 * @param {ColumnModel} this
49366 * @param {Number} columnIndex The column index
49367 * @param {Number} newWidth The new width
49369 "widthchange": true,
49371 * @event headerchange
49372 * Fires when the text of a header changes.
49373 * @param {ColumnModel} this
49374 * @param {Number} columnIndex The column index
49375 * @param {Number} newText The new header text
49377 "headerchange": true,
49379 * @event hiddenchange
49380 * Fires when a column is hidden or "unhidden".
49381 * @param {ColumnModel} this
49382 * @param {Number} columnIndex The column index
49383 * @param {Boolean} hidden true if hidden, false otherwise
49385 "hiddenchange": true,
49387 * @event columnmoved
49388 * Fires when a column is moved.
49389 * @param {ColumnModel} this
49390 * @param {Number} oldIndex
49391 * @param {Number} newIndex
49393 "columnmoved" : true,
49395 * @event columlockchange
49396 * Fires when a column's locked state is changed
49397 * @param {ColumnModel} this
49398 * @param {Number} colIndex
49399 * @param {Boolean} locked true if locked
49401 "columnlockchange" : true
49403 Roo.grid.ColumnModel.superclass.constructor.call(this);
49405 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
49407 * @cfg {String} header The header text to display in the Grid view.
49410 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
49411 * {@link Roo.data.Record} definition from which to draw the column's value. If not
49412 * specified, the column's index is used as an index into the Record's data Array.
49415 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
49416 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
49419 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
49420 * Defaults to the value of the {@link #defaultSortable} property.
49421 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
49424 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
49427 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
49430 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
49433 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
49436 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
49437 * given the cell's data value. See {@link #setRenderer}. If not specified, the
49438 * default renderer uses the raw data value.
49441 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
49444 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
49448 * Returns the id of the column at the specified index.
49449 * @param {Number} index The column index
49450 * @return {String} the id
49452 getColumnId : function(index){
49453 return this.config[index].id;
49457 * Returns the column for a specified id.
49458 * @param {String} id The column id
49459 * @return {Object} the column
49461 getColumnById : function(id){
49462 return this.lookup[id];
49467 * Returns the column for a specified dataIndex.
49468 * @param {String} dataIndex The column dataIndex
49469 * @return {Object|Boolean} the column or false if not found
49471 getColumnByDataIndex: function(dataIndex){
49472 var index = this.findColumnIndex(dataIndex);
49473 return index > -1 ? this.config[index] : false;
49477 * Returns the index for a specified column id.
49478 * @param {String} id The column id
49479 * @return {Number} the index, or -1 if not found
49481 getIndexById : function(id){
49482 for(var i = 0, len = this.config.length; i < len; i++){
49483 if(this.config[i].id == id){
49491 * Returns the index for a specified column dataIndex.
49492 * @param {String} dataIndex The column dataIndex
49493 * @return {Number} the index, or -1 if not found
49496 findColumnIndex : function(dataIndex){
49497 for(var i = 0, len = this.config.length; i < len; i++){
49498 if(this.config[i].dataIndex == dataIndex){
49506 moveColumn : function(oldIndex, newIndex){
49507 var c = this.config[oldIndex];
49508 this.config.splice(oldIndex, 1);
49509 this.config.splice(newIndex, 0, c);
49510 this.dataMap = null;
49511 this.fireEvent("columnmoved", this, oldIndex, newIndex);
49514 isLocked : function(colIndex){
49515 return this.config[colIndex].locked === true;
49518 setLocked : function(colIndex, value, suppressEvent){
49519 if(this.isLocked(colIndex) == value){
49522 this.config[colIndex].locked = value;
49523 if(!suppressEvent){
49524 this.fireEvent("columnlockchange", this, colIndex, value);
49528 getTotalLockedWidth : function(){
49529 var totalWidth = 0;
49530 for(var i = 0; i < this.config.length; i++){
49531 if(this.isLocked(i) && !this.isHidden(i)){
49532 this.totalWidth += this.getColumnWidth(i);
49538 getLockedCount : function(){
49539 for(var i = 0, len = this.config.length; i < len; i++){
49540 if(!this.isLocked(i)){
49547 * Returns the number of columns.
49550 getColumnCount : function(visibleOnly){
49551 if(visibleOnly === true){
49553 for(var i = 0, len = this.config.length; i < len; i++){
49554 if(!this.isHidden(i)){
49560 return this.config.length;
49564 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
49565 * @param {Function} fn
49566 * @param {Object} scope (optional)
49567 * @return {Array} result
49569 getColumnsBy : function(fn, scope){
49571 for(var i = 0, len = this.config.length; i < len; i++){
49572 var c = this.config[i];
49573 if(fn.call(scope||this, c, i) === true){
49581 * Returns true if the specified column is sortable.
49582 * @param {Number} col The column index
49583 * @return {Boolean}
49585 isSortable : function(col){
49586 if(typeof this.config[col].sortable == "undefined"){
49587 return this.defaultSortable;
49589 return this.config[col].sortable;
49593 * Returns the rendering (formatting) function defined for the column.
49594 * @param {Number} col The column index.
49595 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
49597 getRenderer : function(col){
49598 if(!this.config[col].renderer){
49599 return Roo.grid.ColumnModel.defaultRenderer;
49601 return this.config[col].renderer;
49605 * Sets the rendering (formatting) function for a column.
49606 * @param {Number} col The column index
49607 * @param {Function} fn The function to use to process the cell's raw data
49608 * to return HTML markup for the grid view. The render function is called with
49609 * the following parameters:<ul>
49610 * <li>Data value.</li>
49611 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
49612 * <li>css A CSS style string to apply to the table cell.</li>
49613 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
49614 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
49615 * <li>Row index</li>
49616 * <li>Column index</li>
49617 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
49619 setRenderer : function(col, fn){
49620 this.config[col].renderer = fn;
49624 * Returns the width for the specified column.
49625 * @param {Number} col The column index
49628 getColumnWidth : function(col){
49629 return this.config[col].width * 1 || this.defaultWidth;
49633 * Sets the width for a column.
49634 * @param {Number} col The column index
49635 * @param {Number} width The new width
49637 setColumnWidth : function(col, width, suppressEvent){
49638 this.config[col].width = width;
49639 this.totalWidth = null;
49640 if(!suppressEvent){
49641 this.fireEvent("widthchange", this, col, width);
49646 * Returns the total width of all columns.
49647 * @param {Boolean} includeHidden True to include hidden column widths
49650 getTotalWidth : function(includeHidden){
49651 if(!this.totalWidth){
49652 this.totalWidth = 0;
49653 for(var i = 0, len = this.config.length; i < len; i++){
49654 if(includeHidden || !this.isHidden(i)){
49655 this.totalWidth += this.getColumnWidth(i);
49659 return this.totalWidth;
49663 * Returns the header for the specified column.
49664 * @param {Number} col The column index
49667 getColumnHeader : function(col){
49668 return this.config[col].header;
49672 * Sets the header for a column.
49673 * @param {Number} col The column index
49674 * @param {String} header The new header
49676 setColumnHeader : function(col, header){
49677 this.config[col].header = header;
49678 this.fireEvent("headerchange", this, col, header);
49682 * Returns the tooltip for the specified column.
49683 * @param {Number} col The column index
49686 getColumnTooltip : function(col){
49687 return this.config[col].tooltip;
49690 * Sets the tooltip for a column.
49691 * @param {Number} col The column index
49692 * @param {String} tooltip The new tooltip
49694 setColumnTooltip : function(col, tooltip){
49695 this.config[col].tooltip = tooltip;
49699 * Returns the dataIndex for the specified column.
49700 * @param {Number} col The column index
49703 getDataIndex : function(col){
49704 return this.config[col].dataIndex;
49708 * Sets the dataIndex for a column.
49709 * @param {Number} col The column index
49710 * @param {Number} dataIndex The new dataIndex
49712 setDataIndex : function(col, dataIndex){
49713 this.config[col].dataIndex = dataIndex;
49719 * Returns true if the cell is editable.
49720 * @param {Number} colIndex The column index
49721 * @param {Number} rowIndex The row index
49722 * @return {Boolean}
49724 isCellEditable : function(colIndex, rowIndex){
49725 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
49729 * Returns the editor defined for the cell/column.
49730 * return false or null to disable editing.
49731 * @param {Number} colIndex The column index
49732 * @param {Number} rowIndex The row index
49735 getCellEditor : function(colIndex, rowIndex){
49736 return this.config[colIndex].editor;
49740 * Sets if a column is editable.
49741 * @param {Number} col The column index
49742 * @param {Boolean} editable True if the column is editable
49744 setEditable : function(col, editable){
49745 this.config[col].editable = editable;
49750 * Returns true if the column is hidden.
49751 * @param {Number} colIndex The column index
49752 * @return {Boolean}
49754 isHidden : function(colIndex){
49755 return this.config[colIndex].hidden;
49760 * Returns true if the column width cannot be changed
49762 isFixed : function(colIndex){
49763 return this.config[colIndex].fixed;
49767 * Returns true if the column can be resized
49768 * @return {Boolean}
49770 isResizable : function(colIndex){
49771 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
49774 * Sets if a column is hidden.
49775 * @param {Number} colIndex The column index
49776 * @param {Boolean} hidden True if the column is hidden
49778 setHidden : function(colIndex, hidden){
49779 this.config[colIndex].hidden = hidden;
49780 this.totalWidth = null;
49781 this.fireEvent("hiddenchange", this, colIndex, hidden);
49785 * Sets the editor for a column.
49786 * @param {Number} col The column index
49787 * @param {Object} editor The editor object
49789 setEditor : function(col, editor){
49790 this.config[col].editor = editor;
49794 Roo.grid.ColumnModel.defaultRenderer = function(value){
49795 if(typeof value == "string" && value.length < 1){
49801 // Alias for backwards compatibility
49802 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
49805 * Ext JS Library 1.1.1
49806 * Copyright(c) 2006-2007, Ext JS, LLC.
49808 * Originally Released Under LGPL - original licence link has changed is not relivant.
49811 * <script type="text/javascript">
49815 * @class Roo.grid.AbstractSelectionModel
49816 * @extends Roo.util.Observable
49817 * Abstract base class for grid SelectionModels. It provides the interface that should be
49818 * implemented by descendant classes. This class should not be directly instantiated.
49821 Roo.grid.AbstractSelectionModel = function(){
49822 this.locked = false;
49823 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
49826 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
49827 /** @ignore Called by the grid automatically. Do not call directly. */
49828 init : function(grid){
49834 * Locks the selections.
49837 this.locked = true;
49841 * Unlocks the selections.
49843 unlock : function(){
49844 this.locked = false;
49848 * Returns true if the selections are locked.
49849 * @return {Boolean}
49851 isLocked : function(){
49852 return this.locked;
49856 * Ext JS Library 1.1.1
49857 * Copyright(c) 2006-2007, Ext JS, LLC.
49859 * Originally Released Under LGPL - original licence link has changed is not relivant.
49862 * <script type="text/javascript">
49865 * @extends Roo.grid.AbstractSelectionModel
49866 * @class Roo.grid.RowSelectionModel
49867 * The default SelectionModel used by {@link Roo.grid.Grid}.
49868 * It supports multiple selections and keyboard selection/navigation.
49870 * @param {Object} config
49872 Roo.grid.RowSelectionModel = function(config){
49873 Roo.apply(this, config);
49874 this.selections = new Roo.util.MixedCollection(false, function(o){
49879 this.lastActive = false;
49883 * @event selectionchange
49884 * Fires when the selection changes
49885 * @param {SelectionModel} this
49887 "selectionchange" : true,
49889 * @event afterselectionchange
49890 * Fires after the selection changes (eg. by key press or clicking)
49891 * @param {SelectionModel} this
49893 "afterselectionchange" : true,
49895 * @event beforerowselect
49896 * Fires when a row is selected being selected, return false to cancel.
49897 * @param {SelectionModel} this
49898 * @param {Number} rowIndex The selected index
49899 * @param {Boolean} keepExisting False if other selections will be cleared
49901 "beforerowselect" : true,
49904 * Fires when a row is selected.
49905 * @param {SelectionModel} this
49906 * @param {Number} rowIndex The selected index
49907 * @param {Roo.data.Record} r The record
49909 "rowselect" : true,
49911 * @event rowdeselect
49912 * Fires when a row is deselected.
49913 * @param {SelectionModel} this
49914 * @param {Number} rowIndex The selected index
49916 "rowdeselect" : true
49918 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
49919 this.locked = false;
49922 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
49924 * @cfg {Boolean} singleSelect
49925 * True to allow selection of only one row at a time (defaults to false)
49927 singleSelect : false,
49930 initEvents : function(){
49932 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
49933 this.grid.on("mousedown", this.handleMouseDown, this);
49934 }else{ // allow click to work like normal
49935 this.grid.on("rowclick", this.handleDragableRowClick, this);
49938 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
49939 "up" : function(e){
49941 this.selectPrevious(e.shiftKey);
49942 }else if(this.last !== false && this.lastActive !== false){
49943 var last = this.last;
49944 this.selectRange(this.last, this.lastActive-1);
49945 this.grid.getView().focusRow(this.lastActive);
49946 if(last !== false){
49950 this.selectFirstRow();
49952 this.fireEvent("afterselectionchange", this);
49954 "down" : function(e){
49956 this.selectNext(e.shiftKey);
49957 }else if(this.last !== false && this.lastActive !== false){
49958 var last = this.last;
49959 this.selectRange(this.last, this.lastActive+1);
49960 this.grid.getView().focusRow(this.lastActive);
49961 if(last !== false){
49965 this.selectFirstRow();
49967 this.fireEvent("afterselectionchange", this);
49972 var view = this.grid.view;
49973 view.on("refresh", this.onRefresh, this);
49974 view.on("rowupdated", this.onRowUpdated, this);
49975 view.on("rowremoved", this.onRemove, this);
49979 onRefresh : function(){
49980 var ds = this.grid.dataSource, i, v = this.grid.view;
49981 var s = this.selections;
49982 s.each(function(r){
49983 if((i = ds.indexOfId(r.id)) != -1){
49992 onRemove : function(v, index, r){
49993 this.selections.remove(r);
49997 onRowUpdated : function(v, index, r){
49998 if(this.isSelected(r)){
49999 v.onRowSelect(index);
50005 * @param {Array} records The records to select
50006 * @param {Boolean} keepExisting (optional) True to keep existing selections
50008 selectRecords : function(records, keepExisting){
50010 this.clearSelections();
50012 var ds = this.grid.dataSource;
50013 for(var i = 0, len = records.length; i < len; i++){
50014 this.selectRow(ds.indexOf(records[i]), true);
50019 * Gets the number of selected rows.
50022 getCount : function(){
50023 return this.selections.length;
50027 * Selects the first row in the grid.
50029 selectFirstRow : function(){
50034 * Select the last row.
50035 * @param {Boolean} keepExisting (optional) True to keep existing selections
50037 selectLastRow : function(keepExisting){
50038 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
50042 * Selects the row immediately following the last selected row.
50043 * @param {Boolean} keepExisting (optional) True to keep existing selections
50045 selectNext : function(keepExisting){
50046 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
50047 this.selectRow(this.last+1, keepExisting);
50048 this.grid.getView().focusRow(this.last);
50053 * Selects the row that precedes the last selected row.
50054 * @param {Boolean} keepExisting (optional) True to keep existing selections
50056 selectPrevious : function(keepExisting){
50058 this.selectRow(this.last-1, keepExisting);
50059 this.grid.getView().focusRow(this.last);
50064 * Returns the selected records
50065 * @return {Array} Array of selected records
50067 getSelections : function(){
50068 return [].concat(this.selections.items);
50072 * Returns the first selected record.
50075 getSelected : function(){
50076 return this.selections.itemAt(0);
50081 * Clears all selections.
50083 clearSelections : function(fast){
50084 if(this.locked) return;
50086 var ds = this.grid.dataSource;
50087 var s = this.selections;
50088 s.each(function(r){
50089 this.deselectRow(ds.indexOfId(r.id));
50093 this.selections.clear();
50100 * Selects all rows.
50102 selectAll : function(){
50103 if(this.locked) return;
50104 this.selections.clear();
50105 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
50106 this.selectRow(i, true);
50111 * Returns True if there is a selection.
50112 * @return {Boolean}
50114 hasSelection : function(){
50115 return this.selections.length > 0;
50119 * Returns True if the specified row is selected.
50120 * @param {Number/Record} record The record or index of the record to check
50121 * @return {Boolean}
50123 isSelected : function(index){
50124 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
50125 return (r && this.selections.key(r.id) ? true : false);
50129 * Returns True if the specified record id is selected.
50130 * @param {String} id The id of record to check
50131 * @return {Boolean}
50133 isIdSelected : function(id){
50134 return (this.selections.key(id) ? true : false);
50138 handleMouseDown : function(e, t){
50139 var view = this.grid.getView(), rowIndex;
50140 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
50143 if(e.shiftKey && this.last !== false){
50144 var last = this.last;
50145 this.selectRange(last, rowIndex, e.ctrlKey);
50146 this.last = last; // reset the last
50147 view.focusRow(rowIndex);
50149 var isSelected = this.isSelected(rowIndex);
50150 if(e.button !== 0 && isSelected){
50151 view.focusRow(rowIndex);
50152 }else if(e.ctrlKey && isSelected){
50153 this.deselectRow(rowIndex);
50154 }else if(!isSelected){
50155 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
50156 view.focusRow(rowIndex);
50159 this.fireEvent("afterselectionchange", this);
50162 handleDragableRowClick : function(grid, rowIndex, e)
50164 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
50165 this.selectRow(rowIndex, false);
50166 grid.view.focusRow(rowIndex);
50167 this.fireEvent("afterselectionchange", this);
50172 * Selects multiple rows.
50173 * @param {Array} rows Array of the indexes of the row to select
50174 * @param {Boolean} keepExisting (optional) True to keep existing selections
50176 selectRows : function(rows, keepExisting){
50178 this.clearSelections();
50180 for(var i = 0, len = rows.length; i < len; i++){
50181 this.selectRow(rows[i], true);
50186 * Selects a range of rows. All rows in between startRow and endRow are also selected.
50187 * @param {Number} startRow The index of the first row in the range
50188 * @param {Number} endRow The index of the last row in the range
50189 * @param {Boolean} keepExisting (optional) True to retain existing selections
50191 selectRange : function(startRow, endRow, keepExisting){
50192 if(this.locked) return;
50194 this.clearSelections();
50196 if(startRow <= endRow){
50197 for(var i = startRow; i <= endRow; i++){
50198 this.selectRow(i, true);
50201 for(var i = startRow; i >= endRow; i--){
50202 this.selectRow(i, true);
50208 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
50209 * @param {Number} startRow The index of the first row in the range
50210 * @param {Number} endRow The index of the last row in the range
50212 deselectRange : function(startRow, endRow, preventViewNotify){
50213 if(this.locked) return;
50214 for(var i = startRow; i <= endRow; i++){
50215 this.deselectRow(i, preventViewNotify);
50221 * @param {Number} row The index of the row to select
50222 * @param {Boolean} keepExisting (optional) True to keep existing selections
50224 selectRow : function(index, keepExisting, preventViewNotify){
50225 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
50226 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
50227 if(!keepExisting || this.singleSelect){
50228 this.clearSelections();
50230 var r = this.grid.dataSource.getAt(index);
50231 this.selections.add(r);
50232 this.last = this.lastActive = index;
50233 if(!preventViewNotify){
50234 this.grid.getView().onRowSelect(index);
50236 this.fireEvent("rowselect", this, index, r);
50237 this.fireEvent("selectionchange", this);
50243 * @param {Number} row The index of the row to deselect
50245 deselectRow : function(index, preventViewNotify){
50246 if(this.locked) return;
50247 if(this.last == index){
50250 if(this.lastActive == index){
50251 this.lastActive = false;
50253 var r = this.grid.dataSource.getAt(index);
50254 this.selections.remove(r);
50255 if(!preventViewNotify){
50256 this.grid.getView().onRowDeselect(index);
50258 this.fireEvent("rowdeselect", this, index);
50259 this.fireEvent("selectionchange", this);
50263 restoreLast : function(){
50265 this.last = this._last;
50270 acceptsNav : function(row, col, cm){
50271 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50275 onEditorKey : function(field, e){
50276 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50281 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50283 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50285 }else if(k == e.ENTER && !e.ctrlKey){
50289 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
50291 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
50293 }else if(k == e.ESC){
50297 g.startEditing(newCell[0], newCell[1]);
50302 * Ext JS Library 1.1.1
50303 * Copyright(c) 2006-2007, Ext JS, LLC.
50305 * Originally Released Under LGPL - original licence link has changed is not relivant.
50308 * <script type="text/javascript">
50311 * @class Roo.grid.CellSelectionModel
50312 * @extends Roo.grid.AbstractSelectionModel
50313 * This class provides the basic implementation for cell selection in a grid.
50315 * @param {Object} config The object containing the configuration of this model.
50317 Roo.grid.CellSelectionModel = function(config){
50318 Roo.apply(this, config);
50320 this.selection = null;
50324 * @event beforerowselect
50325 * Fires before a cell is selected.
50326 * @param {SelectionModel} this
50327 * @param {Number} rowIndex The selected row index
50328 * @param {Number} colIndex The selected cell index
50330 "beforecellselect" : true,
50332 * @event cellselect
50333 * Fires when a cell is selected.
50334 * @param {SelectionModel} this
50335 * @param {Number} rowIndex The selected row index
50336 * @param {Number} colIndex The selected cell index
50338 "cellselect" : true,
50340 * @event selectionchange
50341 * Fires when the active selection changes.
50342 * @param {SelectionModel} this
50343 * @param {Object} selection null for no selection or an object (o) with two properties
50345 <li>o.record: the record object for the row the selection is in</li>
50346 <li>o.cell: An array of [rowIndex, columnIndex]</li>
50349 "selectionchange" : true
50351 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
50354 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
50357 initEvents : function(){
50358 this.grid.on("mousedown", this.handleMouseDown, this);
50359 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
50360 var view = this.grid.view;
50361 view.on("refresh", this.onViewChange, this);
50362 view.on("rowupdated", this.onRowUpdated, this);
50363 view.on("beforerowremoved", this.clearSelections, this);
50364 view.on("beforerowsinserted", this.clearSelections, this);
50365 if(this.grid.isEditor){
50366 this.grid.on("beforeedit", this.beforeEdit, this);
50371 beforeEdit : function(e){
50372 this.select(e.row, e.column, false, true, e.record);
50376 onRowUpdated : function(v, index, r){
50377 if(this.selection && this.selection.record == r){
50378 v.onCellSelect(index, this.selection.cell[1]);
50383 onViewChange : function(){
50384 this.clearSelections(true);
50388 * Returns the currently selected cell,.
50389 * @return {Array} The selected cell (row, column) or null if none selected.
50391 getSelectedCell : function(){
50392 return this.selection ? this.selection.cell : null;
50396 * Clears all selections.
50397 * @param {Boolean} true to prevent the gridview from being notified about the change.
50399 clearSelections : function(preventNotify){
50400 var s = this.selection;
50402 if(preventNotify !== true){
50403 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
50405 this.selection = null;
50406 this.fireEvent("selectionchange", this, null);
50411 * Returns true if there is a selection.
50412 * @return {Boolean}
50414 hasSelection : function(){
50415 return this.selection ? true : false;
50419 handleMouseDown : function(e, t){
50420 var v = this.grid.getView();
50421 if(this.isLocked()){
50424 var row = v.findRowIndex(t);
50425 var cell = v.findCellIndex(t);
50426 if(row !== false && cell !== false){
50427 this.select(row, cell);
50433 * @param {Number} rowIndex
50434 * @param {Number} collIndex
50436 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
50437 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
50438 this.clearSelections();
50439 r = r || this.grid.dataSource.getAt(rowIndex);
50442 cell : [rowIndex, colIndex]
50444 if(!preventViewNotify){
50445 var v = this.grid.getView();
50446 v.onCellSelect(rowIndex, colIndex);
50447 if(preventFocus !== true){
50448 v.focusCell(rowIndex, colIndex);
50451 this.fireEvent("cellselect", this, rowIndex, colIndex);
50452 this.fireEvent("selectionchange", this, this.selection);
50457 isSelectable : function(rowIndex, colIndex, cm){
50458 return !cm.isHidden(colIndex);
50462 handleKeyDown : function(e){
50463 Roo.log('Cell Sel Model handleKeyDown');
50464 if(!e.isNavKeyPress()){
50467 var g = this.grid, s = this.selection;
50470 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
50472 this.select(cell[0], cell[1]);
50477 var walk = function(row, col, step){
50478 return g.walkCells(row, col, step, sm.isSelectable, sm);
50480 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
50485 // handled by onEditorKey
50486 if (g.isEditor && g.editing) {
50490 newCell = walk(r, c-1, -1);
50492 newCell = walk(r, c+1, 1);
50496 newCell = walk(r+1, c, 1);
50499 newCell = walk(r-1, c, -1);
50502 newCell = walk(r, c+1, 1);
50505 newCell = walk(r, c-1, -1);
50508 if(g.isEditor && !g.editing){
50509 g.startEditing(r, c);
50516 this.select(newCell[0], newCell[1]);
50521 acceptsNav : function(row, col, cm){
50522 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50525 onEditorKey : function(field, e){
50527 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50528 ///Roo.log('onEditorKey' + k);
50532 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50534 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50537 }else if(k == e.ENTER && !e.ctrlKey){
50540 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50541 }else if(k == e.ESC){
50547 //Roo.log('next cell after edit');
50548 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
50553 * Ext JS Library 1.1.1
50554 * Copyright(c) 2006-2007, Ext JS, LLC.
50556 * Originally Released Under LGPL - original licence link has changed is not relivant.
50559 * <script type="text/javascript">
50563 * @class Roo.grid.EditorGrid
50564 * @extends Roo.grid.Grid
50565 * Class for creating and editable grid.
50566 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50567 * The container MUST have some type of size defined for the grid to fill. The container will be
50568 * automatically set to position relative if it isn't already.
50569 * @param {Object} dataSource The data model to bind to
50570 * @param {Object} colModel The column model with info about this grid's columns
50572 Roo.grid.EditorGrid = function(container, config){
50573 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
50574 this.getGridEl().addClass("xedit-grid");
50576 if(!this.selModel){
50577 this.selModel = new Roo.grid.CellSelectionModel();
50580 this.activeEditor = null;
50584 * @event beforeedit
50585 * Fires before cell editing is triggered. The edit event object has the following properties <br />
50586 * <ul style="padding:5px;padding-left:16px;">
50587 * <li>grid - This grid</li>
50588 * <li>record - The record being edited</li>
50589 * <li>field - The field name being edited</li>
50590 * <li>value - The value for the field being edited.</li>
50591 * <li>row - The grid row index</li>
50592 * <li>column - The grid column index</li>
50593 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50595 * @param {Object} e An edit event (see above for description)
50597 "beforeedit" : true,
50600 * Fires after a cell is edited. <br />
50601 * <ul style="padding:5px;padding-left:16px;">
50602 * <li>grid - This grid</li>
50603 * <li>record - The record being edited</li>
50604 * <li>field - The field name being edited</li>
50605 * <li>value - The value being set</li>
50606 * <li>originalValue - The original value for the field, before the edit.</li>
50607 * <li>row - The grid row index</li>
50608 * <li>column - The grid column index</li>
50610 * @param {Object} e An edit event (see above for description)
50612 "afteredit" : true,
50614 * @event validateedit
50615 * Fires after a cell is edited, but before the value is set in the record.
50616 * You can use this to modify the value being set in the field, Return false
50617 * to cancel the change. The edit event object has the following properties <br />
50618 * <ul style="padding:5px;padding-left:16px;">
50619 * <li>editor - This editor</li>
50620 * <li>grid - This grid</li>
50621 * <li>record - The record being edited</li>
50622 * <li>field - The field name being edited</li>
50623 * <li>value - The value being set</li>
50624 * <li>originalValue - The original value for the field, before the edit.</li>
50625 * <li>row - The grid row index</li>
50626 * <li>column - The grid column index</li>
50627 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50629 * @param {Object} e An edit event (see above for description)
50631 "validateedit" : true
50633 this.on("bodyscroll", this.stopEditing, this);
50634 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
50637 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
50639 * @cfg {Number} clicksToEdit
50640 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
50647 trackMouseOver: false, // causes very odd FF errors
50649 onCellDblClick : function(g, row, col){
50650 this.startEditing(row, col);
50653 onEditComplete : function(ed, value, startValue){
50654 this.editing = false;
50655 this.activeEditor = null;
50656 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
50658 var field = this.colModel.getDataIndex(ed.col);
50663 originalValue: startValue,
50670 if(String(value) !== String(startValue)){
50672 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
50673 r.set(field, e.value);
50674 // if we are dealing with a combo box..
50675 // then we also set the 'name' colum to be the displayField
50676 if (ed.field.displayField && ed.field.name) {
50677 r.set(ed.field.name, ed.field.el.dom.value);
50680 delete e.cancel; //?? why!!!
50681 this.fireEvent("afteredit", e);
50684 this.fireEvent("afteredit", e); // always fire it!
50686 this.view.focusCell(ed.row, ed.col);
50690 * Starts editing the specified for the specified row/column
50691 * @param {Number} rowIndex
50692 * @param {Number} colIndex
50694 startEditing : function(row, col){
50695 this.stopEditing();
50696 if(this.colModel.isCellEditable(col, row)){
50697 this.view.ensureVisible(row, col, true);
50698 var r = this.dataSource.getAt(row);
50699 var field = this.colModel.getDataIndex(col);
50704 value: r.data[field],
50709 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
50710 this.editing = true;
50711 var ed = this.colModel.getCellEditor(col, row);
50717 ed.render(ed.parentEl || document.body);
50720 (function(){ // complex but required for focus issues in safari, ie and opera
50724 ed.on("complete", this.onEditComplete, this, {single: true});
50725 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
50726 this.activeEditor = ed;
50727 var v = r.data[field];
50728 ed.startEdit(this.view.getCell(row, col), v);
50729 // combo's with 'displayField and name set
50730 if (ed.field.displayField && ed.field.name) {
50731 ed.field.el.dom.value = r.data[ed.field.name];
50735 }).defer(50, this);
50741 * Stops any active editing
50743 stopEditing : function(){
50744 if(this.activeEditor){
50745 this.activeEditor.completeEdit();
50747 this.activeEditor = null;
50751 * Ext JS Library 1.1.1
50752 * Copyright(c) 2006-2007, Ext JS, LLC.
50754 * Originally Released Under LGPL - original licence link has changed is not relivant.
50757 * <script type="text/javascript">
50760 // private - not really -- you end up using it !
50761 // This is a support class used internally by the Grid components
50764 * @class Roo.grid.GridEditor
50765 * @extends Roo.Editor
50766 * Class for creating and editable grid elements.
50767 * @param {Object} config any settings (must include field)
50769 Roo.grid.GridEditor = function(field, config){
50770 if (!config && field.field) {
50772 field = Roo.factory(config.field, Roo.form);
50774 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
50775 field.monitorTab = false;
50778 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
50781 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
50784 alignment: "tl-tl",
50787 cls: "x-small-editor x-grid-editor",
50792 * Ext JS Library 1.1.1
50793 * Copyright(c) 2006-2007, Ext JS, LLC.
50795 * Originally Released Under LGPL - original licence link has changed is not relivant.
50798 * <script type="text/javascript">
50803 Roo.grid.PropertyRecord = Roo.data.Record.create([
50804 {name:'name',type:'string'}, 'value'
50808 Roo.grid.PropertyStore = function(grid, source){
50810 this.store = new Roo.data.Store({
50811 recordType : Roo.grid.PropertyRecord
50813 this.store.on('update', this.onUpdate, this);
50815 this.setSource(source);
50817 Roo.grid.PropertyStore.superclass.constructor.call(this);
50822 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
50823 setSource : function(o){
50825 this.store.removeAll();
50828 if(this.isEditableValue(o[k])){
50829 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
50832 this.store.loadRecords({records: data}, {}, true);
50835 onUpdate : function(ds, record, type){
50836 if(type == Roo.data.Record.EDIT){
50837 var v = record.data['value'];
50838 var oldValue = record.modified['value'];
50839 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
50840 this.source[record.id] = v;
50842 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
50849 getProperty : function(row){
50850 return this.store.getAt(row);
50853 isEditableValue: function(val){
50854 if(val && val instanceof Date){
50856 }else if(typeof val == 'object' || typeof val == 'function'){
50862 setValue : function(prop, value){
50863 this.source[prop] = value;
50864 this.store.getById(prop).set('value', value);
50867 getSource : function(){
50868 return this.source;
50872 Roo.grid.PropertyColumnModel = function(grid, store){
50875 g.PropertyColumnModel.superclass.constructor.call(this, [
50876 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
50877 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
50879 this.store = store;
50880 this.bselect = Roo.DomHelper.append(document.body, {
50881 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
50882 {tag: 'option', value: 'true', html: 'true'},
50883 {tag: 'option', value: 'false', html: 'false'}
50886 Roo.id(this.bselect);
50889 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
50890 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
50891 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
50892 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
50893 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
50895 this.renderCellDelegate = this.renderCell.createDelegate(this);
50896 this.renderPropDelegate = this.renderProp.createDelegate(this);
50899 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
50903 valueText : 'Value',
50905 dateFormat : 'm/j/Y',
50908 renderDate : function(dateVal){
50909 return dateVal.dateFormat(this.dateFormat);
50912 renderBool : function(bVal){
50913 return bVal ? 'true' : 'false';
50916 isCellEditable : function(colIndex, rowIndex){
50917 return colIndex == 1;
50920 getRenderer : function(col){
50922 this.renderCellDelegate : this.renderPropDelegate;
50925 renderProp : function(v){
50926 return this.getPropertyName(v);
50929 renderCell : function(val){
50931 if(val instanceof Date){
50932 rv = this.renderDate(val);
50933 }else if(typeof val == 'boolean'){
50934 rv = this.renderBool(val);
50936 return Roo.util.Format.htmlEncode(rv);
50939 getPropertyName : function(name){
50940 var pn = this.grid.propertyNames;
50941 return pn && pn[name] ? pn[name] : name;
50944 getCellEditor : function(colIndex, rowIndex){
50945 var p = this.store.getProperty(rowIndex);
50946 var n = p.data['name'], val = p.data['value'];
50948 if(typeof(this.grid.customEditors[n]) == 'string'){
50949 return this.editors[this.grid.customEditors[n]];
50951 if(typeof(this.grid.customEditors[n]) != 'undefined'){
50952 return this.grid.customEditors[n];
50954 if(val instanceof Date){
50955 return this.editors['date'];
50956 }else if(typeof val == 'number'){
50957 return this.editors['number'];
50958 }else if(typeof val == 'boolean'){
50959 return this.editors['boolean'];
50961 return this.editors['string'];
50967 * @class Roo.grid.PropertyGrid
50968 * @extends Roo.grid.EditorGrid
50969 * This class represents the interface of a component based property grid control.
50970 * <br><br>Usage:<pre><code>
50971 var grid = new Roo.grid.PropertyGrid("my-container-id", {
50979 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50980 * The container MUST have some type of size defined for the grid to fill. The container will be
50981 * automatically set to position relative if it isn't already.
50982 * @param {Object} config A config object that sets properties on this grid.
50984 Roo.grid.PropertyGrid = function(container, config){
50985 config = config || {};
50986 var store = new Roo.grid.PropertyStore(this);
50987 this.store = store;
50988 var cm = new Roo.grid.PropertyColumnModel(this, store);
50989 store.store.sort('name', 'ASC');
50990 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
50993 enableColLock:false,
50994 enableColumnMove:false,
50996 trackMouseOver: false,
50999 this.getGridEl().addClass('x-props-grid');
51000 this.lastEditRow = null;
51001 this.on('columnresize', this.onColumnResize, this);
51004 * @event beforepropertychange
51005 * Fires before a property changes (return false to stop?)
51006 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
51007 * @param {String} id Record Id
51008 * @param {String} newval New Value
51009 * @param {String} oldval Old Value
51011 "beforepropertychange": true,
51013 * @event propertychange
51014 * Fires after a property changes
51015 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
51016 * @param {String} id Record Id
51017 * @param {String} newval New Value
51018 * @param {String} oldval Old Value
51020 "propertychange": true
51022 this.customEditors = this.customEditors || {};
51024 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
51027 * @cfg {Object} customEditors map of colnames=> custom editors.
51028 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
51029 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
51030 * false disables editing of the field.
51034 * @cfg {Object} propertyNames map of property Names to their displayed value
51037 render : function(){
51038 Roo.grid.PropertyGrid.superclass.render.call(this);
51039 this.autoSize.defer(100, this);
51042 autoSize : function(){
51043 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
51045 this.view.fitColumns();
51049 onColumnResize : function(){
51050 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
51054 * Sets the data for the Grid
51055 * accepts a Key => Value object of all the elements avaiable.
51056 * @param {Object} data to appear in grid.
51058 setSource : function(source){
51059 this.store.setSource(source);
51063 * Gets all the data from the grid.
51064 * @return {Object} data data stored in grid
51066 getSource : function(){
51067 return this.store.getSource();
51071 * Ext JS Library 1.1.1
51072 * Copyright(c) 2006-2007, Ext JS, LLC.
51074 * Originally Released Under LGPL - original licence link has changed is not relivant.
51077 * <script type="text/javascript">
51081 * @class Roo.LoadMask
51082 * A simple utility class for generically masking elements while loading data. If the element being masked has
51083 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
51084 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
51085 * element's UpdateManager load indicator and will be destroyed after the initial load.
51087 * Create a new LoadMask
51088 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
51089 * @param {Object} config The config object
51091 Roo.LoadMask = function(el, config){
51092 this.el = Roo.get(el);
51093 Roo.apply(this, config);
51095 this.store.on('beforeload', this.onBeforeLoad, this);
51096 this.store.on('load', this.onLoad, this);
51097 this.store.on('loadexception', this.onLoad, this);
51098 this.removeMask = false;
51100 var um = this.el.getUpdateManager();
51101 um.showLoadIndicator = false; // disable the default indicator
51102 um.on('beforeupdate', this.onBeforeLoad, this);
51103 um.on('update', this.onLoad, this);
51104 um.on('failure', this.onLoad, this);
51105 this.removeMask = true;
51109 Roo.LoadMask.prototype = {
51111 * @cfg {Boolean} removeMask
51112 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
51113 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
51116 * @cfg {String} msg
51117 * The text to display in a centered loading message box (defaults to 'Loading...')
51119 msg : 'Loading...',
51121 * @cfg {String} msgCls
51122 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
51124 msgCls : 'x-mask-loading',
51127 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
51133 * Disables the mask to prevent it from being displayed
51135 disable : function(){
51136 this.disabled = true;
51140 * Enables the mask so that it can be displayed
51142 enable : function(){
51143 this.disabled = false;
51147 onLoad : function(){
51148 this.el.unmask(this.removeMask);
51152 onBeforeLoad : function(){
51153 if(!this.disabled){
51154 this.el.mask(this.msg, this.msgCls);
51159 destroy : function(){
51161 this.store.un('beforeload', this.onBeforeLoad, this);
51162 this.store.un('load', this.onLoad, this);
51163 this.store.un('loadexception', this.onLoad, this);
51165 var um = this.el.getUpdateManager();
51166 um.un('beforeupdate', this.onBeforeLoad, this);
51167 um.un('update', this.onLoad, this);
51168 um.un('failure', this.onLoad, this);
51173 * Ext JS Library 1.1.1
51174 * Copyright(c) 2006-2007, Ext JS, LLC.
51176 * Originally Released Under LGPL - original licence link has changed is not relivant.
51179 * <script type="text/javascript">
51181 Roo.XTemplate = function(){
51182 Roo.XTemplate.superclass.constructor.apply(this, arguments);
51185 s = ['<tpl>', s, '</tpl>'].join('');
51187 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
51189 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
51190 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
51191 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
51195 while(m = s.match(re)){
51196 var m2 = m[0].match(nameRe);
51197 var m3 = m[0].match(ifRe);
51198 var m4 = m[0].match(execRe);
51199 var exp = null, fn = null, exec = null;
51200 var name = m2 && m2[1] ? m2[1] : '';
51202 exp = m3 && m3[1] ? m3[1] : null;
51204 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
51208 exp = m4 && m4[1] ? m4[1] : null;
51210 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
51215 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
51216 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
51217 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
51227 s = s.replace(m[0], '{xtpl'+ id + '}');
51230 for(var i = tpls.length-1; i >= 0; --i){
51231 this.compileTpl(tpls[i]);
51233 this.master = tpls[tpls.length-1];
51236 Roo.extend(Roo.XTemplate, Roo.Template, {
51238 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
51240 applySubTemplate : function(id, values, parent){
51241 var t = this.tpls[id];
51242 if(t.test && !t.test.call(this, values, parent)){
51245 if(t.exec && t.exec.call(this, values, parent)){
51248 var vs = t.target ? t.target.call(this, values, parent) : values;
51249 parent = t.target ? values : parent;
51250 if(t.target && vs instanceof Array){
51252 for(var i = 0, len = vs.length; i < len; i++){
51253 buf[buf.length] = t.compiled.call(this, vs[i], parent);
51255 return buf.join('');
51257 return t.compiled.call(this, vs, parent);
51260 compileTpl : function(tpl){
51261 var fm = Roo.util.Format;
51262 var useF = this.disableFormats !== true;
51263 var sep = Roo.isGecko ? "+" : ",";
51264 var fn = function(m, name, format, args){
51265 if(name.substr(0, 4) == 'xtpl'){
51266 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
51269 if(name.indexOf('.') != -1){
51272 v = "values['" + name + "']";
51274 if(format && useF){
51275 args = args ? ',' + args : "";
51276 if(format.substr(0, 5) != "this."){
51277 format = "fm." + format + '(';
51279 format = 'this.call("'+ format.substr(5) + '", ';
51283 args= ''; format = "("+v+" === undefined ? '' : ";
51285 return "'"+ sep + format + v + args + ")"+sep+"'";
51288 // branched to use + in gecko and [].join() in others
51290 body = "tpl.compiled = function(values, parent){ return '" +
51291 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
51294 body = ["tpl.compiled = function(values, parent){ return ['"];
51295 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
51296 body.push("'].join('');};");
51297 body = body.join('');
51299 /** eval:var:zzzzzzz */
51304 applyTemplate : function(values){
51305 return this.master.compiled.call(this, values, {});
51309 apply : function(){
51310 return this.applyTemplate.apply(this, arguments);
51313 compile : function(){return this;}
51316 Roo.XTemplate.from = function(el){
51317 el = Roo.getDom(el);
51318 return new Roo.XTemplate(el.value || el.innerHTML);
51320 * Original code for Roojs - LGPL
51321 * <script type="text/javascript">
51325 * @class Roo.XComponent
51326 * A delayed Element creator...
51327 * Or a way to group chunks of interface together.
51329 * Mypart.xyx = new Roo.XComponent({
51331 parent : 'Mypart.xyz', // empty == document.element.!!
51335 disabled : function() {}
51337 tree : function() { // return an tree of xtype declared components
51341 xtype : 'NestedLayoutPanel',
51348 * It can be used to build a big heiracy, with parent etc.
51349 * or you can just use this to render a single compoent to a dom element
51350 * MYPART.render(Roo.Element | String(id) | dom_element )
51352 * @extends Roo.util.Observable
51354 * @param cfg {Object} configuration of component
51357 Roo.XComponent = function(cfg) {
51358 Roo.apply(this, cfg);
51362 * Fires when this the componnt is built
51363 * @param {Roo.XComponent} c the component
51367 * @event buildcomplete
51368 * Fires on the top level element when all elements have been built
51369 * @param {Roo.XComponent} c the top level component.
51371 'buildcomplete' : true
51374 this.region = this.region || 'center'; // default..
51375 Roo.XComponent.register(this);
51376 this.modules = false;
51377 this.el = false; // where the layout goes..
51381 Roo.extend(Roo.XComponent, Roo.util.Observable, {
51384 * The created element (with Roo.factory())
51385 * @type {Roo.Layout}
51391 * for BC - use el in new code
51392 * @type {Roo.Layout}
51398 * for BC - use el in new code
51399 * @type {Roo.Layout}
51404 * @cfg {Function|boolean} disabled
51405 * If this module is disabled by some rule, return true from the funtion
51410 * @cfg {String} parent
51411 * Name of parent element which it get xtype added to..
51416 * @cfg {String} order
51417 * Used to set the order in which elements are created (usefull for multiple tabs)
51422 * @cfg {String} name
51423 * String to display while loading.
51427 * @cfg {String} region
51428 * Region to render component to (defaults to center)
51433 * @cfg {Array} items
51434 * A single item array - the first element is the root of the tree..
51435 * It's done this way to stay compatible with the Xtype system...
51442 * render element to dom or tree
51443 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
51446 render : function(el)
51450 var hp = this.parent ? 1 : 0;
51452 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
51453 // if parent is a '#.....' string, then let's use that..
51454 var ename = this.parent.substr(1)
51455 this.parent = false;
51456 el = Roo.get(ename);
51458 Roo.log("Warning - element can not be found :#" + ename );
51464 if (!this.parent) {
51466 el = el ? Roo.get(el) : false;
51468 // it's a top level one..
51470 el : new Roo.BorderLayout(el || document.body, {
51476 tabPosition: 'top',
51477 //resizeTabs: true,
51478 alwaysShowTabs: el && hp? false : true,
51479 hideTabs: el || !hp ? true : false,
51488 var tree = this.tree();
51489 tree.region = tree.region || this.region;
51490 this.el = this.parent.el.addxtype(tree);
51491 this.fireEvent('built', this);
51493 this.panel = this.el;
51494 this.layout = this.panel.layout;
51500 Roo.apply(Roo.XComponent, {
51503 * @property buildCompleted
51504 * True when the builder has completed building the interface.
51507 buildCompleted : false,
51510 * @property topModule
51511 * the upper most module - uses document.element as it's constructor.
51518 * @property modules
51519 * array of modules to be created by registration system.
51520 * @type {Array} of Roo.XComponent
51525 * @property elmodules
51526 * array of modules to be created by which use #ID
51527 * @type {Array} of Roo.XComponent
51534 * Register components to be built later.
51536 * This solves the following issues
51537 * - Building is not done on page load, but after an authentication process has occured.
51538 * - Interface elements are registered on page load
51539 * - Parent Interface elements may not be loaded before child, so this handles that..
51546 module : 'Pman.Tab.projectMgr',
51548 parent : 'Pman.layout',
51549 disabled : false, // or use a function..
51552 * * @param {Object} details about module
51554 register : function(obj) {
51555 this.modules.push(obj);
51559 * convert a string to an object..
51560 * eg. 'AAA.BBB' -> finds AAA.BBB
51564 toObject : function(str)
51566 if (!str || typeof(str) == 'object') {
51569 if (str.substring(0,1) == '#') {
51573 var ar = str.split('.');
51578 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
51580 throw "Module not found : " + str;
51584 throw "Module not found : " + str;
51586 Roo.each(ar, function(e) {
51587 if (typeof(o[e]) == 'undefined') {
51588 throw "Module not found : " + str;
51599 * move modules into their correct place in the tree..
51602 preBuild : function ()
51605 Roo.each(this.modules , function (obj)
51607 var opar = obj.parent;
51609 obj.parent = this.toObject(opar);
51611 Roo.log(e.toString());
51616 this.topModule = obj;
51619 if (typeof(obj.parent) == 'string') {
51620 this.elmodules.push(obj);
51623 if (obj.parent.constructor != Roo.XComponent) {
51624 Roo.log("Object Parent is not instance of XComponent:" + obj.name)
51626 if (!obj.parent.modules) {
51627 obj.parent.modules = new Roo.util.MixedCollection(false,
51628 function(o) { return o.order + '' }
51632 obj.parent.modules.add(obj);
51637 * make a list of modules to build.
51638 * @return {Array} list of modules.
51641 buildOrder : function()
51644 var cmp = function(a,b) {
51645 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
51647 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
51648 throw "No top level modules to build";
51651 // make a flat list in order of modules to build.
51652 var mods = this.topModule ? [ this.topModule ] : [];
51653 Roo.each(this.elmodules,function(e) { mods.push(e) });
51656 // add modules to their parents..
51657 var addMod = function(m) {
51658 // Roo.debug && Roo.log(m.modKey);
51662 m.modules.keySort('ASC', cmp );
51663 m.modules.each(addMod);
51665 // not sure if this is used any more..
51667 m.finalize.name = m.name + " (clean up) ";
51668 mods.push(m.finalize);
51672 if (this.topModule) {
51673 this.topModule.modules.keySort('ASC', cmp );
51674 this.topModule.modules.each(addMod);
51680 * Build the registered modules.
51681 * @param {Object} parent element.
51682 * @param {Function} optional method to call after module has been added.
51690 var mods = this.buildOrder();
51692 //this.allmods = mods;
51693 //Roo.debug && Roo.log(mods);
51695 if (!mods.length) { // should not happen
51696 throw "NO modules!!!";
51701 // flash it up as modal - so we store the mask!?
51702 Roo.MessageBox.show({ title: 'loading' });
51703 Roo.MessageBox.show({
51704 title: "Please wait...",
51705 msg: "Building Interface...",
51712 var total = mods.length;
51715 var progressRun = function() {
51716 if (!mods.length) {
51717 Roo.debug && Roo.log('hide?');
51718 Roo.MessageBox.hide();
51719 if (_this.topModule) {
51720 _this.topModule.fireEvent('buildcomplete', _this.topModule);
51726 var m = mods.shift();
51729 Roo.debug && Roo.log(m);
51730 // not sure if this is supported any more.. - modules that are are just function
51731 if (typeof(m) == 'function') {
51733 return progressRun.defer(10, _this);
51738 Roo.MessageBox.updateProgress(
51739 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
51741 (m.name ? (' - ' + m.name) : '')
51745 // is the module disabled?
51746 var disabled = (typeof(m.disabled) == 'function') ?
51747 m.disabled.call(m.module.disabled) : m.disabled;
51751 return progressRun(); // we do not update the display!
51757 // it's 10 on top level, and 1 on others??? why...
51758 return progressRun.defer(10, _this);
51761 progressRun.defer(1, _this);
51772 //<script type="text/javascript">
51777 * @extends Roo.LayoutDialog
51778 * A generic Login Dialog..... - only one needed in theory!?!?
51780 * Fires XComponent builder on success...
51783 * username,password, lang = for login actions.
51784 * check = 1 for periodic checking that sesion is valid.
51785 * passwordRequest = email request password
51786 * logout = 1 = to logout
51788 * Affects: (this id="????" elements)
51789 * loading (removed) (used to indicate application is loading)
51790 * loading-mask (hides) (used to hide application when it's building loading)
51796 * Myapp.login = Roo.Login({
51812 Roo.Login = function(cfg)
51818 Roo.apply(this,cfg);
51820 Roo.onReady(function() {
51826 Roo.Login.superclass.constructor.call(this, this);
51827 //this.addxtype(this.items[0]);
51833 Roo.extend(Roo.Login, Roo.LayoutDialog, {
51836 * @cfg {String} method
51837 * Method used to query for login details.
51842 * @cfg {String} url
51843 * URL to query login data. - eg. baseURL + '/Login.php'
51849 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
51854 * @property checkFails
51855 * Number of times we have attempted to get authentication check, and failed.
51860 * @property intervalID
51861 * The window interval that does the constant login checking.
51867 onLoad : function() // called on page load...
51871 if (Roo.get('loading')) { // clear any loading indicator..
51872 Roo.get('loading').remove();
51875 //this.switchLang('en'); // set the language to english..
51878 success: function(response, opts) { // check successfull...
51880 var res = this.processResponse(response);
51881 this.checkFails =0;
51882 if (!res.success) { // error!
51883 this.checkFails = 5;
51884 //console.log('call failure');
51885 return this.failure(response,opts);
51888 if (!res.data.id) { // id=0 == login failure.
51889 return this.show();
51893 //console.log(success);
51894 this.fillAuth(res.data);
51895 this.checkFails =0;
51896 Roo.XComponent.build();
51898 failure : this.show
51904 check: function(cfg) // called every so often to refresh cookie etc..
51906 if (cfg.again) { // could be undefined..
51909 this.checkFails = 0;
51912 if (this.sending) {
51913 if ( this.checkFails > 4) {
51914 Roo.MessageBox.alert("Error",
51915 "Error getting authentication status. - try reloading, or wait a while", function() {
51916 _this.sending = false;
51921 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
51924 this.sending = true;
51931 method: this.method,
51932 success: cfg.success || this.success,
51933 failure : cfg.failure || this.failure,
51943 window.onbeforeunload = function() { }; // false does not work for IE..
51953 failure : function() {
51954 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
51955 document.location = document.location.toString() + '?ts=' + Math.random();
51959 success : function() {
51960 _this.user = false;
51961 this.checkFails =0;
51963 document.location = document.location.toString() + '?ts=' + Math.random();
51970 processResponse : function (response)
51974 res = Roo.decode(response.responseText);
51976 if (typeof(res) != 'object') {
51977 res = { success : false, errorMsg : res, errors : true };
51979 if (typeof(res.success) == 'undefined') {
51980 res.success = false;
51984 res = { success : false, errorMsg : response.responseText, errors : true };
51989 success : function(response, opts) // check successfull...
51991 this.sending = false;
51992 var res = this.processResponse(response);
51993 if (!res.success) {
51994 return this.failure(response, opts);
51996 if (!res.data || !res.data.id) {
51997 return this.failure(response,opts);
51999 //console.log(res);
52000 this.fillAuth(res.data);
52002 this.checkFails =0;
52007 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
52009 this.authUser = -1;
52010 this.sending = false;
52011 var res = this.processResponse(response);
52012 //console.log(res);
52013 if ( this.checkFails > 2) {
52015 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
52016 "Error getting authentication status. - try reloading");
52019 opts.callCfg.again = true;
52020 this.check.defer(1000, this, [ opts.callCfg ]);
52026 fillAuth: function(au) {
52027 this.startAuthCheck();
52028 this.authUserId = au.id;
52029 this.authUser = au;
52030 this.lastChecked = new Date();
52031 this.fireEvent('refreshed', au);
52032 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
52033 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
52034 au.lang = au.lang || 'en';
52035 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
52036 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
52037 this.switchLang(au.lang );
52040 // open system... - -on setyp..
52041 if (this.authUserId < 0) {
52042 Roo.MessageBox.alert("Warning",
52043 "This is an open system - please set up a admin user with a password.");
52046 //Pman.onload(); // which should do nothing if it's a re-auth result...
52051 startAuthCheck : function() // starter for timeout checking..
52053 if (this.intervalID) { // timer already in place...
52057 this.intervalID = window.setInterval(function() {
52058 _this.check(false);
52059 }, 120000); // every 120 secs = 2mins..
52065 switchLang : function (lang)
52067 _T = typeof(_T) == 'undefined' ? false : _T;
52068 if (!_T || !lang.length) {
52072 if (!_T && lang != 'en') {
52073 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
52077 if (typeof(_T.en) == 'undefined') {
52079 Roo.apply(_T.en, _T);
52082 if (typeof(_T[lang]) == 'undefined') {
52083 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
52088 Roo.apply(_T, _T[lang]);
52089 // just need to set the text values for everything...
52091 /* this will not work ...
52095 function formLabel(name, val) {
52096 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
52099 formLabel('password', "Password"+':');
52100 formLabel('username', "Email Address"+':');
52101 formLabel('lang', "Language"+':');
52102 this.dialog.setTitle("Login");
52103 this.dialog.buttons[0].setText("Forgot Password");
52104 this.dialog.buttons[1].setText("Login");
52123 collapsible: false,
52125 center: { // needed??
52128 // tabPosition: 'top',
52131 alwaysShowTabs: false
52135 show : function(dlg)
52137 //console.log(this);
52138 this.form = this.layout.getRegion('center').activePanel.form;
52139 this.form.dialog = dlg;
52140 this.buttons[0].form = this.form;
52141 this.buttons[0].dialog = dlg;
52142 this.buttons[1].form = this.form;
52143 this.buttons[1].dialog = dlg;
52145 //this.resizeToLogo.defer(1000,this);
52146 // this is all related to resizing for logos..
52147 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
52149 // this.resizeToLogo.defer(1000,this);
52152 //var w = Ext.lib.Dom.getViewWidth() - 100;
52153 //var h = Ext.lib.Dom.getViewHeight() - 100;
52154 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
52156 if (this.disabled) {
52161 if (this.user.id < 0) { // used for inital setup situations.
52165 if (this.intervalID) {
52166 // remove the timer
52167 window.clearInterval(this.intervalID);
52168 this.intervalID = false;
52172 if (Roo.get('loading')) {
52173 Roo.get('loading').remove();
52175 if (Roo.get('loading-mask')) {
52176 Roo.get('loading-mask').hide();
52179 //incomming._node = tnode;
52181 //this.dialog.modal = !modal;
52182 //this.dialog.show();
52186 this.form.setValues({
52187 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
52188 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
52191 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
52192 if (this.form.findField('username').getValue().length > 0 ){
52193 this.form.findField('password').focus();
52195 this.form.findField('username').focus();
52203 xtype : 'ContentPanel',
52215 style : 'margin: 10px;',
52218 actionfailed : function(f, act) {
52219 // form can return { errors: .... }
52221 //act.result.errors // invalid form element list...
52222 //act.result.errorMsg// invalid form element list...
52224 this.dialog.el.unmask();
52225 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
52226 "Login failed - communication error - try again.");
52229 actioncomplete: function(re, act) {
52231 Roo.state.Manager.set(
52232 this.dialog.realm + '.username',
52233 this.findField('username').getValue()
52235 Roo.state.Manager.set(
52236 this.dialog.realm + '.lang',
52237 this.findField('lang').getValue()
52240 this.dialog.fillAuth(act.result.data);
52242 this.dialog.hide();
52244 if (Roo.get('loading-mask')) {
52245 Roo.get('loading-mask').show();
52247 Roo.XComponent.build();
52255 xtype : 'TextField',
52257 fieldLabel: "Email Address",
52260 autoCreate : {tag: "input", type: "text", size: "20"}
52263 xtype : 'TextField',
52265 fieldLabel: "Password",
52266 inputType: 'password',
52269 autoCreate : {tag: "input", type: "text", size: "20"},
52271 specialkey : function(e,ev) {
52272 if (ev.keyCode == 13) {
52273 this.form.dialog.el.mask("Logging in");
52274 this.form.doAction('submit', {
52275 url: this.form.dialog.url,
52276 method: this.form.dialog.method
52283 xtype : 'ComboBox',
52285 fieldLabel: "Language",
52288 xtype : 'SimpleStore',
52289 fields: ['lang', 'ldisp'],
52291 [ 'en', 'English' ],
52292 [ 'zh_HK' , '\u7E41\u4E2D' ],
52293 [ 'zh_CN', '\u7C21\u4E2D' ]
52297 valueField : 'lang',
52298 hiddenName: 'lang',
52300 displayField:'ldisp',
52304 triggerAction: 'all',
52305 emptyText:'Select a Language...',
52306 selectOnFocus:true,
52308 select : function(cb, rec, ix) {
52309 this.form.switchLang(rec.data.lang);
52325 text : "Forgot Password",
52327 click : function() {
52328 //console.log(this);
52329 var n = this.form.findField('username').getValue();
52331 Roo.MessageBox.alert("Error", "Fill in your email address");
52335 url: this.dialog.url,
52339 method: this.dialog.method,
52340 success: function(response, opts) { // check successfull...
52342 var res = this.dialog.processResponse(response);
52343 if (!res.success) { // error!
52344 Roo.MessageBox.alert("Error" ,
52345 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
52348 Roo.MessageBox.alert("Notice" ,
52349 "Please check you email for the Password Reset message");
52351 failure : function() {
52352 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
52365 click : function () {
52367 this.dialog.el.mask("Logging in");
52368 this.form.doAction('submit', {
52369 url: this.dialog.url,
52370 method: this.dialog.method