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)
23675 "preparedata" : true
23679 "click": this.onClick,
23680 "dblclick": this.onDblClick,
23681 "contextmenu": this.onContextMenu,
23685 this.selections = [];
23687 this.cmp = new Roo.CompositeElementLite([]);
23689 this.store = Roo.factory(this.store, Roo.data);
23690 this.setStore(this.store, true);
23692 Roo.View.superclass.constructor.call(this);
23695 Roo.extend(Roo.View, Roo.util.Observable, {
23698 * @cfg {Roo.data.Store} store Data store to load data from.
23703 * @cfg {String|Roo.Element} el The container element.
23708 * @cfg {String|Roo.Template} tpl The template used by this View
23713 * @cfg {String} selectedClass The css class to add to selected nodes
23715 selectedClass : "x-view-selected",
23717 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23721 * @cfg {Boolean} multiSelect Allow multiple selection
23724 multiSelect : false,
23726 * @cfg {Boolean} singleSelect Allow single selection
23728 singleSelect: false,
23731 * Returns the element this view is bound to.
23732 * @return {Roo.Element}
23734 getEl : function(){
23739 * Refreshes the view.
23741 refresh : function(){
23743 this.clearSelections();
23744 this.el.update("");
23746 var records = this.store.getRange();
23747 if(records.length < 1){
23748 this.el.update(this.emptyText);
23751 for(var i = 0, len = records.length; i < len; i++){
23752 var data = this.prepareData(records[i].data, i, records[i]);
23753 this.fireEvent("preparedata", this, data, i, records[i]);
23754 html[html.length] = t.apply(data);
23756 this.el.update(html.join(""));
23757 this.nodes = this.el.dom.childNodes;
23758 this.updateIndexes(0);
23762 * Function to override to reformat the data that is sent to
23763 * the template for each node.
23764 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23765 * a JSON object for an UpdateManager bound view).
23767 prepareData : function(data){
23771 onUpdate : function(ds, record){
23772 this.clearSelections();
23773 var index = this.store.indexOf(record);
23774 var n = this.nodes[index];
23775 this.tpl.insertBefore(n, this.prepareData(record.data));
23776 n.parentNode.removeChild(n);
23777 this.updateIndexes(index, index);
23780 onAdd : function(ds, records, index){
23781 this.clearSelections();
23782 if(this.nodes.length == 0){
23786 var n = this.nodes[index];
23787 for(var i = 0, len = records.length; i < len; i++){
23788 var d = this.prepareData(records[i].data);
23790 this.tpl.insertBefore(n, d);
23792 this.tpl.append(this.el, d);
23795 this.updateIndexes(index);
23798 onRemove : function(ds, record, index){
23799 this.clearSelections();
23800 this.el.dom.removeChild(this.nodes[index]);
23801 this.updateIndexes(index);
23805 * Refresh an individual node.
23806 * @param {Number} index
23808 refreshNode : function(index){
23809 this.onUpdate(this.store, this.store.getAt(index));
23812 updateIndexes : function(startIndex, endIndex){
23813 var ns = this.nodes;
23814 startIndex = startIndex || 0;
23815 endIndex = endIndex || ns.length - 1;
23816 for(var i = startIndex; i <= endIndex; i++){
23817 ns[i].nodeIndex = i;
23822 * Changes the data store this view uses and refresh the view.
23823 * @param {Store} store
23825 setStore : function(store, initial){
23826 if(!initial && this.store){
23827 this.store.un("datachanged", this.refresh);
23828 this.store.un("add", this.onAdd);
23829 this.store.un("remove", this.onRemove);
23830 this.store.un("update", this.onUpdate);
23831 this.store.un("clear", this.refresh);
23835 store.on("datachanged", this.refresh, this);
23836 store.on("add", this.onAdd, this);
23837 store.on("remove", this.onRemove, this);
23838 store.on("update", this.onUpdate, this);
23839 store.on("clear", this.refresh, this);
23848 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23849 * @param {HTMLElement} node
23850 * @return {HTMLElement} The template node
23852 findItemFromChild : function(node){
23853 var el = this.el.dom;
23854 if(!node || node.parentNode == el){
23857 var p = node.parentNode;
23858 while(p && p != el){
23859 if(p.parentNode == el){
23868 onClick : function(e){
23869 var item = this.findItemFromChild(e.getTarget());
23871 var index = this.indexOf(item);
23872 if(this.onItemClick(item, index, e) !== false){
23873 this.fireEvent("click", this, index, item, e);
23876 this.clearSelections();
23881 onContextMenu : function(e){
23882 var item = this.findItemFromChild(e.getTarget());
23884 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23889 onDblClick : function(e){
23890 var item = this.findItemFromChild(e.getTarget());
23892 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23896 onItemClick : function(item, index, e){
23897 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23900 if(this.multiSelect || this.singleSelect){
23901 if(this.multiSelect && e.shiftKey && this.lastSelection){
23902 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23904 this.select(item, this.multiSelect && e.ctrlKey);
23905 this.lastSelection = item;
23907 e.preventDefault();
23913 * Get the number of selected nodes.
23916 getSelectionCount : function(){
23917 return this.selections.length;
23921 * Get the currently selected nodes.
23922 * @return {Array} An array of HTMLElements
23924 getSelectedNodes : function(){
23925 return this.selections;
23929 * Get the indexes of the selected nodes.
23932 getSelectedIndexes : function(){
23933 var indexes = [], s = this.selections;
23934 for(var i = 0, len = s.length; i < len; i++){
23935 indexes.push(s[i].nodeIndex);
23941 * Clear all selections
23942 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23944 clearSelections : function(suppressEvent){
23945 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23946 this.cmp.elements = this.selections;
23947 this.cmp.removeClass(this.selectedClass);
23948 this.selections = [];
23949 if(!suppressEvent){
23950 this.fireEvent("selectionchange", this, this.selections);
23956 * Returns true if the passed node is selected
23957 * @param {HTMLElement/Number} node The node or node index
23958 * @return {Boolean}
23960 isSelected : function(node){
23961 var s = this.selections;
23965 node = this.getNode(node);
23966 return s.indexOf(node) !== -1;
23971 * @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
23972 * @param {Boolean} keepExisting (optional) true to keep existing selections
23973 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23975 select : function(nodeInfo, keepExisting, suppressEvent){
23976 if(nodeInfo instanceof Array){
23978 this.clearSelections(true);
23980 for(var i = 0, len = nodeInfo.length; i < len; i++){
23981 this.select(nodeInfo[i], true, true);
23984 var node = this.getNode(nodeInfo);
23985 if(node && !this.isSelected(node)){
23987 this.clearSelections(true);
23989 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23990 Roo.fly(node).addClass(this.selectedClass);
23991 this.selections.push(node);
23992 if(!suppressEvent){
23993 this.fireEvent("selectionchange", this, this.selections);
24001 * Gets a template node.
24002 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24003 * @return {HTMLElement} The node or null if it wasn't found
24005 getNode : function(nodeInfo){
24006 if(typeof nodeInfo == "string"){
24007 return document.getElementById(nodeInfo);
24008 }else if(typeof nodeInfo == "number"){
24009 return this.nodes[nodeInfo];
24015 * Gets a range template nodes.
24016 * @param {Number} startIndex
24017 * @param {Number} endIndex
24018 * @return {Array} An array of nodes
24020 getNodes : function(start, end){
24021 var ns = this.nodes;
24022 start = start || 0;
24023 end = typeof end == "undefined" ? ns.length - 1 : end;
24026 for(var i = start; i <= end; i++){
24030 for(var i = start; i >= end; i--){
24038 * Finds the index of the passed node
24039 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24040 * @return {Number} The index of the node or -1
24042 indexOf : function(node){
24043 node = this.getNode(node);
24044 if(typeof node.nodeIndex == "number"){
24045 return node.nodeIndex;
24047 var ns = this.nodes;
24048 for(var i = 0, len = ns.length; i < len; i++){
24058 * Ext JS Library 1.1.1
24059 * Copyright(c) 2006-2007, Ext JS, LLC.
24061 * Originally Released Under LGPL - original licence link has changed is not relivant.
24064 * <script type="text/javascript">
24068 * @class Roo.JsonView
24069 * @extends Roo.View
24070 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24072 var view = new Roo.JsonView({
24073 container: "my-element",
24074 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24079 // listen for node click?
24080 view.on("click", function(vw, index, node, e){
24081 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24084 // direct load of JSON data
24085 view.load("foobar.php");
24087 // Example from my blog list
24088 var tpl = new Roo.Template(
24089 '<div class="entry">' +
24090 '<a class="entry-title" href="{link}">{title}</a>' +
24091 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24092 "</div><hr />"
24095 var moreView = new Roo.JsonView({
24096 container : "entry-list",
24100 moreView.on("beforerender", this.sortEntries, this);
24102 url: "/blog/get-posts.php",
24103 params: "allposts=true",
24104 text: "Loading Blog Entries..."
24108 * Note: old code is supported with arguments : (container, template, config)
24112 * Create a new JsonView
24114 * @param {Object} config The config object
24117 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24120 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24122 var um = this.el.getUpdateManager();
24123 um.setRenderer(this);
24124 um.on("update", this.onLoad, this);
24125 um.on("failure", this.onLoadException, this);
24128 * @event beforerender
24129 * Fires before rendering of the downloaded JSON data.
24130 * @param {Roo.JsonView} this
24131 * @param {Object} data The JSON data loaded
24135 * Fires when data is loaded.
24136 * @param {Roo.JsonView} this
24137 * @param {Object} data The JSON data loaded
24138 * @param {Object} response The raw Connect response object
24141 * @event loadexception
24142 * Fires when loading fails.
24143 * @param {Roo.JsonView} this
24144 * @param {Object} response The raw Connect response object
24147 'beforerender' : true,
24149 'loadexception' : true
24152 Roo.extend(Roo.JsonView, Roo.View, {
24154 * @type {String} The root property in the loaded JSON object that contains the data
24159 * Refreshes the view.
24161 refresh : function(){
24162 this.clearSelections();
24163 this.el.update("");
24165 var o = this.jsonData;
24166 if(o && o.length > 0){
24167 for(var i = 0, len = o.length; i < len; i++){
24168 var data = this.prepareData(o[i], i, o);
24169 html[html.length] = this.tpl.apply(data);
24172 html.push(this.emptyText);
24174 this.el.update(html.join(""));
24175 this.nodes = this.el.dom.childNodes;
24176 this.updateIndexes(0);
24180 * 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.
24181 * @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:
24184 url: "your-url.php",
24185 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24186 callback: yourFunction,
24187 scope: yourObject, //(optional scope)
24190 text: "Loading...",
24195 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24196 * 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.
24197 * @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}
24198 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24199 * @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.
24202 var um = this.el.getUpdateManager();
24203 um.update.apply(um, arguments);
24206 render : function(el, response){
24207 this.clearSelections();
24208 this.el.update("");
24211 o = Roo.util.JSON.decode(response.responseText);
24214 o = o[this.jsonRoot];
24219 * The current JSON data or null
24222 this.beforeRender();
24227 * Get the number of records in the current JSON dataset
24230 getCount : function(){
24231 return this.jsonData ? this.jsonData.length : 0;
24235 * Returns the JSON object for the specified node(s)
24236 * @param {HTMLElement/Array} node The node or an array of nodes
24237 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24238 * you get the JSON object for the node
24240 getNodeData : function(node){
24241 if(node instanceof Array){
24243 for(var i = 0, len = node.length; i < len; i++){
24244 data.push(this.getNodeData(node[i]));
24248 return this.jsonData[this.indexOf(node)] || null;
24251 beforeRender : function(){
24252 this.snapshot = this.jsonData;
24254 this.sort.apply(this, this.sortInfo);
24256 this.fireEvent("beforerender", this, this.jsonData);
24259 onLoad : function(el, o){
24260 this.fireEvent("load", this, this.jsonData, o);
24263 onLoadException : function(el, o){
24264 this.fireEvent("loadexception", this, o);
24268 * Filter the data by a specific property.
24269 * @param {String} property A property on your JSON objects
24270 * @param {String/RegExp} value Either string that the property values
24271 * should start with, or a RegExp to test against the property
24273 filter : function(property, value){
24276 var ss = this.snapshot;
24277 if(typeof value == "string"){
24278 var vlen = value.length;
24280 this.clearFilter();
24283 value = value.toLowerCase();
24284 for(var i = 0, len = ss.length; i < len; i++){
24286 if(o[property].substr(0, vlen).toLowerCase() == value){
24290 } else if(value.exec){ // regex?
24291 for(var i = 0, len = ss.length; i < len; i++){
24293 if(value.test(o[property])){
24300 this.jsonData = data;
24306 * Filter by a function. The passed function will be called with each
24307 * object in the current dataset. If the function returns true the value is kept,
24308 * otherwise it is filtered.
24309 * @param {Function} fn
24310 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24312 filterBy : function(fn, scope){
24315 var ss = this.snapshot;
24316 for(var i = 0, len = ss.length; i < len; i++){
24318 if(fn.call(scope || this, o)){
24322 this.jsonData = data;
24328 * Clears the current filter.
24330 clearFilter : function(){
24331 if(this.snapshot && this.jsonData != this.snapshot){
24332 this.jsonData = this.snapshot;
24339 * Sorts the data for this view and refreshes it.
24340 * @param {String} property A property on your JSON objects to sort on
24341 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24342 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24344 sort : function(property, dir, sortType){
24345 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24348 var dsc = dir && dir.toLowerCase() == "desc";
24349 var f = function(o1, o2){
24350 var v1 = sortType ? sortType(o1[p]) : o1[p];
24351 var v2 = sortType ? sortType(o2[p]) : o2[p];
24354 return dsc ? +1 : -1;
24355 } else if(v1 > v2){
24356 return dsc ? -1 : +1;
24361 this.jsonData.sort(f);
24363 if(this.jsonData != this.snapshot){
24364 this.snapshot.sort(f);
24370 * Ext JS Library 1.1.1
24371 * Copyright(c) 2006-2007, Ext JS, LLC.
24373 * Originally Released Under LGPL - original licence link has changed is not relivant.
24376 * <script type="text/javascript">
24381 * @class Roo.ColorPalette
24382 * @extends Roo.Component
24383 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24384 * Here's an example of typical usage:
24386 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24387 cp.render('my-div');
24389 cp.on('select', function(palette, selColor){
24390 // do something with selColor
24394 * Create a new ColorPalette
24395 * @param {Object} config The config object
24397 Roo.ColorPalette = function(config){
24398 Roo.ColorPalette.superclass.constructor.call(this, config);
24402 * Fires when a color is selected
24403 * @param {ColorPalette} this
24404 * @param {String} color The 6-digit color hex code (without the # symbol)
24410 this.on("select", this.handler, this.scope, true);
24413 Roo.extend(Roo.ColorPalette, Roo.Component, {
24415 * @cfg {String} itemCls
24416 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24418 itemCls : "x-color-palette",
24420 * @cfg {String} value
24421 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24422 * the hex codes are case-sensitive.
24425 clickEvent:'click',
24427 ctype: "Roo.ColorPalette",
24430 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24432 allowReselect : false,
24435 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24436 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24437 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24438 * of colors with the width setting until the box is symmetrical.</p>
24439 * <p>You can override individual colors if needed:</p>
24441 var cp = new Roo.ColorPalette();
24442 cp.colors[0] = "FF0000"; // change the first box to red
24445 Or you can provide a custom array of your own for complete control:
24447 var cp = new Roo.ColorPalette();
24448 cp.colors = ["000000", "993300", "333300"];
24453 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24454 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24455 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24456 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24457 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24461 onRender : function(container, position){
24462 var t = new Roo.MasterTemplate(
24463 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24465 var c = this.colors;
24466 for(var i = 0, len = c.length; i < len; i++){
24469 var el = document.createElement("div");
24470 el.className = this.itemCls;
24472 container.dom.insertBefore(el, position);
24473 this.el = Roo.get(el);
24474 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24475 if(this.clickEvent != 'click'){
24476 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24481 afterRender : function(){
24482 Roo.ColorPalette.superclass.afterRender.call(this);
24484 var s = this.value;
24491 handleClick : function(e, t){
24492 e.preventDefault();
24493 if(!this.disabled){
24494 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24495 this.select(c.toUpperCase());
24500 * Selects the specified color in the palette (fires the select event)
24501 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24503 select : function(color){
24504 color = color.replace("#", "");
24505 if(color != this.value || this.allowReselect){
24508 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24510 el.child("a.color-"+color).addClass("x-color-palette-sel");
24511 this.value = color;
24512 this.fireEvent("select", this, color);
24517 * Ext JS Library 1.1.1
24518 * Copyright(c) 2006-2007, Ext JS, LLC.
24520 * Originally Released Under LGPL - original licence link has changed is not relivant.
24523 * <script type="text/javascript">
24527 * @class Roo.DatePicker
24528 * @extends Roo.Component
24529 * Simple date picker class.
24531 * Create a new DatePicker
24532 * @param {Object} config The config object
24534 Roo.DatePicker = function(config){
24535 Roo.DatePicker.superclass.constructor.call(this, config);
24537 this.value = config && config.value ?
24538 config.value.clearTime() : new Date().clearTime();
24543 * Fires when a date is selected
24544 * @param {DatePicker} this
24545 * @param {Date} date The selected date
24551 this.on("select", this.handler, this.scope || this);
24553 // build the disabledDatesRE
24554 if(!this.disabledDatesRE && this.disabledDates){
24555 var dd = this.disabledDates;
24557 for(var i = 0; i < dd.length; i++){
24559 if(i != dd.length-1) re += "|";
24561 this.disabledDatesRE = new RegExp(re + ")");
24565 Roo.extend(Roo.DatePicker, Roo.Component, {
24567 * @cfg {String} todayText
24568 * The text to display on the button that selects the current date (defaults to "Today")
24570 todayText : "Today",
24572 * @cfg {String} okText
24573 * The text to display on the ok button
24575 okText : " OK ", //   to give the user extra clicking room
24577 * @cfg {String} cancelText
24578 * The text to display on the cancel button
24580 cancelText : "Cancel",
24582 * @cfg {String} todayTip
24583 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24585 todayTip : "{0} (Spacebar)",
24587 * @cfg {Date} minDate
24588 * Minimum allowable date (JavaScript date object, defaults to null)
24592 * @cfg {Date} maxDate
24593 * Maximum allowable date (JavaScript date object, defaults to null)
24597 * @cfg {String} minText
24598 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24600 minText : "This date is before the minimum date",
24602 * @cfg {String} maxText
24603 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24605 maxText : "This date is after the maximum date",
24607 * @cfg {String} format
24608 * The default date format string which can be overriden for localization support. The format must be
24609 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24613 * @cfg {Array} disabledDays
24614 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24616 disabledDays : null,
24618 * @cfg {String} disabledDaysText
24619 * The tooltip to display when the date falls on a disabled day (defaults to "")
24621 disabledDaysText : "",
24623 * @cfg {RegExp} disabledDatesRE
24624 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24626 disabledDatesRE : null,
24628 * @cfg {String} disabledDatesText
24629 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24631 disabledDatesText : "",
24633 * @cfg {Boolean} constrainToViewport
24634 * True to constrain the date picker to the viewport (defaults to true)
24636 constrainToViewport : true,
24638 * @cfg {Array} monthNames
24639 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24641 monthNames : Date.monthNames,
24643 * @cfg {Array} dayNames
24644 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24646 dayNames : Date.dayNames,
24648 * @cfg {String} nextText
24649 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24651 nextText: 'Next Month (Control+Right)',
24653 * @cfg {String} prevText
24654 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24656 prevText: 'Previous Month (Control+Left)',
24658 * @cfg {String} monthYearText
24659 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24661 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24663 * @cfg {Number} startDay
24664 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24668 * @cfg {Bool} showClear
24669 * Show a clear button (usefull for date form elements that can be blank.)
24675 * Sets the value of the date field
24676 * @param {Date} value The date to set
24678 setValue : function(value){
24679 var old = this.value;
24680 this.value = value.clearTime(true);
24682 this.update(this.value);
24687 * Gets the current selected value of the date field
24688 * @return {Date} The selected date
24690 getValue : function(){
24695 focus : function(){
24697 this.update(this.activeDate);
24702 onRender : function(container, position){
24704 '<table cellspacing="0">',
24705 '<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>',
24706 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24707 var dn = this.dayNames;
24708 for(var i = 0; i < 7; i++){
24709 var d = this.startDay+i;
24713 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24715 m[m.length] = "</tr></thead><tbody><tr>";
24716 for(var i = 0; i < 42; i++) {
24717 if(i % 7 == 0 && i != 0){
24718 m[m.length] = "</tr><tr>";
24720 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24722 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24723 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24725 var el = document.createElement("div");
24726 el.className = "x-date-picker";
24727 el.innerHTML = m.join("");
24729 container.dom.insertBefore(el, position);
24731 this.el = Roo.get(el);
24732 this.eventEl = Roo.get(el.firstChild);
24734 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24735 handler: this.showPrevMonth,
24737 preventDefault:true,
24741 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24742 handler: this.showNextMonth,
24744 preventDefault:true,
24748 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24750 this.monthPicker = this.el.down('div.x-date-mp');
24751 this.monthPicker.enableDisplayMode('block');
24753 var kn = new Roo.KeyNav(this.eventEl, {
24754 "left" : function(e){
24756 this.showPrevMonth() :
24757 this.update(this.activeDate.add("d", -1));
24760 "right" : function(e){
24762 this.showNextMonth() :
24763 this.update(this.activeDate.add("d", 1));
24766 "up" : function(e){
24768 this.showNextYear() :
24769 this.update(this.activeDate.add("d", -7));
24772 "down" : function(e){
24774 this.showPrevYear() :
24775 this.update(this.activeDate.add("d", 7));
24778 "pageUp" : function(e){
24779 this.showNextMonth();
24782 "pageDown" : function(e){
24783 this.showPrevMonth();
24786 "enter" : function(e){
24787 e.stopPropagation();
24794 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24796 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24798 this.el.unselectable();
24800 this.cells = this.el.select("table.x-date-inner tbody td");
24801 this.textNodes = this.el.query("table.x-date-inner tbody span");
24803 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24805 tooltip: this.monthYearText
24808 this.mbtn.on('click', this.showMonthPicker, this);
24809 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24812 var today = (new Date()).dateFormat(this.format);
24814 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24815 if (this.showClear) {
24816 baseTb.add( new Roo.Toolbar.Fill());
24819 text: String.format(this.todayText, today),
24820 tooltip: String.format(this.todayTip, today),
24821 handler: this.selectToday,
24825 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24828 if (this.showClear) {
24830 baseTb.add( new Roo.Toolbar.Fill());
24833 cls: 'x-btn-icon x-btn-clear',
24834 handler: function() {
24836 this.fireEvent("select", this, '');
24846 this.update(this.value);
24849 createMonthPicker : function(){
24850 if(!this.monthPicker.dom.firstChild){
24851 var buf = ['<table border="0" cellspacing="0">'];
24852 for(var i = 0; i < 6; i++){
24854 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24855 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24857 '<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>' :
24858 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24862 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24864 '</button><button type="button" class="x-date-mp-cancel">',
24866 '</button></td></tr>',
24869 this.monthPicker.update(buf.join(''));
24870 this.monthPicker.on('click', this.onMonthClick, this);
24871 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24873 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24874 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24876 this.mpMonths.each(function(m, a, i){
24879 m.dom.xmonth = 5 + Math.round(i * .5);
24881 m.dom.xmonth = Math.round((i-1) * .5);
24887 showMonthPicker : function(){
24888 this.createMonthPicker();
24889 var size = this.el.getSize();
24890 this.monthPicker.setSize(size);
24891 this.monthPicker.child('table').setSize(size);
24893 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24894 this.updateMPMonth(this.mpSelMonth);
24895 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24896 this.updateMPYear(this.mpSelYear);
24898 this.monthPicker.slideIn('t', {duration:.2});
24901 updateMPYear : function(y){
24903 var ys = this.mpYears.elements;
24904 for(var i = 1; i <= 10; i++){
24905 var td = ys[i-1], y2;
24907 y2 = y + Math.round(i * .5);
24908 td.firstChild.innerHTML = y2;
24911 y2 = y - (5-Math.round(i * .5));
24912 td.firstChild.innerHTML = y2;
24915 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24919 updateMPMonth : function(sm){
24920 this.mpMonths.each(function(m, a, i){
24921 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24925 selectMPMonth: function(m){
24929 onMonthClick : function(e, t){
24931 var el = new Roo.Element(t), pn;
24932 if(el.is('button.x-date-mp-cancel')){
24933 this.hideMonthPicker();
24935 else if(el.is('button.x-date-mp-ok')){
24936 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24937 this.hideMonthPicker();
24939 else if(pn = el.up('td.x-date-mp-month', 2)){
24940 this.mpMonths.removeClass('x-date-mp-sel');
24941 pn.addClass('x-date-mp-sel');
24942 this.mpSelMonth = pn.dom.xmonth;
24944 else if(pn = el.up('td.x-date-mp-year', 2)){
24945 this.mpYears.removeClass('x-date-mp-sel');
24946 pn.addClass('x-date-mp-sel');
24947 this.mpSelYear = pn.dom.xyear;
24949 else if(el.is('a.x-date-mp-prev')){
24950 this.updateMPYear(this.mpyear-10);
24952 else if(el.is('a.x-date-mp-next')){
24953 this.updateMPYear(this.mpyear+10);
24957 onMonthDblClick : function(e, t){
24959 var el = new Roo.Element(t), pn;
24960 if(pn = el.up('td.x-date-mp-month', 2)){
24961 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24962 this.hideMonthPicker();
24964 else if(pn = el.up('td.x-date-mp-year', 2)){
24965 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24966 this.hideMonthPicker();
24970 hideMonthPicker : function(disableAnim){
24971 if(this.monthPicker){
24972 if(disableAnim === true){
24973 this.monthPicker.hide();
24975 this.monthPicker.slideOut('t', {duration:.2});
24981 showPrevMonth : function(e){
24982 this.update(this.activeDate.add("mo", -1));
24986 showNextMonth : function(e){
24987 this.update(this.activeDate.add("mo", 1));
24991 showPrevYear : function(){
24992 this.update(this.activeDate.add("y", -1));
24996 showNextYear : function(){
24997 this.update(this.activeDate.add("y", 1));
25001 handleMouseWheel : function(e){
25002 var delta = e.getWheelDelta();
25004 this.showPrevMonth();
25006 } else if(delta < 0){
25007 this.showNextMonth();
25013 handleDateClick : function(e, t){
25015 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25016 this.setValue(new Date(t.dateValue));
25017 this.fireEvent("select", this, this.value);
25022 selectToday : function(){
25023 this.setValue(new Date().clearTime());
25024 this.fireEvent("select", this, this.value);
25028 update : function(date){
25029 var vd = this.activeDate;
25030 this.activeDate = date;
25032 var t = date.getTime();
25033 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25034 this.cells.removeClass("x-date-selected");
25035 this.cells.each(function(c){
25036 if(c.dom.firstChild.dateValue == t){
25037 c.addClass("x-date-selected");
25038 setTimeout(function(){
25039 try{c.dom.firstChild.focus();}catch(e){}
25047 var days = date.getDaysInMonth();
25048 var firstOfMonth = date.getFirstDateOfMonth();
25049 var startingPos = firstOfMonth.getDay()-this.startDay;
25051 if(startingPos <= this.startDay){
25055 var pm = date.add("mo", -1);
25056 var prevStart = pm.getDaysInMonth()-startingPos;
25058 var cells = this.cells.elements;
25059 var textEls = this.textNodes;
25060 days += startingPos;
25062 // convert everything to numbers so it's fast
25063 var day = 86400000;
25064 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25065 var today = new Date().clearTime().getTime();
25066 var sel = date.clearTime().getTime();
25067 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25068 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25069 var ddMatch = this.disabledDatesRE;
25070 var ddText = this.disabledDatesText;
25071 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25072 var ddaysText = this.disabledDaysText;
25073 var format = this.format;
25075 var setCellClass = function(cal, cell){
25077 var t = d.getTime();
25078 cell.firstChild.dateValue = t;
25080 cell.className += " x-date-today";
25081 cell.title = cal.todayText;
25084 cell.className += " x-date-selected";
25085 setTimeout(function(){
25086 try{cell.firstChild.focus();}catch(e){}
25091 cell.className = " x-date-disabled";
25092 cell.title = cal.minText;
25096 cell.className = " x-date-disabled";
25097 cell.title = cal.maxText;
25101 if(ddays.indexOf(d.getDay()) != -1){
25102 cell.title = ddaysText;
25103 cell.className = " x-date-disabled";
25106 if(ddMatch && format){
25107 var fvalue = d.dateFormat(format);
25108 if(ddMatch.test(fvalue)){
25109 cell.title = ddText.replace("%0", fvalue);
25110 cell.className = " x-date-disabled";
25116 for(; i < startingPos; i++) {
25117 textEls[i].innerHTML = (++prevStart);
25118 d.setDate(d.getDate()+1);
25119 cells[i].className = "x-date-prevday";
25120 setCellClass(this, cells[i]);
25122 for(; i < days; i++){
25123 intDay = i - startingPos + 1;
25124 textEls[i].innerHTML = (intDay);
25125 d.setDate(d.getDate()+1);
25126 cells[i].className = "x-date-active";
25127 setCellClass(this, cells[i]);
25130 for(; i < 42; i++) {
25131 textEls[i].innerHTML = (++extraDays);
25132 d.setDate(d.getDate()+1);
25133 cells[i].className = "x-date-nextday";
25134 setCellClass(this, cells[i]);
25137 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25139 if(!this.internalRender){
25140 var main = this.el.dom.firstChild;
25141 var w = main.offsetWidth;
25142 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25143 Roo.fly(main).setWidth(w);
25144 this.internalRender = true;
25145 // opera does not respect the auto grow header center column
25146 // then, after it gets a width opera refuses to recalculate
25147 // without a second pass
25148 if(Roo.isOpera && !this.secondPass){
25149 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25150 this.secondPass = true;
25151 this.update.defer(10, this, [date]);
25157 * Ext JS Library 1.1.1
25158 * Copyright(c) 2006-2007, Ext JS, LLC.
25160 * Originally Released Under LGPL - original licence link has changed is not relivant.
25163 * <script type="text/javascript">
25166 * @class Roo.TabPanel
25167 * @extends Roo.util.Observable
25168 * A lightweight tab container.
25172 // basic tabs 1, built from existing content
25173 var tabs = new Roo.TabPanel("tabs1");
25174 tabs.addTab("script", "View Script");
25175 tabs.addTab("markup", "View Markup");
25176 tabs.activate("script");
25178 // more advanced tabs, built from javascript
25179 var jtabs = new Roo.TabPanel("jtabs");
25180 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25182 // set up the UpdateManager
25183 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25184 var updater = tab2.getUpdateManager();
25185 updater.setDefaultUrl("ajax1.htm");
25186 tab2.on('activate', updater.refresh, updater, true);
25188 // Use setUrl for Ajax loading
25189 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25190 tab3.setUrl("ajax2.htm", null, true);
25193 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25196 jtabs.activate("jtabs-1");
25199 * Create a new TabPanel.
25200 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25201 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25203 Roo.TabPanel = function(container, config){
25205 * The container element for this TabPanel.
25206 * @type Roo.Element
25208 this.el = Roo.get(container, true);
25210 if(typeof config == "boolean"){
25211 this.tabPosition = config ? "bottom" : "top";
25213 Roo.apply(this, config);
25216 if(this.tabPosition == "bottom"){
25217 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25218 this.el.addClass("x-tabs-bottom");
25220 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25221 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25222 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25224 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25226 if(this.tabPosition != "bottom"){
25227 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
25228 * @type Roo.Element
25230 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25231 this.el.addClass("x-tabs-top");
25235 this.bodyEl.setStyle("position", "relative");
25237 this.active = null;
25238 this.activateDelegate = this.activate.createDelegate(this);
25243 * Fires when the active tab changes
25244 * @param {Roo.TabPanel} this
25245 * @param {Roo.TabPanelItem} activePanel The new active tab
25249 * @event beforetabchange
25250 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25251 * @param {Roo.TabPanel} this
25252 * @param {Object} e Set cancel to true on this object to cancel the tab change
25253 * @param {Roo.TabPanelItem} tab The tab being changed to
25255 "beforetabchange" : true
25258 Roo.EventManager.onWindowResize(this.onResize, this);
25259 this.cpad = this.el.getPadding("lr");
25260 this.hiddenCount = 0;
25263 // toolbar on the tabbar support...
25264 if (this.toolbar) {
25265 var tcfg = this.toolbar;
25266 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
25267 this.toolbar = new Roo.Toolbar(tcfg);
25268 if (Roo.isSafari) {
25269 var tbl = tcfg.container.child('table', true);
25270 tbl.setAttribute('width', '100%');
25277 Roo.TabPanel.superclass.constructor.call(this);
25280 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25282 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25284 tabPosition : "top",
25286 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25288 currentTabWidth : 0,
25290 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25294 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25298 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25300 preferredTabWidth : 175,
25302 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25304 resizeTabs : false,
25306 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25308 monitorResize : true,
25310 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
25315 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25316 * @param {String} id The id of the div to use <b>or create</b>
25317 * @param {String} text The text for the tab
25318 * @param {String} content (optional) Content to put in the TabPanelItem body
25319 * @param {Boolean} closable (optional) True to create a close icon on the tab
25320 * @return {Roo.TabPanelItem} The created TabPanelItem
25322 addTab : function(id, text, content, closable){
25323 var item = new Roo.TabPanelItem(this, id, text, closable);
25324 this.addTabItem(item);
25326 item.setContent(content);
25332 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25333 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25334 * @return {Roo.TabPanelItem}
25336 getTab : function(id){
25337 return this.items[id];
25341 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25342 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25344 hideTab : function(id){
25345 var t = this.items[id];
25348 this.hiddenCount++;
25349 this.autoSizeTabs();
25354 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25355 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25357 unhideTab : function(id){
25358 var t = this.items[id];
25360 t.setHidden(false);
25361 this.hiddenCount--;
25362 this.autoSizeTabs();
25367 * Adds an existing {@link Roo.TabPanelItem}.
25368 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25370 addTabItem : function(item){
25371 this.items[item.id] = item;
25372 this.items.push(item);
25373 if(this.resizeTabs){
25374 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25375 this.autoSizeTabs();
25382 * Removes a {@link Roo.TabPanelItem}.
25383 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25385 removeTab : function(id){
25386 var items = this.items;
25387 var tab = items[id];
25388 if(!tab) { return; }
25389 var index = items.indexOf(tab);
25390 if(this.active == tab && items.length > 1){
25391 var newTab = this.getNextAvailable(index);
25396 this.stripEl.dom.removeChild(tab.pnode.dom);
25397 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25398 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25400 items.splice(index, 1);
25401 delete this.items[tab.id];
25402 tab.fireEvent("close", tab);
25403 tab.purgeListeners();
25404 this.autoSizeTabs();
25407 getNextAvailable : function(start){
25408 var items = this.items;
25410 // look for a next tab that will slide over to
25411 // replace the one being removed
25412 while(index < items.length){
25413 var item = items[++index];
25414 if(item && !item.isHidden()){
25418 // if one isn't found select the previous tab (on the left)
25421 var item = items[--index];
25422 if(item && !item.isHidden()){
25430 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25431 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25433 disableTab : function(id){
25434 var tab = this.items[id];
25435 if(tab && this.active != tab){
25441 * Enables a {@link Roo.TabPanelItem} that is disabled.
25442 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25444 enableTab : function(id){
25445 var tab = this.items[id];
25450 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25451 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25452 * @return {Roo.TabPanelItem} The TabPanelItem.
25454 activate : function(id){
25455 var tab = this.items[id];
25459 if(tab == this.active || tab.disabled){
25463 this.fireEvent("beforetabchange", this, e, tab);
25464 if(e.cancel !== true && !tab.disabled){
25466 this.active.hide();
25468 this.active = this.items[id];
25469 this.active.show();
25470 this.fireEvent("tabchange", this, this.active);
25476 * Gets the active {@link Roo.TabPanelItem}.
25477 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25479 getActiveTab : function(){
25480 return this.active;
25484 * Updates the tab body element to fit the height of the container element
25485 * for overflow scrolling
25486 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25488 syncHeight : function(targetHeight){
25489 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25490 var bm = this.bodyEl.getMargins();
25491 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25492 this.bodyEl.setHeight(newHeight);
25496 onResize : function(){
25497 if(this.monitorResize){
25498 this.autoSizeTabs();
25503 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25505 beginUpdate : function(){
25506 this.updating = true;
25510 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25512 endUpdate : function(){
25513 this.updating = false;
25514 this.autoSizeTabs();
25518 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25520 autoSizeTabs : function(){
25521 var count = this.items.length;
25522 var vcount = count - this.hiddenCount;
25523 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25524 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25525 var availWidth = Math.floor(w / vcount);
25526 var b = this.stripBody;
25527 if(b.getWidth() > w){
25528 var tabs = this.items;
25529 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25530 if(availWidth < this.minTabWidth){
25531 /*if(!this.sleft){ // incomplete scrolling code
25532 this.createScrollButtons();
25535 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25538 if(this.currentTabWidth < this.preferredTabWidth){
25539 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25545 * Returns the number of tabs in this TabPanel.
25548 getCount : function(){
25549 return this.items.length;
25553 * Resizes all the tabs to the passed width
25554 * @param {Number} The new width
25556 setTabWidth : function(width){
25557 this.currentTabWidth = width;
25558 for(var i = 0, len = this.items.length; i < len; i++) {
25559 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25564 * Destroys this TabPanel
25565 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25567 destroy : function(removeEl){
25568 Roo.EventManager.removeResizeListener(this.onResize, this);
25569 for(var i = 0, len = this.items.length; i < len; i++){
25570 this.items[i].purgeListeners();
25572 if(removeEl === true){
25573 this.el.update("");
25580 * @class Roo.TabPanelItem
25581 * @extends Roo.util.Observable
25582 * Represents an individual item (tab plus body) in a TabPanel.
25583 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25584 * @param {String} id The id of this TabPanelItem
25585 * @param {String} text The text for the tab of this TabPanelItem
25586 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25588 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25590 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25591 * @type Roo.TabPanel
25593 this.tabPanel = tabPanel;
25595 * The id for this TabPanelItem
25600 this.disabled = false;
25604 this.loaded = false;
25605 this.closable = closable;
25608 * The body element for this TabPanelItem.
25609 * @type Roo.Element
25611 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25612 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25613 this.bodyEl.setStyle("display", "block");
25614 this.bodyEl.setStyle("zoom", "1");
25617 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25619 this.el = Roo.get(els.el, true);
25620 this.inner = Roo.get(els.inner, true);
25621 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25622 this.pnode = Roo.get(els.el.parentNode, true);
25623 this.el.on("mousedown", this.onTabMouseDown, this);
25624 this.el.on("click", this.onTabClick, this);
25627 var c = Roo.get(els.close, true);
25628 c.dom.title = this.closeText;
25629 c.addClassOnOver("close-over");
25630 c.on("click", this.closeClick, this);
25636 * Fires when this tab becomes the active tab.
25637 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25638 * @param {Roo.TabPanelItem} this
25642 * @event beforeclose
25643 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25644 * @param {Roo.TabPanelItem} this
25645 * @param {Object} e Set cancel to true on this object to cancel the close.
25647 "beforeclose": true,
25650 * Fires when this tab is closed.
25651 * @param {Roo.TabPanelItem} this
25655 * @event deactivate
25656 * Fires when this tab is no longer the active tab.
25657 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25658 * @param {Roo.TabPanelItem} this
25660 "deactivate" : true
25662 this.hidden = false;
25664 Roo.TabPanelItem.superclass.constructor.call(this);
25667 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25668 purgeListeners : function(){
25669 Roo.util.Observable.prototype.purgeListeners.call(this);
25670 this.el.removeAllListeners();
25673 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25676 this.pnode.addClass("on");
25679 this.tabPanel.stripWrap.repaint();
25681 this.fireEvent("activate", this.tabPanel, this);
25685 * Returns true if this tab is the active tab.
25686 * @return {Boolean}
25688 isActive : function(){
25689 return this.tabPanel.getActiveTab() == this;
25693 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25696 this.pnode.removeClass("on");
25698 this.fireEvent("deactivate", this.tabPanel, this);
25701 hideAction : function(){
25702 this.bodyEl.hide();
25703 this.bodyEl.setStyle("position", "absolute");
25704 this.bodyEl.setLeft("-20000px");
25705 this.bodyEl.setTop("-20000px");
25708 showAction : function(){
25709 this.bodyEl.setStyle("position", "relative");
25710 this.bodyEl.setTop("");
25711 this.bodyEl.setLeft("");
25712 this.bodyEl.show();
25716 * Set the tooltip for the tab.
25717 * @param {String} tooltip The tab's tooltip
25719 setTooltip : function(text){
25720 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25721 this.textEl.dom.qtip = text;
25722 this.textEl.dom.removeAttribute('title');
25724 this.textEl.dom.title = text;
25728 onTabClick : function(e){
25729 e.preventDefault();
25730 this.tabPanel.activate(this.id);
25733 onTabMouseDown : function(e){
25734 e.preventDefault();
25735 this.tabPanel.activate(this.id);
25738 getWidth : function(){
25739 return this.inner.getWidth();
25742 setWidth : function(width){
25743 var iwidth = width - this.pnode.getPadding("lr");
25744 this.inner.setWidth(iwidth);
25745 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25746 this.pnode.setWidth(width);
25750 * Show or hide the tab
25751 * @param {Boolean} hidden True to hide or false to show.
25753 setHidden : function(hidden){
25754 this.hidden = hidden;
25755 this.pnode.setStyle("display", hidden ? "none" : "");
25759 * Returns true if this tab is "hidden"
25760 * @return {Boolean}
25762 isHidden : function(){
25763 return this.hidden;
25767 * Returns the text for this tab
25770 getText : function(){
25774 autoSize : function(){
25775 //this.el.beginMeasure();
25776 this.textEl.setWidth(1);
25777 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25778 //this.el.endMeasure();
25782 * Sets the text for the tab (Note: this also sets the tooltip text)
25783 * @param {String} text The tab's text and tooltip
25785 setText : function(text){
25787 this.textEl.update(text);
25788 this.setTooltip(text);
25789 if(!this.tabPanel.resizeTabs){
25794 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25796 activate : function(){
25797 this.tabPanel.activate(this.id);
25801 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25803 disable : function(){
25804 if(this.tabPanel.active != this){
25805 this.disabled = true;
25806 this.pnode.addClass("disabled");
25811 * Enables this TabPanelItem if it was previously disabled.
25813 enable : function(){
25814 this.disabled = false;
25815 this.pnode.removeClass("disabled");
25819 * Sets the content for this TabPanelItem.
25820 * @param {String} content The content
25821 * @param {Boolean} loadScripts true to look for and load scripts
25823 setContent : function(content, loadScripts){
25824 this.bodyEl.update(content, loadScripts);
25828 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25829 * @return {Roo.UpdateManager} The UpdateManager
25831 getUpdateManager : function(){
25832 return this.bodyEl.getUpdateManager();
25836 * Set a URL to be used to load the content for this TabPanelItem.
25837 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25838 * @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)
25839 * @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)
25840 * @return {Roo.UpdateManager} The UpdateManager
25842 setUrl : function(url, params, loadOnce){
25843 if(this.refreshDelegate){
25844 this.un('activate', this.refreshDelegate);
25846 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25847 this.on("activate", this.refreshDelegate);
25848 return this.bodyEl.getUpdateManager();
25852 _handleRefresh : function(url, params, loadOnce){
25853 if(!loadOnce || !this.loaded){
25854 var updater = this.bodyEl.getUpdateManager();
25855 updater.update(url, params, this._setLoaded.createDelegate(this));
25860 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25861 * Will fail silently if the setUrl method has not been called.
25862 * This does not activate the panel, just updates its content.
25864 refresh : function(){
25865 if(this.refreshDelegate){
25866 this.loaded = false;
25867 this.refreshDelegate();
25872 _setLoaded : function(){
25873 this.loaded = true;
25877 closeClick : function(e){
25880 this.fireEvent("beforeclose", this, o);
25881 if(o.cancel !== true){
25882 this.tabPanel.removeTab(this.id);
25886 * The text displayed in the tooltip for the close icon.
25889 closeText : "Close this tab"
25893 Roo.TabPanel.prototype.createStrip = function(container){
25894 var strip = document.createElement("div");
25895 strip.className = "x-tabs-wrap";
25896 container.appendChild(strip);
25900 Roo.TabPanel.prototype.createStripList = function(strip){
25901 // div wrapper for retard IE
25902 // returns the "tr" element.
25903 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
25904 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
25905 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
25906 return strip.firstChild.firstChild.firstChild.firstChild;
25909 Roo.TabPanel.prototype.createBody = function(container){
25910 var body = document.createElement("div");
25911 Roo.id(body, "tab-body");
25912 Roo.fly(body).addClass("x-tabs-body");
25913 container.appendChild(body);
25917 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25918 var body = Roo.getDom(id);
25920 body = document.createElement("div");
25923 Roo.fly(body).addClass("x-tabs-item-body");
25924 bodyEl.insertBefore(body, bodyEl.firstChild);
25928 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25929 var td = document.createElement("td");
25930 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
25931 //stripEl.appendChild(td);
25933 td.className = "x-tabs-closable";
25934 if(!this.closeTpl){
25935 this.closeTpl = new Roo.Template(
25936 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25937 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25938 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25941 var el = this.closeTpl.overwrite(td, {"text": text});
25942 var close = el.getElementsByTagName("div")[0];
25943 var inner = el.getElementsByTagName("em")[0];
25944 return {"el": el, "close": close, "inner": inner};
25947 this.tabTpl = new Roo.Template(
25948 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25949 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25952 var el = this.tabTpl.overwrite(td, {"text": text});
25953 var inner = el.getElementsByTagName("em")[0];
25954 return {"el": el, "inner": inner};
25958 * Ext JS Library 1.1.1
25959 * Copyright(c) 2006-2007, Ext JS, LLC.
25961 * Originally Released Under LGPL - original licence link has changed is not relivant.
25964 * <script type="text/javascript">
25968 * @class Roo.Button
25969 * @extends Roo.util.Observable
25970 * Simple Button class
25971 * @cfg {String} text The button text
25972 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25973 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25974 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25975 * @cfg {Object} scope The scope of the handler
25976 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25977 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25978 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25979 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25980 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25981 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25982 applies if enableToggle = true)
25983 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25984 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25985 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25987 * Create a new button
25988 * @param {Object} config The config object
25990 Roo.Button = function(renderTo, config)
25994 renderTo = config.renderTo || false;
25997 Roo.apply(this, config);
26001 * Fires when this button is clicked
26002 * @param {Button} this
26003 * @param {EventObject} e The click event
26008 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26009 * @param {Button} this
26010 * @param {Boolean} pressed
26015 * Fires when the mouse hovers over the button
26016 * @param {Button} this
26017 * @param {Event} e The event object
26019 'mouseover' : true,
26022 * Fires when the mouse exits the button
26023 * @param {Button} this
26024 * @param {Event} e The event object
26029 * Fires when the button is rendered
26030 * @param {Button} this
26035 this.menu = Roo.menu.MenuMgr.get(this.menu);
26037 // register listeners first!! - so render can be captured..
26038 Roo.util.Observable.call(this);
26040 this.render(renderTo);
26046 Roo.extend(Roo.Button, Roo.util.Observable, {
26052 * Read-only. True if this button is hidden
26057 * Read-only. True if this button is disabled
26062 * Read-only. True if this button is pressed (only if enableToggle = true)
26068 * @cfg {Number} tabIndex
26069 * The DOM tabIndex for this button (defaults to undefined)
26071 tabIndex : undefined,
26074 * @cfg {Boolean} enableToggle
26075 * True to enable pressed/not pressed toggling (defaults to false)
26077 enableToggle: false,
26079 * @cfg {Mixed} menu
26080 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26084 * @cfg {String} menuAlign
26085 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26087 menuAlign : "tl-bl?",
26090 * @cfg {String} iconCls
26091 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26093 iconCls : undefined,
26095 * @cfg {String} type
26096 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26101 menuClassTarget: 'tr',
26104 * @cfg {String} clickEvent
26105 * The type of event to map to the button's event handler (defaults to 'click')
26107 clickEvent : 'click',
26110 * @cfg {Boolean} handleMouseEvents
26111 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26113 handleMouseEvents : true,
26116 * @cfg {String} tooltipType
26117 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26119 tooltipType : 'qtip',
26122 * @cfg {String} cls
26123 * A CSS class to apply to the button's main element.
26127 * @cfg {Roo.Template} template (Optional)
26128 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26129 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26130 * require code modifications if required elements (e.g. a button) aren't present.
26134 render : function(renderTo){
26136 if(this.hideParent){
26137 this.parentEl = Roo.get(renderTo);
26139 if(!this.dhconfig){
26140 if(!this.template){
26141 if(!Roo.Button.buttonTemplate){
26142 // hideous table template
26143 Roo.Button.buttonTemplate = new Roo.Template(
26144 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26145 '<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>',
26146 "</tr></tbody></table>");
26148 this.template = Roo.Button.buttonTemplate;
26150 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26151 var btnEl = btn.child("button:first");
26152 btnEl.on('focus', this.onFocus, this);
26153 btnEl.on('blur', this.onBlur, this);
26155 btn.addClass(this.cls);
26158 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26161 btnEl.addClass(this.iconCls);
26163 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26166 if(this.tabIndex !== undefined){
26167 btnEl.dom.tabIndex = this.tabIndex;
26170 if(typeof this.tooltip == 'object'){
26171 Roo.QuickTips.tips(Roo.apply({
26175 btnEl.dom[this.tooltipType] = this.tooltip;
26179 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26183 this.el.dom.id = this.el.id = this.id;
26186 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26187 this.menu.on("show", this.onMenuShow, this);
26188 this.menu.on("hide", this.onMenuHide, this);
26190 btn.addClass("x-btn");
26191 if(Roo.isIE && !Roo.isIE7){
26192 this.autoWidth.defer(1, this);
26196 if(this.handleMouseEvents){
26197 btn.on("mouseover", this.onMouseOver, this);
26198 btn.on("mouseout", this.onMouseOut, this);
26199 btn.on("mousedown", this.onMouseDown, this);
26201 btn.on(this.clickEvent, this.onClick, this);
26202 //btn.on("mouseup", this.onMouseUp, this);
26209 Roo.ButtonToggleMgr.register(this);
26211 this.el.addClass("x-btn-pressed");
26214 var repeater = new Roo.util.ClickRepeater(btn,
26215 typeof this.repeat == "object" ? this.repeat : {}
26217 repeater.on("click", this.onClick, this);
26220 this.fireEvent('render', this);
26224 * Returns the button's underlying element
26225 * @return {Roo.Element} The element
26227 getEl : function(){
26232 * Destroys this Button and removes any listeners.
26234 destroy : function(){
26235 Roo.ButtonToggleMgr.unregister(this);
26236 this.el.removeAllListeners();
26237 this.purgeListeners();
26242 autoWidth : function(){
26244 this.el.setWidth("auto");
26245 if(Roo.isIE7 && Roo.isStrict){
26246 var ib = this.el.child('button');
26247 if(ib && ib.getWidth() > 20){
26249 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26254 this.el.beginMeasure();
26256 if(this.el.getWidth() < this.minWidth){
26257 this.el.setWidth(this.minWidth);
26260 this.el.endMeasure();
26267 * Assigns this button's click handler
26268 * @param {Function} handler The function to call when the button is clicked
26269 * @param {Object} scope (optional) Scope for the function passed in
26271 setHandler : function(handler, scope){
26272 this.handler = handler;
26273 this.scope = scope;
26277 * Sets this button's text
26278 * @param {String} text The button text
26280 setText : function(text){
26283 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26289 * Gets the text for this button
26290 * @return {String} The button text
26292 getText : function(){
26300 this.hidden = false;
26302 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26310 this.hidden = true;
26312 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26317 * Convenience function for boolean show/hide
26318 * @param {Boolean} visible True to show, false to hide
26320 setVisible: function(visible){
26329 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26330 * @param {Boolean} state (optional) Force a particular state
26332 toggle : function(state){
26333 state = state === undefined ? !this.pressed : state;
26334 if(state != this.pressed){
26336 this.el.addClass("x-btn-pressed");
26337 this.pressed = true;
26338 this.fireEvent("toggle", this, true);
26340 this.el.removeClass("x-btn-pressed");
26341 this.pressed = false;
26342 this.fireEvent("toggle", this, false);
26344 if(this.toggleHandler){
26345 this.toggleHandler.call(this.scope || this, this, state);
26353 focus : function(){
26354 this.el.child('button:first').focus();
26358 * Disable this button
26360 disable : function(){
26362 this.el.addClass("x-btn-disabled");
26364 this.disabled = true;
26368 * Enable this button
26370 enable : function(){
26372 this.el.removeClass("x-btn-disabled");
26374 this.disabled = false;
26378 * Convenience function for boolean enable/disable
26379 * @param {Boolean} enabled True to enable, false to disable
26381 setDisabled : function(v){
26382 this[v !== true ? "enable" : "disable"]();
26386 onClick : function(e){
26388 e.preventDefault();
26393 if(!this.disabled){
26394 if(this.enableToggle){
26397 if(this.menu && !this.menu.isVisible()){
26398 this.menu.show(this.el, this.menuAlign);
26400 this.fireEvent("click", this, e);
26402 this.el.removeClass("x-btn-over");
26403 this.handler.call(this.scope || this, this, e);
26408 onMouseOver : function(e){
26409 if(!this.disabled){
26410 this.el.addClass("x-btn-over");
26411 this.fireEvent('mouseover', this, e);
26415 onMouseOut : function(e){
26416 if(!e.within(this.el, true)){
26417 this.el.removeClass("x-btn-over");
26418 this.fireEvent('mouseout', this, e);
26422 onFocus : function(e){
26423 if(!this.disabled){
26424 this.el.addClass("x-btn-focus");
26428 onBlur : function(e){
26429 this.el.removeClass("x-btn-focus");
26432 onMouseDown : function(e){
26433 if(!this.disabled && e.button == 0){
26434 this.el.addClass("x-btn-click");
26435 Roo.get(document).on('mouseup', this.onMouseUp, this);
26439 onMouseUp : function(e){
26441 this.el.removeClass("x-btn-click");
26442 Roo.get(document).un('mouseup', this.onMouseUp, this);
26446 onMenuShow : function(e){
26447 this.el.addClass("x-btn-menu-active");
26450 onMenuHide : function(e){
26451 this.el.removeClass("x-btn-menu-active");
26455 // Private utility class used by Button
26456 Roo.ButtonToggleMgr = function(){
26459 function toggleGroup(btn, state){
26461 var g = groups[btn.toggleGroup];
26462 for(var i = 0, l = g.length; i < l; i++){
26464 g[i].toggle(false);
26471 register : function(btn){
26472 if(!btn.toggleGroup){
26475 var g = groups[btn.toggleGroup];
26477 g = groups[btn.toggleGroup] = [];
26480 btn.on("toggle", toggleGroup);
26483 unregister : function(btn){
26484 if(!btn.toggleGroup){
26487 var g = groups[btn.toggleGroup];
26490 btn.un("toggle", toggleGroup);
26496 * Ext JS Library 1.1.1
26497 * Copyright(c) 2006-2007, Ext JS, LLC.
26499 * Originally Released Under LGPL - original licence link has changed is not relivant.
26502 * <script type="text/javascript">
26506 * @class Roo.SplitButton
26507 * @extends Roo.Button
26508 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26509 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26510 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26511 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26512 * @cfg {String} arrowTooltip The title attribute of the arrow
26514 * Create a new menu button
26515 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26516 * @param {Object} config The config object
26518 Roo.SplitButton = function(renderTo, config){
26519 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26521 * @event arrowclick
26522 * Fires when this button's arrow is clicked
26523 * @param {SplitButton} this
26524 * @param {EventObject} e The click event
26526 this.addEvents({"arrowclick":true});
26529 Roo.extend(Roo.SplitButton, Roo.Button, {
26530 render : function(renderTo){
26531 // this is one sweet looking template!
26532 var tpl = new Roo.Template(
26533 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26534 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26535 '<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>',
26536 "</tbody></table></td><td>",
26537 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26538 '<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>',
26539 "</tbody></table></td></tr></table>"
26541 var btn = tpl.append(renderTo, [this.text, this.type], true);
26542 var btnEl = btn.child("button");
26544 btn.addClass(this.cls);
26547 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26550 btnEl.addClass(this.iconCls);
26552 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26556 if(this.handleMouseEvents){
26557 btn.on("mouseover", this.onMouseOver, this);
26558 btn.on("mouseout", this.onMouseOut, this);
26559 btn.on("mousedown", this.onMouseDown, this);
26560 btn.on("mouseup", this.onMouseUp, this);
26562 btn.on(this.clickEvent, this.onClick, this);
26564 if(typeof this.tooltip == 'object'){
26565 Roo.QuickTips.tips(Roo.apply({
26569 btnEl.dom[this.tooltipType] = this.tooltip;
26572 if(this.arrowTooltip){
26573 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26582 this.el.addClass("x-btn-pressed");
26584 if(Roo.isIE && !Roo.isIE7){
26585 this.autoWidth.defer(1, this);
26590 this.menu.on("show", this.onMenuShow, this);
26591 this.menu.on("hide", this.onMenuHide, this);
26593 this.fireEvent('render', this);
26597 autoWidth : function(){
26599 var tbl = this.el.child("table:first");
26600 var tbl2 = this.el.child("table:last");
26601 this.el.setWidth("auto");
26602 tbl.setWidth("auto");
26603 if(Roo.isIE7 && Roo.isStrict){
26604 var ib = this.el.child('button:first');
26605 if(ib && ib.getWidth() > 20){
26607 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26612 this.el.beginMeasure();
26614 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26615 tbl.setWidth(this.minWidth-tbl2.getWidth());
26618 this.el.endMeasure();
26621 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26625 * Sets this button's click handler
26626 * @param {Function} handler The function to call when the button is clicked
26627 * @param {Object} scope (optional) Scope for the function passed above
26629 setHandler : function(handler, scope){
26630 this.handler = handler;
26631 this.scope = scope;
26635 * Sets this button's arrow click handler
26636 * @param {Function} handler The function to call when the arrow is clicked
26637 * @param {Object} scope (optional) Scope for the function passed above
26639 setArrowHandler : function(handler, scope){
26640 this.arrowHandler = handler;
26641 this.scope = scope;
26647 focus : function(){
26649 this.el.child("button:first").focus();
26654 onClick : function(e){
26655 e.preventDefault();
26656 if(!this.disabled){
26657 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26658 if(this.menu && !this.menu.isVisible()){
26659 this.menu.show(this.el, this.menuAlign);
26661 this.fireEvent("arrowclick", this, e);
26662 if(this.arrowHandler){
26663 this.arrowHandler.call(this.scope || this, this, e);
26666 this.fireEvent("click", this, e);
26668 this.handler.call(this.scope || this, this, e);
26674 onMouseDown : function(e){
26675 if(!this.disabled){
26676 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26680 onMouseUp : function(e){
26681 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26686 // backwards compat
26687 Roo.MenuButton = Roo.SplitButton;/*
26689 * Ext JS Library 1.1.1
26690 * Copyright(c) 2006-2007, Ext JS, LLC.
26692 * Originally Released Under LGPL - original licence link has changed is not relivant.
26695 * <script type="text/javascript">
26699 * @class Roo.Toolbar
26700 * Basic Toolbar class.
26702 * Creates a new Toolbar
26703 * @param {Object} config The config object
26705 Roo.Toolbar = function(container, buttons, config)
26707 /// old consturctor format still supported..
26708 if(container instanceof Array){ // omit the container for later rendering
26709 buttons = container;
26713 if (typeof(container) == 'object' && container.xtype) {
26714 config = container;
26715 container = config.container;
26716 buttons = config.buttons; // not really - use items!!
26719 if (config && config.items) {
26720 xitems = config.items;
26721 delete config.items;
26723 Roo.apply(this, config);
26724 this.buttons = buttons;
26727 this.render(container);
26729 Roo.each(xitems, function(b) {
26735 Roo.Toolbar.prototype = {
26737 * @cfg {Roo.data.Store} items
26738 * array of button configs or elements to add
26742 * @cfg {String/HTMLElement/Element} container
26743 * The id or element that will contain the toolbar
26746 render : function(ct){
26747 this.el = Roo.get(ct);
26749 this.el.addClass(this.cls);
26751 // using a table allows for vertical alignment
26752 // 100% width is needed by Safari...
26753 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26754 this.tr = this.el.child("tr", true);
26756 this.items = new Roo.util.MixedCollection(false, function(o){
26757 return o.id || ("item" + (++autoId));
26760 this.add.apply(this, this.buttons);
26761 delete this.buttons;
26766 * Adds element(s) to the toolbar -- this function takes a variable number of
26767 * arguments of mixed type and adds them to the toolbar.
26768 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26770 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26771 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26772 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26773 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26774 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26775 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26776 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26777 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26778 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26780 * @param {Mixed} arg2
26781 * @param {Mixed} etc.
26784 var a = arguments, l = a.length;
26785 for(var i = 0; i < l; i++){
26790 _add : function(el) {
26793 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26796 if (el.applyTo){ // some kind of form field
26797 return this.addField(el);
26799 if (el.render){ // some kind of Toolbar.Item
26800 return this.addItem(el);
26802 if (typeof el == "string"){ // string
26803 if(el == "separator" || el == "-"){
26804 return this.addSeparator();
26807 return this.addSpacer();
26810 return this.addFill();
26812 return this.addText(el);
26815 if(el.tagName){ // element
26816 return this.addElement(el);
26818 if(typeof el == "object"){ // must be button config?
26819 return this.addButton(el);
26821 // and now what?!?!
26827 * Add an Xtype element
26828 * @param {Object} xtype Xtype Object
26829 * @return {Object} created Object
26831 addxtype : function(e){
26832 return this.add(e);
26836 * Returns the Element for this toolbar.
26837 * @return {Roo.Element}
26839 getEl : function(){
26845 * @return {Roo.Toolbar.Item} The separator item
26847 addSeparator : function(){
26848 return this.addItem(new Roo.Toolbar.Separator());
26852 * Adds a spacer element
26853 * @return {Roo.Toolbar.Spacer} The spacer item
26855 addSpacer : function(){
26856 return this.addItem(new Roo.Toolbar.Spacer());
26860 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26861 * @return {Roo.Toolbar.Fill} The fill item
26863 addFill : function(){
26864 return this.addItem(new Roo.Toolbar.Fill());
26868 * Adds any standard HTML element to the toolbar
26869 * @param {String/HTMLElement/Element} el The element or id of the element to add
26870 * @return {Roo.Toolbar.Item} The element's item
26872 addElement : function(el){
26873 return this.addItem(new Roo.Toolbar.Item(el));
26876 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26877 * @type Roo.util.MixedCollection
26882 * Adds any Toolbar.Item or subclass
26883 * @param {Roo.Toolbar.Item} item
26884 * @return {Roo.Toolbar.Item} The item
26886 addItem : function(item){
26887 var td = this.nextBlock();
26889 this.items.add(item);
26894 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26895 * @param {Object/Array} config A button config or array of configs
26896 * @return {Roo.Toolbar.Button/Array}
26898 addButton : function(config){
26899 if(config instanceof Array){
26901 for(var i = 0, len = config.length; i < len; i++) {
26902 buttons.push(this.addButton(config[i]));
26907 if(!(config instanceof Roo.Toolbar.Button)){
26909 new Roo.Toolbar.SplitButton(config) :
26910 new Roo.Toolbar.Button(config);
26912 var td = this.nextBlock();
26919 * Adds text to the toolbar
26920 * @param {String} text The text to add
26921 * @return {Roo.Toolbar.Item} The element's item
26923 addText : function(text){
26924 return this.addItem(new Roo.Toolbar.TextItem(text));
26928 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26929 * @param {Number} index The index where the item is to be inserted
26930 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26931 * @return {Roo.Toolbar.Button/Item}
26933 insertButton : function(index, item){
26934 if(item instanceof Array){
26936 for(var i = 0, len = item.length; i < len; i++) {
26937 buttons.push(this.insertButton(index + i, item[i]));
26941 if (!(item instanceof Roo.Toolbar.Button)){
26942 item = new Roo.Toolbar.Button(item);
26944 var td = document.createElement("td");
26945 this.tr.insertBefore(td, this.tr.childNodes[index]);
26947 this.items.insert(index, item);
26952 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26953 * @param {Object} config
26954 * @return {Roo.Toolbar.Item} The element's item
26956 addDom : function(config, returnEl){
26957 var td = this.nextBlock();
26958 Roo.DomHelper.overwrite(td, config);
26959 var ti = new Roo.Toolbar.Item(td.firstChild);
26961 this.items.add(ti);
26966 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26967 * @type Roo.util.MixedCollection
26972 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26973 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26974 * @param {Roo.form.Field} field
26975 * @return {Roo.ToolbarItem}
26979 addField : function(field) {
26980 if (!this.fields) {
26982 this.fields = new Roo.util.MixedCollection(false, function(o){
26983 return o.id || ("item" + (++autoId));
26988 var td = this.nextBlock();
26990 var ti = new Roo.Toolbar.Item(td.firstChild);
26992 this.items.add(ti);
26993 this.fields.add(field);
27004 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
27005 this.el.child('div').hide();
27013 this.el.child('div').show();
27017 nextBlock : function(){
27018 var td = document.createElement("td");
27019 this.tr.appendChild(td);
27024 destroy : function(){
27025 if(this.items){ // rendered?
27026 Roo.destroy.apply(Roo, this.items.items);
27028 if(this.fields){ // rendered?
27029 Roo.destroy.apply(Roo, this.fields.items);
27031 Roo.Element.uncache(this.el, this.tr);
27036 * @class Roo.Toolbar.Item
27037 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27039 * Creates a new Item
27040 * @param {HTMLElement} el
27042 Roo.Toolbar.Item = function(el){
27043 this.el = Roo.getDom(el);
27044 this.id = Roo.id(this.el);
27045 this.hidden = false;
27048 Roo.Toolbar.Item.prototype = {
27051 * Get this item's HTML Element
27052 * @return {HTMLElement}
27054 getEl : function(){
27059 render : function(td){
27061 td.appendChild(this.el);
27065 * Removes and destroys this item.
27067 destroy : function(){
27068 this.td.parentNode.removeChild(this.td);
27075 this.hidden = false;
27076 this.td.style.display = "";
27083 this.hidden = true;
27084 this.td.style.display = "none";
27088 * Convenience function for boolean show/hide.
27089 * @param {Boolean} visible true to show/false to hide
27091 setVisible: function(visible){
27100 * Try to focus this item.
27102 focus : function(){
27103 Roo.fly(this.el).focus();
27107 * Disables this item.
27109 disable : function(){
27110 Roo.fly(this.td).addClass("x-item-disabled");
27111 this.disabled = true;
27112 this.el.disabled = true;
27116 * Enables this item.
27118 enable : function(){
27119 Roo.fly(this.td).removeClass("x-item-disabled");
27120 this.disabled = false;
27121 this.el.disabled = false;
27127 * @class Roo.Toolbar.Separator
27128 * @extends Roo.Toolbar.Item
27129 * A simple toolbar separator class
27131 * Creates a new Separator
27133 Roo.Toolbar.Separator = function(){
27134 var s = document.createElement("span");
27135 s.className = "ytb-sep";
27136 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27138 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27139 enable:Roo.emptyFn,
27140 disable:Roo.emptyFn,
27145 * @class Roo.Toolbar.Spacer
27146 * @extends Roo.Toolbar.Item
27147 * A simple element that adds extra horizontal space to a toolbar.
27149 * Creates a new Spacer
27151 Roo.Toolbar.Spacer = function(){
27152 var s = document.createElement("div");
27153 s.className = "ytb-spacer";
27154 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27156 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27157 enable:Roo.emptyFn,
27158 disable:Roo.emptyFn,
27163 * @class Roo.Toolbar.Fill
27164 * @extends Roo.Toolbar.Spacer
27165 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27167 * Creates a new Spacer
27169 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27171 render : function(td){
27172 td.style.width = '100%';
27173 Roo.Toolbar.Fill.superclass.render.call(this, td);
27178 * @class Roo.Toolbar.TextItem
27179 * @extends Roo.Toolbar.Item
27180 * A simple class that renders text directly into a toolbar.
27182 * Creates a new TextItem
27183 * @param {String} text
27185 Roo.Toolbar.TextItem = function(text){
27186 if (typeof(text) == 'object') {
27189 var s = document.createElement("span");
27190 s.className = "ytb-text";
27191 s.innerHTML = text;
27192 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27194 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27195 enable:Roo.emptyFn,
27196 disable:Roo.emptyFn,
27201 * @class Roo.Toolbar.Button
27202 * @extends Roo.Button
27203 * A button that renders into a toolbar.
27205 * Creates a new Button
27206 * @param {Object} config A standard {@link Roo.Button} config object
27208 Roo.Toolbar.Button = function(config){
27209 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27211 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27212 render : function(td){
27214 Roo.Toolbar.Button.superclass.render.call(this, td);
27218 * Removes and destroys this button
27220 destroy : function(){
27221 Roo.Toolbar.Button.superclass.destroy.call(this);
27222 this.td.parentNode.removeChild(this.td);
27226 * Shows this button
27229 this.hidden = false;
27230 this.td.style.display = "";
27234 * Hides this button
27237 this.hidden = true;
27238 this.td.style.display = "none";
27242 * Disables this item
27244 disable : function(){
27245 Roo.fly(this.td).addClass("x-item-disabled");
27246 this.disabled = true;
27250 * Enables this item
27252 enable : function(){
27253 Roo.fly(this.td).removeClass("x-item-disabled");
27254 this.disabled = false;
27257 // backwards compat
27258 Roo.ToolbarButton = Roo.Toolbar.Button;
27261 * @class Roo.Toolbar.SplitButton
27262 * @extends Roo.SplitButton
27263 * A menu button that renders into a toolbar.
27265 * Creates a new SplitButton
27266 * @param {Object} config A standard {@link Roo.SplitButton} config object
27268 Roo.Toolbar.SplitButton = function(config){
27269 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27271 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27272 render : function(td){
27274 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27278 * Removes and destroys this button
27280 destroy : function(){
27281 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27282 this.td.parentNode.removeChild(this.td);
27286 * Shows this button
27289 this.hidden = false;
27290 this.td.style.display = "";
27294 * Hides this button
27297 this.hidden = true;
27298 this.td.style.display = "none";
27302 // backwards compat
27303 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27305 * Ext JS Library 1.1.1
27306 * Copyright(c) 2006-2007, Ext JS, LLC.
27308 * Originally Released Under LGPL - original licence link has changed is not relivant.
27311 * <script type="text/javascript">
27315 * @class Roo.PagingToolbar
27316 * @extends Roo.Toolbar
27317 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27319 * Create a new PagingToolbar
27320 * @param {Object} config The config object
27322 Roo.PagingToolbar = function(el, ds, config)
27324 // old args format still supported... - xtype is prefered..
27325 if (typeof(el) == 'object' && el.xtype) {
27326 // created from xtype...
27328 ds = el.dataSource;
27329 el = config.container;
27332 if (config.items) {
27333 items = config.items;
27337 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27340 this.renderButtons(this.el);
27343 // supprot items array.
27345 Roo.each(items, function(e) {
27346 this.add(Roo.factory(e));
27351 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27353 * @cfg {Roo.data.Store} dataSource
27354 * The underlying data store providing the paged data
27357 * @cfg {String/HTMLElement/Element} container
27358 * container The id or element that will contain the toolbar
27361 * @cfg {Boolean} displayInfo
27362 * True to display the displayMsg (defaults to false)
27365 * @cfg {Number} pageSize
27366 * The number of records to display per page (defaults to 20)
27370 * @cfg {String} displayMsg
27371 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27373 displayMsg : 'Displaying {0} - {1} of {2}',
27375 * @cfg {String} emptyMsg
27376 * The message to display when no records are found (defaults to "No data to display")
27378 emptyMsg : 'No data to display',
27380 * Customizable piece of the default paging text (defaults to "Page")
27383 beforePageText : "Page",
27385 * Customizable piece of the default paging text (defaults to "of %0")
27388 afterPageText : "of {0}",
27390 * Customizable piece of the default paging text (defaults to "First Page")
27393 firstText : "First Page",
27395 * Customizable piece of the default paging text (defaults to "Previous Page")
27398 prevText : "Previous Page",
27400 * Customizable piece of the default paging text (defaults to "Next Page")
27403 nextText : "Next Page",
27405 * Customizable piece of the default paging text (defaults to "Last Page")
27408 lastText : "Last Page",
27410 * Customizable piece of the default paging text (defaults to "Refresh")
27413 refreshText : "Refresh",
27416 renderButtons : function(el){
27417 Roo.PagingToolbar.superclass.render.call(this, el);
27418 this.first = this.addButton({
27419 tooltip: this.firstText,
27420 cls: "x-btn-icon x-grid-page-first",
27422 handler: this.onClick.createDelegate(this, ["first"])
27424 this.prev = this.addButton({
27425 tooltip: this.prevText,
27426 cls: "x-btn-icon x-grid-page-prev",
27428 handler: this.onClick.createDelegate(this, ["prev"])
27430 //this.addSeparator();
27431 this.add(this.beforePageText);
27432 this.field = Roo.get(this.addDom({
27437 cls: "x-grid-page-number"
27439 this.field.on("keydown", this.onPagingKeydown, this);
27440 this.field.on("focus", function(){this.dom.select();});
27441 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27442 this.field.setHeight(18);
27443 //this.addSeparator();
27444 this.next = this.addButton({
27445 tooltip: this.nextText,
27446 cls: "x-btn-icon x-grid-page-next",
27448 handler: this.onClick.createDelegate(this, ["next"])
27450 this.last = this.addButton({
27451 tooltip: this.lastText,
27452 cls: "x-btn-icon x-grid-page-last",
27454 handler: this.onClick.createDelegate(this, ["last"])
27456 //this.addSeparator();
27457 this.loading = this.addButton({
27458 tooltip: this.refreshText,
27459 cls: "x-btn-icon x-grid-loading",
27460 handler: this.onClick.createDelegate(this, ["refresh"])
27463 if(this.displayInfo){
27464 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27469 updateInfo : function(){
27470 if(this.displayEl){
27471 var count = this.ds.getCount();
27472 var msg = count == 0 ?
27476 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27478 this.displayEl.update(msg);
27483 onLoad : function(ds, r, o){
27484 this.cursor = o.params ? o.params.start : 0;
27485 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27487 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27488 this.field.dom.value = ap;
27489 this.first.setDisabled(ap == 1);
27490 this.prev.setDisabled(ap == 1);
27491 this.next.setDisabled(ap == ps);
27492 this.last.setDisabled(ap == ps);
27493 this.loading.enable();
27498 getPageData : function(){
27499 var total = this.ds.getTotalCount();
27502 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27503 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27508 onLoadError : function(){
27509 this.loading.enable();
27513 onPagingKeydown : function(e){
27514 var k = e.getKey();
27515 var d = this.getPageData();
27517 var v = this.field.dom.value, pageNum;
27518 if(!v || isNaN(pageNum = parseInt(v, 10))){
27519 this.field.dom.value = d.activePage;
27522 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27523 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27526 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))
27528 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27529 this.field.dom.value = pageNum;
27530 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27533 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27535 var v = this.field.dom.value, pageNum;
27536 var increment = (e.shiftKey) ? 10 : 1;
27537 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27539 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27540 this.field.dom.value = d.activePage;
27543 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27545 this.field.dom.value = parseInt(v, 10) + increment;
27546 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27547 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27554 beforeLoad : function(){
27556 this.loading.disable();
27561 onClick : function(which){
27565 ds.load({params:{start: 0, limit: this.pageSize}});
27568 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27571 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27574 var total = ds.getTotalCount();
27575 var extra = total % this.pageSize;
27576 var lastStart = extra ? (total - extra) : total-this.pageSize;
27577 ds.load({params:{start: lastStart, limit: this.pageSize}});
27580 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27586 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27587 * @param {Roo.data.Store} store The data store to unbind
27589 unbind : function(ds){
27590 ds.un("beforeload", this.beforeLoad, this);
27591 ds.un("load", this.onLoad, this);
27592 ds.un("loadexception", this.onLoadError, this);
27593 ds.un("remove", this.updateInfo, this);
27594 ds.un("add", this.updateInfo, this);
27595 this.ds = undefined;
27599 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27600 * @param {Roo.data.Store} store The data store to bind
27602 bind : function(ds){
27603 ds.on("beforeload", this.beforeLoad, this);
27604 ds.on("load", this.onLoad, this);
27605 ds.on("loadexception", this.onLoadError, this);
27606 ds.on("remove", this.updateInfo, this);
27607 ds.on("add", this.updateInfo, this);
27612 * Ext JS Library 1.1.1
27613 * Copyright(c) 2006-2007, Ext JS, LLC.
27615 * Originally Released Under LGPL - original licence link has changed is not relivant.
27618 * <script type="text/javascript">
27622 * @class Roo.Resizable
27623 * @extends Roo.util.Observable
27624 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27625 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27626 * 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
27627 * the element will be wrapped for you automatically.</p>
27628 * <p>Here is the list of valid resize handles:</p>
27631 ------ -------------------
27640 'hd' horizontal drag
27643 * <p>Here's an example showing the creation of a typical Resizable:</p>
27645 var resizer = new Roo.Resizable("element-id", {
27653 resizer.on("resize", myHandler);
27655 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27656 * resizer.east.setDisplayed(false);</p>
27657 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27658 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27659 * resize operation's new size (defaults to [0, 0])
27660 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27661 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27662 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27663 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27664 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27665 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27666 * @cfg {Number} width The width of the element in pixels (defaults to null)
27667 * @cfg {Number} height The height of the element in pixels (defaults to null)
27668 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27669 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27670 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27671 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27672 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27673 * in favor of the handles config option (defaults to false)
27674 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27675 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27676 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27677 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27678 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27679 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27680 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27681 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27682 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27683 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27684 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27686 * Create a new resizable component
27687 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27688 * @param {Object} config configuration options
27690 Roo.Resizable = function(el, config)
27692 this.el = Roo.get(el);
27694 if(config && config.wrap){
27695 config.resizeChild = this.el;
27696 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27697 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27698 this.el.setStyle("overflow", "hidden");
27699 this.el.setPositioning(config.resizeChild.getPositioning());
27700 config.resizeChild.clearPositioning();
27701 if(!config.width || !config.height){
27702 var csize = config.resizeChild.getSize();
27703 this.el.setSize(csize.width, csize.height);
27705 if(config.pinned && !config.adjustments){
27706 config.adjustments = "auto";
27710 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27711 this.proxy.unselectable();
27712 this.proxy.enableDisplayMode('block');
27714 Roo.apply(this, config);
27717 this.disableTrackOver = true;
27718 this.el.addClass("x-resizable-pinned");
27720 // if the element isn't positioned, make it relative
27721 var position = this.el.getStyle("position");
27722 if(position != "absolute" && position != "fixed"){
27723 this.el.setStyle("position", "relative");
27725 if(!this.handles){ // no handles passed, must be legacy style
27726 this.handles = 's,e,se';
27727 if(this.multiDirectional){
27728 this.handles += ',n,w';
27731 if(this.handles == "all"){
27732 this.handles = "n s e w ne nw se sw";
27734 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27735 var ps = Roo.Resizable.positions;
27736 for(var i = 0, len = hs.length; i < len; i++){
27737 if(hs[i] && ps[hs[i]]){
27738 var pos = ps[hs[i]];
27739 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27743 this.corner = this.southeast;
27745 // updateBox = the box can move..
27746 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27747 this.updateBox = true;
27750 this.activeHandle = null;
27752 if(this.resizeChild){
27753 if(typeof this.resizeChild == "boolean"){
27754 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27756 this.resizeChild = Roo.get(this.resizeChild, true);
27760 if(this.adjustments == "auto"){
27761 var rc = this.resizeChild;
27762 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27763 if(rc && (hw || hn)){
27764 rc.position("relative");
27765 rc.setLeft(hw ? hw.el.getWidth() : 0);
27766 rc.setTop(hn ? hn.el.getHeight() : 0);
27768 this.adjustments = [
27769 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27770 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27774 if(this.draggable){
27775 this.dd = this.dynamic ?
27776 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27777 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27783 * @event beforeresize
27784 * Fired before resize is allowed. Set enabled to false to cancel resize.
27785 * @param {Roo.Resizable} this
27786 * @param {Roo.EventObject} e The mousedown event
27788 "beforeresize" : true,
27791 * Fired after a resize.
27792 * @param {Roo.Resizable} this
27793 * @param {Number} width The new width
27794 * @param {Number} height The new height
27795 * @param {Roo.EventObject} e The mouseup event
27800 if(this.width !== null && this.height !== null){
27801 this.resizeTo(this.width, this.height);
27803 this.updateChildSize();
27806 this.el.dom.style.zoom = 1;
27808 Roo.Resizable.superclass.constructor.call(this);
27811 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27812 resizeChild : false,
27813 adjustments : [0, 0],
27823 multiDirectional : false,
27824 disableTrackOver : false,
27825 easing : 'easeOutStrong',
27826 widthIncrement : 0,
27827 heightIncrement : 0,
27831 preserveRatio : false,
27832 transparent: false,
27838 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27840 constrainTo: undefined,
27842 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27844 resizeRegion: undefined,
27848 * Perform a manual resize
27849 * @param {Number} width
27850 * @param {Number} height
27852 resizeTo : function(width, height){
27853 this.el.setSize(width, height);
27854 this.updateChildSize();
27855 this.fireEvent("resize", this, width, height, null);
27859 startSizing : function(e, handle){
27860 this.fireEvent("beforeresize", this, e);
27861 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27864 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27865 this.overlay.unselectable();
27866 this.overlay.enableDisplayMode("block");
27867 this.overlay.on("mousemove", this.onMouseMove, this);
27868 this.overlay.on("mouseup", this.onMouseUp, this);
27870 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27872 this.resizing = true;
27873 this.startBox = this.el.getBox();
27874 this.startPoint = e.getXY();
27875 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27876 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27878 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27879 this.overlay.show();
27881 if(this.constrainTo) {
27882 var ct = Roo.get(this.constrainTo);
27883 this.resizeRegion = ct.getRegion().adjust(
27884 ct.getFrameWidth('t'),
27885 ct.getFrameWidth('l'),
27886 -ct.getFrameWidth('b'),
27887 -ct.getFrameWidth('r')
27891 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27893 this.proxy.setBox(this.startBox);
27895 this.proxy.setStyle('visibility', 'visible');
27901 onMouseDown : function(handle, e){
27904 this.activeHandle = handle;
27905 this.startSizing(e, handle);
27910 onMouseUp : function(e){
27911 var size = this.resizeElement();
27912 this.resizing = false;
27914 this.overlay.hide();
27916 this.fireEvent("resize", this, size.width, size.height, e);
27920 updateChildSize : function(){
27921 if(this.resizeChild){
27923 var child = this.resizeChild;
27924 var adj = this.adjustments;
27925 if(el.dom.offsetWidth){
27926 var b = el.getSize(true);
27927 child.setSize(b.width+adj[0], b.height+adj[1]);
27929 // Second call here for IE
27930 // The first call enables instant resizing and
27931 // the second call corrects scroll bars if they
27934 setTimeout(function(){
27935 if(el.dom.offsetWidth){
27936 var b = el.getSize(true);
27937 child.setSize(b.width+adj[0], b.height+adj[1]);
27945 snap : function(value, inc, min){
27946 if(!inc || !value) return value;
27947 var newValue = value;
27948 var m = value % inc;
27951 newValue = value + (inc-m);
27953 newValue = value - m;
27956 return Math.max(min, newValue);
27960 resizeElement : function(){
27961 var box = this.proxy.getBox();
27962 if(this.updateBox){
27963 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27965 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27967 this.updateChildSize();
27975 constrain : function(v, diff, m, mx){
27978 }else if(v - diff > mx){
27985 onMouseMove : function(e){
27987 try{// try catch so if something goes wrong the user doesn't get hung
27989 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27993 //var curXY = this.startPoint;
27994 var curSize = this.curSize || this.startBox;
27995 var x = this.startBox.x, y = this.startBox.y;
27996 var ox = x, oy = y;
27997 var w = curSize.width, h = curSize.height;
27998 var ow = w, oh = h;
27999 var mw = this.minWidth, mh = this.minHeight;
28000 var mxw = this.maxWidth, mxh = this.maxHeight;
28001 var wi = this.widthIncrement;
28002 var hi = this.heightIncrement;
28004 var eventXY = e.getXY();
28005 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
28006 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28008 var pos = this.activeHandle.position;
28013 w = Math.min(Math.max(mw, w), mxw);
28018 h = Math.min(Math.max(mh, h), mxh);
28023 w = Math.min(Math.max(mw, w), mxw);
28024 h = Math.min(Math.max(mh, h), mxh);
28027 diffY = this.constrain(h, diffY, mh, mxh);
28034 var adiffX = Math.abs(diffX);
28035 var sub = (adiffX % wi); // how much
28036 if (sub > (wi/2)) { // far enough to snap
28037 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28039 // remove difference..
28040 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28044 x = Math.max(this.minX, x);
28047 diffX = this.constrain(w, diffX, mw, mxw);
28053 w = Math.min(Math.max(mw, w), mxw);
28054 diffY = this.constrain(h, diffY, mh, mxh);
28059 diffX = this.constrain(w, diffX, mw, mxw);
28060 diffY = this.constrain(h, diffY, mh, mxh);
28067 diffX = this.constrain(w, diffX, mw, mxw);
28069 h = Math.min(Math.max(mh, h), mxh);
28075 var sw = this.snap(w, wi, mw);
28076 var sh = this.snap(h, hi, mh);
28077 if(sw != w || sh != h){
28100 if(this.preserveRatio){
28105 h = Math.min(Math.max(mh, h), mxh);
28110 w = Math.min(Math.max(mw, w), mxw);
28115 w = Math.min(Math.max(mw, w), mxw);
28121 w = Math.min(Math.max(mw, w), mxw);
28127 h = Math.min(Math.max(mh, h), mxh);
28135 h = Math.min(Math.max(mh, h), mxh);
28145 h = Math.min(Math.max(mh, h), mxh);
28153 if (pos == 'hdrag') {
28156 this.proxy.setBounds(x, y, w, h);
28158 this.resizeElement();
28165 handleOver : function(){
28167 this.el.addClass("x-resizable-over");
28172 handleOut : function(){
28173 if(!this.resizing){
28174 this.el.removeClass("x-resizable-over");
28179 * Returns the element this component is bound to.
28180 * @return {Roo.Element}
28182 getEl : function(){
28187 * Returns the resizeChild element (or null).
28188 * @return {Roo.Element}
28190 getResizeChild : function(){
28191 return this.resizeChild;
28195 * Destroys this resizable. If the element was wrapped and
28196 * removeEl is not true then the element remains.
28197 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28199 destroy : function(removeEl){
28200 this.proxy.remove();
28202 this.overlay.removeAllListeners();
28203 this.overlay.remove();
28205 var ps = Roo.Resizable.positions;
28207 if(typeof ps[k] != "function" && this[ps[k]]){
28208 var h = this[ps[k]];
28209 h.el.removeAllListeners();
28214 this.el.update("");
28221 // hash to map config positions to true positions
28222 Roo.Resizable.positions = {
28223 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28228 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28230 // only initialize the template if resizable is used
28231 var tpl = Roo.DomHelper.createTemplate(
28232 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28235 Roo.Resizable.Handle.prototype.tpl = tpl;
28237 this.position = pos;
28239 // show north drag fro topdra
28240 var handlepos = pos == 'hdrag' ? 'north' : pos;
28242 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28243 if (pos == 'hdrag') {
28244 this.el.setStyle('cursor', 'pointer');
28246 this.el.unselectable();
28248 this.el.setOpacity(0);
28250 this.el.on("mousedown", this.onMouseDown, this);
28251 if(!disableTrackOver){
28252 this.el.on("mouseover", this.onMouseOver, this);
28253 this.el.on("mouseout", this.onMouseOut, this);
28258 Roo.Resizable.Handle.prototype = {
28259 afterResize : function(rz){
28263 onMouseDown : function(e){
28264 this.rz.onMouseDown(this, e);
28267 onMouseOver : function(e){
28268 this.rz.handleOver(this, e);
28271 onMouseOut : function(e){
28272 this.rz.handleOut(this, e);
28276 * Ext JS Library 1.1.1
28277 * Copyright(c) 2006-2007, Ext JS, LLC.
28279 * Originally Released Under LGPL - original licence link has changed is not relivant.
28282 * <script type="text/javascript">
28286 * @class Roo.Editor
28287 * @extends Roo.Component
28288 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28290 * Create a new Editor
28291 * @param {Roo.form.Field} field The Field object (or descendant)
28292 * @param {Object} config The config object
28294 Roo.Editor = function(field, config){
28295 Roo.Editor.superclass.constructor.call(this, config);
28296 this.field = field;
28299 * @event beforestartedit
28300 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28301 * false from the handler of this event.
28302 * @param {Editor} this
28303 * @param {Roo.Element} boundEl The underlying element bound to this editor
28304 * @param {Mixed} value The field value being set
28306 "beforestartedit" : true,
28309 * Fires when this editor is displayed
28310 * @param {Roo.Element} boundEl The underlying element bound to this editor
28311 * @param {Mixed} value The starting field value
28313 "startedit" : true,
28315 * @event beforecomplete
28316 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28317 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28318 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28319 * event will not fire since no edit actually occurred.
28320 * @param {Editor} this
28321 * @param {Mixed} value The current field value
28322 * @param {Mixed} startValue The original field value
28324 "beforecomplete" : true,
28327 * Fires after editing is complete and any changed value has been written to the underlying field.
28328 * @param {Editor} this
28329 * @param {Mixed} value The current field value
28330 * @param {Mixed} startValue The original field value
28334 * @event specialkey
28335 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28336 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28337 * @param {Roo.form.Field} this
28338 * @param {Roo.EventObject} e The event object
28340 "specialkey" : true
28344 Roo.extend(Roo.Editor, Roo.Component, {
28346 * @cfg {Boolean/String} autosize
28347 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28348 * or "height" to adopt the height only (defaults to false)
28351 * @cfg {Boolean} revertInvalid
28352 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28353 * validation fails (defaults to true)
28356 * @cfg {Boolean} ignoreNoChange
28357 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28358 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28359 * will never be ignored.
28362 * @cfg {Boolean} hideEl
28363 * False to keep the bound element visible while the editor is displayed (defaults to true)
28366 * @cfg {Mixed} value
28367 * The data value of the underlying field (defaults to "")
28371 * @cfg {String} alignment
28372 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28376 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28377 * for bottom-right shadow (defaults to "frame")
28381 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28385 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28387 completeOnEnter : false,
28389 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28391 cancelOnEsc : false,
28393 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28398 onRender : function(ct, position){
28399 this.el = new Roo.Layer({
28400 shadow: this.shadow,
28406 constrain: this.constrain
28408 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28409 if(this.field.msgTarget != 'title'){
28410 this.field.msgTarget = 'qtip';
28412 this.field.render(this.el);
28414 this.field.el.dom.setAttribute('autocomplete', 'off');
28416 this.field.on("specialkey", this.onSpecialKey, this);
28417 if(this.swallowKeys){
28418 this.field.el.swallowEvent(['keydown','keypress']);
28421 this.field.on("blur", this.onBlur, this);
28422 if(this.field.grow){
28423 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28427 onSpecialKey : function(field, e)
28429 //Roo.log('editor onSpecialKey');
28430 if(this.completeOnEnter && e.getKey() == e.ENTER){
28432 this.completeEdit();
28435 // do not fire special key otherwise it might hide close the editor...
28436 if(e.getKey() == e.ENTER){
28439 if(this.cancelOnEsc && e.getKey() == e.ESC){
28443 this.fireEvent('specialkey', field, e);
28448 * Starts the editing process and shows the editor.
28449 * @param {String/HTMLElement/Element} el The element to edit
28450 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28451 * to the innerHTML of el.
28453 startEdit : function(el, value){
28455 this.completeEdit();
28457 this.boundEl = Roo.get(el);
28458 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28459 if(!this.rendered){
28460 this.render(this.parentEl || document.body);
28462 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28465 this.startValue = v;
28466 this.field.setValue(v);
28468 var sz = this.boundEl.getSize();
28469 switch(this.autoSize){
28471 this.setSize(sz.width, "");
28474 this.setSize("", sz.height);
28477 this.setSize(sz.width, sz.height);
28480 this.el.alignTo(this.boundEl, this.alignment);
28481 this.editing = true;
28483 Roo.QuickTips.disable();
28489 * Sets the height and width of this editor.
28490 * @param {Number} width The new width
28491 * @param {Number} height The new height
28493 setSize : function(w, h){
28494 this.field.setSize(w, h);
28501 * Realigns the editor to the bound field based on the current alignment config value.
28503 realign : function(){
28504 this.el.alignTo(this.boundEl, this.alignment);
28508 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28509 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28511 completeEdit : function(remainVisible){
28515 var v = this.getValue();
28516 if(this.revertInvalid !== false && !this.field.isValid()){
28517 v = this.startValue;
28518 this.cancelEdit(true);
28520 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28521 this.editing = false;
28525 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28526 this.editing = false;
28527 if(this.updateEl && this.boundEl){
28528 this.boundEl.update(v);
28530 if(remainVisible !== true){
28533 this.fireEvent("complete", this, v, this.startValue);
28538 onShow : function(){
28540 if(this.hideEl !== false){
28541 this.boundEl.hide();
28544 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28545 this.fixIEFocus = true;
28546 this.deferredFocus.defer(50, this);
28548 this.field.focus();
28550 this.fireEvent("startedit", this.boundEl, this.startValue);
28553 deferredFocus : function(){
28555 this.field.focus();
28560 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28561 * reverted to the original starting value.
28562 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28563 * cancel (defaults to false)
28565 cancelEdit : function(remainVisible){
28567 this.setValue(this.startValue);
28568 if(remainVisible !== true){
28575 onBlur : function(){
28576 if(this.allowBlur !== true && this.editing){
28577 this.completeEdit();
28582 onHide : function(){
28584 this.completeEdit();
28588 if(this.field.collapse){
28589 this.field.collapse();
28592 if(this.hideEl !== false){
28593 this.boundEl.show();
28596 Roo.QuickTips.enable();
28601 * Sets the data value of the editor
28602 * @param {Mixed} value Any valid value supported by the underlying field
28604 setValue : function(v){
28605 this.field.setValue(v);
28609 * Gets the data value of the editor
28610 * @return {Mixed} The data value
28612 getValue : function(){
28613 return this.field.getValue();
28617 * Ext JS Library 1.1.1
28618 * Copyright(c) 2006-2007, Ext JS, LLC.
28620 * Originally Released Under LGPL - original licence link has changed is not relivant.
28623 * <script type="text/javascript">
28627 * @class Roo.BasicDialog
28628 * @extends Roo.util.Observable
28629 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28631 var dlg = new Roo.BasicDialog("my-dlg", {
28640 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28641 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28642 dlg.addButton('Cancel', dlg.hide, dlg);
28645 <b>A Dialog should always be a direct child of the body element.</b>
28646 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28647 * @cfg {String} title Default text to display in the title bar (defaults to null)
28648 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28649 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28650 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28651 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28652 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28653 * (defaults to null with no animation)
28654 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28655 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28656 * property for valid values (defaults to 'all')
28657 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28658 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28659 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28660 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28661 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28662 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28663 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28664 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28665 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28666 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28667 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28668 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28669 * draggable = true (defaults to false)
28670 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28671 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28672 * shadow (defaults to false)
28673 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28674 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28675 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28676 * @cfg {Array} buttons Array of buttons
28677 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28679 * Create a new BasicDialog.
28680 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28681 * @param {Object} config Configuration options
28683 Roo.BasicDialog = function(el, config){
28684 this.el = Roo.get(el);
28685 var dh = Roo.DomHelper;
28686 if(!this.el && config && config.autoCreate){
28687 if(typeof config.autoCreate == "object"){
28688 if(!config.autoCreate.id){
28689 config.autoCreate.id = el;
28691 this.el = dh.append(document.body,
28692 config.autoCreate, true);
28694 this.el = dh.append(document.body,
28695 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28699 el.setDisplayed(true);
28700 el.hide = this.hideAction;
28702 el.addClass("x-dlg");
28704 Roo.apply(this, config);
28706 this.proxy = el.createProxy("x-dlg-proxy");
28707 this.proxy.hide = this.hideAction;
28708 this.proxy.setOpacity(.5);
28712 el.setWidth(config.width);
28715 el.setHeight(config.height);
28717 this.size = el.getSize();
28718 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28719 this.xy = [config.x,config.y];
28721 this.xy = el.getCenterXY(true);
28723 /** The header element @type Roo.Element */
28724 this.header = el.child("> .x-dlg-hd");
28725 /** The body element @type Roo.Element */
28726 this.body = el.child("> .x-dlg-bd");
28727 /** The footer element @type Roo.Element */
28728 this.footer = el.child("> .x-dlg-ft");
28731 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28734 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28737 this.header.unselectable();
28739 this.header.update(this.title);
28741 // this element allows the dialog to be focused for keyboard event
28742 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28743 this.focusEl.swallowEvent("click", true);
28745 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28747 // wrap the body and footer for special rendering
28748 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28750 this.bwrap.dom.appendChild(this.footer.dom);
28753 this.bg = this.el.createChild({
28754 tag: "div", cls:"x-dlg-bg",
28755 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28757 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28760 if(this.autoScroll !== false && !this.autoTabs){
28761 this.body.setStyle("overflow", "auto");
28764 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28766 if(this.closable !== false){
28767 this.el.addClass("x-dlg-closable");
28768 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28769 this.close.on("click", this.closeClick, this);
28770 this.close.addClassOnOver("x-dlg-close-over");
28772 if(this.collapsible !== false){
28773 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28774 this.collapseBtn.on("click", this.collapseClick, this);
28775 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28776 this.header.on("dblclick", this.collapseClick, this);
28778 if(this.resizable !== false){
28779 this.el.addClass("x-dlg-resizable");
28780 this.resizer = new Roo.Resizable(el, {
28781 minWidth: this.minWidth || 80,
28782 minHeight:this.minHeight || 80,
28783 handles: this.resizeHandles || "all",
28786 this.resizer.on("beforeresize", this.beforeResize, this);
28787 this.resizer.on("resize", this.onResize, this);
28789 if(this.draggable !== false){
28790 el.addClass("x-dlg-draggable");
28791 if (!this.proxyDrag) {
28792 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28795 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28797 dd.setHandleElId(this.header.id);
28798 dd.endDrag = this.endMove.createDelegate(this);
28799 dd.startDrag = this.startMove.createDelegate(this);
28800 dd.onDrag = this.onDrag.createDelegate(this);
28805 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28806 this.mask.enableDisplayMode("block");
28808 this.el.addClass("x-dlg-modal");
28811 this.shadow = new Roo.Shadow({
28812 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28813 offset : this.shadowOffset
28816 this.shadowOffset = 0;
28818 if(Roo.useShims && this.shim !== false){
28819 this.shim = this.el.createShim();
28820 this.shim.hide = this.hideAction;
28828 if (this.buttons) {
28829 var bts= this.buttons;
28831 Roo.each(bts, function(b) {
28840 * Fires when a key is pressed
28841 * @param {Roo.BasicDialog} this
28842 * @param {Roo.EventObject} e
28847 * Fires when this dialog is moved by the user.
28848 * @param {Roo.BasicDialog} this
28849 * @param {Number} x The new page X
28850 * @param {Number} y The new page Y
28855 * Fires when this dialog is resized by the user.
28856 * @param {Roo.BasicDialog} this
28857 * @param {Number} width The new width
28858 * @param {Number} height The new height
28862 * @event beforehide
28863 * Fires before this dialog is hidden.
28864 * @param {Roo.BasicDialog} this
28866 "beforehide" : true,
28869 * Fires when this dialog is hidden.
28870 * @param {Roo.BasicDialog} this
28874 * @event beforeshow
28875 * Fires before this dialog is shown.
28876 * @param {Roo.BasicDialog} this
28878 "beforeshow" : true,
28881 * Fires when this dialog is shown.
28882 * @param {Roo.BasicDialog} this
28886 el.on("keydown", this.onKeyDown, this);
28887 el.on("mousedown", this.toFront, this);
28888 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28890 Roo.DialogManager.register(this);
28891 Roo.BasicDialog.superclass.constructor.call(this);
28894 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28895 shadowOffset: Roo.isIE ? 6 : 5,
28898 minButtonWidth: 75,
28899 defaultButton: null,
28900 buttonAlign: "right",
28905 * Sets the dialog title text
28906 * @param {String} text The title text to display
28907 * @return {Roo.BasicDialog} this
28909 setTitle : function(text){
28910 this.header.update(text);
28915 closeClick : function(){
28920 collapseClick : function(){
28921 this[this.collapsed ? "expand" : "collapse"]();
28925 * Collapses the dialog to its minimized state (only the title bar is visible).
28926 * Equivalent to the user clicking the collapse dialog button.
28928 collapse : function(){
28929 if(!this.collapsed){
28930 this.collapsed = true;
28931 this.el.addClass("x-dlg-collapsed");
28932 this.restoreHeight = this.el.getHeight();
28933 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28938 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28939 * clicking the expand dialog button.
28941 expand : function(){
28942 if(this.collapsed){
28943 this.collapsed = false;
28944 this.el.removeClass("x-dlg-collapsed");
28945 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28950 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28951 * @return {Roo.TabPanel} The tabs component
28953 initTabs : function(){
28954 var tabs = this.getTabs();
28955 while(tabs.getTab(0)){
28958 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28960 tabs.addTab(Roo.id(dom), dom.title);
28968 beforeResize : function(){
28969 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28973 onResize : function(){
28974 this.refreshSize();
28975 this.syncBodyHeight();
28976 this.adjustAssets();
28978 this.fireEvent("resize", this, this.size.width, this.size.height);
28982 onKeyDown : function(e){
28983 if(this.isVisible()){
28984 this.fireEvent("keydown", this, e);
28989 * Resizes the dialog.
28990 * @param {Number} width
28991 * @param {Number} height
28992 * @return {Roo.BasicDialog} this
28994 resizeTo : function(width, height){
28995 this.el.setSize(width, height);
28996 this.size = {width: width, height: height};
28997 this.syncBodyHeight();
28998 if(this.fixedcenter){
29001 if(this.isVisible()){
29002 this.constrainXY();
29003 this.adjustAssets();
29005 this.fireEvent("resize", this, width, height);
29011 * Resizes the dialog to fit the specified content size.
29012 * @param {Number} width
29013 * @param {Number} height
29014 * @return {Roo.BasicDialog} this
29016 setContentSize : function(w, h){
29017 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29018 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29019 //if(!this.el.isBorderBox()){
29020 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29021 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29024 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29025 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29027 this.resizeTo(w, h);
29032 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29033 * executed in response to a particular key being pressed while the dialog is active.
29034 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29035 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29036 * @param {Function} fn The function to call
29037 * @param {Object} scope (optional) The scope of the function
29038 * @return {Roo.BasicDialog} this
29040 addKeyListener : function(key, fn, scope){
29041 var keyCode, shift, ctrl, alt;
29042 if(typeof key == "object" && !(key instanceof Array)){
29043 keyCode = key["key"];
29044 shift = key["shift"];
29045 ctrl = key["ctrl"];
29050 var handler = function(dlg, e){
29051 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29052 var k = e.getKey();
29053 if(keyCode instanceof Array){
29054 for(var i = 0, len = keyCode.length; i < len; i++){
29055 if(keyCode[i] == k){
29056 fn.call(scope || window, dlg, k, e);
29062 fn.call(scope || window, dlg, k, e);
29067 this.on("keydown", handler);
29072 * Returns the TabPanel component (creates it if it doesn't exist).
29073 * Note: If you wish to simply check for the existence of tabs without creating them,
29074 * check for a null 'tabs' property.
29075 * @return {Roo.TabPanel} The tabs component
29077 getTabs : function(){
29079 this.el.addClass("x-dlg-auto-tabs");
29080 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29081 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29087 * Adds a button to the footer section of the dialog.
29088 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29089 * object or a valid Roo.DomHelper element config
29090 * @param {Function} handler The function called when the button is clicked
29091 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29092 * @return {Roo.Button} The new button
29094 addButton : function(config, handler, scope){
29095 var dh = Roo.DomHelper;
29097 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29099 if(!this.btnContainer){
29100 var tb = this.footer.createChild({
29102 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29103 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29105 this.btnContainer = tb.firstChild.firstChild.firstChild;
29110 minWidth: this.minButtonWidth,
29113 if(typeof config == "string"){
29114 bconfig.text = config;
29117 bconfig.dhconfig = config;
29119 Roo.apply(bconfig, config);
29123 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29124 bconfig.position = Math.max(0, bconfig.position);
29125 fc = this.btnContainer.childNodes[bconfig.position];
29128 var btn = new Roo.Button(
29130 this.btnContainer.insertBefore(document.createElement("td"),fc)
29131 : this.btnContainer.appendChild(document.createElement("td")),
29132 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29135 this.syncBodyHeight();
29138 * Array of all the buttons that have been added to this dialog via addButton
29143 this.buttons.push(btn);
29148 * Sets the default button to be focused when the dialog is displayed.
29149 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29150 * @return {Roo.BasicDialog} this
29152 setDefaultButton : function(btn){
29153 this.defaultButton = btn;
29158 getHeaderFooterHeight : function(safe){
29161 height += this.header.getHeight();
29164 var fm = this.footer.getMargins();
29165 height += (this.footer.getHeight()+fm.top+fm.bottom);
29167 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29168 height += this.centerBg.getPadding("tb");
29173 syncBodyHeight : function(){
29174 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29175 var height = this.size.height - this.getHeaderFooterHeight(false);
29176 bd.setHeight(height-bd.getMargins("tb"));
29177 var hh = this.header.getHeight();
29178 var h = this.size.height-hh;
29180 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29181 bw.setHeight(h-cb.getPadding("tb"));
29182 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29183 bd.setWidth(bw.getWidth(true));
29185 this.tabs.syncHeight();
29187 this.tabs.el.repaint();
29193 * Restores the previous state of the dialog if Roo.state is configured.
29194 * @return {Roo.BasicDialog} this
29196 restoreState : function(){
29197 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29198 if(box && box.width){
29199 this.xy = [box.x, box.y];
29200 this.resizeTo(box.width, box.height);
29206 beforeShow : function(){
29208 if(this.fixedcenter){
29209 this.xy = this.el.getCenterXY(true);
29212 Roo.get(document.body).addClass("x-body-masked");
29213 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29216 this.constrainXY();
29220 animShow : function(){
29221 var b = Roo.get(this.animateTarget).getBox();
29222 this.proxy.setSize(b.width, b.height);
29223 this.proxy.setLocation(b.x, b.y);
29225 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29226 true, .35, this.showEl.createDelegate(this));
29230 * Shows the dialog.
29231 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29232 * @return {Roo.BasicDialog} this
29234 show : function(animateTarget){
29235 if (this.fireEvent("beforeshow", this) === false){
29238 if(this.syncHeightBeforeShow){
29239 this.syncBodyHeight();
29240 }else if(this.firstShow){
29241 this.firstShow = false;
29242 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29244 this.animateTarget = animateTarget || this.animateTarget;
29245 if(!this.el.isVisible()){
29247 if(this.animateTarget && Roo.get(this.animateTarget)){
29257 showEl : function(){
29259 this.el.setXY(this.xy);
29261 this.adjustAssets(true);
29264 // IE peekaboo bug - fix found by Dave Fenwick
29268 this.fireEvent("show", this);
29272 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29273 * dialog itself will receive focus.
29275 focus : function(){
29276 if(this.defaultButton){
29277 this.defaultButton.focus();
29279 this.focusEl.focus();
29284 constrainXY : function(){
29285 if(this.constraintoviewport !== false){
29286 if(!this.viewSize){
29287 if(this.container){
29288 var s = this.container.getSize();
29289 this.viewSize = [s.width, s.height];
29291 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29294 var s = Roo.get(this.container||document).getScroll();
29296 var x = this.xy[0], y = this.xy[1];
29297 var w = this.size.width, h = this.size.height;
29298 var vw = this.viewSize[0], vh = this.viewSize[1];
29299 // only move it if it needs it
29301 // first validate right/bottom
29302 if(x + w > vw+s.left){
29306 if(y + h > vh+s.top){
29310 // then make sure top/left isn't negative
29322 if(this.isVisible()){
29323 this.el.setLocation(x, y);
29324 this.adjustAssets();
29331 onDrag : function(){
29332 if(!this.proxyDrag){
29333 this.xy = this.el.getXY();
29334 this.adjustAssets();
29339 adjustAssets : function(doShow){
29340 var x = this.xy[0], y = this.xy[1];
29341 var w = this.size.width, h = this.size.height;
29342 if(doShow === true){
29344 this.shadow.show(this.el);
29350 if(this.shadow && this.shadow.isVisible()){
29351 this.shadow.show(this.el);
29353 if(this.shim && this.shim.isVisible()){
29354 this.shim.setBounds(x, y, w, h);
29359 adjustViewport : function(w, h){
29361 w = Roo.lib.Dom.getViewWidth();
29362 h = Roo.lib.Dom.getViewHeight();
29365 this.viewSize = [w, h];
29366 if(this.modal && this.mask.isVisible()){
29367 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29368 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29370 if(this.isVisible()){
29371 this.constrainXY();
29376 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29377 * shadow, proxy, mask, etc.) Also removes all event listeners.
29378 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29380 destroy : function(removeEl){
29381 if(this.isVisible()){
29382 this.animateTarget = null;
29385 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29387 this.tabs.destroy(removeEl);
29400 for(var i = 0, len = this.buttons.length; i < len; i++){
29401 this.buttons[i].destroy();
29404 this.el.removeAllListeners();
29405 if(removeEl === true){
29406 this.el.update("");
29409 Roo.DialogManager.unregister(this);
29413 startMove : function(){
29414 if(this.proxyDrag){
29417 if(this.constraintoviewport !== false){
29418 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29423 endMove : function(){
29424 if(!this.proxyDrag){
29425 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29427 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29430 this.refreshSize();
29431 this.adjustAssets();
29433 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29437 * Brings this dialog to the front of any other visible dialogs
29438 * @return {Roo.BasicDialog} this
29440 toFront : function(){
29441 Roo.DialogManager.bringToFront(this);
29446 * Sends this dialog to the back (under) of any other visible dialogs
29447 * @return {Roo.BasicDialog} this
29449 toBack : function(){
29450 Roo.DialogManager.sendToBack(this);
29455 * Centers this dialog in the viewport
29456 * @return {Roo.BasicDialog} this
29458 center : function(){
29459 var xy = this.el.getCenterXY(true);
29460 this.moveTo(xy[0], xy[1]);
29465 * Moves the dialog's top-left corner to the specified point
29466 * @param {Number} x
29467 * @param {Number} y
29468 * @return {Roo.BasicDialog} this
29470 moveTo : function(x, y){
29472 if(this.isVisible()){
29473 this.el.setXY(this.xy);
29474 this.adjustAssets();
29480 * Aligns the dialog to the specified element
29481 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29482 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29483 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29484 * @return {Roo.BasicDialog} this
29486 alignTo : function(element, position, offsets){
29487 this.xy = this.el.getAlignToXY(element, position, offsets);
29488 if(this.isVisible()){
29489 this.el.setXY(this.xy);
29490 this.adjustAssets();
29496 * Anchors an element to another element and realigns it when the window is resized.
29497 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29498 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29499 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29500 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29501 * is a number, it is used as the buffer delay (defaults to 50ms).
29502 * @return {Roo.BasicDialog} this
29504 anchorTo : function(el, alignment, offsets, monitorScroll){
29505 var action = function(){
29506 this.alignTo(el, alignment, offsets);
29508 Roo.EventManager.onWindowResize(action, this);
29509 var tm = typeof monitorScroll;
29510 if(tm != 'undefined'){
29511 Roo.EventManager.on(window, 'scroll', action, this,
29512 {buffer: tm == 'number' ? monitorScroll : 50});
29519 * Returns true if the dialog is visible
29520 * @return {Boolean}
29522 isVisible : function(){
29523 return this.el.isVisible();
29527 animHide : function(callback){
29528 var b = Roo.get(this.animateTarget).getBox();
29530 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29532 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29533 this.hideEl.createDelegate(this, [callback]));
29537 * Hides the dialog.
29538 * @param {Function} callback (optional) Function to call when the dialog is hidden
29539 * @return {Roo.BasicDialog} this
29541 hide : function(callback){
29542 if (this.fireEvent("beforehide", this) === false){
29546 this.shadow.hide();
29551 // sometimes animateTarget seems to get set.. causing problems...
29552 // this just double checks..
29553 if(this.animateTarget && Roo.get(this.animateTarget)) {
29554 this.animHide(callback);
29557 this.hideEl(callback);
29563 hideEl : function(callback){
29567 Roo.get(document.body).removeClass("x-body-masked");
29569 this.fireEvent("hide", this);
29570 if(typeof callback == "function"){
29576 hideAction : function(){
29577 this.setLeft("-10000px");
29578 this.setTop("-10000px");
29579 this.setStyle("visibility", "hidden");
29583 refreshSize : function(){
29584 this.size = this.el.getSize();
29585 this.xy = this.el.getXY();
29586 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29590 // z-index is managed by the DialogManager and may be overwritten at any time
29591 setZIndex : function(index){
29593 this.mask.setStyle("z-index", index);
29596 this.shim.setStyle("z-index", ++index);
29599 this.shadow.setZIndex(++index);
29601 this.el.setStyle("z-index", ++index);
29603 this.proxy.setStyle("z-index", ++index);
29606 this.resizer.proxy.setStyle("z-index", ++index);
29609 this.lastZIndex = index;
29613 * Returns the element for this dialog
29614 * @return {Roo.Element} The underlying dialog Element
29616 getEl : function(){
29622 * @class Roo.DialogManager
29623 * Provides global access to BasicDialogs that have been created and
29624 * support for z-indexing (layering) multiple open dialogs.
29626 Roo.DialogManager = function(){
29628 var accessList = [];
29632 var sortDialogs = function(d1, d2){
29633 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29637 var orderDialogs = function(){
29638 accessList.sort(sortDialogs);
29639 var seed = Roo.DialogManager.zseed;
29640 for(var i = 0, len = accessList.length; i < len; i++){
29641 var dlg = accessList[i];
29643 dlg.setZIndex(seed + (i*10));
29650 * The starting z-index for BasicDialogs (defaults to 9000)
29651 * @type Number The z-index value
29656 register : function(dlg){
29657 list[dlg.id] = dlg;
29658 accessList.push(dlg);
29662 unregister : function(dlg){
29663 delete list[dlg.id];
29666 if(!accessList.indexOf){
29667 for( i = 0, len = accessList.length; i < len; i++){
29668 if(accessList[i] == dlg){
29669 accessList.splice(i, 1);
29674 i = accessList.indexOf(dlg);
29676 accessList.splice(i, 1);
29682 * Gets a registered dialog by id
29683 * @param {String/Object} id The id of the dialog or a dialog
29684 * @return {Roo.BasicDialog} this
29686 get : function(id){
29687 return typeof id == "object" ? id : list[id];
29691 * Brings the specified dialog to the front
29692 * @param {String/Object} dlg The id of the dialog or a dialog
29693 * @return {Roo.BasicDialog} this
29695 bringToFront : function(dlg){
29696 dlg = this.get(dlg);
29699 dlg._lastAccess = new Date().getTime();
29706 * Sends the specified dialog to the back
29707 * @param {String/Object} dlg The id of the dialog or a dialog
29708 * @return {Roo.BasicDialog} this
29710 sendToBack : function(dlg){
29711 dlg = this.get(dlg);
29712 dlg._lastAccess = -(new Date().getTime());
29718 * Hides all dialogs
29720 hideAll : function(){
29721 for(var id in list){
29722 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29731 * @class Roo.LayoutDialog
29732 * @extends Roo.BasicDialog
29733 * Dialog which provides adjustments for working with a layout in a Dialog.
29734 * Add your necessary layout config options to the dialog's config.<br>
29735 * Example usage (including a nested layout):
29738 dialog = new Roo.LayoutDialog("download-dlg", {
29747 // layout config merges with the dialog config
29749 tabPosition: "top",
29750 alwaysShowTabs: true
29753 dialog.addKeyListener(27, dialog.hide, dialog);
29754 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29755 dialog.addButton("Build It!", this.getDownload, this);
29757 // we can even add nested layouts
29758 var innerLayout = new Roo.BorderLayout("dl-inner", {
29768 innerLayout.beginUpdate();
29769 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29770 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29771 innerLayout.endUpdate(true);
29773 var layout = dialog.getLayout();
29774 layout.beginUpdate();
29775 layout.add("center", new Roo.ContentPanel("standard-panel",
29776 {title: "Download the Source", fitToFrame:true}));
29777 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29778 {title: "Build your own roo.js"}));
29779 layout.getRegion("center").showPanel(sp);
29780 layout.endUpdate();
29784 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29785 * @param {Object} config configuration options
29787 Roo.LayoutDialog = function(el, cfg){
29790 if (typeof(cfg) == 'undefined') {
29791 config = Roo.apply({}, el);
29792 // not sure why we use documentElement here.. - it should always be body.
29793 // IE7 borks horribly if we use documentElement.
29794 // webkit also does not like documentElement - it creates a body element...
29795 el = Roo.get( document.body || document.documentElement ).createChild();
29796 //config.autoCreate = true;
29800 config.autoTabs = false;
29801 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29802 this.body.setStyle({overflow:"hidden", position:"relative"});
29803 this.layout = new Roo.BorderLayout(this.body.dom, config);
29804 this.layout.monitorWindowResize = false;
29805 this.el.addClass("x-dlg-auto-layout");
29806 // fix case when center region overwrites center function
29807 this.center = Roo.BasicDialog.prototype.center;
29808 this.on("show", this.layout.layout, this.layout, true);
29809 if (config.items) {
29810 var xitems = config.items;
29811 delete config.items;
29812 Roo.each(xitems, this.addxtype, this);
29817 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29819 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29822 endUpdate : function(){
29823 this.layout.endUpdate();
29827 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29830 beginUpdate : function(){
29831 this.layout.beginUpdate();
29835 * Get the BorderLayout for this dialog
29836 * @return {Roo.BorderLayout}
29838 getLayout : function(){
29839 return this.layout;
29842 showEl : function(){
29843 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29845 this.layout.layout();
29850 // Use the syncHeightBeforeShow config option to control this automatically
29851 syncBodyHeight : function(){
29852 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29853 if(this.layout){this.layout.layout();}
29857 * Add an xtype element (actually adds to the layout.)
29858 * @return {Object} xdata xtype object data.
29861 addxtype : function(c) {
29862 return this.layout.addxtype(c);
29866 * Ext JS Library 1.1.1
29867 * Copyright(c) 2006-2007, Ext JS, LLC.
29869 * Originally Released Under LGPL - original licence link has changed is not relivant.
29872 * <script type="text/javascript">
29876 * @class Roo.MessageBox
29877 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29881 Roo.Msg.alert('Status', 'Changes saved successfully.');
29883 // Prompt for user data:
29884 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29886 // process text value...
29890 // Show a dialog using config options:
29892 title:'Save Changes?',
29893 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29894 buttons: Roo.Msg.YESNOCANCEL,
29901 Roo.MessageBox = function(){
29902 var dlg, opt, mask, waitTimer;
29903 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29904 var buttons, activeTextEl, bwidth;
29907 var handleButton = function(button){
29909 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29913 var handleHide = function(){
29914 if(opt && opt.cls){
29915 dlg.el.removeClass(opt.cls);
29918 Roo.TaskMgr.stop(waitTimer);
29924 var updateButtons = function(b){
29927 buttons["ok"].hide();
29928 buttons["cancel"].hide();
29929 buttons["yes"].hide();
29930 buttons["no"].hide();
29931 dlg.footer.dom.style.display = 'none';
29934 dlg.footer.dom.style.display = '';
29935 for(var k in buttons){
29936 if(typeof buttons[k] != "function"){
29939 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29940 width += buttons[k].el.getWidth()+15;
29950 var handleEsc = function(d, k, e){
29951 if(opt && opt.closable !== false){
29961 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29962 * @return {Roo.BasicDialog} The BasicDialog element
29964 getDialog : function(){
29966 dlg = new Roo.BasicDialog("x-msg-box", {
29971 constraintoviewport:false,
29973 collapsible : false,
29976 width:400, height:100,
29977 buttonAlign:"center",
29978 closeClick : function(){
29979 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29980 handleButton("no");
29982 handleButton("cancel");
29986 dlg.on("hide", handleHide);
29988 dlg.addKeyListener(27, handleEsc);
29990 var bt = this.buttonText;
29991 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29992 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29993 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29994 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29995 bodyEl = dlg.body.createChild({
29997 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>'
29999 msgEl = bodyEl.dom.firstChild;
30000 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
30001 textboxEl.enableDisplayMode();
30002 textboxEl.addKeyListener([10,13], function(){
30003 if(dlg.isVisible() && opt && opt.buttons){
30004 if(opt.buttons.ok){
30005 handleButton("ok");
30006 }else if(opt.buttons.yes){
30007 handleButton("yes");
30011 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
30012 textareaEl.enableDisplayMode();
30013 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
30014 progressEl.enableDisplayMode();
30015 var pf = progressEl.dom.firstChild;
30017 pp = Roo.get(pf.firstChild);
30018 pp.setHeight(pf.offsetHeight);
30026 * Updates the message box body text
30027 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30028 * the XHTML-compliant non-breaking space character '&#160;')
30029 * @return {Roo.MessageBox} This message box
30031 updateText : function(text){
30032 if(!dlg.isVisible() && !opt.width){
30033 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30035 msgEl.innerHTML = text || ' ';
30036 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
30037 Math.max(opt.minWidth || this.minWidth, bwidth));
30039 activeTextEl.setWidth(w);
30041 if(dlg.isVisible()){
30042 dlg.fixedcenter = false;
30044 dlg.setContentSize(w, bodyEl.getHeight());
30045 if(dlg.isVisible()){
30046 dlg.fixedcenter = true;
30052 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30053 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30054 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30055 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30056 * @return {Roo.MessageBox} This message box
30058 updateProgress : function(value, text){
30060 this.updateText(text);
30062 if (pp) { // weird bug on my firefox - for some reason this is not defined
30063 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30069 * Returns true if the message box is currently displayed
30070 * @return {Boolean} True if the message box is visible, else false
30072 isVisible : function(){
30073 return dlg && dlg.isVisible();
30077 * Hides the message box if it is displayed
30080 if(this.isVisible()){
30086 * Displays a new message box, or reinitializes an existing message box, based on the config options
30087 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30088 * The following config object properties are supported:
30090 Property Type Description
30091 ---------- --------------- ------------------------------------------------------------------------------------
30092 animEl String/Element An id or Element from which the message box should animate as it opens and
30093 closes (defaults to undefined)
30094 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30095 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30096 closable Boolean False to hide the top-right close button (defaults to true). Note that
30097 progress and wait dialogs will ignore this property and always hide the
30098 close button as they can only be closed programmatically.
30099 cls String A custom CSS class to apply to the message box element
30100 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30101 displayed (defaults to 75)
30102 fn Function A callback function to execute after closing the dialog. The arguments to the
30103 function will be btn (the name of the button that was clicked, if applicable,
30104 e.g. "ok"), and text (the value of the active text field, if applicable).
30105 Progress and wait dialogs will ignore this option since they do not respond to
30106 user actions and can only be closed programmatically, so any required function
30107 should be called by the same code after it closes the dialog.
30108 icon String A CSS class that provides a background image to be used as an icon for
30109 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30110 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30111 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30112 modal Boolean False to allow user interaction with the page while the message box is
30113 displayed (defaults to true)
30114 msg String A string that will replace the existing message box body text (defaults
30115 to the XHTML-compliant non-breaking space character ' ')
30116 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30117 progress Boolean True to display a progress bar (defaults to false)
30118 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30119 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30120 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30121 title String The title text
30122 value String The string value to set into the active textbox element if displayed
30123 wait Boolean True to display a progress bar (defaults to false)
30124 width Number The width of the dialog in pixels
30131 msg: 'Please enter your address:',
30133 buttons: Roo.MessageBox.OKCANCEL,
30136 animEl: 'addAddressBtn'
30139 * @param {Object} config Configuration options
30140 * @return {Roo.MessageBox} This message box
30142 show : function(options){
30143 if(this.isVisible()){
30146 var d = this.getDialog();
30148 d.setTitle(opt.title || " ");
30149 d.close.setDisplayed(opt.closable !== false);
30150 activeTextEl = textboxEl;
30151 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30156 textareaEl.setHeight(typeof opt.multiline == "number" ?
30157 opt.multiline : this.defaultTextHeight);
30158 activeTextEl = textareaEl;
30167 progressEl.setDisplayed(opt.progress === true);
30168 this.updateProgress(0);
30169 activeTextEl.dom.value = opt.value || "";
30171 dlg.setDefaultButton(activeTextEl);
30173 var bs = opt.buttons;
30176 db = buttons["ok"];
30177 }else if(bs && bs.yes){
30178 db = buttons["yes"];
30180 dlg.setDefaultButton(db);
30182 bwidth = updateButtons(opt.buttons);
30183 this.updateText(opt.msg);
30185 d.el.addClass(opt.cls);
30187 d.proxyDrag = opt.proxyDrag === true;
30188 d.modal = opt.modal !== false;
30189 d.mask = opt.modal !== false ? mask : false;
30190 if(!d.isVisible()){
30191 // force it to the end of the z-index stack so it gets a cursor in FF
30192 document.body.appendChild(dlg.el.dom);
30193 d.animateTarget = null;
30194 d.show(options.animEl);
30200 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30201 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30202 * and closing the message box when the process is complete.
30203 * @param {String} title The title bar text
30204 * @param {String} msg The message box body text
30205 * @return {Roo.MessageBox} This message box
30207 progress : function(title, msg){
30214 minWidth: this.minProgressWidth,
30221 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30222 * If a callback function is passed it will be called after the user clicks the button, and the
30223 * id of the button that was clicked will be passed as the only parameter to the callback
30224 * (could also be the top-right close button).
30225 * @param {String} title The title bar text
30226 * @param {String} msg The message box body text
30227 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30228 * @param {Object} scope (optional) The scope of the callback function
30229 * @return {Roo.MessageBox} This message box
30231 alert : function(title, msg, fn, scope){
30244 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30245 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30246 * You are responsible for closing the message box when the process is complete.
30247 * @param {String} msg The message box body text
30248 * @param {String} title (optional) The title bar text
30249 * @return {Roo.MessageBox} This message box
30251 wait : function(msg, title){
30262 waitTimer = Roo.TaskMgr.start({
30264 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30272 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30273 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30274 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30275 * @param {String} title The title bar text
30276 * @param {String} msg The message box body text
30277 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30278 * @param {Object} scope (optional) The scope of the callback function
30279 * @return {Roo.MessageBox} This message box
30281 confirm : function(title, msg, fn, scope){
30285 buttons: this.YESNO,
30294 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30295 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30296 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30297 * (could also be the top-right close button) and the text that was entered will be passed as the two
30298 * parameters to the callback.
30299 * @param {String} title The title bar text
30300 * @param {String} msg The message box body text
30301 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30302 * @param {Object} scope (optional) The scope of the callback function
30303 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30304 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30305 * @return {Roo.MessageBox} This message box
30307 prompt : function(title, msg, fn, scope, multiline){
30311 buttons: this.OKCANCEL,
30316 multiline: multiline,
30323 * Button config that displays a single OK button
30328 * Button config that displays Yes and No buttons
30331 YESNO : {yes:true, no:true},
30333 * Button config that displays OK and Cancel buttons
30336 OKCANCEL : {ok:true, cancel:true},
30338 * Button config that displays Yes, No and Cancel buttons
30341 YESNOCANCEL : {yes:true, no:true, cancel:true},
30344 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30347 defaultTextHeight : 75,
30349 * The maximum width in pixels of the message box (defaults to 600)
30354 * The minimum width in pixels of the message box (defaults to 100)
30359 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30360 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30363 minProgressWidth : 250,
30365 * An object containing the default button text strings that can be overriden for localized language support.
30366 * Supported properties are: ok, cancel, yes and no.
30367 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30380 * Shorthand for {@link Roo.MessageBox}
30382 Roo.Msg = Roo.MessageBox;/*
30384 * Ext JS Library 1.1.1
30385 * Copyright(c) 2006-2007, Ext JS, LLC.
30387 * Originally Released Under LGPL - original licence link has changed is not relivant.
30390 * <script type="text/javascript">
30393 * @class Roo.QuickTips
30394 * Provides attractive and customizable tooltips for any element.
30397 Roo.QuickTips = function(){
30398 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30399 var ce, bd, xy, dd;
30400 var visible = false, disabled = true, inited = false;
30401 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30403 var onOver = function(e){
30407 var t = e.getTarget();
30408 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30411 if(ce && t == ce.el){
30412 clearTimeout(hideProc);
30415 if(t && tagEls[t.id]){
30416 tagEls[t.id].el = t;
30417 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30420 var ttp, et = Roo.fly(t);
30421 var ns = cfg.namespace;
30422 if(tm.interceptTitles && t.title){
30425 t.removeAttribute("title");
30426 e.preventDefault();
30428 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30431 showProc = show.defer(tm.showDelay, tm, [{
30434 width: et.getAttributeNS(ns, cfg.width),
30435 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30436 title: et.getAttributeNS(ns, cfg.title),
30437 cls: et.getAttributeNS(ns, cfg.cls)
30442 var onOut = function(e){
30443 clearTimeout(showProc);
30444 var t = e.getTarget();
30445 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30446 hideProc = setTimeout(hide, tm.hideDelay);
30450 var onMove = function(e){
30456 if(tm.trackMouse && ce){
30461 var onDown = function(e){
30462 clearTimeout(showProc);
30463 clearTimeout(hideProc);
30465 if(tm.hideOnClick){
30468 tm.enable.defer(100, tm);
30473 var getPad = function(){
30474 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30477 var show = function(o){
30481 clearTimeout(dismissProc);
30483 if(removeCls){ // in case manually hidden
30484 el.removeClass(removeCls);
30488 el.addClass(ce.cls);
30489 removeCls = ce.cls;
30492 tipTitle.update(ce.title);
30495 tipTitle.update('');
30498 el.dom.style.width = tm.maxWidth+'px';
30499 //tipBody.dom.style.width = '';
30500 tipBodyText.update(o.text);
30501 var p = getPad(), w = ce.width;
30503 var td = tipBodyText.dom;
30504 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30505 if(aw > tm.maxWidth){
30507 }else if(aw < tm.minWidth){
30513 //tipBody.setWidth(w);
30514 el.setWidth(parseInt(w, 10) + p);
30515 if(ce.autoHide === false){
30516 close.setDisplayed(true);
30521 close.setDisplayed(false);
30527 el.avoidY = xy[1]-18;
30532 el.setStyle("visibility", "visible");
30533 el.fadeIn({callback: afterShow});
30539 var afterShow = function(){
30543 if(tm.autoDismiss && ce.autoHide !== false){
30544 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30549 var hide = function(noanim){
30550 clearTimeout(dismissProc);
30551 clearTimeout(hideProc);
30553 if(el.isVisible()){
30555 if(noanim !== true && tm.animate){
30556 el.fadeOut({callback: afterHide});
30563 var afterHide = function(){
30566 el.removeClass(removeCls);
30573 * @cfg {Number} minWidth
30574 * The minimum width of the quick tip (defaults to 40)
30578 * @cfg {Number} maxWidth
30579 * The maximum width of the quick tip (defaults to 300)
30583 * @cfg {Boolean} interceptTitles
30584 * True to automatically use the element's DOM title value if available (defaults to false)
30586 interceptTitles : false,
30588 * @cfg {Boolean} trackMouse
30589 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30591 trackMouse : false,
30593 * @cfg {Boolean} hideOnClick
30594 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30596 hideOnClick : true,
30598 * @cfg {Number} showDelay
30599 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30603 * @cfg {Number} hideDelay
30604 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30608 * @cfg {Boolean} autoHide
30609 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30610 * Used in conjunction with hideDelay.
30615 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30616 * (defaults to true). Used in conjunction with autoDismissDelay.
30618 autoDismiss : true,
30621 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30623 autoDismissDelay : 5000,
30625 * @cfg {Boolean} animate
30626 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30631 * @cfg {String} title
30632 * Title text to display (defaults to ''). This can be any valid HTML markup.
30636 * @cfg {String} text
30637 * Body text to display (defaults to ''). This can be any valid HTML markup.
30641 * @cfg {String} cls
30642 * A CSS class to apply to the base quick tip element (defaults to '').
30646 * @cfg {Number} width
30647 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30648 * minWidth or maxWidth.
30653 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30654 * or display QuickTips in a page.
30657 tm = Roo.QuickTips;
30658 cfg = tm.tagConfig;
30660 if(!Roo.isReady){ // allow calling of init() before onReady
30661 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30664 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30665 el.fxDefaults = {stopFx: true};
30666 // maximum custom styling
30667 //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>');
30668 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>');
30669 tipTitle = el.child('h3');
30670 tipTitle.enableDisplayMode("block");
30671 tipBody = el.child('div.x-tip-bd');
30672 tipBodyText = el.child('div.x-tip-bd-inner');
30673 //bdLeft = el.child('div.x-tip-bd-left');
30674 //bdRight = el.child('div.x-tip-bd-right');
30675 close = el.child('div.x-tip-close');
30676 close.enableDisplayMode("block");
30677 close.on("click", hide);
30678 var d = Roo.get(document);
30679 d.on("mousedown", onDown);
30680 d.on("mouseover", onOver);
30681 d.on("mouseout", onOut);
30682 d.on("mousemove", onMove);
30683 esc = d.addKeyListener(27, hide);
30686 dd = el.initDD("default", null, {
30687 onDrag : function(){
30691 dd.setHandleElId(tipTitle.id);
30700 * Configures a new quick tip instance and assigns it to a target element. The following config options
30703 Property Type Description
30704 ---------- --------------------- ------------------------------------------------------------------------
30705 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30707 * @param {Object} config The config object
30709 register : function(config){
30710 var cs = config instanceof Array ? config : arguments;
30711 for(var i = 0, len = cs.length; i < len; i++) {
30713 var target = c.target;
30715 if(target instanceof Array){
30716 for(var j = 0, jlen = target.length; j < jlen; j++){
30717 tagEls[target[j]] = c;
30720 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30727 * Removes this quick tip from its element and destroys it.
30728 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30730 unregister : function(el){
30731 delete tagEls[Roo.id(el)];
30735 * Enable this quick tip.
30737 enable : function(){
30738 if(inited && disabled){
30740 if(locks.length < 1){
30747 * Disable this quick tip.
30749 disable : function(){
30751 clearTimeout(showProc);
30752 clearTimeout(hideProc);
30753 clearTimeout(dismissProc);
30761 * Returns true if the quick tip is enabled, else false.
30763 isEnabled : function(){
30770 attribute : "qtip",
30780 // backwards compat
30781 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30783 * Ext JS Library 1.1.1
30784 * Copyright(c) 2006-2007, Ext JS, LLC.
30786 * Originally Released Under LGPL - original licence link has changed is not relivant.
30789 * <script type="text/javascript">
30794 * @class Roo.tree.TreePanel
30795 * @extends Roo.data.Tree
30797 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30798 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30799 * @cfg {Boolean} enableDD true to enable drag and drop
30800 * @cfg {Boolean} enableDrag true to enable just drag
30801 * @cfg {Boolean} enableDrop true to enable just drop
30802 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30803 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30804 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30805 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30806 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30807 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30808 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30809 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30810 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30811 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30812 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30813 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30814 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30815 * @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>
30816 * @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>
30819 * @param {String/HTMLElement/Element} el The container element
30820 * @param {Object} config
30822 Roo.tree.TreePanel = function(el, config){
30824 var loader = false;
30826 root = config.root;
30827 delete config.root;
30829 if (config.loader) {
30830 loader = config.loader;
30831 delete config.loader;
30834 Roo.apply(this, config);
30835 Roo.tree.TreePanel.superclass.constructor.call(this);
30836 this.el = Roo.get(el);
30837 this.el.addClass('x-tree');
30838 //console.log(root);
30840 this.setRootNode( Roo.factory(root, Roo.tree));
30843 this.loader = Roo.factory(loader, Roo.tree);
30846 * Read-only. The id of the container element becomes this TreePanel's id.
30848 this.id = this.el.id;
30851 * @event beforeload
30852 * Fires before a node is loaded, return false to cancel
30853 * @param {Node} node The node being loaded
30855 "beforeload" : true,
30858 * Fires when a node is loaded
30859 * @param {Node} node The node that was loaded
30863 * @event textchange
30864 * Fires when the text for a node is changed
30865 * @param {Node} node The node
30866 * @param {String} text The new text
30867 * @param {String} oldText The old text
30869 "textchange" : true,
30871 * @event beforeexpand
30872 * Fires before a node is expanded, return false to cancel.
30873 * @param {Node} node The node
30874 * @param {Boolean} deep
30875 * @param {Boolean} anim
30877 "beforeexpand" : true,
30879 * @event beforecollapse
30880 * Fires before a node is collapsed, return false to cancel.
30881 * @param {Node} node The node
30882 * @param {Boolean} deep
30883 * @param {Boolean} anim
30885 "beforecollapse" : true,
30888 * Fires when a node is expanded
30889 * @param {Node} node The node
30893 * @event disabledchange
30894 * Fires when the disabled status of a node changes
30895 * @param {Node} node The node
30896 * @param {Boolean} disabled
30898 "disabledchange" : true,
30901 * Fires when a node is collapsed
30902 * @param {Node} node The node
30906 * @event beforeclick
30907 * Fires before click processing on a node. Return false to cancel the default action.
30908 * @param {Node} node The node
30909 * @param {Roo.EventObject} e The event object
30911 "beforeclick":true,
30913 * @event checkchange
30914 * Fires when a node with a checkbox's checked property changes
30915 * @param {Node} this This node
30916 * @param {Boolean} checked
30918 "checkchange":true,
30921 * Fires when a node is clicked
30922 * @param {Node} node The node
30923 * @param {Roo.EventObject} e The event object
30928 * Fires when a node is double clicked
30929 * @param {Node} node The node
30930 * @param {Roo.EventObject} e The event object
30934 * @event contextmenu
30935 * Fires when a node is right clicked
30936 * @param {Node} node The node
30937 * @param {Roo.EventObject} e The event object
30939 "contextmenu":true,
30941 * @event beforechildrenrendered
30942 * Fires right before the child nodes for a node are rendered
30943 * @param {Node} node The node
30945 "beforechildrenrendered":true,
30948 * Fires when a node starts being dragged
30949 * @param {Roo.tree.TreePanel} this
30950 * @param {Roo.tree.TreeNode} node
30951 * @param {event} e The raw browser event
30953 "startdrag" : true,
30956 * Fires when a drag operation is complete
30957 * @param {Roo.tree.TreePanel} this
30958 * @param {Roo.tree.TreeNode} node
30959 * @param {event} e The raw browser event
30964 * Fires when a dragged node is dropped on a valid DD target
30965 * @param {Roo.tree.TreePanel} this
30966 * @param {Roo.tree.TreeNode} node
30967 * @param {DD} dd The dd it was dropped on
30968 * @param {event} e The raw browser event
30972 * @event beforenodedrop
30973 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30974 * passed to handlers has the following properties:<br />
30975 * <ul style="padding:5px;padding-left:16px;">
30976 * <li>tree - The TreePanel</li>
30977 * <li>target - The node being targeted for the drop</li>
30978 * <li>data - The drag data from the drag source</li>
30979 * <li>point - The point of the drop - append, above or below</li>
30980 * <li>source - The drag source</li>
30981 * <li>rawEvent - Raw mouse event</li>
30982 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30983 * to be inserted by setting them on this object.</li>
30984 * <li>cancel - Set this to true to cancel the drop.</li>
30986 * @param {Object} dropEvent
30988 "beforenodedrop" : true,
30991 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30992 * passed to handlers has the following properties:<br />
30993 * <ul style="padding:5px;padding-left:16px;">
30994 * <li>tree - The TreePanel</li>
30995 * <li>target - The node being targeted for the drop</li>
30996 * <li>data - The drag data from the drag source</li>
30997 * <li>point - The point of the drop - append, above or below</li>
30998 * <li>source - The drag source</li>
30999 * <li>rawEvent - Raw mouse event</li>
31000 * <li>dropNode - Dropped node(s).</li>
31002 * @param {Object} dropEvent
31006 * @event nodedragover
31007 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31008 * passed to handlers has the following properties:<br />
31009 * <ul style="padding:5px;padding-left:16px;">
31010 * <li>tree - The TreePanel</li>
31011 * <li>target - The node being targeted for the drop</li>
31012 * <li>data - The drag data from the drag source</li>
31013 * <li>point - The point of the drop - append, above or below</li>
31014 * <li>source - The drag source</li>
31015 * <li>rawEvent - Raw mouse event</li>
31016 * <li>dropNode - Drop node(s) provided by the source.</li>
31017 * <li>cancel - Set this to true to signal drop not allowed.</li>
31019 * @param {Object} dragOverEvent
31021 "nodedragover" : true
31024 if(this.singleExpand){
31025 this.on("beforeexpand", this.restrictExpand, this);
31028 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31029 rootVisible : true,
31030 animate: Roo.enableFx,
31033 hlDrop : Roo.enableFx,
31037 rendererTip: false,
31039 restrictExpand : function(node){
31040 var p = node.parentNode;
31042 if(p.expandedChild && p.expandedChild.parentNode == p){
31043 p.expandedChild.collapse();
31045 p.expandedChild = node;
31049 // private override
31050 setRootNode : function(node){
31051 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31052 if(!this.rootVisible){
31053 node.ui = new Roo.tree.RootTreeNodeUI(node);
31059 * Returns the container element for this TreePanel
31061 getEl : function(){
31066 * Returns the default TreeLoader for this TreePanel
31068 getLoader : function(){
31069 return this.loader;
31075 expandAll : function(){
31076 this.root.expand(true);
31080 * Collapse all nodes
31082 collapseAll : function(){
31083 this.root.collapse(true);
31087 * Returns the selection model used by this TreePanel
31089 getSelectionModel : function(){
31090 if(!this.selModel){
31091 this.selModel = new Roo.tree.DefaultSelectionModel();
31093 return this.selModel;
31097 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31098 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31099 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31102 getChecked : function(a, startNode){
31103 startNode = startNode || this.root;
31105 var f = function(){
31106 if(this.attributes.checked){
31107 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31110 startNode.cascade(f);
31115 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31116 * @param {String} path
31117 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31118 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31119 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31121 expandPath : function(path, attr, callback){
31122 attr = attr || "id";
31123 var keys = path.split(this.pathSeparator);
31124 var curNode = this.root;
31125 if(curNode.attributes[attr] != keys[1]){ // invalid root
31127 callback(false, null);
31132 var f = function(){
31133 if(++index == keys.length){
31135 callback(true, curNode);
31139 var c = curNode.findChild(attr, keys[index]);
31142 callback(false, curNode);
31147 c.expand(false, false, f);
31149 curNode.expand(false, false, f);
31153 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31154 * @param {String} path
31155 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31156 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31157 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31159 selectPath : function(path, attr, callback){
31160 attr = attr || "id";
31161 var keys = path.split(this.pathSeparator);
31162 var v = keys.pop();
31163 if(keys.length > 0){
31164 var f = function(success, node){
31165 if(success && node){
31166 var n = node.findChild(attr, v);
31172 }else if(callback){
31173 callback(false, n);
31177 callback(false, n);
31181 this.expandPath(keys.join(this.pathSeparator), attr, f);
31183 this.root.select();
31185 callback(true, this.root);
31190 getTreeEl : function(){
31195 * Trigger rendering of this TreePanel
31197 render : function(){
31198 if (this.innerCt) {
31199 return this; // stop it rendering more than once!!
31202 this.innerCt = this.el.createChild({tag:"ul",
31203 cls:"x-tree-root-ct " +
31204 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31206 if(this.containerScroll){
31207 Roo.dd.ScrollManager.register(this.el);
31209 if((this.enableDD || this.enableDrop) && !this.dropZone){
31211 * The dropZone used by this tree if drop is enabled
31212 * @type Roo.tree.TreeDropZone
31214 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31215 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31218 if((this.enableDD || this.enableDrag) && !this.dragZone){
31220 * The dragZone used by this tree if drag is enabled
31221 * @type Roo.tree.TreeDragZone
31223 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31224 ddGroup: this.ddGroup || "TreeDD",
31225 scroll: this.ddScroll
31228 this.getSelectionModel().init(this);
31230 console.log("ROOT not set in tree");
31233 this.root.render();
31234 if(!this.rootVisible){
31235 this.root.renderChildren();
31241 * Ext JS Library 1.1.1
31242 * Copyright(c) 2006-2007, Ext JS, LLC.
31244 * Originally Released Under LGPL - original licence link has changed is not relivant.
31247 * <script type="text/javascript">
31252 * @class Roo.tree.DefaultSelectionModel
31253 * @extends Roo.util.Observable
31254 * The default single selection for a TreePanel.
31256 Roo.tree.DefaultSelectionModel = function(){
31257 this.selNode = null;
31261 * @event selectionchange
31262 * Fires when the selected node changes
31263 * @param {DefaultSelectionModel} this
31264 * @param {TreeNode} node the new selection
31266 "selectionchange" : true,
31269 * @event beforeselect
31270 * Fires before the selected node changes, return false to cancel the change
31271 * @param {DefaultSelectionModel} this
31272 * @param {TreeNode} node the new selection
31273 * @param {TreeNode} node the old selection
31275 "beforeselect" : true
31279 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31280 init : function(tree){
31282 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31283 tree.on("click", this.onNodeClick, this);
31286 onNodeClick : function(node, e){
31287 if (e.ctrlKey && this.selNode == node) {
31288 this.unselect(node);
31296 * @param {TreeNode} node The node to select
31297 * @return {TreeNode} The selected node
31299 select : function(node){
31300 var last = this.selNode;
31301 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31303 last.ui.onSelectedChange(false);
31305 this.selNode = node;
31306 node.ui.onSelectedChange(true);
31307 this.fireEvent("selectionchange", this, node, last);
31314 * @param {TreeNode} node The node to unselect
31316 unselect : function(node){
31317 if(this.selNode == node){
31318 this.clearSelections();
31323 * Clear all selections
31325 clearSelections : function(){
31326 var n = this.selNode;
31328 n.ui.onSelectedChange(false);
31329 this.selNode = null;
31330 this.fireEvent("selectionchange", this, null);
31336 * Get the selected node
31337 * @return {TreeNode} The selected node
31339 getSelectedNode : function(){
31340 return this.selNode;
31344 * Returns true if the node is selected
31345 * @param {TreeNode} node The node to check
31346 * @return {Boolean}
31348 isSelected : function(node){
31349 return this.selNode == node;
31353 * Selects the node above the selected node in the tree, intelligently walking the nodes
31354 * @return TreeNode The new selection
31356 selectPrevious : function(){
31357 var s = this.selNode || this.lastSelNode;
31361 var ps = s.previousSibling;
31363 if(!ps.isExpanded() || ps.childNodes.length < 1){
31364 return this.select(ps);
31366 var lc = ps.lastChild;
31367 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31370 return this.select(lc);
31372 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31373 return this.select(s.parentNode);
31379 * Selects the node above the selected node in the tree, intelligently walking the nodes
31380 * @return TreeNode The new selection
31382 selectNext : function(){
31383 var s = this.selNode || this.lastSelNode;
31387 if(s.firstChild && s.isExpanded()){
31388 return this.select(s.firstChild);
31389 }else if(s.nextSibling){
31390 return this.select(s.nextSibling);
31391 }else if(s.parentNode){
31393 s.parentNode.bubble(function(){
31394 if(this.nextSibling){
31395 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31404 onKeyDown : function(e){
31405 var s = this.selNode || this.lastSelNode;
31406 // undesirable, but required
31411 var k = e.getKey();
31419 this.selectPrevious();
31422 e.preventDefault();
31423 if(s.hasChildNodes()){
31424 if(!s.isExpanded()){
31426 }else if(s.firstChild){
31427 this.select(s.firstChild, e);
31432 e.preventDefault();
31433 if(s.hasChildNodes() && s.isExpanded()){
31435 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31436 this.select(s.parentNode, e);
31444 * @class Roo.tree.MultiSelectionModel
31445 * @extends Roo.util.Observable
31446 * Multi selection for a TreePanel.
31448 Roo.tree.MultiSelectionModel = function(){
31449 this.selNodes = [];
31453 * @event selectionchange
31454 * Fires when the selected nodes change
31455 * @param {MultiSelectionModel} this
31456 * @param {Array} nodes Array of the selected nodes
31458 "selectionchange" : true
31462 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31463 init : function(tree){
31465 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31466 tree.on("click", this.onNodeClick, this);
31469 onNodeClick : function(node, e){
31470 this.select(node, e, e.ctrlKey);
31475 * @param {TreeNode} node The node to select
31476 * @param {EventObject} e (optional) An event associated with the selection
31477 * @param {Boolean} keepExisting True to retain existing selections
31478 * @return {TreeNode} The selected node
31480 select : function(node, e, keepExisting){
31481 if(keepExisting !== true){
31482 this.clearSelections(true);
31484 if(this.isSelected(node)){
31485 this.lastSelNode = node;
31488 this.selNodes.push(node);
31489 this.selMap[node.id] = node;
31490 this.lastSelNode = node;
31491 node.ui.onSelectedChange(true);
31492 this.fireEvent("selectionchange", this, this.selNodes);
31498 * @param {TreeNode} node The node to unselect
31500 unselect : function(node){
31501 if(this.selMap[node.id]){
31502 node.ui.onSelectedChange(false);
31503 var sn = this.selNodes;
31506 index = sn.indexOf(node);
31508 for(var i = 0, len = sn.length; i < len; i++){
31516 this.selNodes.splice(index, 1);
31518 delete this.selMap[node.id];
31519 this.fireEvent("selectionchange", this, this.selNodes);
31524 * Clear all selections
31526 clearSelections : function(suppressEvent){
31527 var sn = this.selNodes;
31529 for(var i = 0, len = sn.length; i < len; i++){
31530 sn[i].ui.onSelectedChange(false);
31532 this.selNodes = [];
31534 if(suppressEvent !== true){
31535 this.fireEvent("selectionchange", this, this.selNodes);
31541 * Returns true if the node is selected
31542 * @param {TreeNode} node The node to check
31543 * @return {Boolean}
31545 isSelected : function(node){
31546 return this.selMap[node.id] ? true : false;
31550 * Returns an array of the selected nodes
31553 getSelectedNodes : function(){
31554 return this.selNodes;
31557 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31559 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31561 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31564 * Ext JS Library 1.1.1
31565 * Copyright(c) 2006-2007, Ext JS, LLC.
31567 * Originally Released Under LGPL - original licence link has changed is not relivant.
31570 * <script type="text/javascript">
31574 * @class Roo.tree.TreeNode
31575 * @extends Roo.data.Node
31576 * @cfg {String} text The text for this node
31577 * @cfg {Boolean} expanded true to start the node expanded
31578 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31579 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31580 * @cfg {Boolean} disabled true to start the node disabled
31581 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31582 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31583 * @cfg {String} cls A css class to be added to the node
31584 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31585 * @cfg {String} href URL of the link used for the node (defaults to #)
31586 * @cfg {String} hrefTarget target frame for the link
31587 * @cfg {String} qtip An Ext QuickTip for the node
31588 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31589 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31590 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31591 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31592 * (defaults to undefined with no checkbox rendered)
31594 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31596 Roo.tree.TreeNode = function(attributes){
31597 attributes = attributes || {};
31598 if(typeof attributes == "string"){
31599 attributes = {text: attributes};
31601 this.childrenRendered = false;
31602 this.rendered = false;
31603 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31604 this.expanded = attributes.expanded === true;
31605 this.isTarget = attributes.isTarget !== false;
31606 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31607 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31610 * Read-only. The text for this node. To change it use setText().
31613 this.text = attributes.text;
31615 * True if this node is disabled.
31618 this.disabled = attributes.disabled === true;
31622 * @event textchange
31623 * Fires when the text for this node is changed
31624 * @param {Node} this This node
31625 * @param {String} text The new text
31626 * @param {String} oldText The old text
31628 "textchange" : true,
31630 * @event beforeexpand
31631 * Fires before this node is expanded, return false to cancel.
31632 * @param {Node} this This node
31633 * @param {Boolean} deep
31634 * @param {Boolean} anim
31636 "beforeexpand" : true,
31638 * @event beforecollapse
31639 * Fires before this node is collapsed, return false to cancel.
31640 * @param {Node} this This node
31641 * @param {Boolean} deep
31642 * @param {Boolean} anim
31644 "beforecollapse" : true,
31647 * Fires when this node is expanded
31648 * @param {Node} this This node
31652 * @event disabledchange
31653 * Fires when the disabled status of this node changes
31654 * @param {Node} this This node
31655 * @param {Boolean} disabled
31657 "disabledchange" : true,
31660 * Fires when this node is collapsed
31661 * @param {Node} this This node
31665 * @event beforeclick
31666 * Fires before click processing. Return false to cancel the default action.
31667 * @param {Node} this This node
31668 * @param {Roo.EventObject} e The event object
31670 "beforeclick":true,
31672 * @event checkchange
31673 * Fires when a node with a checkbox's checked property changes
31674 * @param {Node} this This node
31675 * @param {Boolean} checked
31677 "checkchange":true,
31680 * Fires when this node is clicked
31681 * @param {Node} this This node
31682 * @param {Roo.EventObject} e The event object
31687 * Fires when this node is double clicked
31688 * @param {Node} this This node
31689 * @param {Roo.EventObject} e The event object
31693 * @event contextmenu
31694 * Fires when this node is right clicked
31695 * @param {Node} this This node
31696 * @param {Roo.EventObject} e The event object
31698 "contextmenu":true,
31700 * @event beforechildrenrendered
31701 * Fires right before the child nodes for this node are rendered
31702 * @param {Node} this This node
31704 "beforechildrenrendered":true
31707 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31710 * Read-only. The UI for this node
31713 this.ui = new uiClass(this);
31715 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31716 preventHScroll: true,
31718 * Returns true if this node is expanded
31719 * @return {Boolean}
31721 isExpanded : function(){
31722 return this.expanded;
31726 * Returns the UI object for this node
31727 * @return {TreeNodeUI}
31729 getUI : function(){
31733 // private override
31734 setFirstChild : function(node){
31735 var of = this.firstChild;
31736 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31737 if(this.childrenRendered && of && node != of){
31738 of.renderIndent(true, true);
31741 this.renderIndent(true, true);
31745 // private override
31746 setLastChild : function(node){
31747 var ol = this.lastChild;
31748 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31749 if(this.childrenRendered && ol && node != ol){
31750 ol.renderIndent(true, true);
31753 this.renderIndent(true, true);
31757 // these methods are overridden to provide lazy rendering support
31758 // private override
31759 appendChild : function(){
31760 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31761 if(node && this.childrenRendered){
31764 this.ui.updateExpandIcon();
31768 // private override
31769 removeChild : function(node){
31770 this.ownerTree.getSelectionModel().unselect(node);
31771 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31772 // if it's been rendered remove dom node
31773 if(this.childrenRendered){
31776 if(this.childNodes.length < 1){
31777 this.collapse(false, false);
31779 this.ui.updateExpandIcon();
31781 if(!this.firstChild) {
31782 this.childrenRendered = false;
31787 // private override
31788 insertBefore : function(node, refNode){
31789 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31790 if(newNode && refNode && this.childrenRendered){
31793 this.ui.updateExpandIcon();
31798 * Sets the text for this node
31799 * @param {String} text
31801 setText : function(text){
31802 var oldText = this.text;
31804 this.attributes.text = text;
31805 if(this.rendered){ // event without subscribing
31806 this.ui.onTextChange(this, text, oldText);
31808 this.fireEvent("textchange", this, text, oldText);
31812 * Triggers selection of this node
31814 select : function(){
31815 this.getOwnerTree().getSelectionModel().select(this);
31819 * Triggers deselection of this node
31821 unselect : function(){
31822 this.getOwnerTree().getSelectionModel().unselect(this);
31826 * Returns true if this node is selected
31827 * @return {Boolean}
31829 isSelected : function(){
31830 return this.getOwnerTree().getSelectionModel().isSelected(this);
31834 * Expand this node.
31835 * @param {Boolean} deep (optional) True to expand all children as well
31836 * @param {Boolean} anim (optional) false to cancel the default animation
31837 * @param {Function} callback (optional) A callback to be called when
31838 * expanding this node completes (does not wait for deep expand to complete).
31839 * Called with 1 parameter, this node.
31841 expand : function(deep, anim, callback){
31842 if(!this.expanded){
31843 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31846 if(!this.childrenRendered){
31847 this.renderChildren();
31849 this.expanded = true;
31850 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31851 this.ui.animExpand(function(){
31852 this.fireEvent("expand", this);
31853 if(typeof callback == "function"){
31857 this.expandChildNodes(true);
31859 }.createDelegate(this));
31863 this.fireEvent("expand", this);
31864 if(typeof callback == "function"){
31869 if(typeof callback == "function"){
31874 this.expandChildNodes(true);
31878 isHiddenRoot : function(){
31879 return this.isRoot && !this.getOwnerTree().rootVisible;
31883 * Collapse this node.
31884 * @param {Boolean} deep (optional) True to collapse all children as well
31885 * @param {Boolean} anim (optional) false to cancel the default animation
31887 collapse : function(deep, anim){
31888 if(this.expanded && !this.isHiddenRoot()){
31889 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31892 this.expanded = false;
31893 if((this.getOwnerTree().animate && anim !== false) || anim){
31894 this.ui.animCollapse(function(){
31895 this.fireEvent("collapse", this);
31897 this.collapseChildNodes(true);
31899 }.createDelegate(this));
31902 this.ui.collapse();
31903 this.fireEvent("collapse", this);
31907 var cs = this.childNodes;
31908 for(var i = 0, len = cs.length; i < len; i++) {
31909 cs[i].collapse(true, false);
31915 delayedExpand : function(delay){
31916 if(!this.expandProcId){
31917 this.expandProcId = this.expand.defer(delay, this);
31922 cancelExpand : function(){
31923 if(this.expandProcId){
31924 clearTimeout(this.expandProcId);
31926 this.expandProcId = false;
31930 * Toggles expanded/collapsed state of the node
31932 toggle : function(){
31941 * Ensures all parent nodes are expanded
31943 ensureVisible : function(callback){
31944 var tree = this.getOwnerTree();
31945 tree.expandPath(this.parentNode.getPath(), false, function(){
31946 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31947 Roo.callback(callback);
31948 }.createDelegate(this));
31952 * Expand all child nodes
31953 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31955 expandChildNodes : function(deep){
31956 var cs = this.childNodes;
31957 for(var i = 0, len = cs.length; i < len; i++) {
31958 cs[i].expand(deep);
31963 * Collapse all child nodes
31964 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31966 collapseChildNodes : function(deep){
31967 var cs = this.childNodes;
31968 for(var i = 0, len = cs.length; i < len; i++) {
31969 cs[i].collapse(deep);
31974 * Disables this node
31976 disable : function(){
31977 this.disabled = true;
31979 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31980 this.ui.onDisableChange(this, true);
31982 this.fireEvent("disabledchange", this, true);
31986 * Enables this node
31988 enable : function(){
31989 this.disabled = false;
31990 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31991 this.ui.onDisableChange(this, false);
31993 this.fireEvent("disabledchange", this, false);
31997 renderChildren : function(suppressEvent){
31998 if(suppressEvent !== false){
31999 this.fireEvent("beforechildrenrendered", this);
32001 var cs = this.childNodes;
32002 for(var i = 0, len = cs.length; i < len; i++){
32003 cs[i].render(true);
32005 this.childrenRendered = true;
32009 sort : function(fn, scope){
32010 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32011 if(this.childrenRendered){
32012 var cs = this.childNodes;
32013 for(var i = 0, len = cs.length; i < len; i++){
32014 cs[i].render(true);
32020 render : function(bulkRender){
32021 this.ui.render(bulkRender);
32022 if(!this.rendered){
32023 this.rendered = true;
32025 this.expanded = false;
32026 this.expand(false, false);
32032 renderIndent : function(deep, refresh){
32034 this.ui.childIndent = null;
32036 this.ui.renderIndent();
32037 if(deep === true && this.childrenRendered){
32038 var cs = this.childNodes;
32039 for(var i = 0, len = cs.length; i < len; i++){
32040 cs[i].renderIndent(true, refresh);
32046 * Ext JS Library 1.1.1
32047 * Copyright(c) 2006-2007, Ext JS, LLC.
32049 * Originally Released Under LGPL - original licence link has changed is not relivant.
32052 * <script type="text/javascript">
32056 * @class Roo.tree.AsyncTreeNode
32057 * @extends Roo.tree.TreeNode
32058 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32060 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32062 Roo.tree.AsyncTreeNode = function(config){
32063 this.loaded = false;
32064 this.loading = false;
32065 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32067 * @event beforeload
32068 * Fires before this node is loaded, return false to cancel
32069 * @param {Node} this This node
32071 this.addEvents({'beforeload':true, 'load': true});
32074 * Fires when this node is loaded
32075 * @param {Node} this This node
32078 * The loader used by this node (defaults to using the tree's defined loader)
32083 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32084 expand : function(deep, anim, callback){
32085 if(this.loading){ // if an async load is already running, waiting til it's done
32087 var f = function(){
32088 if(!this.loading){ // done loading
32089 clearInterval(timer);
32090 this.expand(deep, anim, callback);
32092 }.createDelegate(this);
32093 timer = setInterval(f, 200);
32097 if(this.fireEvent("beforeload", this) === false){
32100 this.loading = true;
32101 this.ui.beforeLoad(this);
32102 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32104 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32108 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32112 * Returns true if this node is currently loading
32113 * @return {Boolean}
32115 isLoading : function(){
32116 return this.loading;
32119 loadComplete : function(deep, anim, callback){
32120 this.loading = false;
32121 this.loaded = true;
32122 this.ui.afterLoad(this);
32123 this.fireEvent("load", this);
32124 this.expand(deep, anim, callback);
32128 * Returns true if this node has been loaded
32129 * @return {Boolean}
32131 isLoaded : function(){
32132 return this.loaded;
32135 hasChildNodes : function(){
32136 if(!this.isLeaf() && !this.loaded){
32139 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32144 * Trigger a reload for this node
32145 * @param {Function} callback
32147 reload : function(callback){
32148 this.collapse(false, false);
32149 while(this.firstChild){
32150 this.removeChild(this.firstChild);
32152 this.childrenRendered = false;
32153 this.loaded = false;
32154 if(this.isHiddenRoot()){
32155 this.expanded = false;
32157 this.expand(false, false, callback);
32161 * Ext JS Library 1.1.1
32162 * Copyright(c) 2006-2007, Ext JS, LLC.
32164 * Originally Released Under LGPL - original licence link has changed is not relivant.
32167 * <script type="text/javascript">
32171 * @class Roo.tree.TreeNodeUI
32173 * @param {Object} node The node to render
32174 * The TreeNode UI implementation is separate from the
32175 * tree implementation. Unless you are customizing the tree UI,
32176 * you should never have to use this directly.
32178 Roo.tree.TreeNodeUI = function(node){
32180 this.rendered = false;
32181 this.animating = false;
32182 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32185 Roo.tree.TreeNodeUI.prototype = {
32186 removeChild : function(node){
32188 this.ctNode.removeChild(node.ui.getEl());
32192 beforeLoad : function(){
32193 this.addClass("x-tree-node-loading");
32196 afterLoad : function(){
32197 this.removeClass("x-tree-node-loading");
32200 onTextChange : function(node, text, oldText){
32202 this.textNode.innerHTML = text;
32206 onDisableChange : function(node, state){
32207 this.disabled = state;
32209 this.addClass("x-tree-node-disabled");
32211 this.removeClass("x-tree-node-disabled");
32215 onSelectedChange : function(state){
32218 this.addClass("x-tree-selected");
32221 this.removeClass("x-tree-selected");
32225 onMove : function(tree, node, oldParent, newParent, index, refNode){
32226 this.childIndent = null;
32228 var targetNode = newParent.ui.getContainer();
32229 if(!targetNode){//target not rendered
32230 this.holder = document.createElement("div");
32231 this.holder.appendChild(this.wrap);
32234 var insertBefore = refNode ? refNode.ui.getEl() : null;
32236 targetNode.insertBefore(this.wrap, insertBefore);
32238 targetNode.appendChild(this.wrap);
32240 this.node.renderIndent(true);
32244 addClass : function(cls){
32246 Roo.fly(this.elNode).addClass(cls);
32250 removeClass : function(cls){
32252 Roo.fly(this.elNode).removeClass(cls);
32256 remove : function(){
32258 this.holder = document.createElement("div");
32259 this.holder.appendChild(this.wrap);
32263 fireEvent : function(){
32264 return this.node.fireEvent.apply(this.node, arguments);
32267 initEvents : function(){
32268 this.node.on("move", this.onMove, this);
32269 var E = Roo.EventManager;
32270 var a = this.anchor;
32272 var el = Roo.fly(a, '_treeui');
32274 if(Roo.isOpera){ // opera render bug ignores the CSS
32275 el.setStyle("text-decoration", "none");
32278 el.on("click", this.onClick, this);
32279 el.on("dblclick", this.onDblClick, this);
32282 Roo.EventManager.on(this.checkbox,
32283 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32286 el.on("contextmenu", this.onContextMenu, this);
32288 var icon = Roo.fly(this.iconNode);
32289 icon.on("click", this.onClick, this);
32290 icon.on("dblclick", this.onDblClick, this);
32291 icon.on("contextmenu", this.onContextMenu, this);
32292 E.on(this.ecNode, "click", this.ecClick, this, true);
32294 if(this.node.disabled){
32295 this.addClass("x-tree-node-disabled");
32297 if(this.node.hidden){
32298 this.addClass("x-tree-node-disabled");
32300 var ot = this.node.getOwnerTree();
32301 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32302 if(dd && (!this.node.isRoot || ot.rootVisible)){
32303 Roo.dd.Registry.register(this.elNode, {
32305 handles: this.getDDHandles(),
32311 getDDHandles : function(){
32312 return [this.iconNode, this.textNode];
32317 this.wrap.style.display = "none";
32323 this.wrap.style.display = "";
32327 onContextMenu : function(e){
32328 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32329 e.preventDefault();
32331 this.fireEvent("contextmenu", this.node, e);
32335 onClick : function(e){
32340 if(this.fireEvent("beforeclick", this.node, e) !== false){
32341 if(!this.disabled && this.node.attributes.href){
32342 this.fireEvent("click", this.node, e);
32345 e.preventDefault();
32350 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32351 this.node.toggle();
32354 this.fireEvent("click", this.node, e);
32360 onDblClick : function(e){
32361 e.preventDefault();
32366 this.toggleCheck();
32368 if(!this.animating && this.node.hasChildNodes()){
32369 this.node.toggle();
32371 this.fireEvent("dblclick", this.node, e);
32374 onCheckChange : function(){
32375 var checked = this.checkbox.checked;
32376 this.node.attributes.checked = checked;
32377 this.fireEvent('checkchange', this.node, checked);
32380 ecClick : function(e){
32381 if(!this.animating && this.node.hasChildNodes()){
32382 this.node.toggle();
32386 startDrop : function(){
32387 this.dropping = true;
32390 // delayed drop so the click event doesn't get fired on a drop
32391 endDrop : function(){
32392 setTimeout(function(){
32393 this.dropping = false;
32394 }.createDelegate(this), 50);
32397 expand : function(){
32398 this.updateExpandIcon();
32399 this.ctNode.style.display = "";
32402 focus : function(){
32403 if(!this.node.preventHScroll){
32404 try{this.anchor.focus();
32406 }else if(!Roo.isIE){
32408 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32409 var l = noscroll.scrollLeft;
32410 this.anchor.focus();
32411 noscroll.scrollLeft = l;
32416 toggleCheck : function(value){
32417 var cb = this.checkbox;
32419 cb.checked = (value === undefined ? !cb.checked : value);
32425 this.anchor.blur();
32429 animExpand : function(callback){
32430 var ct = Roo.get(this.ctNode);
32432 if(!this.node.hasChildNodes()){
32433 this.updateExpandIcon();
32434 this.ctNode.style.display = "";
32435 Roo.callback(callback);
32438 this.animating = true;
32439 this.updateExpandIcon();
32442 callback : function(){
32443 this.animating = false;
32444 Roo.callback(callback);
32447 duration: this.node.ownerTree.duration || .25
32451 highlight : function(){
32452 var tree = this.node.getOwnerTree();
32453 Roo.fly(this.wrap).highlight(
32454 tree.hlColor || "C3DAF9",
32455 {endColor: tree.hlBaseColor}
32459 collapse : function(){
32460 this.updateExpandIcon();
32461 this.ctNode.style.display = "none";
32464 animCollapse : function(callback){
32465 var ct = Roo.get(this.ctNode);
32466 ct.enableDisplayMode('block');
32469 this.animating = true;
32470 this.updateExpandIcon();
32473 callback : function(){
32474 this.animating = false;
32475 Roo.callback(callback);
32478 duration: this.node.ownerTree.duration || .25
32482 getContainer : function(){
32483 return this.ctNode;
32486 getEl : function(){
32490 appendDDGhost : function(ghostNode){
32491 ghostNode.appendChild(this.elNode.cloneNode(true));
32494 getDDRepairXY : function(){
32495 return Roo.lib.Dom.getXY(this.iconNode);
32498 onRender : function(){
32502 render : function(bulkRender){
32503 var n = this.node, a = n.attributes;
32504 var targetNode = n.parentNode ?
32505 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32507 if(!this.rendered){
32508 this.rendered = true;
32510 this.renderElements(n, a, targetNode, bulkRender);
32513 if(this.textNode.setAttributeNS){
32514 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32516 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32519 this.textNode.setAttribute("ext:qtip", a.qtip);
32521 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32524 }else if(a.qtipCfg){
32525 a.qtipCfg.target = Roo.id(this.textNode);
32526 Roo.QuickTips.register(a.qtipCfg);
32529 if(!this.node.expanded){
32530 this.updateExpandIcon();
32533 if(bulkRender === true) {
32534 targetNode.appendChild(this.wrap);
32539 renderElements : function(n, a, targetNode, bulkRender){
32540 // add some indent caching, this helps performance when rendering a large tree
32541 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32542 var t = n.getOwnerTree();
32543 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32544 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32545 var cb = typeof a.checked == 'boolean';
32546 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32547 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32548 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32549 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32550 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32551 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32552 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32553 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32554 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32555 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32558 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32559 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32560 n.nextSibling.ui.getEl(), buf.join(""));
32562 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32565 this.elNode = this.wrap.childNodes[0];
32566 this.ctNode = this.wrap.childNodes[1];
32567 var cs = this.elNode.childNodes;
32568 this.indentNode = cs[0];
32569 this.ecNode = cs[1];
32570 this.iconNode = cs[2];
32573 this.checkbox = cs[3];
32576 this.anchor = cs[index];
32577 this.textNode = cs[index].firstChild;
32580 getAnchor : function(){
32581 return this.anchor;
32584 getTextEl : function(){
32585 return this.textNode;
32588 getIconEl : function(){
32589 return this.iconNode;
32592 isChecked : function(){
32593 return this.checkbox ? this.checkbox.checked : false;
32596 updateExpandIcon : function(){
32598 var n = this.node, c1, c2;
32599 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32600 var hasChild = n.hasChildNodes();
32604 c1 = "x-tree-node-collapsed";
32605 c2 = "x-tree-node-expanded";
32608 c1 = "x-tree-node-expanded";
32609 c2 = "x-tree-node-collapsed";
32612 this.removeClass("x-tree-node-leaf");
32613 this.wasLeaf = false;
32615 if(this.c1 != c1 || this.c2 != c2){
32616 Roo.fly(this.elNode).replaceClass(c1, c2);
32617 this.c1 = c1; this.c2 = c2;
32621 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32624 this.wasLeaf = true;
32627 var ecc = "x-tree-ec-icon "+cls;
32628 if(this.ecc != ecc){
32629 this.ecNode.className = ecc;
32635 getChildIndent : function(){
32636 if(!this.childIndent){
32640 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32642 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32644 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32649 this.childIndent = buf.join("");
32651 return this.childIndent;
32654 renderIndent : function(){
32657 var p = this.node.parentNode;
32659 indent = p.ui.getChildIndent();
32661 if(this.indentMarkup != indent){ // don't rerender if not required
32662 this.indentNode.innerHTML = indent;
32663 this.indentMarkup = indent;
32665 this.updateExpandIcon();
32670 Roo.tree.RootTreeNodeUI = function(){
32671 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32673 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32674 render : function(){
32675 if(!this.rendered){
32676 var targetNode = this.node.ownerTree.innerCt.dom;
32677 this.node.expanded = true;
32678 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32679 this.wrap = this.ctNode = targetNode.firstChild;
32682 collapse : function(){
32684 expand : function(){
32688 * Ext JS Library 1.1.1
32689 * Copyright(c) 2006-2007, Ext JS, LLC.
32691 * Originally Released Under LGPL - original licence link has changed is not relivant.
32694 * <script type="text/javascript">
32697 * @class Roo.tree.TreeLoader
32698 * @extends Roo.util.Observable
32699 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32700 * nodes from a specified URL. The response must be a javascript Array definition
32701 * who's elements are node definition objects. eg:
32703 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32704 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32707 * A server request is sent, and child nodes are loaded only when a node is expanded.
32708 * The loading node's id is passed to the server under the parameter name "node" to
32709 * enable the server to produce the correct child nodes.
32711 * To pass extra parameters, an event handler may be attached to the "beforeload"
32712 * event, and the parameters specified in the TreeLoader's baseParams property:
32714 myTreeLoader.on("beforeload", function(treeLoader, node) {
32715 this.baseParams.category = node.attributes.category;
32718 * This would pass an HTTP parameter called "category" to the server containing
32719 * the value of the Node's "category" attribute.
32721 * Creates a new Treeloader.
32722 * @param {Object} config A config object containing config properties.
32724 Roo.tree.TreeLoader = function(config){
32725 this.baseParams = {};
32726 this.requestMethod = "POST";
32727 Roo.apply(this, config);
32732 * @event beforeload
32733 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32734 * @param {Object} This TreeLoader object.
32735 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32736 * @param {Object} callback The callback function specified in the {@link #load} call.
32741 * Fires when the node has been successfuly loaded.
32742 * @param {Object} This TreeLoader object.
32743 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32744 * @param {Object} response The response object containing the data from the server.
32748 * @event loadexception
32749 * Fires if the network request failed.
32750 * @param {Object} This TreeLoader object.
32751 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32752 * @param {Object} response The response object containing the data from the server.
32754 loadexception : true,
32757 * Fires before a node is created, enabling you to return custom Node types
32758 * @param {Object} This TreeLoader object.
32759 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32764 Roo.tree.TreeLoader.superclass.constructor.call(this);
32767 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32769 * @cfg {String} dataUrl The URL from which to request a Json string which
32770 * specifies an array of node definition object representing the child nodes
32774 * @cfg {Object} baseParams (optional) An object containing properties which
32775 * specify HTTP parameters to be passed to each request for child nodes.
32778 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32779 * created by this loader. If the attributes sent by the server have an attribute in this object,
32780 * they take priority.
32783 * @cfg {Object} uiProviders (optional) An object containing properties which
32785 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32786 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32787 * <i>uiProvider</i> attribute of a returned child node is a string rather
32788 * than a reference to a TreeNodeUI implementation, this that string value
32789 * is used as a property name in the uiProviders object. You can define the provider named
32790 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32795 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32796 * child nodes before loading.
32798 clearOnLoad : true,
32801 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32802 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32803 * Grid query { data : [ .....] }
32808 * @cfg {String} queryParam (optional)
32809 * Name of the query as it will be passed on the querystring (defaults to 'node')
32810 * eg. the request will be ?node=[id]
32817 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32818 * This is called automatically when a node is expanded, but may be used to reload
32819 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32820 * @param {Roo.tree.TreeNode} node
32821 * @param {Function} callback
32823 load : function(node, callback){
32824 if(this.clearOnLoad){
32825 while(node.firstChild){
32826 node.removeChild(node.firstChild);
32829 if(node.attributes.children){ // preloaded json children
32830 var cs = node.attributes.children;
32831 for(var i = 0, len = cs.length; i < len; i++){
32832 node.appendChild(this.createNode(cs[i]));
32834 if(typeof callback == "function"){
32837 }else if(this.dataUrl){
32838 this.requestData(node, callback);
32842 getParams: function(node){
32843 var buf = [], bp = this.baseParams;
32844 for(var key in bp){
32845 if(typeof bp[key] != "function"){
32846 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32849 var n = this.queryParam === false ? 'node' : this.queryParam;
32850 buf.push(n + "=", encodeURIComponent(node.id));
32851 return buf.join("");
32854 requestData : function(node, callback){
32855 if(this.fireEvent("beforeload", this, node, callback) !== false){
32856 this.transId = Roo.Ajax.request({
32857 method:this.requestMethod,
32858 url: this.dataUrl||this.url,
32859 success: this.handleResponse,
32860 failure: this.handleFailure,
32862 argument: {callback: callback, node: node},
32863 params: this.getParams(node)
32866 // if the load is cancelled, make sure we notify
32867 // the node that we are done
32868 if(typeof callback == "function"){
32874 isLoading : function(){
32875 return this.transId ? true : false;
32878 abort : function(){
32879 if(this.isLoading()){
32880 Roo.Ajax.abort(this.transId);
32885 createNode : function(attr){
32886 // apply baseAttrs, nice idea Corey!
32887 if(this.baseAttrs){
32888 Roo.applyIf(attr, this.baseAttrs);
32890 if(this.applyLoader !== false){
32891 attr.loader = this;
32893 // uiProvider = depreciated..
32895 if(typeof(attr.uiProvider) == 'string'){
32896 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32897 /** eval:var:attr */ eval(attr.uiProvider);
32899 if(typeof(this.uiProviders['default']) != 'undefined') {
32900 attr.uiProvider = this.uiProviders['default'];
32903 this.fireEvent('create', this, attr);
32905 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32907 new Roo.tree.TreeNode(attr) :
32908 new Roo.tree.AsyncTreeNode(attr));
32911 processResponse : function(response, node, callback){
32912 var json = response.responseText;
32915 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32916 if (this.root !== false) {
32920 for(var i = 0, len = o.length; i < len; i++){
32921 var n = this.createNode(o[i]);
32923 node.appendChild(n);
32926 if(typeof callback == "function"){
32927 callback(this, node);
32930 this.handleFailure(response);
32934 handleResponse : function(response){
32935 this.transId = false;
32936 var a = response.argument;
32937 this.processResponse(response, a.node, a.callback);
32938 this.fireEvent("load", this, a.node, response);
32941 handleFailure : function(response){
32942 this.transId = false;
32943 var a = response.argument;
32944 this.fireEvent("loadexception", this, a.node, response);
32945 if(typeof a.callback == "function"){
32946 a.callback(this, a.node);
32951 * Ext JS Library 1.1.1
32952 * Copyright(c) 2006-2007, Ext JS, LLC.
32954 * Originally Released Under LGPL - original licence link has changed is not relivant.
32957 * <script type="text/javascript">
32961 * @class Roo.tree.TreeFilter
32962 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32963 * @param {TreePanel} tree
32964 * @param {Object} config (optional)
32966 Roo.tree.TreeFilter = function(tree, config){
32968 this.filtered = {};
32969 Roo.apply(this, config);
32972 Roo.tree.TreeFilter.prototype = {
32979 * Filter the data by a specific attribute.
32980 * @param {String/RegExp} value Either string that the attribute value
32981 * should start with or a RegExp to test against the attribute
32982 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32983 * @param {TreeNode} startNode (optional) The node to start the filter at.
32985 filter : function(value, attr, startNode){
32986 attr = attr || "text";
32988 if(typeof value == "string"){
32989 var vlen = value.length;
32990 // auto clear empty filter
32991 if(vlen == 0 && this.clearBlank){
32995 value = value.toLowerCase();
32997 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32999 }else if(value.exec){ // regex?
33001 return value.test(n.attributes[attr]);
33004 throw 'Illegal filter type, must be string or regex';
33006 this.filterBy(f, null, startNode);
33010 * Filter by a function. The passed function will be called with each
33011 * node in the tree (or from the startNode). If the function returns true, the node is kept
33012 * otherwise it is filtered. If a node is filtered, its children are also filtered.
33013 * @param {Function} fn The filter function
33014 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33016 filterBy : function(fn, scope, startNode){
33017 startNode = startNode || this.tree.root;
33018 if(this.autoClear){
33021 var af = this.filtered, rv = this.reverse;
33022 var f = function(n){
33023 if(n == startNode){
33029 var m = fn.call(scope || n, n);
33037 startNode.cascade(f);
33040 if(typeof id != "function"){
33042 if(n && n.parentNode){
33043 n.parentNode.removeChild(n);
33051 * Clears the current filter. Note: with the "remove" option
33052 * set a filter cannot be cleared.
33054 clear : function(){
33056 var af = this.filtered;
33058 if(typeof id != "function"){
33065 this.filtered = {};
33070 * Ext JS Library 1.1.1
33071 * Copyright(c) 2006-2007, Ext JS, LLC.
33073 * Originally Released Under LGPL - original licence link has changed is not relivant.
33076 * <script type="text/javascript">
33081 * @class Roo.tree.TreeSorter
33082 * Provides sorting of nodes in a TreePanel
33084 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33085 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33086 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33087 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33088 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33089 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33091 * @param {TreePanel} tree
33092 * @param {Object} config
33094 Roo.tree.TreeSorter = function(tree, config){
33095 Roo.apply(this, config);
33096 tree.on("beforechildrenrendered", this.doSort, this);
33097 tree.on("append", this.updateSort, this);
33098 tree.on("insert", this.updateSort, this);
33100 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33101 var p = this.property || "text";
33102 var sortType = this.sortType;
33103 var fs = this.folderSort;
33104 var cs = this.caseSensitive === true;
33105 var leafAttr = this.leafAttr || 'leaf';
33107 this.sortFn = function(n1, n2){
33109 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33112 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33116 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33117 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33119 return dsc ? +1 : -1;
33121 return dsc ? -1 : +1;
33128 Roo.tree.TreeSorter.prototype = {
33129 doSort : function(node){
33130 node.sort(this.sortFn);
33133 compareNodes : function(n1, n2){
33134 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33137 updateSort : function(tree, node){
33138 if(node.childrenRendered){
33139 this.doSort.defer(1, this, [node]);
33144 * Ext JS Library 1.1.1
33145 * Copyright(c) 2006-2007, Ext JS, LLC.
33147 * Originally Released Under LGPL - original licence link has changed is not relivant.
33150 * <script type="text/javascript">
33153 if(Roo.dd.DropZone){
33155 Roo.tree.TreeDropZone = function(tree, config){
33156 this.allowParentInsert = false;
33157 this.allowContainerDrop = false;
33158 this.appendOnly = false;
33159 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33161 this.lastInsertClass = "x-tree-no-status";
33162 this.dragOverData = {};
33165 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33166 ddGroup : "TreeDD",
33168 expandDelay : 1000,
33170 expandNode : function(node){
33171 if(node.hasChildNodes() && !node.isExpanded()){
33172 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33176 queueExpand : function(node){
33177 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33180 cancelExpand : function(){
33181 if(this.expandProcId){
33182 clearTimeout(this.expandProcId);
33183 this.expandProcId = false;
33187 isValidDropPoint : function(n, pt, dd, e, data){
33188 if(!n || !data){ return false; }
33189 var targetNode = n.node;
33190 var dropNode = data.node;
33191 // default drop rules
33192 if(!(targetNode && targetNode.isTarget && pt)){
33195 if(pt == "append" && targetNode.allowChildren === false){
33198 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33201 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33204 // reuse the object
33205 var overEvent = this.dragOverData;
33206 overEvent.tree = this.tree;
33207 overEvent.target = targetNode;
33208 overEvent.data = data;
33209 overEvent.point = pt;
33210 overEvent.source = dd;
33211 overEvent.rawEvent = e;
33212 overEvent.dropNode = dropNode;
33213 overEvent.cancel = false;
33214 var result = this.tree.fireEvent("nodedragover", overEvent);
33215 return overEvent.cancel === false && result !== false;
33218 getDropPoint : function(e, n, dd){
33221 return tn.allowChildren !== false ? "append" : false; // always append for root
33223 var dragEl = n.ddel;
33224 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33225 var y = Roo.lib.Event.getPageY(e);
33226 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33228 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33229 var noAppend = tn.allowChildren === false;
33230 if(this.appendOnly || tn.parentNode.allowChildren === false){
33231 return noAppend ? false : "append";
33233 var noBelow = false;
33234 if(!this.allowParentInsert){
33235 noBelow = tn.hasChildNodes() && tn.isExpanded();
33237 var q = (b - t) / (noAppend ? 2 : 3);
33238 if(y >= t && y < (t + q)){
33240 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33247 onNodeEnter : function(n, dd, e, data){
33248 this.cancelExpand();
33251 onNodeOver : function(n, dd, e, data){
33252 var pt = this.getDropPoint(e, n, dd);
33255 // auto node expand check
33256 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33257 this.queueExpand(node);
33258 }else if(pt != "append"){
33259 this.cancelExpand();
33262 // set the insert point style on the target node
33263 var returnCls = this.dropNotAllowed;
33264 if(this.isValidDropPoint(n, pt, dd, e, data)){
33269 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33270 cls = "x-tree-drag-insert-above";
33271 }else if(pt == "below"){
33272 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33273 cls = "x-tree-drag-insert-below";
33275 returnCls = "x-tree-drop-ok-append";
33276 cls = "x-tree-drag-append";
33278 if(this.lastInsertClass != cls){
33279 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33280 this.lastInsertClass = cls;
33287 onNodeOut : function(n, dd, e, data){
33288 this.cancelExpand();
33289 this.removeDropIndicators(n);
33292 onNodeDrop : function(n, dd, e, data){
33293 var point = this.getDropPoint(e, n, dd);
33294 var targetNode = n.node;
33295 targetNode.ui.startDrop();
33296 if(!this.isValidDropPoint(n, point, dd, e, data)){
33297 targetNode.ui.endDrop();
33300 // first try to find the drop node
33301 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33304 target: targetNode,
33309 dropNode: dropNode,
33312 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33313 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33314 targetNode.ui.endDrop();
33317 // allow target changing
33318 targetNode = dropEvent.target;
33319 if(point == "append" && !targetNode.isExpanded()){
33320 targetNode.expand(false, null, function(){
33321 this.completeDrop(dropEvent);
33322 }.createDelegate(this));
33324 this.completeDrop(dropEvent);
33329 completeDrop : function(de){
33330 var ns = de.dropNode, p = de.point, t = de.target;
33331 if(!(ns instanceof Array)){
33335 for(var i = 0, len = ns.length; i < len; i++){
33338 t.parentNode.insertBefore(n, t);
33339 }else if(p == "below"){
33340 t.parentNode.insertBefore(n, t.nextSibling);
33346 if(this.tree.hlDrop){
33350 this.tree.fireEvent("nodedrop", de);
33353 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33354 if(this.tree.hlDrop){
33355 dropNode.ui.focus();
33356 dropNode.ui.highlight();
33358 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33361 getTree : function(){
33365 removeDropIndicators : function(n){
33368 Roo.fly(el).removeClass([
33369 "x-tree-drag-insert-above",
33370 "x-tree-drag-insert-below",
33371 "x-tree-drag-append"]);
33372 this.lastInsertClass = "_noclass";
33376 beforeDragDrop : function(target, e, id){
33377 this.cancelExpand();
33381 afterRepair : function(data){
33382 if(data && Roo.enableFx){
33383 data.node.ui.highlight();
33392 * Ext JS Library 1.1.1
33393 * Copyright(c) 2006-2007, Ext JS, LLC.
33395 * Originally Released Under LGPL - original licence link has changed is not relivant.
33398 * <script type="text/javascript">
33402 if(Roo.dd.DragZone){
33403 Roo.tree.TreeDragZone = function(tree, config){
33404 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33408 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33409 ddGroup : "TreeDD",
33411 onBeforeDrag : function(data, e){
33413 return n && n.draggable && !n.disabled;
33416 onInitDrag : function(e){
33417 var data = this.dragData;
33418 this.tree.getSelectionModel().select(data.node);
33419 this.proxy.update("");
33420 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33421 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33424 getRepairXY : function(e, data){
33425 return data.node.ui.getDDRepairXY();
33428 onEndDrag : function(data, e){
33429 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33432 onValidDrop : function(dd, e, id){
33433 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33437 beforeInvalidDrop : function(e, id){
33438 // this scrolls the original position back into view
33439 var sm = this.tree.getSelectionModel();
33440 sm.clearSelections();
33441 sm.select(this.dragData.node);
33446 * Ext JS Library 1.1.1
33447 * Copyright(c) 2006-2007, Ext JS, LLC.
33449 * Originally Released Under LGPL - original licence link has changed is not relivant.
33452 * <script type="text/javascript">
33455 * @class Roo.tree.TreeEditor
33456 * @extends Roo.Editor
33457 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33458 * as the editor field.
33460 * @param {TreePanel} tree
33461 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33463 Roo.tree.TreeEditor = function(tree, config){
33464 config = config || {};
33465 var field = config.events ? config : new Roo.form.TextField(config);
33466 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33470 tree.on('beforeclick', this.beforeNodeClick, this);
33471 tree.getTreeEl().on('mousedown', this.hide, this);
33472 this.on('complete', this.updateNode, this);
33473 this.on('beforestartedit', this.fitToTree, this);
33474 this.on('startedit', this.bindScroll, this, {delay:10});
33475 this.on('specialkey', this.onSpecialKey, this);
33478 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33480 * @cfg {String} alignment
33481 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33487 * @cfg {Boolean} hideEl
33488 * True to hide the bound element while the editor is displayed (defaults to false)
33492 * @cfg {String} cls
33493 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33495 cls: "x-small-editor x-tree-editor",
33497 * @cfg {Boolean} shim
33498 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33504 * @cfg {Number} maxWidth
33505 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33506 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33507 * scroll and client offsets into account prior to each edit.
33514 fitToTree : function(ed, el){
33515 var td = this.tree.getTreeEl().dom, nd = el.dom;
33516 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33517 td.scrollLeft = nd.offsetLeft;
33521 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33522 this.setSize(w, '');
33526 triggerEdit : function(node){
33527 this.completeEdit();
33528 this.editNode = node;
33529 this.startEdit(node.ui.textNode, node.text);
33533 bindScroll : function(){
33534 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33538 beforeNodeClick : function(node, e){
33539 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33540 this.lastClick = new Date();
33541 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33543 this.triggerEdit(node);
33549 updateNode : function(ed, value){
33550 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33551 this.editNode.setText(value);
33555 onHide : function(){
33556 Roo.tree.TreeEditor.superclass.onHide.call(this);
33558 this.editNode.ui.focus();
33563 onSpecialKey : function(field, e){
33564 var k = e.getKey();
33568 }else if(k == e.ENTER && !e.hasModifier()){
33570 this.completeEdit();
33573 });//<Script type="text/javascript">
33576 * Ext JS Library 1.1.1
33577 * Copyright(c) 2006-2007, Ext JS, LLC.
33579 * Originally Released Under LGPL - original licence link has changed is not relivant.
33582 * <script type="text/javascript">
33586 * Not documented??? - probably should be...
33589 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33590 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33592 renderElements : function(n, a, targetNode, bulkRender){
33593 //consel.log("renderElements?");
33594 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33596 var t = n.getOwnerTree();
33597 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33599 var cols = t.columns;
33600 var bw = t.borderWidth;
33602 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33603 var cb = typeof a.checked == "boolean";
33604 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33605 var colcls = 'x-t-' + tid + '-c0';
33607 '<li class="x-tree-node">',
33610 '<div class="x-tree-node-el ', a.cls,'">',
33612 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33615 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33616 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33617 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33618 (a.icon ? ' x-tree-node-inline-icon' : ''),
33619 (a.iconCls ? ' '+a.iconCls : ''),
33620 '" unselectable="on" />',
33621 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33622 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33624 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33625 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33626 '<span unselectable="on" qtip="' + tx + '">',
33630 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33631 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33633 for(var i = 1, len = cols.length; i < len; i++){
33635 colcls = 'x-t-' + tid + '-c' +i;
33636 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33637 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33638 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33644 '<div class="x-clear"></div></div>',
33645 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33648 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33649 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33650 n.nextSibling.ui.getEl(), buf.join(""));
33652 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33654 var el = this.wrap.firstChild;
33656 this.elNode = el.firstChild;
33657 this.ranchor = el.childNodes[1];
33658 this.ctNode = this.wrap.childNodes[1];
33659 var cs = el.firstChild.childNodes;
33660 this.indentNode = cs[0];
33661 this.ecNode = cs[1];
33662 this.iconNode = cs[2];
33665 this.checkbox = cs[3];
33668 this.anchor = cs[index];
33670 this.textNode = cs[index].firstChild;
33672 //el.on("click", this.onClick, this);
33673 //el.on("dblclick", this.onDblClick, this);
33676 // console.log(this);
33678 initEvents : function(){
33679 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33682 var a = this.ranchor;
33684 var el = Roo.get(a);
33686 if(Roo.isOpera){ // opera render bug ignores the CSS
33687 el.setStyle("text-decoration", "none");
33690 el.on("click", this.onClick, this);
33691 el.on("dblclick", this.onDblClick, this);
33692 el.on("contextmenu", this.onContextMenu, this);
33696 /*onSelectedChange : function(state){
33699 this.addClass("x-tree-selected");
33702 this.removeClass("x-tree-selected");
33705 addClass : function(cls){
33707 Roo.fly(this.elRow).addClass(cls);
33713 removeClass : function(cls){
33715 Roo.fly(this.elRow).removeClass(cls);
33721 });//<Script type="text/javascript">
33725 * Ext JS Library 1.1.1
33726 * Copyright(c) 2006-2007, Ext JS, LLC.
33728 * Originally Released Under LGPL - original licence link has changed is not relivant.
33731 * <script type="text/javascript">
33736 * @class Roo.tree.ColumnTree
33737 * @extends Roo.data.TreePanel
33738 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33739 * @cfg {int} borderWidth compined right/left border allowance
33741 * @param {String/HTMLElement/Element} el The container element
33742 * @param {Object} config
33744 Roo.tree.ColumnTree = function(el, config)
33746 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33750 * Fire this event on a container when it resizes
33751 * @param {int} w Width
33752 * @param {int} h Height
33756 this.on('resize', this.onResize, this);
33759 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33763 borderWidth: Roo.isBorderBox ? 0 : 2,
33766 render : function(){
33767 // add the header.....
33769 Roo.tree.ColumnTree.superclass.render.apply(this);
33771 this.el.addClass('x-column-tree');
33773 this.headers = this.el.createChild(
33774 {cls:'x-tree-headers'},this.innerCt.dom);
33776 var cols = this.columns, c;
33777 var totalWidth = 0;
33779 var len = cols.length;
33780 for(var i = 0; i < len; i++){
33782 totalWidth += c.width;
33783 this.headEls.push(this.headers.createChild({
33784 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33786 cls:'x-tree-hd-text',
33789 style:'width:'+(c.width-this.borderWidth)+'px;'
33792 this.headers.createChild({cls:'x-clear'});
33793 // prevent floats from wrapping when clipped
33794 this.headers.setWidth(totalWidth);
33795 //this.innerCt.setWidth(totalWidth);
33796 this.innerCt.setStyle({ overflow: 'auto' });
33797 this.onResize(this.width, this.height);
33801 onResize : function(w,h)
33806 this.innerCt.setWidth(this.width);
33807 this.innerCt.setHeight(this.height-20);
33810 var cols = this.columns, c;
33811 var totalWidth = 0;
33813 var len = cols.length;
33814 for(var i = 0; i < len; i++){
33816 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33817 // it's the expander..
33818 expEl = this.headEls[i];
33821 totalWidth += c.width;
33825 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33827 this.headers.setWidth(w-20);
33836 * Ext JS Library 1.1.1
33837 * Copyright(c) 2006-2007, Ext JS, LLC.
33839 * Originally Released Under LGPL - original licence link has changed is not relivant.
33842 * <script type="text/javascript">
33846 * @class Roo.menu.Menu
33847 * @extends Roo.util.Observable
33848 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33849 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33851 * Creates a new Menu
33852 * @param {Object} config Configuration options
33854 Roo.menu.Menu = function(config){
33855 Roo.apply(this, config);
33856 this.id = this.id || Roo.id();
33859 * @event beforeshow
33860 * Fires before this menu is displayed
33861 * @param {Roo.menu.Menu} this
33865 * @event beforehide
33866 * Fires before this menu is hidden
33867 * @param {Roo.menu.Menu} this
33872 * Fires after this menu is displayed
33873 * @param {Roo.menu.Menu} this
33878 * Fires after this menu is hidden
33879 * @param {Roo.menu.Menu} this
33884 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33885 * @param {Roo.menu.Menu} this
33886 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33887 * @param {Roo.EventObject} e
33892 * Fires when the mouse is hovering over this menu
33893 * @param {Roo.menu.Menu} this
33894 * @param {Roo.EventObject} e
33895 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33900 * Fires when the mouse exits this menu
33901 * @param {Roo.menu.Menu} this
33902 * @param {Roo.EventObject} e
33903 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33908 * Fires when a menu item contained in this menu is clicked
33909 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33910 * @param {Roo.EventObject} e
33914 if (this.registerMenu) {
33915 Roo.menu.MenuMgr.register(this);
33918 var mis = this.items;
33919 this.items = new Roo.util.MixedCollection();
33921 this.add.apply(this, mis);
33925 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33927 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33931 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33932 * for bottom-right shadow (defaults to "sides")
33936 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33937 * this menu (defaults to "tl-tr?")
33939 subMenuAlign : "tl-tr?",
33941 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33942 * relative to its element of origin (defaults to "tl-bl?")
33944 defaultAlign : "tl-bl?",
33946 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33948 allowOtherMenus : false,
33950 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33952 registerMenu : true,
33957 render : function(){
33961 var el = this.el = new Roo.Layer({
33963 shadow:this.shadow,
33965 parentEl: this.parentEl || document.body,
33969 this.keyNav = new Roo.menu.MenuNav(this);
33972 el.addClass("x-menu-plain");
33975 el.addClass(this.cls);
33977 // generic focus element
33978 this.focusEl = el.createChild({
33979 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33981 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33982 ul.on("click", this.onClick, this);
33983 ul.on("mouseover", this.onMouseOver, this);
33984 ul.on("mouseout", this.onMouseOut, this);
33985 this.items.each(function(item){
33986 var li = document.createElement("li");
33987 li.className = "x-menu-list-item";
33988 ul.dom.appendChild(li);
33989 item.render(li, this);
33996 autoWidth : function(){
33997 var el = this.el, ul = this.ul;
34001 var w = this.width;
34004 }else if(Roo.isIE){
34005 el.setWidth(this.minWidth);
34006 var t = el.dom.offsetWidth; // force recalc
34007 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34012 delayAutoWidth : function(){
34015 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
34017 this.awTask.delay(20);
34022 findTargetItem : function(e){
34023 var t = e.getTarget(".x-menu-list-item", this.ul, true);
34024 if(t && t.menuItemId){
34025 return this.items.get(t.menuItemId);
34030 onClick : function(e){
34032 if(t = this.findTargetItem(e)){
34034 this.fireEvent("click", this, t, e);
34039 setActiveItem : function(item, autoExpand){
34040 if(item != this.activeItem){
34041 if(this.activeItem){
34042 this.activeItem.deactivate();
34044 this.activeItem = item;
34045 item.activate(autoExpand);
34046 }else if(autoExpand){
34052 tryActivate : function(start, step){
34053 var items = this.items;
34054 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34055 var item = items.get(i);
34056 if(!item.disabled && item.canActivate){
34057 this.setActiveItem(item, false);
34065 onMouseOver : function(e){
34067 if(t = this.findTargetItem(e)){
34068 if(t.canActivate && !t.disabled){
34069 this.setActiveItem(t, true);
34072 this.fireEvent("mouseover", this, e, t);
34076 onMouseOut : function(e){
34078 if(t = this.findTargetItem(e)){
34079 if(t == this.activeItem && t.shouldDeactivate(e)){
34080 this.activeItem.deactivate();
34081 delete this.activeItem;
34084 this.fireEvent("mouseout", this, e, t);
34088 * Read-only. Returns true if the menu is currently displayed, else false.
34091 isVisible : function(){
34092 return this.el && !this.hidden;
34096 * Displays this menu relative to another element
34097 * @param {String/HTMLElement/Roo.Element} element The element to align to
34098 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34099 * the element (defaults to this.defaultAlign)
34100 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34102 show : function(el, pos, parentMenu){
34103 this.parentMenu = parentMenu;
34107 this.fireEvent("beforeshow", this);
34108 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34112 * Displays this menu at a specific xy position
34113 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34114 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34116 showAt : function(xy, parentMenu, /* private: */_e){
34117 this.parentMenu = parentMenu;
34122 this.fireEvent("beforeshow", this);
34123 xy = this.el.adjustForConstraints(xy);
34127 this.hidden = false;
34129 this.fireEvent("show", this);
34132 focus : function(){
34134 this.doFocus.defer(50, this);
34138 doFocus : function(){
34140 this.focusEl.focus();
34145 * Hides this menu and optionally all parent menus
34146 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34148 hide : function(deep){
34149 if(this.el && this.isVisible()){
34150 this.fireEvent("beforehide", this);
34151 if(this.activeItem){
34152 this.activeItem.deactivate();
34153 this.activeItem = null;
34156 this.hidden = true;
34157 this.fireEvent("hide", this);
34159 if(deep === true && this.parentMenu){
34160 this.parentMenu.hide(true);
34165 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34166 * Any of the following are valid:
34168 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34169 * <li>An HTMLElement object which will be converted to a menu item</li>
34170 * <li>A menu item config object that will be created as a new menu item</li>
34171 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34172 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34177 var menu = new Roo.menu.Menu();
34179 // Create a menu item to add by reference
34180 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34182 // Add a bunch of items at once using different methods.
34183 // Only the last item added will be returned.
34184 var item = menu.add(
34185 menuItem, // add existing item by ref
34186 'Dynamic Item', // new TextItem
34187 '-', // new separator
34188 { text: 'Config Item' } // new item by config
34191 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34192 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34195 var a = arguments, l = a.length, item;
34196 for(var i = 0; i < l; i++){
34198 if ((typeof(el) == "object") && el.xtype && el.xns) {
34199 el = Roo.factory(el, Roo.menu);
34202 if(el.render){ // some kind of Item
34203 item = this.addItem(el);
34204 }else if(typeof el == "string"){ // string
34205 if(el == "separator" || el == "-"){
34206 item = this.addSeparator();
34208 item = this.addText(el);
34210 }else if(el.tagName || el.el){ // element
34211 item = this.addElement(el);
34212 }else if(typeof el == "object"){ // must be menu item config?
34213 item = this.addMenuItem(el);
34220 * Returns this menu's underlying {@link Roo.Element} object
34221 * @return {Roo.Element} The element
34223 getEl : function(){
34231 * Adds a separator bar to the menu
34232 * @return {Roo.menu.Item} The menu item that was added
34234 addSeparator : function(){
34235 return this.addItem(new Roo.menu.Separator());
34239 * Adds an {@link Roo.Element} object to the menu
34240 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34241 * @return {Roo.menu.Item} The menu item that was added
34243 addElement : function(el){
34244 return this.addItem(new Roo.menu.BaseItem(el));
34248 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34249 * @param {Roo.menu.Item} item The menu item to add
34250 * @return {Roo.menu.Item} The menu item that was added
34252 addItem : function(item){
34253 this.items.add(item);
34255 var li = document.createElement("li");
34256 li.className = "x-menu-list-item";
34257 this.ul.dom.appendChild(li);
34258 item.render(li, this);
34259 this.delayAutoWidth();
34265 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34266 * @param {Object} config A MenuItem config object
34267 * @return {Roo.menu.Item} The menu item that was added
34269 addMenuItem : function(config){
34270 if(!(config instanceof Roo.menu.Item)){
34271 if(typeof config.checked == "boolean"){ // must be check menu item config?
34272 config = new Roo.menu.CheckItem(config);
34274 config = new Roo.menu.Item(config);
34277 return this.addItem(config);
34281 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34282 * @param {String} text The text to display in the menu item
34283 * @return {Roo.menu.Item} The menu item that was added
34285 addText : function(text){
34286 return this.addItem(new Roo.menu.TextItem({ text : text }));
34290 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34291 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34292 * @param {Roo.menu.Item} item The menu item to add
34293 * @return {Roo.menu.Item} The menu item that was added
34295 insert : function(index, item){
34296 this.items.insert(index, item);
34298 var li = document.createElement("li");
34299 li.className = "x-menu-list-item";
34300 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34301 item.render(li, this);
34302 this.delayAutoWidth();
34308 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34309 * @param {Roo.menu.Item} item The menu item to remove
34311 remove : function(item){
34312 this.items.removeKey(item.id);
34317 * Removes and destroys all items in the menu
34319 removeAll : function(){
34321 while(f = this.items.first()){
34327 // MenuNav is a private utility class used internally by the Menu
34328 Roo.menu.MenuNav = function(menu){
34329 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34330 this.scope = this.menu = menu;
34333 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34334 doRelay : function(e, h){
34335 var k = e.getKey();
34336 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34337 this.menu.tryActivate(0, 1);
34340 return h.call(this.scope || this, e, this.menu);
34343 up : function(e, m){
34344 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34345 m.tryActivate(m.items.length-1, -1);
34349 down : function(e, m){
34350 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34351 m.tryActivate(0, 1);
34355 right : function(e, m){
34357 m.activeItem.expandMenu(true);
34361 left : function(e, m){
34363 if(m.parentMenu && m.parentMenu.activeItem){
34364 m.parentMenu.activeItem.activate();
34368 enter : function(e, m){
34370 e.stopPropagation();
34371 m.activeItem.onClick(e);
34372 m.fireEvent("click", this, m.activeItem);
34378 * Ext JS Library 1.1.1
34379 * Copyright(c) 2006-2007, Ext JS, LLC.
34381 * Originally Released Under LGPL - original licence link has changed is not relivant.
34384 * <script type="text/javascript">
34388 * @class Roo.menu.MenuMgr
34389 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34392 Roo.menu.MenuMgr = function(){
34393 var menus, active, groups = {}, attached = false, lastShow = new Date();
34395 // private - called when first menu is created
34398 active = new Roo.util.MixedCollection();
34399 Roo.get(document).addKeyListener(27, function(){
34400 if(active.length > 0){
34407 function hideAll(){
34408 if(active && active.length > 0){
34409 var c = active.clone();
34410 c.each(function(m){
34417 function onHide(m){
34419 if(active.length < 1){
34420 Roo.get(document).un("mousedown", onMouseDown);
34426 function onShow(m){
34427 var last = active.last();
34428 lastShow = new Date();
34431 Roo.get(document).on("mousedown", onMouseDown);
34435 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34436 m.parentMenu.activeChild = m;
34437 }else if(last && last.isVisible()){
34438 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34443 function onBeforeHide(m){
34445 m.activeChild.hide();
34447 if(m.autoHideTimer){
34448 clearTimeout(m.autoHideTimer);
34449 delete m.autoHideTimer;
34454 function onBeforeShow(m){
34455 var pm = m.parentMenu;
34456 if(!pm && !m.allowOtherMenus){
34458 }else if(pm && pm.activeChild && active != m){
34459 pm.activeChild.hide();
34464 function onMouseDown(e){
34465 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34471 function onBeforeCheck(mi, state){
34473 var g = groups[mi.group];
34474 for(var i = 0, l = g.length; i < l; i++){
34476 g[i].setChecked(false);
34485 * Hides all menus that are currently visible
34487 hideAll : function(){
34492 register : function(menu){
34496 menus[menu.id] = menu;
34497 menu.on("beforehide", onBeforeHide);
34498 menu.on("hide", onHide);
34499 menu.on("beforeshow", onBeforeShow);
34500 menu.on("show", onShow);
34501 var g = menu.group;
34502 if(g && menu.events["checkchange"]){
34506 groups[g].push(menu);
34507 menu.on("checkchange", onCheck);
34512 * Returns a {@link Roo.menu.Menu} object
34513 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34514 * be used to generate and return a new Menu instance.
34516 get : function(menu){
34517 if(typeof menu == "string"){ // menu id
34518 return menus[menu];
34519 }else if(menu.events){ // menu instance
34521 }else if(typeof menu.length == 'number'){ // array of menu items?
34522 return new Roo.menu.Menu({items:menu});
34523 }else{ // otherwise, must be a config
34524 return new Roo.menu.Menu(menu);
34529 unregister : function(menu){
34530 delete menus[menu.id];
34531 menu.un("beforehide", onBeforeHide);
34532 menu.un("hide", onHide);
34533 menu.un("beforeshow", onBeforeShow);
34534 menu.un("show", onShow);
34535 var g = menu.group;
34536 if(g && menu.events["checkchange"]){
34537 groups[g].remove(menu);
34538 menu.un("checkchange", onCheck);
34543 registerCheckable : function(menuItem){
34544 var g = menuItem.group;
34549 groups[g].push(menuItem);
34550 menuItem.on("beforecheckchange", onBeforeCheck);
34555 unregisterCheckable : function(menuItem){
34556 var g = menuItem.group;
34558 groups[g].remove(menuItem);
34559 menuItem.un("beforecheckchange", onBeforeCheck);
34565 * Ext JS Library 1.1.1
34566 * Copyright(c) 2006-2007, Ext JS, LLC.
34568 * Originally Released Under LGPL - original licence link has changed is not relivant.
34571 * <script type="text/javascript">
34576 * @class Roo.menu.BaseItem
34577 * @extends Roo.Component
34578 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34579 * management and base configuration options shared by all menu components.
34581 * Creates a new BaseItem
34582 * @param {Object} config Configuration options
34584 Roo.menu.BaseItem = function(config){
34585 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34590 * Fires when this item is clicked
34591 * @param {Roo.menu.BaseItem} this
34592 * @param {Roo.EventObject} e
34597 * Fires when this item is activated
34598 * @param {Roo.menu.BaseItem} this
34602 * @event deactivate
34603 * Fires when this item is deactivated
34604 * @param {Roo.menu.BaseItem} this
34610 this.on("click", this.handler, this.scope, true);
34614 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34616 * @cfg {Function} handler
34617 * A function that will handle the click event of this menu item (defaults to undefined)
34620 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34622 canActivate : false,
34624 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34626 activeClass : "x-menu-item-active",
34628 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34630 hideOnClick : true,
34632 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34637 ctype: "Roo.menu.BaseItem",
34640 actionMode : "container",
34643 render : function(container, parentMenu){
34644 this.parentMenu = parentMenu;
34645 Roo.menu.BaseItem.superclass.render.call(this, container);
34646 this.container.menuItemId = this.id;
34650 onRender : function(container, position){
34651 this.el = Roo.get(this.el);
34652 container.dom.appendChild(this.el.dom);
34656 onClick : function(e){
34657 if(!this.disabled && this.fireEvent("click", this, e) !== false
34658 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34659 this.handleClick(e);
34666 activate : function(){
34670 var li = this.container;
34671 li.addClass(this.activeClass);
34672 this.region = li.getRegion().adjust(2, 2, -2, -2);
34673 this.fireEvent("activate", this);
34678 deactivate : function(){
34679 this.container.removeClass(this.activeClass);
34680 this.fireEvent("deactivate", this);
34684 shouldDeactivate : function(e){
34685 return !this.region || !this.region.contains(e.getPoint());
34689 handleClick : function(e){
34690 if(this.hideOnClick){
34691 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34696 expandMenu : function(autoActivate){
34701 hideMenu : function(){
34706 * Ext JS Library 1.1.1
34707 * Copyright(c) 2006-2007, Ext JS, LLC.
34709 * Originally Released Under LGPL - original licence link has changed is not relivant.
34712 * <script type="text/javascript">
34716 * @class Roo.menu.Adapter
34717 * @extends Roo.menu.BaseItem
34718 * 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.
34719 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34721 * Creates a new Adapter
34722 * @param {Object} config Configuration options
34724 Roo.menu.Adapter = function(component, config){
34725 Roo.menu.Adapter.superclass.constructor.call(this, config);
34726 this.component = component;
34728 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34730 canActivate : true,
34733 onRender : function(container, position){
34734 this.component.render(container);
34735 this.el = this.component.getEl();
34739 activate : function(){
34743 this.component.focus();
34744 this.fireEvent("activate", this);
34749 deactivate : function(){
34750 this.fireEvent("deactivate", this);
34754 disable : function(){
34755 this.component.disable();
34756 Roo.menu.Adapter.superclass.disable.call(this);
34760 enable : function(){
34761 this.component.enable();
34762 Roo.menu.Adapter.superclass.enable.call(this);
34766 * Ext JS Library 1.1.1
34767 * Copyright(c) 2006-2007, Ext JS, LLC.
34769 * Originally Released Under LGPL - original licence link has changed is not relivant.
34772 * <script type="text/javascript">
34776 * @class Roo.menu.TextItem
34777 * @extends Roo.menu.BaseItem
34778 * Adds a static text string to a menu, usually used as either a heading or group separator.
34779 * Note: old style constructor with text is still supported.
34782 * Creates a new TextItem
34783 * @param {Object} cfg Configuration
34785 Roo.menu.TextItem = function(cfg){
34786 if (typeof(cfg) == 'string') {
34789 Roo.apply(this,cfg);
34792 Roo.menu.TextItem.superclass.constructor.call(this);
34795 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34797 * @cfg {Boolean} text Text to show on item.
34802 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34804 hideOnClick : false,
34806 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34808 itemCls : "x-menu-text",
34811 onRender : function(){
34812 var s = document.createElement("span");
34813 s.className = this.itemCls;
34814 s.innerHTML = this.text;
34816 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34820 * Ext JS Library 1.1.1
34821 * Copyright(c) 2006-2007, Ext JS, LLC.
34823 * Originally Released Under LGPL - original licence link has changed is not relivant.
34826 * <script type="text/javascript">
34830 * @class Roo.menu.Separator
34831 * @extends Roo.menu.BaseItem
34832 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34833 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34835 * @param {Object} config Configuration options
34837 Roo.menu.Separator = function(config){
34838 Roo.menu.Separator.superclass.constructor.call(this, config);
34841 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34843 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34845 itemCls : "x-menu-sep",
34847 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34849 hideOnClick : false,
34852 onRender : function(li){
34853 var s = document.createElement("span");
34854 s.className = this.itemCls;
34855 s.innerHTML = " ";
34857 li.addClass("x-menu-sep-li");
34858 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34862 * Ext JS Library 1.1.1
34863 * Copyright(c) 2006-2007, Ext JS, LLC.
34865 * Originally Released Under LGPL - original licence link has changed is not relivant.
34868 * <script type="text/javascript">
34871 * @class Roo.menu.Item
34872 * @extends Roo.menu.BaseItem
34873 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34874 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34875 * activation and click handling.
34877 * Creates a new Item
34878 * @param {Object} config Configuration options
34880 Roo.menu.Item = function(config){
34881 Roo.menu.Item.superclass.constructor.call(this, config);
34883 this.menu = Roo.menu.MenuMgr.get(this.menu);
34886 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34889 * @cfg {String} text
34890 * The text to show on the menu item.
34894 * @cfg {String} HTML to render in menu
34895 * The text to show on the menu item (HTML version).
34899 * @cfg {String} icon
34900 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34904 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34906 itemCls : "x-menu-item",
34908 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34910 canActivate : true,
34912 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34915 // doc'd in BaseItem
34919 ctype: "Roo.menu.Item",
34922 onRender : function(container, position){
34923 var el = document.createElement("a");
34924 el.hideFocus = true;
34925 el.unselectable = "on";
34926 el.href = this.href || "#";
34927 if(this.hrefTarget){
34928 el.target = this.hrefTarget;
34930 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34932 var html = this.html.length ? this.html : String.format('{0}',this.text);
34934 el.innerHTML = String.format(
34935 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
34936 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
34938 Roo.menu.Item.superclass.onRender.call(this, container, position);
34942 * Sets the text to display in this menu item
34943 * @param {String} text The text to display
34944 * @param {Boolean} isHTML true to indicate text is pure html.
34946 setText : function(text, isHTML){
34954 var html = this.html.length ? this.html : String.format('{0}',this.text);
34956 this.el.update(String.format(
34957 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
34958 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34959 this.parentMenu.autoWidth();
34964 handleClick : function(e){
34965 if(!this.href){ // if no link defined, stop the event automatically
34968 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34972 activate : function(autoExpand){
34973 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34983 shouldDeactivate : function(e){
34984 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34985 if(this.menu && this.menu.isVisible()){
34986 return !this.menu.getEl().getRegion().contains(e.getPoint());
34994 deactivate : function(){
34995 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
35000 expandMenu : function(autoActivate){
35001 if(!this.disabled && this.menu){
35002 clearTimeout(this.hideTimer);
35003 delete this.hideTimer;
35004 if(!this.menu.isVisible() && !this.showTimer){
35005 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
35006 }else if (this.menu.isVisible() && autoActivate){
35007 this.menu.tryActivate(0, 1);
35013 deferExpand : function(autoActivate){
35014 delete this.showTimer;
35015 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35017 this.menu.tryActivate(0, 1);
35022 hideMenu : function(){
35023 clearTimeout(this.showTimer);
35024 delete this.showTimer;
35025 if(!this.hideTimer && this.menu && this.menu.isVisible()){
35026 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35031 deferHide : function(){
35032 delete this.hideTimer;
35037 * Ext JS Library 1.1.1
35038 * Copyright(c) 2006-2007, Ext JS, LLC.
35040 * Originally Released Under LGPL - original licence link has changed is not relivant.
35043 * <script type="text/javascript">
35047 * @class Roo.menu.CheckItem
35048 * @extends Roo.menu.Item
35049 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35051 * Creates a new CheckItem
35052 * @param {Object} config Configuration options
35054 Roo.menu.CheckItem = function(config){
35055 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35058 * @event beforecheckchange
35059 * Fires before the checked value is set, providing an opportunity to cancel if needed
35060 * @param {Roo.menu.CheckItem} this
35061 * @param {Boolean} checked The new checked value that will be set
35063 "beforecheckchange" : true,
35065 * @event checkchange
35066 * Fires after the checked value has been set
35067 * @param {Roo.menu.CheckItem} this
35068 * @param {Boolean} checked The checked value that was set
35070 "checkchange" : true
35072 if(this.checkHandler){
35073 this.on('checkchange', this.checkHandler, this.scope);
35076 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35078 * @cfg {String} group
35079 * All check items with the same group name will automatically be grouped into a single-select
35080 * radio button group (defaults to '')
35083 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35085 itemCls : "x-menu-item x-menu-check-item",
35087 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35089 groupClass : "x-menu-group-item",
35092 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35093 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35094 * initialized with checked = true will be rendered as checked.
35099 ctype: "Roo.menu.CheckItem",
35102 onRender : function(c){
35103 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35105 this.el.addClass(this.groupClass);
35107 Roo.menu.MenuMgr.registerCheckable(this);
35109 this.checked = false;
35110 this.setChecked(true, true);
35115 destroy : function(){
35117 Roo.menu.MenuMgr.unregisterCheckable(this);
35119 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35123 * Set the checked state of this item
35124 * @param {Boolean} checked The new checked value
35125 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35127 setChecked : function(state, suppressEvent){
35128 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35129 if(this.container){
35130 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35132 this.checked = state;
35133 if(suppressEvent !== true){
35134 this.fireEvent("checkchange", this, state);
35140 handleClick : function(e){
35141 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35142 this.setChecked(!this.checked);
35144 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35148 * Ext JS Library 1.1.1
35149 * Copyright(c) 2006-2007, Ext JS, LLC.
35151 * Originally Released Under LGPL - original licence link has changed is not relivant.
35154 * <script type="text/javascript">
35158 * @class Roo.menu.DateItem
35159 * @extends Roo.menu.Adapter
35160 * A menu item that wraps the {@link Roo.DatPicker} component.
35162 * Creates a new DateItem
35163 * @param {Object} config Configuration options
35165 Roo.menu.DateItem = function(config){
35166 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35167 /** The Roo.DatePicker object @type Roo.DatePicker */
35168 this.picker = this.component;
35169 this.addEvents({select: true});
35171 this.picker.on("render", function(picker){
35172 picker.getEl().swallowEvent("click");
35173 picker.container.addClass("x-menu-date-item");
35176 this.picker.on("select", this.onSelect, this);
35179 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35181 onSelect : function(picker, date){
35182 this.fireEvent("select", this, date, picker);
35183 Roo.menu.DateItem.superclass.handleClick.call(this);
35187 * Ext JS Library 1.1.1
35188 * Copyright(c) 2006-2007, Ext JS, LLC.
35190 * Originally Released Under LGPL - original licence link has changed is not relivant.
35193 * <script type="text/javascript">
35197 * @class Roo.menu.ColorItem
35198 * @extends Roo.menu.Adapter
35199 * A menu item that wraps the {@link Roo.ColorPalette} component.
35201 * Creates a new ColorItem
35202 * @param {Object} config Configuration options
35204 Roo.menu.ColorItem = function(config){
35205 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35206 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35207 this.palette = this.component;
35208 this.relayEvents(this.palette, ["select"]);
35209 if(this.selectHandler){
35210 this.on('select', this.selectHandler, this.scope);
35213 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35215 * Ext JS Library 1.1.1
35216 * Copyright(c) 2006-2007, Ext JS, LLC.
35218 * Originally Released Under LGPL - original licence link has changed is not relivant.
35221 * <script type="text/javascript">
35226 * @class Roo.menu.DateMenu
35227 * @extends Roo.menu.Menu
35228 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35230 * Creates a new DateMenu
35231 * @param {Object} config Configuration options
35233 Roo.menu.DateMenu = function(config){
35234 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35236 var di = new Roo.menu.DateItem(config);
35239 * The {@link Roo.DatePicker} instance for this DateMenu
35242 this.picker = di.picker;
35245 * @param {DatePicker} picker
35246 * @param {Date} date
35248 this.relayEvents(di, ["select"]);
35250 this.on('beforeshow', function(){
35252 this.picker.hideMonthPicker(true);
35256 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35260 * Ext JS Library 1.1.1
35261 * Copyright(c) 2006-2007, Ext JS, LLC.
35263 * Originally Released Under LGPL - original licence link has changed is not relivant.
35266 * <script type="text/javascript">
35271 * @class Roo.menu.ColorMenu
35272 * @extends Roo.menu.Menu
35273 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35275 * Creates a new ColorMenu
35276 * @param {Object} config Configuration options
35278 Roo.menu.ColorMenu = function(config){
35279 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35281 var ci = new Roo.menu.ColorItem(config);
35284 * The {@link Roo.ColorPalette} instance for this ColorMenu
35285 * @type ColorPalette
35287 this.palette = ci.palette;
35290 * @param {ColorPalette} palette
35291 * @param {String} color
35293 this.relayEvents(ci, ["select"]);
35295 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35297 * Ext JS Library 1.1.1
35298 * Copyright(c) 2006-2007, Ext JS, LLC.
35300 * Originally Released Under LGPL - original licence link has changed is not relivant.
35303 * <script type="text/javascript">
35307 * @class Roo.form.Field
35308 * @extends Roo.BoxComponent
35309 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35311 * Creates a new Field
35312 * @param {Object} config Configuration options
35314 Roo.form.Field = function(config){
35315 Roo.form.Field.superclass.constructor.call(this, config);
35318 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35320 * @cfg {String} fieldLabel Label to use when rendering a form.
35323 * @cfg {String} qtip Mouse over tip
35327 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35329 invalidClass : "x-form-invalid",
35331 * @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")
35333 invalidText : "The value in this field is invalid",
35335 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35337 focusClass : "x-form-focus",
35339 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35340 automatic validation (defaults to "keyup").
35342 validationEvent : "keyup",
35344 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35346 validateOnBlur : true,
35348 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35350 validationDelay : 250,
35352 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35353 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35355 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35357 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35359 fieldClass : "x-form-field",
35361 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35364 ----------- ----------------------------------------------------------------------
35365 qtip Display a quick tip when the user hovers over the field
35366 title Display a default browser title attribute popup
35367 under Add a block div beneath the field containing the error text
35368 side Add an error icon to the right of the field with a popup on hover
35369 [element id] Add the error text directly to the innerHTML of the specified element
35372 msgTarget : 'qtip',
35374 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35379 * @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.
35384 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35389 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35391 inputType : undefined,
35394 * @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).
35396 tabIndex : undefined,
35399 isFormField : true,
35404 * @property {Roo.Element} fieldEl
35405 * Element Containing the rendered Field (with label etc.)
35408 * @cfg {Mixed} value A value to initialize this field with.
35413 * @cfg {String} name The field's HTML name attribute.
35416 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35420 initComponent : function(){
35421 Roo.form.Field.superclass.initComponent.call(this);
35425 * Fires when this field receives input focus.
35426 * @param {Roo.form.Field} this
35431 * Fires when this field loses input focus.
35432 * @param {Roo.form.Field} this
35436 * @event specialkey
35437 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35438 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35439 * @param {Roo.form.Field} this
35440 * @param {Roo.EventObject} e The event object
35445 * Fires just before the field blurs if the field value has changed.
35446 * @param {Roo.form.Field} this
35447 * @param {Mixed} newValue The new value
35448 * @param {Mixed} oldValue The original value
35453 * Fires after the field has been marked as invalid.
35454 * @param {Roo.form.Field} this
35455 * @param {String} msg The validation message
35460 * Fires after the field has been validated with no errors.
35461 * @param {Roo.form.Field} this
35466 * Fires after the key up
35467 * @param {Roo.form.Field} this
35468 * @param {Roo.EventObject} e The event Object
35475 * Returns the name attribute of the field if available
35476 * @return {String} name The field name
35478 getName: function(){
35479 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35483 onRender : function(ct, position){
35484 Roo.form.Field.superclass.onRender.call(this, ct, position);
35486 var cfg = this.getAutoCreate();
35488 cfg.name = this.name || this.id;
35490 if(this.inputType){
35491 cfg.type = this.inputType;
35493 this.el = ct.createChild(cfg, position);
35495 var type = this.el.dom.type;
35497 if(type == 'password'){
35500 this.el.addClass('x-form-'+type);
35503 this.el.dom.readOnly = true;
35505 if(this.tabIndex !== undefined){
35506 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35509 this.el.addClass([this.fieldClass, this.cls]);
35514 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35515 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35516 * @return {Roo.form.Field} this
35518 applyTo : function(target){
35519 this.allowDomMove = false;
35520 this.el = Roo.get(target);
35521 this.render(this.el.dom.parentNode);
35526 initValue : function(){
35527 if(this.value !== undefined){
35528 this.setValue(this.value);
35529 }else if(this.el.dom.value.length > 0){
35530 this.setValue(this.el.dom.value);
35535 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35537 isDirty : function() {
35538 if(this.disabled) {
35541 return String(this.getValue()) !== String(this.originalValue);
35545 afterRender : function(){
35546 Roo.form.Field.superclass.afterRender.call(this);
35551 fireKey : function(e){
35552 //Roo.log('field ' + e.getKey());
35553 if(e.isNavKeyPress()){
35554 this.fireEvent("specialkey", this, e);
35559 * Resets the current field value to the originally loaded value and clears any validation messages
35561 reset : function(){
35562 this.setValue(this.originalValue);
35563 this.clearInvalid();
35567 initEvents : function(){
35568 // safari killled keypress - so keydown is now used..
35569 this.el.on("keydown" , this.fireKey, this);
35570 this.el.on("focus", this.onFocus, this);
35571 this.el.on("blur", this.onBlur, this);
35572 this.el.relayEvent('keyup', this);
35574 // reference to original value for reset
35575 this.originalValue = this.getValue();
35579 onFocus : function(){
35580 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35581 this.el.addClass(this.focusClass);
35583 if(!this.hasFocus){
35584 this.hasFocus = true;
35585 this.startValue = this.getValue();
35586 this.fireEvent("focus", this);
35590 beforeBlur : Roo.emptyFn,
35593 onBlur : function(){
35595 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35596 this.el.removeClass(this.focusClass);
35598 this.hasFocus = false;
35599 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35602 var v = this.getValue();
35603 if(String(v) !== String(this.startValue)){
35604 this.fireEvent('change', this, v, this.startValue);
35606 this.fireEvent("blur", this);
35610 * Returns whether or not the field value is currently valid
35611 * @param {Boolean} preventMark True to disable marking the field invalid
35612 * @return {Boolean} True if the value is valid, else false
35614 isValid : function(preventMark){
35618 var restore = this.preventMark;
35619 this.preventMark = preventMark === true;
35620 var v = this.validateValue(this.processValue(this.getRawValue()));
35621 this.preventMark = restore;
35626 * Validates the field value
35627 * @return {Boolean} True if the value is valid, else false
35629 validate : function(){
35630 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35631 this.clearInvalid();
35637 processValue : function(value){
35642 // Subclasses should provide the validation implementation by overriding this
35643 validateValue : function(value){
35648 * Mark this field as invalid
35649 * @param {String} msg The validation message
35651 markInvalid : function(msg){
35652 if(!this.rendered || this.preventMark){ // not rendered
35655 this.el.addClass(this.invalidClass);
35656 msg = msg || this.invalidText;
35657 switch(this.msgTarget){
35659 this.el.dom.qtip = msg;
35660 this.el.dom.qclass = 'x-form-invalid-tip';
35661 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35662 Roo.QuickTips.enable();
35666 this.el.dom.title = msg;
35670 var elp = this.el.findParent('.x-form-element', 5, true);
35671 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35672 this.errorEl.setWidth(elp.getWidth(true)-20);
35674 this.errorEl.update(msg);
35675 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35678 if(!this.errorIcon){
35679 var elp = this.el.findParent('.x-form-element', 5, true);
35680 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35682 this.alignErrorIcon();
35683 this.errorIcon.dom.qtip = msg;
35684 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35685 this.errorIcon.show();
35686 this.on('resize', this.alignErrorIcon, this);
35689 var t = Roo.getDom(this.msgTarget);
35691 t.style.display = this.msgDisplay;
35694 this.fireEvent('invalid', this, msg);
35698 alignErrorIcon : function(){
35699 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35703 * Clear any invalid styles/messages for this field
35705 clearInvalid : function(){
35706 if(!this.rendered || this.preventMark){ // not rendered
35709 this.el.removeClass(this.invalidClass);
35710 switch(this.msgTarget){
35712 this.el.dom.qtip = '';
35715 this.el.dom.title = '';
35719 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35723 if(this.errorIcon){
35724 this.errorIcon.dom.qtip = '';
35725 this.errorIcon.hide();
35726 this.un('resize', this.alignErrorIcon, this);
35730 var t = Roo.getDom(this.msgTarget);
35732 t.style.display = 'none';
35735 this.fireEvent('valid', this);
35739 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35740 * @return {Mixed} value The field value
35742 getRawValue : function(){
35743 var v = this.el.getValue();
35744 if(v === this.emptyText){
35751 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35752 * @return {Mixed} value The field value
35754 getValue : function(){
35755 var v = this.el.getValue();
35756 if(v === this.emptyText || v === undefined){
35763 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35764 * @param {Mixed} value The value to set
35766 setRawValue : function(v){
35767 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35771 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35772 * @param {Mixed} value The value to set
35774 setValue : function(v){
35777 this.el.dom.value = (v === null || v === undefined ? '' : v);
35782 adjustSize : function(w, h){
35783 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35784 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35788 adjustWidth : function(tag, w){
35789 tag = tag.toLowerCase();
35790 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35791 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35792 if(tag == 'input'){
35795 if(tag = 'textarea'){
35798 }else if(Roo.isOpera){
35799 if(tag == 'input'){
35802 if(tag = 'textarea'){
35812 // anything other than normal should be considered experimental
35813 Roo.form.Field.msgFx = {
35815 show: function(msgEl, f){
35816 msgEl.setDisplayed('block');
35819 hide : function(msgEl, f){
35820 msgEl.setDisplayed(false).update('');
35825 show: function(msgEl, f){
35826 msgEl.slideIn('t', {stopFx:true});
35829 hide : function(msgEl, f){
35830 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35835 show: function(msgEl, f){
35836 msgEl.fixDisplay();
35837 msgEl.alignTo(f.el, 'tl-tr');
35838 msgEl.slideIn('l', {stopFx:true});
35841 hide : function(msgEl, f){
35842 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35847 * Ext JS Library 1.1.1
35848 * Copyright(c) 2006-2007, Ext JS, LLC.
35850 * Originally Released Under LGPL - original licence link has changed is not relivant.
35853 * <script type="text/javascript">
35858 * @class Roo.form.TextField
35859 * @extends Roo.form.Field
35860 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35861 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35863 * Creates a new TextField
35864 * @param {Object} config Configuration options
35866 Roo.form.TextField = function(config){
35867 Roo.form.TextField.superclass.constructor.call(this, config);
35871 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35872 * according to the default logic, but this event provides a hook for the developer to apply additional
35873 * logic at runtime to resize the field if needed.
35874 * @param {Roo.form.Field} this This text field
35875 * @param {Number} width The new field width
35881 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35883 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35887 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35891 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35895 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35899 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35903 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35905 disableKeyFilter : false,
35907 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35911 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35915 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35917 maxLength : Number.MAX_VALUE,
35919 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35921 minLengthText : "The minimum length for this field is {0}",
35923 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35925 maxLengthText : "The maximum length for this field is {0}",
35927 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35929 selectOnFocus : false,
35931 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35933 blankText : "This field is required",
35935 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35936 * If available, this function will be called only after the basic validators all return true, and will be passed the
35937 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35941 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35942 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35943 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35947 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35951 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35955 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35956 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35958 emptyClass : 'x-form-empty-field',
35961 initEvents : function(){
35962 Roo.form.TextField.superclass.initEvents.call(this);
35963 if(this.validationEvent == 'keyup'){
35964 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35965 this.el.on('keyup', this.filterValidation, this);
35967 else if(this.validationEvent !== false){
35968 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35970 if(this.selectOnFocus || this.emptyText){
35971 this.on("focus", this.preFocus, this);
35972 if(this.emptyText){
35973 this.on('blur', this.postBlur, this);
35974 this.applyEmptyText();
35977 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35978 this.el.on("keypress", this.filterKeys, this);
35981 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35982 this.el.on("click", this.autoSize, this);
35986 processValue : function(value){
35987 if(this.stripCharsRe){
35988 var newValue = value.replace(this.stripCharsRe, '');
35989 if(newValue !== value){
35990 this.setRawValue(newValue);
35997 filterValidation : function(e){
35998 if(!e.isNavKeyPress()){
35999 this.validationTask.delay(this.validationDelay);
36004 onKeyUp : function(e){
36005 if(!e.isNavKeyPress()){
36011 * Resets the current field value to the originally-loaded value and clears any validation messages.
36012 * Also adds emptyText and emptyClass if the original value was blank.
36014 reset : function(){
36015 Roo.form.TextField.superclass.reset.call(this);
36016 this.applyEmptyText();
36019 applyEmptyText : function(){
36020 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
36021 this.setRawValue(this.emptyText);
36022 this.el.addClass(this.emptyClass);
36027 preFocus : function(){
36028 if(this.emptyText){
36029 if(this.el.dom.value == this.emptyText){
36030 this.setRawValue('');
36032 this.el.removeClass(this.emptyClass);
36034 if(this.selectOnFocus){
36035 this.el.dom.select();
36040 postBlur : function(){
36041 this.applyEmptyText();
36045 filterKeys : function(e){
36046 var k = e.getKey();
36047 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36050 var c = e.getCharCode(), cc = String.fromCharCode(c);
36051 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36054 if(!this.maskRe.test(cc)){
36059 setValue : function(v){
36060 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
36061 this.el.removeClass(this.emptyClass);
36063 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36064 this.applyEmptyText();
36069 * Validates a value according to the field's validation rules and marks the field as invalid
36070 * if the validation fails
36071 * @param {Mixed} value The value to validate
36072 * @return {Boolean} True if the value is valid, else false
36074 validateValue : function(value){
36075 if(value.length < 1 || value === this.emptyText){ // if it's blank
36076 if(this.allowBlank){
36077 this.clearInvalid();
36080 this.markInvalid(this.blankText);
36084 if(value.length < this.minLength){
36085 this.markInvalid(String.format(this.minLengthText, this.minLength));
36088 if(value.length > this.maxLength){
36089 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36093 var vt = Roo.form.VTypes;
36094 if(!vt[this.vtype](value, this)){
36095 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36099 if(typeof this.validator == "function"){
36100 var msg = this.validator(value);
36102 this.markInvalid(msg);
36106 if(this.regex && !this.regex.test(value)){
36107 this.markInvalid(this.regexText);
36114 * Selects text in this field
36115 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36116 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36118 selectText : function(start, end){
36119 var v = this.getRawValue();
36121 start = start === undefined ? 0 : start;
36122 end = end === undefined ? v.length : end;
36123 var d = this.el.dom;
36124 if(d.setSelectionRange){
36125 d.setSelectionRange(start, end);
36126 }else if(d.createTextRange){
36127 var range = d.createTextRange();
36128 range.moveStart("character", start);
36129 range.moveEnd("character", v.length-end);
36136 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36137 * This only takes effect if grow = true, and fires the autosize event.
36139 autoSize : function(){
36140 if(!this.grow || !this.rendered){
36144 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36147 var v = el.dom.value;
36148 var d = document.createElement('div');
36149 d.appendChild(document.createTextNode(v));
36153 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36154 this.el.setWidth(w);
36155 this.fireEvent("autosize", this, w);
36159 * Ext JS Library 1.1.1
36160 * Copyright(c) 2006-2007, Ext JS, LLC.
36162 * Originally Released Under LGPL - original licence link has changed is not relivant.
36165 * <script type="text/javascript">
36169 * @class Roo.form.Hidden
36170 * @extends Roo.form.TextField
36171 * Simple Hidden element used on forms
36173 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36176 * Creates a new Hidden form element.
36177 * @param {Object} config Configuration options
36182 // easy hidden field...
36183 Roo.form.Hidden = function(config){
36184 Roo.form.Hidden.superclass.constructor.call(this, config);
36187 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36189 inputType: 'hidden',
36192 labelSeparator: '',
36194 itemCls : 'x-form-item-display-none'
36202 * Ext JS Library 1.1.1
36203 * Copyright(c) 2006-2007, Ext JS, LLC.
36205 * Originally Released Under LGPL - original licence link has changed is not relivant.
36208 * <script type="text/javascript">
36212 * @class Roo.form.TriggerField
36213 * @extends Roo.form.TextField
36214 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36215 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36216 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36217 * for which you can provide a custom implementation. For example:
36219 var trigger = new Roo.form.TriggerField();
36220 trigger.onTriggerClick = myTriggerFn;
36221 trigger.applyTo('my-field');
36224 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36225 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36226 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36227 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36229 * Create a new TriggerField.
36230 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36231 * to the base TextField)
36233 Roo.form.TriggerField = function(config){
36234 this.mimicing = false;
36235 Roo.form.TriggerField.superclass.constructor.call(this, config);
36238 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36240 * @cfg {String} triggerClass A CSS class to apply to the trigger
36243 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36244 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36246 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36248 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36252 /** @cfg {Boolean} grow @hide */
36253 /** @cfg {Number} growMin @hide */
36254 /** @cfg {Number} growMax @hide */
36260 autoSize: Roo.emptyFn,
36264 deferHeight : true,
36267 actionMode : 'wrap',
36269 onResize : function(w, h){
36270 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36271 if(typeof w == 'number'){
36272 var x = w - this.trigger.getWidth();
36273 this.el.setWidth(this.adjustWidth('input', x));
36274 this.trigger.setStyle('left', x+'px');
36279 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36282 getResizeEl : function(){
36287 getPositionEl : function(){
36292 alignErrorIcon : function(){
36293 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36297 onRender : function(ct, position){
36298 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36299 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36300 this.trigger = this.wrap.createChild(this.triggerConfig ||
36301 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36302 if(this.hideTrigger){
36303 this.trigger.setDisplayed(false);
36305 this.initTrigger();
36307 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36312 initTrigger : function(){
36313 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36314 this.trigger.addClassOnOver('x-form-trigger-over');
36315 this.trigger.addClassOnClick('x-form-trigger-click');
36319 onDestroy : function(){
36321 this.trigger.removeAllListeners();
36322 this.trigger.remove();
36325 this.wrap.remove();
36327 Roo.form.TriggerField.superclass.onDestroy.call(this);
36331 onFocus : function(){
36332 Roo.form.TriggerField.superclass.onFocus.call(this);
36333 if(!this.mimicing){
36334 this.wrap.addClass('x-trigger-wrap-focus');
36335 this.mimicing = true;
36336 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36337 if(this.monitorTab){
36338 this.el.on("keydown", this.checkTab, this);
36344 checkTab : function(e){
36345 if(e.getKey() == e.TAB){
36346 this.triggerBlur();
36351 onBlur : function(){
36356 mimicBlur : function(e, t){
36357 if(!this.wrap.contains(t) && this.validateBlur()){
36358 this.triggerBlur();
36363 triggerBlur : function(){
36364 this.mimicing = false;
36365 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36366 if(this.monitorTab){
36367 this.el.un("keydown", this.checkTab, this);
36369 this.wrap.removeClass('x-trigger-wrap-focus');
36370 Roo.form.TriggerField.superclass.onBlur.call(this);
36374 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36375 validateBlur : function(e, t){
36380 onDisable : function(){
36381 Roo.form.TriggerField.superclass.onDisable.call(this);
36383 this.wrap.addClass('x-item-disabled');
36388 onEnable : function(){
36389 Roo.form.TriggerField.superclass.onEnable.call(this);
36391 this.wrap.removeClass('x-item-disabled');
36396 onShow : function(){
36397 var ae = this.getActionEl();
36400 ae.dom.style.display = '';
36401 ae.dom.style.visibility = 'visible';
36407 onHide : function(){
36408 var ae = this.getActionEl();
36409 ae.dom.style.display = 'none';
36413 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36414 * by an implementing function.
36416 * @param {EventObject} e
36418 onTriggerClick : Roo.emptyFn
36421 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36422 // to be extended by an implementing class. For an example of implementing this class, see the custom
36423 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36424 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36425 initComponent : function(){
36426 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36428 this.triggerConfig = {
36429 tag:'span', cls:'x-form-twin-triggers', cn:[
36430 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36431 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36435 getTrigger : function(index){
36436 return this.triggers[index];
36439 initTrigger : function(){
36440 var ts = this.trigger.select('.x-form-trigger', true);
36441 this.wrap.setStyle('overflow', 'hidden');
36442 var triggerField = this;
36443 ts.each(function(t, all, index){
36444 t.hide = function(){
36445 var w = triggerField.wrap.getWidth();
36446 this.dom.style.display = 'none';
36447 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36449 t.show = function(){
36450 var w = triggerField.wrap.getWidth();
36451 this.dom.style.display = '';
36452 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36454 var triggerIndex = 'Trigger'+(index+1);
36456 if(this['hide'+triggerIndex]){
36457 t.dom.style.display = 'none';
36459 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36460 t.addClassOnOver('x-form-trigger-over');
36461 t.addClassOnClick('x-form-trigger-click');
36463 this.triggers = ts.elements;
36466 onTrigger1Click : Roo.emptyFn,
36467 onTrigger2Click : Roo.emptyFn
36470 * Ext JS Library 1.1.1
36471 * Copyright(c) 2006-2007, Ext JS, LLC.
36473 * Originally Released Under LGPL - original licence link has changed is not relivant.
36476 * <script type="text/javascript">
36480 * @class Roo.form.TextArea
36481 * @extends Roo.form.TextField
36482 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36483 * support for auto-sizing.
36485 * Creates a new TextArea
36486 * @param {Object} config Configuration options
36488 Roo.form.TextArea = function(config){
36489 Roo.form.TextArea.superclass.constructor.call(this, config);
36490 // these are provided exchanges for backwards compat
36491 // minHeight/maxHeight were replaced by growMin/growMax to be
36492 // compatible with TextField growing config values
36493 if(this.minHeight !== undefined){
36494 this.growMin = this.minHeight;
36496 if(this.maxHeight !== undefined){
36497 this.growMax = this.maxHeight;
36501 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36503 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36507 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36511 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36512 * in the field (equivalent to setting overflow: hidden, defaults to false)
36514 preventScrollbars: false,
36516 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36517 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36521 onRender : function(ct, position){
36523 this.defaultAutoCreate = {
36525 style:"width:300px;height:60px;",
36526 autocomplete: "off"
36529 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36531 this.textSizeEl = Roo.DomHelper.append(document.body, {
36532 tag: "pre", cls: "x-form-grow-sizer"
36534 if(this.preventScrollbars){
36535 this.el.setStyle("overflow", "hidden");
36537 this.el.setHeight(this.growMin);
36541 onDestroy : function(){
36542 if(this.textSizeEl){
36543 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36545 Roo.form.TextArea.superclass.onDestroy.call(this);
36549 onKeyUp : function(e){
36550 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36556 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36557 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36559 autoSize : function(){
36560 if(!this.grow || !this.textSizeEl){
36564 var v = el.dom.value;
36565 var ts = this.textSizeEl;
36568 ts.appendChild(document.createTextNode(v));
36571 Roo.fly(ts).setWidth(this.el.getWidth());
36573 v = "  ";
36576 v = v.replace(/\n/g, '<p> </p>');
36578 v += " \n ";
36581 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36582 if(h != this.lastHeight){
36583 this.lastHeight = h;
36584 this.el.setHeight(h);
36585 this.fireEvent("autosize", this, h);
36590 * Ext JS Library 1.1.1
36591 * Copyright(c) 2006-2007, Ext JS, LLC.
36593 * Originally Released Under LGPL - original licence link has changed is not relivant.
36596 * <script type="text/javascript">
36601 * @class Roo.form.NumberField
36602 * @extends Roo.form.TextField
36603 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36605 * Creates a new NumberField
36606 * @param {Object} config Configuration options
36608 Roo.form.NumberField = function(config){
36609 Roo.form.NumberField.superclass.constructor.call(this, config);
36612 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36614 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36616 fieldClass: "x-form-field x-form-num-field",
36618 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36620 allowDecimals : true,
36622 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36624 decimalSeparator : ".",
36626 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36628 decimalPrecision : 2,
36630 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36632 allowNegative : true,
36634 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36636 minValue : Number.NEGATIVE_INFINITY,
36638 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36640 maxValue : Number.MAX_VALUE,
36642 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36644 minText : "The minimum value for this field is {0}",
36646 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36648 maxText : "The maximum value for this field is {0}",
36650 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36651 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36653 nanText : "{0} is not a valid number",
36656 initEvents : function(){
36657 Roo.form.NumberField.superclass.initEvents.call(this);
36658 var allowed = "0123456789";
36659 if(this.allowDecimals){
36660 allowed += this.decimalSeparator;
36662 if(this.allowNegative){
36665 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36666 var keyPress = function(e){
36667 var k = e.getKey();
36668 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36671 var c = e.getCharCode();
36672 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36676 this.el.on("keypress", keyPress, this);
36680 validateValue : function(value){
36681 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36684 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36687 var num = this.parseValue(value);
36689 this.markInvalid(String.format(this.nanText, value));
36692 if(num < this.minValue){
36693 this.markInvalid(String.format(this.minText, this.minValue));
36696 if(num > this.maxValue){
36697 this.markInvalid(String.format(this.maxText, this.maxValue));
36703 getValue : function(){
36704 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36708 parseValue : function(value){
36709 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36710 return isNaN(value) ? '' : value;
36714 fixPrecision : function(value){
36715 var nan = isNaN(value);
36716 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36717 return nan ? '' : value;
36719 return parseFloat(value).toFixed(this.decimalPrecision);
36722 setValue : function(v){
36723 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36727 decimalPrecisionFcn : function(v){
36728 return Math.floor(v);
36731 beforeBlur : function(){
36732 var v = this.parseValue(this.getRawValue());
36734 this.setValue(this.fixPrecision(v));
36739 * Ext JS Library 1.1.1
36740 * Copyright(c) 2006-2007, Ext JS, LLC.
36742 * Originally Released Under LGPL - original licence link has changed is not relivant.
36745 * <script type="text/javascript">
36749 * @class Roo.form.DateField
36750 * @extends Roo.form.TriggerField
36751 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36753 * Create a new DateField
36754 * @param {Object} config
36756 Roo.form.DateField = function(config){
36757 Roo.form.DateField.superclass.constructor.call(this, config);
36763 * Fires when a date is selected
36764 * @param {Roo.form.DateField} combo This combo box
36765 * @param {Date} date The date selected
36772 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36773 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36774 this.ddMatch = null;
36775 if(this.disabledDates){
36776 var dd = this.disabledDates;
36778 for(var i = 0; i < dd.length; i++){
36780 if(i != dd.length-1) re += "|";
36782 this.ddMatch = new RegExp(re + ")");
36786 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36788 * @cfg {String} format
36789 * The default date format string which can be overriden for localization support. The format must be
36790 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36794 * @cfg {String} altFormats
36795 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36796 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36798 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36800 * @cfg {Array} disabledDays
36801 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36803 disabledDays : null,
36805 * @cfg {String} disabledDaysText
36806 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36808 disabledDaysText : "Disabled",
36810 * @cfg {Array} disabledDates
36811 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36812 * expression so they are very powerful. Some examples:
36814 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36815 * <li>["03/08", "09/16"] would disable those days for every year</li>
36816 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36817 * <li>["03/../2006"] would disable every day in March 2006</li>
36818 * <li>["^03"] would disable every day in every March</li>
36820 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36821 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36823 disabledDates : null,
36825 * @cfg {String} disabledDatesText
36826 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36828 disabledDatesText : "Disabled",
36830 * @cfg {Date/String} minValue
36831 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36832 * valid format (defaults to null).
36836 * @cfg {Date/String} maxValue
36837 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36838 * valid format (defaults to null).
36842 * @cfg {String} minText
36843 * The error text to display when the date in the cell is before minValue (defaults to
36844 * 'The date in this field must be after {minValue}').
36846 minText : "The date in this field must be equal to or after {0}",
36848 * @cfg {String} maxText
36849 * The error text to display when the date in the cell is after maxValue (defaults to
36850 * 'The date in this field must be before {maxValue}').
36852 maxText : "The date in this field must be equal to or before {0}",
36854 * @cfg {String} invalidText
36855 * The error text to display when the date in the field is invalid (defaults to
36856 * '{value} is not a valid date - it must be in the format {format}').
36858 invalidText : "{0} is not a valid date - it must be in the format {1}",
36860 * @cfg {String} triggerClass
36861 * An additional CSS class used to style the trigger button. The trigger will always get the
36862 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36863 * which displays a calendar icon).
36865 triggerClass : 'x-form-date-trigger',
36869 * @cfg {bool} useIso
36870 * if enabled, then the date field will use a hidden field to store the
36871 * real value as iso formated date. default (false)
36875 * @cfg {String/Object} autoCreate
36876 * A DomHelper element spec, or true for a default element spec (defaults to
36877 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36880 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36883 hiddenField: false,
36885 onRender : function(ct, position)
36887 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36889 this.el.dom.removeAttribute('name');
36890 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36892 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36893 // prevent input submission
36894 this.hiddenName = this.name;
36901 validateValue : function(value)
36903 value = this.formatDate(value);
36904 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36907 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36910 var svalue = value;
36911 value = this.parseDate(value);
36913 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36916 var time = value.getTime();
36917 if(this.minValue && time < this.minValue.getTime()){
36918 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36921 if(this.maxValue && time > this.maxValue.getTime()){
36922 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36925 if(this.disabledDays){
36926 var day = value.getDay();
36927 for(var i = 0; i < this.disabledDays.length; i++) {
36928 if(day === this.disabledDays[i]){
36929 this.markInvalid(this.disabledDaysText);
36934 var fvalue = this.formatDate(value);
36935 if(this.ddMatch && this.ddMatch.test(fvalue)){
36936 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36943 // Provides logic to override the default TriggerField.validateBlur which just returns true
36944 validateBlur : function(){
36945 return !this.menu || !this.menu.isVisible();
36949 * Returns the current date value of the date field.
36950 * @return {Date} The date value
36952 getValue : function(){
36954 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36958 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36959 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36960 * (the default format used is "m/d/y").
36963 //All of these calls set the same date value (May 4, 2006)
36965 //Pass a date object:
36966 var dt = new Date('5/4/06');
36967 dateField.setValue(dt);
36969 //Pass a date string (default format):
36970 dateField.setValue('5/4/06');
36972 //Pass a date string (custom format):
36973 dateField.format = 'Y-m-d';
36974 dateField.setValue('2006-5-4');
36976 * @param {String/Date} date The date or valid date string
36978 setValue : function(date){
36979 if (this.hiddenField) {
36980 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36982 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36986 parseDate : function(value){
36987 if(!value || value instanceof Date){
36990 var v = Date.parseDate(value, this.format);
36991 if(!v && this.altFormats){
36992 if(!this.altFormatsArray){
36993 this.altFormatsArray = this.altFormats.split("|");
36995 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36996 v = Date.parseDate(value, this.altFormatsArray[i]);
37003 formatDate : function(date, fmt){
37004 return (!date || !(date instanceof Date)) ?
37005 date : date.dateFormat(fmt || this.format);
37010 select: function(m, d){
37012 this.fireEvent('select', this, d);
37014 show : function(){ // retain focus styling
37018 this.focus.defer(10, this);
37019 var ml = this.menuListeners;
37020 this.menu.un("select", ml.select, this);
37021 this.menu.un("show", ml.show, this);
37022 this.menu.un("hide", ml.hide, this);
37027 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37028 onTriggerClick : function(){
37032 if(this.menu == null){
37033 this.menu = new Roo.menu.DateMenu();
37035 Roo.apply(this.menu.picker, {
37036 showClear: this.allowBlank,
37037 minDate : this.minValue,
37038 maxDate : this.maxValue,
37039 disabledDatesRE : this.ddMatch,
37040 disabledDatesText : this.disabledDatesText,
37041 disabledDays : this.disabledDays,
37042 disabledDaysText : this.disabledDaysText,
37043 format : this.format,
37044 minText : String.format(this.minText, this.formatDate(this.minValue)),
37045 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37047 this.menu.on(Roo.apply({}, this.menuListeners, {
37050 this.menu.picker.setValue(this.getValue() || new Date());
37051 this.menu.show(this.el, "tl-bl?");
37054 beforeBlur : function(){
37055 var v = this.parseDate(this.getRawValue());
37061 /** @cfg {Boolean} grow @hide */
37062 /** @cfg {Number} growMin @hide */
37063 /** @cfg {Number} growMax @hide */
37070 * Ext JS Library 1.1.1
37071 * Copyright(c) 2006-2007, Ext JS, LLC.
37073 * Originally Released Under LGPL - original licence link has changed is not relivant.
37076 * <script type="text/javascript">
37081 * @class Roo.form.ComboBox
37082 * @extends Roo.form.TriggerField
37083 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
37085 * Create a new ComboBox.
37086 * @param {Object} config Configuration options
37088 Roo.form.ComboBox = function(config){
37089 Roo.form.ComboBox.superclass.constructor.call(this, config);
37093 * Fires when the dropdown list is expanded
37094 * @param {Roo.form.ComboBox} combo This combo box
37099 * Fires when the dropdown list is collapsed
37100 * @param {Roo.form.ComboBox} combo This combo box
37104 * @event beforeselect
37105 * Fires before a list item is selected. Return false to cancel the selection.
37106 * @param {Roo.form.ComboBox} combo This combo box
37107 * @param {Roo.data.Record} record The data record returned from the underlying store
37108 * @param {Number} index The index of the selected item in the dropdown list
37110 'beforeselect' : true,
37113 * Fires when a list item is selected
37114 * @param {Roo.form.ComboBox} combo This combo box
37115 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37116 * @param {Number} index The index of the selected item in the dropdown list
37120 * @event beforequery
37121 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37122 * The event object passed has these properties:
37123 * @param {Roo.form.ComboBox} combo This combo box
37124 * @param {String} query The query
37125 * @param {Boolean} forceAll true to force "all" query
37126 * @param {Boolean} cancel true to cancel the query
37127 * @param {Object} e The query event object
37129 'beforequery': true,
37132 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37133 * @param {Roo.form.ComboBox} combo This combo box
37138 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37139 * @param {Roo.form.ComboBox} combo This combo box
37140 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37146 if(this.transform){
37147 this.allowDomMove = false;
37148 var s = Roo.getDom(this.transform);
37149 if(!this.hiddenName){
37150 this.hiddenName = s.name;
37153 this.mode = 'local';
37154 var d = [], opts = s.options;
37155 for(var i = 0, len = opts.length;i < len; i++){
37157 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37159 this.value = value;
37161 d.push([value, o.text]);
37163 this.store = new Roo.data.SimpleStore({
37165 fields: ['value', 'text'],
37168 this.valueField = 'value';
37169 this.displayField = 'text';
37171 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37172 if(!this.lazyRender){
37173 this.target = true;
37174 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37175 s.parentNode.removeChild(s); // remove it
37176 this.render(this.el.parentNode);
37178 s.parentNode.removeChild(s); // remove it
37183 this.store = Roo.factory(this.store, Roo.data);
37186 this.selectedIndex = -1;
37187 if(this.mode == 'local'){
37188 if(config.queryDelay === undefined){
37189 this.queryDelay = 10;
37191 if(config.minChars === undefined){
37197 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37199 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37202 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37203 * rendering into an Roo.Editor, defaults to false)
37206 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37207 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37210 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37213 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37214 * the dropdown list (defaults to undefined, with no header element)
37218 * @cfg {String/Roo.Template} tpl The template to use to render the output
37222 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37224 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37226 listWidth: undefined,
37228 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37229 * mode = 'remote' or 'text' if mode = 'local')
37231 displayField: undefined,
37233 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37234 * mode = 'remote' or 'value' if mode = 'local').
37235 * Note: use of a valueField requires the user make a selection
37236 * in order for a value to be mapped.
37238 valueField: undefined,
37240 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37241 * field's data value (defaults to the underlying DOM element's name)
37243 hiddenName: undefined,
37245 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37249 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37251 selectedClass: 'x-combo-selected',
37253 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37254 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37255 * which displays a downward arrow icon).
37257 triggerClass : 'x-form-arrow-trigger',
37259 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37263 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37264 * anchor positions (defaults to 'tl-bl')
37266 listAlign: 'tl-bl?',
37268 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37272 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37273 * query specified by the allQuery config option (defaults to 'query')
37275 triggerAction: 'query',
37277 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37278 * (defaults to 4, does not apply if editable = false)
37282 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37283 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37287 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37288 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37292 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37293 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37297 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37298 * when editable = true (defaults to false)
37300 selectOnFocus:false,
37302 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37304 queryParam: 'query',
37306 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37307 * when mode = 'remote' (defaults to 'Loading...')
37309 loadingText: 'Loading...',
37311 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37315 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37319 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37320 * traditional select (defaults to true)
37324 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37328 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37332 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37333 * listWidth has a higher value)
37337 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37338 * allow the user to set arbitrary text into the field (defaults to false)
37340 forceSelection:false,
37342 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37343 * if typeAhead = true (defaults to 250)
37345 typeAheadDelay : 250,
37347 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37348 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37350 valueNotFoundText : undefined,
37352 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37354 blockFocus : false,
37357 * @cfg {Boolean} disableClear Disable showing of clear button.
37359 disableClear : false,
37361 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37363 alwaysQuery : false,
37371 onRender : function(ct, position){
37372 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37373 if(this.hiddenName){
37374 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37376 this.hiddenField.value =
37377 this.hiddenValue !== undefined ? this.hiddenValue :
37378 this.value !== undefined ? this.value : '';
37380 // prevent input submission
37381 this.el.dom.removeAttribute('name');
37384 this.el.dom.setAttribute('autocomplete', 'off');
37387 var cls = 'x-combo-list';
37389 this.list = new Roo.Layer({
37390 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37393 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37394 this.list.setWidth(lw);
37395 this.list.swallowEvent('mousewheel');
37396 this.assetHeight = 0;
37399 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37400 this.assetHeight += this.header.getHeight();
37403 this.innerList = this.list.createChild({cls:cls+'-inner'});
37404 this.innerList.on('mouseover', this.onViewOver, this);
37405 this.innerList.on('mousemove', this.onViewMove, this);
37406 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37408 if(this.allowBlank && !this.pageSize && !this.disableClear){
37409 this.footer = this.list.createChild({cls:cls+'-ft'});
37410 this.pageTb = new Roo.Toolbar(this.footer);
37414 this.footer = this.list.createChild({cls:cls+'-ft'});
37415 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37416 {pageSize: this.pageSize});
37420 if (this.pageTb && this.allowBlank && !this.disableClear) {
37422 this.pageTb.add(new Roo.Toolbar.Fill(), {
37423 cls: 'x-btn-icon x-btn-clear',
37425 handler: function()
37428 _this.clearValue();
37429 _this.onSelect(false, -1);
37434 this.assetHeight += this.footer.getHeight();
37439 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37442 this.view = new Roo.View(this.innerList, this.tpl, {
37443 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37446 this.view.on('click', this.onViewClick, this);
37448 this.store.on('beforeload', this.onBeforeLoad, this);
37449 this.store.on('load', this.onLoad, this);
37450 this.store.on('loadexception', this.collapse, this);
37452 if(this.resizable){
37453 this.resizer = new Roo.Resizable(this.list, {
37454 pinned:true, handles:'se'
37456 this.resizer.on('resize', function(r, w, h){
37457 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37458 this.listWidth = w;
37459 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37460 this.restrictHeight();
37462 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37464 if(!this.editable){
37465 this.editable = true;
37466 this.setEditable(false);
37470 if (typeof(this.events.add.listeners) != 'undefined') {
37472 this.addicon = this.wrap.createChild(
37473 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37475 this.addicon.on('click', function(e) {
37476 this.fireEvent('add', this);
37479 if (typeof(this.events.edit.listeners) != 'undefined') {
37481 this.editicon = this.wrap.createChild(
37482 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37483 if (this.addicon) {
37484 this.editicon.setStyle('margin-left', '40px');
37486 this.editicon.on('click', function(e) {
37488 // we fire even if inothing is selected..
37489 this.fireEvent('edit', this, this.lastData );
37499 initEvents : function(){
37500 Roo.form.ComboBox.superclass.initEvents.call(this);
37502 this.keyNav = new Roo.KeyNav(this.el, {
37503 "up" : function(e){
37504 this.inKeyMode = true;
37508 "down" : function(e){
37509 if(!this.isExpanded()){
37510 this.onTriggerClick();
37512 this.inKeyMode = true;
37517 "enter" : function(e){
37518 this.onViewClick();
37522 "esc" : function(e){
37526 "tab" : function(e){
37527 this.onViewClick(false);
37533 doRelay : function(foo, bar, hname){
37534 if(hname == 'down' || this.scope.isExpanded()){
37535 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37542 this.queryDelay = Math.max(this.queryDelay || 10,
37543 this.mode == 'local' ? 10 : 250);
37544 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37545 if(this.typeAhead){
37546 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37548 if(this.editable !== false){
37549 this.el.on("keyup", this.onKeyUp, this);
37551 if(this.forceSelection){
37552 this.on('blur', this.doForce, this);
37556 onDestroy : function(){
37558 this.view.setStore(null);
37559 this.view.el.removeAllListeners();
37560 this.view.el.remove();
37561 this.view.purgeListeners();
37564 this.list.destroy();
37567 this.store.un('beforeload', this.onBeforeLoad, this);
37568 this.store.un('load', this.onLoad, this);
37569 this.store.un('loadexception', this.collapse, this);
37571 Roo.form.ComboBox.superclass.onDestroy.call(this);
37575 fireKey : function(e){
37576 if(e.isNavKeyPress() && !this.list.isVisible()){
37577 this.fireEvent("specialkey", this, e);
37582 onResize: function(w, h){
37583 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37585 if(typeof w != 'number'){
37586 // we do not handle it!?!?
37589 var tw = this.trigger.getWidth();
37590 tw += this.addicon ? this.addicon.getWidth() : 0;
37591 tw += this.editicon ? this.editicon.getWidth() : 0;
37593 this.el.setWidth( this.adjustWidth('input', x));
37595 this.trigger.setStyle('left', x+'px');
37597 if(this.list && this.listWidth === undefined){
37598 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37599 this.list.setWidth(lw);
37600 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37608 * Allow or prevent the user from directly editing the field text. If false is passed,
37609 * the user will only be able to select from the items defined in the dropdown list. This method
37610 * is the runtime equivalent of setting the 'editable' config option at config time.
37611 * @param {Boolean} value True to allow the user to directly edit the field text
37613 setEditable : function(value){
37614 if(value == this.editable){
37617 this.editable = value;
37619 this.el.dom.setAttribute('readOnly', true);
37620 this.el.on('mousedown', this.onTriggerClick, this);
37621 this.el.addClass('x-combo-noedit');
37623 this.el.dom.setAttribute('readOnly', false);
37624 this.el.un('mousedown', this.onTriggerClick, this);
37625 this.el.removeClass('x-combo-noedit');
37630 onBeforeLoad : function(){
37631 if(!this.hasFocus){
37634 this.innerList.update(this.loadingText ?
37635 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37636 this.restrictHeight();
37637 this.selectedIndex = -1;
37641 onLoad : function(){
37642 if(!this.hasFocus){
37645 if(this.store.getCount() > 0){
37647 this.restrictHeight();
37648 if(this.lastQuery == this.allQuery){
37650 this.el.dom.select();
37652 if(!this.selectByValue(this.value, true)){
37653 this.select(0, true);
37657 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37658 this.taTask.delay(this.typeAheadDelay);
37662 this.onEmptyResults();
37668 onTypeAhead : function(){
37669 if(this.store.getCount() > 0){
37670 var r = this.store.getAt(0);
37671 var newValue = r.data[this.displayField];
37672 var len = newValue.length;
37673 var selStart = this.getRawValue().length;
37674 if(selStart != len){
37675 this.setRawValue(newValue);
37676 this.selectText(selStart, newValue.length);
37682 onSelect : function(record, index){
37683 if(this.fireEvent('beforeselect', this, record, index) !== false){
37684 this.setFromData(index > -1 ? record.data : false);
37686 this.fireEvent('select', this, record, index);
37691 * Returns the currently selected field value or empty string if no value is set.
37692 * @return {String} value The selected value
37694 getValue : function(){
37695 if(this.valueField){
37696 return typeof this.value != 'undefined' ? this.value : '';
37698 return Roo.form.ComboBox.superclass.getValue.call(this);
37703 * Clears any text/value currently set in the field
37705 clearValue : function(){
37706 if(this.hiddenField){
37707 this.hiddenField.value = '';
37710 this.setRawValue('');
37711 this.lastSelectionText = '';
37712 this.applyEmptyText();
37716 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37717 * will be displayed in the field. If the value does not match the data value of an existing item,
37718 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37719 * Otherwise the field will be blank (although the value will still be set).
37720 * @param {String} value The value to match
37722 setValue : function(v){
37724 if(this.valueField){
37725 var r = this.findRecord(this.valueField, v);
37727 text = r.data[this.displayField];
37728 }else if(this.valueNotFoundText !== undefined){
37729 text = this.valueNotFoundText;
37732 this.lastSelectionText = text;
37733 if(this.hiddenField){
37734 this.hiddenField.value = v;
37736 Roo.form.ComboBox.superclass.setValue.call(this, text);
37740 * @property {Object} the last set data for the element
37745 * Sets the value of the field based on a object which is related to the record format for the store.
37746 * @param {Object} value the value to set as. or false on reset?
37748 setFromData : function(o){
37749 var dv = ''; // display value
37750 var vv = ''; // value value..
37752 if (this.displayField) {
37753 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37755 // this is an error condition!!!
37756 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
37759 if(this.valueField){
37760 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37762 if(this.hiddenField){
37763 this.hiddenField.value = vv;
37765 this.lastSelectionText = dv;
37766 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37770 // no hidden field.. - we store the value in 'value', but still display
37771 // display field!!!!
37772 this.lastSelectionText = dv;
37773 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37779 reset : function(){
37780 // overridden so that last data is reset..
37781 this.setValue(this.originalValue);
37782 this.clearInvalid();
37783 this.lastData = false;
37786 findRecord : function(prop, value){
37788 if(this.store.getCount() > 0){
37789 this.store.each(function(r){
37790 if(r.data[prop] == value){
37800 onViewMove : function(e, t){
37801 this.inKeyMode = false;
37805 onViewOver : function(e, t){
37806 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37809 var item = this.view.findItemFromChild(t);
37811 var index = this.view.indexOf(item);
37812 this.select(index, false);
37817 onViewClick : function(doFocus){
37818 var index = this.view.getSelectedIndexes()[0];
37819 var r = this.store.getAt(index);
37821 this.onSelect(r, index);
37823 if(doFocus !== false && !this.blockFocus){
37829 restrictHeight : function(){
37830 this.innerList.dom.style.height = '';
37831 var inner = this.innerList.dom;
37832 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37833 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37834 this.list.beginUpdate();
37835 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37836 this.list.alignTo(this.el, this.listAlign);
37837 this.list.endUpdate();
37841 onEmptyResults : function(){
37846 * Returns true if the dropdown list is expanded, else false.
37848 isExpanded : function(){
37849 return this.list.isVisible();
37853 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37854 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37855 * @param {String} value The data value of the item to select
37856 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37857 * selected item if it is not currently in view (defaults to true)
37858 * @return {Boolean} True if the value matched an item in the list, else false
37860 selectByValue : function(v, scrollIntoView){
37861 if(v !== undefined && v !== null){
37862 var r = this.findRecord(this.valueField || this.displayField, v);
37864 this.select(this.store.indexOf(r), scrollIntoView);
37872 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37873 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37874 * @param {Number} index The zero-based index of the list item to select
37875 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37876 * selected item if it is not currently in view (defaults to true)
37878 select : function(index, scrollIntoView){
37879 this.selectedIndex = index;
37880 this.view.select(index);
37881 if(scrollIntoView !== false){
37882 var el = this.view.getNode(index);
37884 this.innerList.scrollChildIntoView(el, false);
37890 selectNext : function(){
37891 var ct = this.store.getCount();
37893 if(this.selectedIndex == -1){
37895 }else if(this.selectedIndex < ct-1){
37896 this.select(this.selectedIndex+1);
37902 selectPrev : function(){
37903 var ct = this.store.getCount();
37905 if(this.selectedIndex == -1){
37907 }else if(this.selectedIndex != 0){
37908 this.select(this.selectedIndex-1);
37914 onKeyUp : function(e){
37915 if(this.editable !== false && !e.isSpecialKey()){
37916 this.lastKey = e.getKey();
37917 this.dqTask.delay(this.queryDelay);
37922 validateBlur : function(){
37923 return !this.list || !this.list.isVisible();
37927 initQuery : function(){
37928 this.doQuery(this.getRawValue());
37932 doForce : function(){
37933 if(this.el.dom.value.length > 0){
37934 this.el.dom.value =
37935 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37936 this.applyEmptyText();
37941 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37942 * query allowing the query action to be canceled if needed.
37943 * @param {String} query The SQL query to execute
37944 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37945 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37946 * saved in the current store (defaults to false)
37948 doQuery : function(q, forceAll){
37949 if(q === undefined || q === null){
37954 forceAll: forceAll,
37958 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37962 forceAll = qe.forceAll;
37963 if(forceAll === true || (q.length >= this.minChars)){
37964 if(this.lastQuery != q || this.alwaysQuery){
37965 this.lastQuery = q;
37966 if(this.mode == 'local'){
37967 this.selectedIndex = -1;
37969 this.store.clearFilter();
37971 this.store.filter(this.displayField, q);
37975 this.store.baseParams[this.queryParam] = q;
37977 params: this.getParams(q)
37982 this.selectedIndex = -1;
37989 getParams : function(q){
37991 //p[this.queryParam] = q;
37994 p.limit = this.pageSize;
38000 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
38002 collapse : function(){
38003 if(!this.isExpanded()){
38007 Roo.get(document).un('mousedown', this.collapseIf, this);
38008 Roo.get(document).un('mousewheel', this.collapseIf, this);
38009 if (!this.editable) {
38010 Roo.get(document).un('keydown', this.listKeyPress, this);
38012 this.fireEvent('collapse', this);
38016 collapseIf : function(e){
38017 if(!e.within(this.wrap) && !e.within(this.list)){
38023 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
38025 expand : function(){
38026 if(this.isExpanded() || !this.hasFocus){
38029 this.list.alignTo(this.el, this.listAlign);
38031 Roo.get(document).on('mousedown', this.collapseIf, this);
38032 Roo.get(document).on('mousewheel', this.collapseIf, this);
38033 if (!this.editable) {
38034 Roo.get(document).on('keydown', this.listKeyPress, this);
38037 this.fireEvent('expand', this);
38041 // Implements the default empty TriggerField.onTriggerClick function
38042 onTriggerClick : function(){
38046 if(this.isExpanded()){
38048 if (!this.blockFocus) {
38053 this.hasFocus = true;
38054 if(this.triggerAction == 'all') {
38055 this.doQuery(this.allQuery, true);
38057 this.doQuery(this.getRawValue());
38059 if (!this.blockFocus) {
38064 listKeyPress : function(e)
38066 //Roo.log('listkeypress');
38067 // scroll to first matching element based on key pres..
38068 if (e.isSpecialKey()) {
38071 var k = String.fromCharCode(e.getKey()).toUpperCase();
38074 var csel = this.view.getSelectedNodes();
38075 var cselitem = false;
38077 var ix = this.view.indexOf(csel[0]);
38078 cselitem = this.store.getAt(ix);
38079 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
38085 this.store.each(function(v) {
38087 // start at existing selection.
38088 if (cselitem.id == v.id) {
38094 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
38095 match = this.store.indexOf(v);
38100 if (match === false) {
38101 return true; // no more action?
38104 this.view.select(match);
38105 var sn = Roo.get(this.view.getSelectedNodes()[0])
38106 sn.scrollIntoView(sn.dom.parentNode, false);
38110 * @cfg {Boolean} grow
38114 * @cfg {Number} growMin
38118 * @cfg {Number} growMax
38127 * Ext JS Library 1.1.1
38128 * Copyright(c) 2006-2007, Ext JS, LLC.
38130 * Originally Released Under LGPL - original licence link has changed is not relivant.
38133 * <script type="text/javascript">
38136 * @class Roo.form.Checkbox
38137 * @extends Roo.form.Field
38138 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
38140 * Creates a new Checkbox
38141 * @param {Object} config Configuration options
38143 Roo.form.Checkbox = function(config){
38144 Roo.form.Checkbox.superclass.constructor.call(this, config);
38148 * Fires when the checkbox is checked or unchecked.
38149 * @param {Roo.form.Checkbox} this This checkbox
38150 * @param {Boolean} checked The new checked value
38156 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38158 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38160 focusClass : undefined,
38162 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38164 fieldClass: "x-form-field",
38166 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38170 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38171 * {tag: "input", type: "checkbox", autocomplete: "off"})
38173 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38175 * @cfg {String} boxLabel The text that appears beside the checkbox
38179 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38183 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38185 valueOff: '0', // value when not checked..
38187 actionMode : 'viewEl',
38190 itemCls : 'x-menu-check-item x-form-item',
38191 groupClass : 'x-menu-group-item',
38192 inputType : 'hidden',
38195 inSetChecked: false, // check that we are not calling self...
38197 inputElement: false, // real input element?
38198 basedOn: false, // ????
38200 isFormField: true, // not sure where this is needed!!!!
38202 onResize : function(){
38203 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38204 if(!this.boxLabel){
38205 this.el.alignTo(this.wrap, 'c-c');
38209 initEvents : function(){
38210 Roo.form.Checkbox.superclass.initEvents.call(this);
38211 this.el.on("click", this.onClick, this);
38212 this.el.on("change", this.onClick, this);
38216 getResizeEl : function(){
38220 getPositionEl : function(){
38225 onRender : function(ct, position){
38226 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38228 if(this.inputValue !== undefined){
38229 this.el.dom.value = this.inputValue;
38232 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38233 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38234 var viewEl = this.wrap.createChild({
38235 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38236 this.viewEl = viewEl;
38237 this.wrap.on('click', this.onClick, this);
38239 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38240 this.el.on('propertychange', this.setFromHidden, this); //ie
38245 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38246 // viewEl.on('click', this.onClick, this);
38248 //if(this.checked){
38249 this.setChecked(this.checked);
38251 //this.checked = this.el.dom;
38257 initValue : Roo.emptyFn,
38260 * Returns the checked state of the checkbox.
38261 * @return {Boolean} True if checked, else false
38263 getValue : function(){
38265 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38267 return this.valueOff;
38272 onClick : function(){
38273 this.setChecked(!this.checked);
38275 //if(this.el.dom.checked != this.checked){
38276 // this.setValue(this.el.dom.checked);
38281 * Sets the checked state of the checkbox.
38282 * On is always based on a string comparison between inputValue and the param.
38283 * @param {Boolean/String} value - the value to set
38284 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38286 setValue : function(v,suppressEvent){
38289 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38290 //if(this.el && this.el.dom){
38291 // this.el.dom.checked = this.checked;
38292 // this.el.dom.defaultChecked = this.checked;
38294 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38295 //this.fireEvent("check", this, this.checked);
38298 setChecked : function(state,suppressEvent)
38300 if (this.inSetChecked) {
38301 this.checked = state;
38307 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38309 this.checked = state;
38310 if(suppressEvent !== true){
38311 this.fireEvent('check', this, state);
38313 this.inSetChecked = true;
38314 this.el.dom.value = state ? this.inputValue : this.valueOff;
38315 this.inSetChecked = false;
38318 // handle setting of hidden value by some other method!!?!?
38319 setFromHidden: function()
38324 //console.log("SET FROM HIDDEN");
38325 //alert('setFrom hidden');
38326 this.setValue(this.el.dom.value);
38329 onDestroy : function()
38332 Roo.get(this.viewEl).remove();
38335 Roo.form.Checkbox.superclass.onDestroy.call(this);
38340 * Ext JS Library 1.1.1
38341 * Copyright(c) 2006-2007, Ext JS, LLC.
38343 * Originally Released Under LGPL - original licence link has changed is not relivant.
38346 * <script type="text/javascript">
38350 * @class Roo.form.Radio
38351 * @extends Roo.form.Checkbox
38352 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38353 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38355 * Creates a new Radio
38356 * @param {Object} config Configuration options
38358 Roo.form.Radio = function(){
38359 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38361 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38362 inputType: 'radio',
38365 * If this radio is part of a group, it will return the selected value
38368 getGroupValue : function(){
38369 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38371 });//<script type="text/javascript">
38374 * Ext JS Library 1.1.1
38375 * Copyright(c) 2006-2007, Ext JS, LLC.
38376 * licensing@extjs.com
38378 * http://www.extjs.com/license
38384 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38385 * - IE ? - no idea how much works there.
38393 * @class Ext.form.HtmlEditor
38394 * @extends Ext.form.Field
38395 * Provides a lightweight HTML Editor component.
38396 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38398 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38399 * supported by this editor.</b><br/><br/>
38400 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38401 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38403 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38405 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38409 * @cfg {String} createLinkText The default text for the create link prompt
38411 createLinkText : 'Please enter the URL for the link:',
38413 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38415 defaultLinkValue : 'http:/'+'/',
38421 // private properties
38422 validationEvent : false,
38424 initialized : false,
38426 sourceEditMode : false,
38427 onFocus : Roo.emptyFn,
38429 hideMode:'offsets',
38430 defaultAutoCreate : {
38432 style:"width:500px;height:300px;",
38433 autocomplete: "off"
38437 initComponent : function(){
38440 * @event initialize
38441 * Fires when the editor is fully initialized (including the iframe)
38442 * @param {HtmlEditor} this
38447 * Fires when the editor is first receives the focus. Any insertion must wait
38448 * until after this event.
38449 * @param {HtmlEditor} this
38453 * @event beforesync
38454 * Fires before the textarea is updated with content from the editor iframe. Return false
38455 * to cancel the sync.
38456 * @param {HtmlEditor} this
38457 * @param {String} html
38461 * @event beforepush
38462 * Fires before the iframe editor is updated with content from the textarea. Return false
38463 * to cancel the push.
38464 * @param {HtmlEditor} this
38465 * @param {String} html
38470 * Fires when the textarea is updated with content from the editor iframe.
38471 * @param {HtmlEditor} this
38472 * @param {String} html
38477 * Fires when the iframe editor is updated with content from the textarea.
38478 * @param {HtmlEditor} this
38479 * @param {String} html
38483 * @event editmodechange
38484 * Fires when the editor switches edit modes
38485 * @param {HtmlEditor} this
38486 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38488 editmodechange: true,
38490 * @event editorevent
38491 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38492 * @param {HtmlEditor} this
38499 * Protected method that will not generally be called directly. It
38500 * is called when the editor creates its toolbar. Override this method if you need to
38501 * add custom toolbar buttons.
38502 * @param {HtmlEditor} editor
38504 createToolbar : function(editor){
38505 if (!editor.toolbars || !editor.toolbars.length) {
38506 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38509 for (var i =0 ; i < editor.toolbars.length;i++) {
38510 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38511 editor.toolbars[i].init(editor);
38518 * Protected method that will not generally be called directly. It
38519 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38520 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38522 getDocMarkup : function(){
38523 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
38527 onRender : function(ct, position){
38528 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38529 this.el.dom.style.border = '0 none';
38530 this.el.dom.setAttribute('tabIndex', -1);
38531 this.el.addClass('x-hidden');
38532 if(Roo.isIE){ // fix IE 1px bogus margin
38533 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38535 this.wrap = this.el.wrap({
38536 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38539 this.frameId = Roo.id();
38540 this.createToolbar(this);
38547 var iframe = this.wrap.createChild({
38550 name: this.frameId,
38551 frameBorder : 'no',
38552 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38555 // console.log(iframe);
38556 //this.wrap.dom.appendChild(iframe);
38558 this.iframe = iframe.dom;
38560 this.assignDocWin();
38562 this.doc.designMode = 'on';
38565 this.doc.write(this.getDocMarkup());
38569 var task = { // must defer to wait for browser to be ready
38571 //console.log("run task?" + this.doc.readyState);
38572 this.assignDocWin();
38573 if(this.doc.body || this.doc.readyState == 'complete'){
38575 this.doc.designMode="on";
38579 Roo.TaskMgr.stop(task);
38580 this.initEditor.defer(10, this);
38587 Roo.TaskMgr.start(task);
38590 this.setSize(this.el.getSize());
38595 onResize : function(w, h){
38596 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38597 if(this.el && this.iframe){
38598 if(typeof w == 'number'){
38599 var aw = w - this.wrap.getFrameWidth('lr');
38600 this.el.setWidth(this.adjustWidth('textarea', aw));
38601 this.iframe.style.width = aw + 'px';
38603 if(typeof h == 'number'){
38605 for (var i =0; i < this.toolbars.length;i++) {
38606 // fixme - ask toolbars for heights?
38607 tbh += this.toolbars[i].tb.el.getHeight();
38613 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38614 this.el.setHeight(this.adjustWidth('textarea', ah));
38615 this.iframe.style.height = ah + 'px';
38617 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38624 * Toggles the editor between standard and source edit mode.
38625 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38627 toggleSourceEdit : function(sourceEditMode){
38629 this.sourceEditMode = sourceEditMode === true;
38631 if(this.sourceEditMode){
38634 this.iframe.className = 'x-hidden';
38635 this.el.removeClass('x-hidden');
38636 this.el.dom.removeAttribute('tabIndex');
38641 this.iframe.className = '';
38642 this.el.addClass('x-hidden');
38643 this.el.dom.setAttribute('tabIndex', -1);
38646 this.setSize(this.wrap.getSize());
38647 this.fireEvent('editmodechange', this, this.sourceEditMode);
38650 // private used internally
38651 createLink : function(){
38652 var url = prompt(this.createLinkText, this.defaultLinkValue);
38653 if(url && url != 'http:/'+'/'){
38654 this.relayCmd('createlink', url);
38658 // private (for BoxComponent)
38659 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38661 // private (for BoxComponent)
38662 getResizeEl : function(){
38666 // private (for BoxComponent)
38667 getPositionEl : function(){
38672 initEvents : function(){
38673 this.originalValue = this.getValue();
38677 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38680 markInvalid : Roo.emptyFn,
38682 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38685 clearInvalid : Roo.emptyFn,
38687 setValue : function(v){
38688 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38693 * Protected method that will not generally be called directly. If you need/want
38694 * custom HTML cleanup, this is the method you should override.
38695 * @param {String} html The HTML to be cleaned
38696 * return {String} The cleaned HTML
38698 cleanHtml : function(html){
38699 html = String(html);
38700 if(html.length > 5){
38701 if(Roo.isSafari){ // strip safari nonsense
38702 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38705 if(html == ' '){
38712 * Protected method that will not generally be called directly. Syncs the contents
38713 * of the editor iframe with the textarea.
38715 syncValue : function(){
38716 if(this.initialized){
38717 var bd = (this.doc.body || this.doc.documentElement);
38718 this.cleanUpPaste();
38719 var html = bd.innerHTML;
38721 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38722 var m = bs.match(/text-align:(.*?);/i);
38724 html = '<div style="'+m[0]+'">' + html + '</div>';
38727 html = this.cleanHtml(html);
38728 if(this.fireEvent('beforesync', this, html) !== false){
38729 this.el.dom.value = html;
38730 this.fireEvent('sync', this, html);
38736 * Protected method that will not generally be called directly. Pushes the value of the textarea
38737 * into the iframe editor.
38739 pushValue : function(){
38740 if(this.initialized){
38741 var v = this.el.dom.value;
38746 if(this.fireEvent('beforepush', this, v) !== false){
38747 var d = (this.doc.body || this.doc.documentElement);
38749 this.cleanUpPaste();
38750 this.el.dom.value = d.innerHTML;
38751 this.fireEvent('push', this, v);
38757 deferFocus : function(){
38758 this.focus.defer(10, this);
38762 focus : function(){
38763 if(this.win && !this.sourceEditMode){
38770 assignDocWin: function()
38772 var iframe = this.iframe;
38775 this.doc = iframe.contentWindow.document;
38776 this.win = iframe.contentWindow;
38778 if (!Roo.get(this.frameId)) {
38781 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38782 this.win = Roo.get(this.frameId).dom.contentWindow;
38787 initEditor : function(){
38788 //console.log("INIT EDITOR");
38789 this.assignDocWin();
38793 this.doc.designMode="on";
38795 this.doc.write(this.getDocMarkup());
38798 var dbody = (this.doc.body || this.doc.documentElement);
38799 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38800 // this copies styles from the containing element into thsi one..
38801 // not sure why we need all of this..
38802 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38803 ss['background-attachment'] = 'fixed'; // w3c
38804 dbody.bgProperties = 'fixed'; // ie
38805 Roo.DomHelper.applyStyles(dbody, ss);
38806 Roo.EventManager.on(this.doc, {
38807 'mousedown': this.onEditorEvent,
38808 'dblclick': this.onEditorEvent,
38809 'click': this.onEditorEvent,
38810 'keyup': this.onEditorEvent,
38815 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
38817 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38818 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38820 this.initialized = true;
38822 this.fireEvent('initialize', this);
38827 onDestroy : function(){
38833 for (var i =0; i < this.toolbars.length;i++) {
38834 // fixme - ask toolbars for heights?
38835 this.toolbars[i].onDestroy();
38838 this.wrap.dom.innerHTML = '';
38839 this.wrap.remove();
38844 onFirstFocus : function(){
38846 this.assignDocWin();
38849 this.activated = true;
38850 for (var i =0; i < this.toolbars.length;i++) {
38851 this.toolbars[i].onFirstFocus();
38854 if(Roo.isGecko){ // prevent silly gecko errors
38856 var s = this.win.getSelection();
38857 if(!s.focusNode || s.focusNode.nodeType != 3){
38858 var r = s.getRangeAt(0);
38859 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38864 this.execCmd('useCSS', true);
38865 this.execCmd('styleWithCSS', false);
38868 this.fireEvent('activate', this);
38872 adjustFont: function(btn){
38873 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38874 //if(Roo.isSafari){ // safari
38877 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38878 if(Roo.isSafari){ // safari
38879 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38880 v = (v < 10) ? 10 : v;
38881 v = (v > 48) ? 48 : v;
38882 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38887 v = Math.max(1, v+adjust);
38889 this.execCmd('FontSize', v );
38892 onEditorEvent : function(e){
38893 this.fireEvent('editorevent', this, e);
38894 // this.updateToolbar();
38898 insertTag : function(tg)
38900 // could be a bit smarter... -> wrap the current selected tRoo..
38902 this.execCmd("formatblock", tg);
38906 insertText : function(txt)
38910 range = this.createRange();
38911 range.deleteContents();
38912 //alert(Sender.getAttribute('label'));
38914 range.insertNode(this.doc.createTextNode(txt));
38918 relayBtnCmd : function(btn){
38919 this.relayCmd(btn.cmd);
38923 * Executes a Midas editor command on the editor document and performs necessary focus and
38924 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38925 * @param {String} cmd The Midas command
38926 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38928 relayCmd : function(cmd, value){
38930 this.execCmd(cmd, value);
38931 this.fireEvent('editorevent', this);
38932 //this.updateToolbar();
38937 * Executes a Midas editor command directly on the editor document.
38938 * For visual commands, you should use {@link #relayCmd} instead.
38939 * <b>This should only be called after the editor is initialized.</b>
38940 * @param {String} cmd The Midas command
38941 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38943 execCmd : function(cmd, value){
38944 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38950 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38952 * @param {String} text
38954 insertAtCursor : function(text){
38955 if(!this.activated){
38960 var r = this.doc.selection.createRange();
38967 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
38969 this.execCmd('InsertHTML', text);
38974 mozKeyPress : function(e){
38976 var c = e.getCharCode(), cmd;
38979 c = String.fromCharCode(c).toLowerCase();
38990 this.cleanUpPaste.defer(100, this);
38998 e.preventDefault();
39006 fixKeys : function(){ // load time branching for fastest keydown performance
39008 return function(e){
39009 var k = e.getKey(), r;
39012 r = this.doc.selection.createRange();
39015 r.pasteHTML('    ');
39022 r = this.doc.selection.createRange();
39024 var target = r.parentElement();
39025 if(!target || target.tagName.toLowerCase() != 'li'){
39027 r.pasteHTML('<br />');
39033 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39034 this.cleanUpPaste.defer(100, this);
39040 }else if(Roo.isOpera){
39041 return function(e){
39042 var k = e.getKey();
39046 this.execCmd('InsertHTML','    ');
39049 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39050 this.cleanUpPaste.defer(100, this);
39055 }else if(Roo.isSafari){
39056 return function(e){
39057 var k = e.getKey();
39061 this.execCmd('InsertText','\t');
39065 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39066 this.cleanUpPaste.defer(100, this);
39074 getAllAncestors: function()
39076 var p = this.getSelectedNode();
39079 a.push(p); // push blank onto stack..
39080 p = this.getParentElement();
39084 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
39088 a.push(this.doc.body);
39092 lastSelNode : false,
39095 getSelection : function()
39097 this.assignDocWin();
39098 return Roo.isIE ? this.doc.selection : this.win.getSelection();
39101 getSelectedNode: function()
39103 // this may only work on Gecko!!!
39105 // should we cache this!!!!
39110 var range = this.createRange(this.getSelection());
39113 var parent = range.parentElement();
39115 var testRange = range.duplicate();
39116 testRange.moveToElementText(parent);
39117 if (testRange.inRange(range)) {
39120 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
39123 parent = parent.parentElement;
39129 var ar = range.endContainer.childNodes;
39131 ar = range.commonAncestorContainer.childNodes;
39132 //alert(ar.length);
39135 var other_nodes = [];
39136 var has_other_nodes = false;
39137 for (var i=0;i<ar.length;i++) {
39138 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
39141 // fullly contained node.
39143 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
39148 // probably selected..
39149 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
39150 other_nodes.push(ar[i]);
39153 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39158 has_other_nodes = true;
39160 if (!nodes.length && other_nodes.length) {
39161 nodes= other_nodes;
39163 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39169 createRange: function(sel)
39171 // this has strange effects when using with
39172 // top toolbar - not sure if it's a great idea.
39173 //this.editor.contentWindow.focus();
39174 if (typeof sel != "undefined") {
39176 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39178 return this.doc.createRange();
39181 return this.doc.createRange();
39184 getParentElement: function()
39187 this.assignDocWin();
39188 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39190 var range = this.createRange(sel);
39193 var p = range.commonAncestorContainer;
39194 while (p.nodeType == 3) { // text node
39206 // BC Hacks - cause I cant work out what i was trying to do..
39207 rangeIntersectsNode : function(range, node)
39209 var nodeRange = node.ownerDocument.createRange();
39211 nodeRange.selectNode(node);
39214 nodeRange.selectNodeContents(node);
39217 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
39218 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
39220 rangeCompareNode : function(range, node) {
39221 var nodeRange = node.ownerDocument.createRange();
39223 nodeRange.selectNode(node);
39225 nodeRange.selectNodeContents(node);
39227 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
39228 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
39230 if (nodeIsBefore && !nodeIsAfter)
39232 if (!nodeIsBefore && nodeIsAfter)
39234 if (nodeIsBefore && nodeIsAfter)
39240 // private? - in a new class?
39241 cleanUpPaste : function()
39243 // cleans up the whole document..
39244 // console.log('cleanuppaste');
39245 this.cleanUpChildren(this.doc.body);
39249 cleanUpChildren : function (n)
39251 if (!n.childNodes.length) {
39254 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39255 this.cleanUpChild(n.childNodes[i]);
39262 cleanUpChild : function (node)
39264 //console.log(node);
39265 if (node.nodeName == "#text") {
39266 // clean up silly Windows -- stuff?
39269 if (node.nodeName == "#comment") {
39270 node.parentNode.removeChild(node);
39271 // clean up silly Windows -- stuff?
39275 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39277 node.parentNode.removeChild(node);
39281 if (!node.attributes || !node.attributes.length) {
39282 this.cleanUpChildren(node);
39286 function cleanAttr(n,v)
39289 if (v.match(/^\./) || v.match(/^\//)) {
39292 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39295 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39296 node.removeAttribute(n);
39300 function cleanStyle(n,v)
39302 if (v.match(/expression/)) { //XSS?? should we even bother..
39303 node.removeAttribute(n);
39308 var parts = v.split(/;/);
39309 Roo.each(parts, function(p) {
39310 p = p.replace(/\s+/g,'');
39314 var l = p.split(':').shift().replace(/\s+/g,'');
39316 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39317 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39318 node.removeAttribute(n);
39327 for (var i = node.attributes.length-1; i > -1 ; i--) {
39328 var a = node.attributes[i];
39330 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39331 node.removeAttribute(a.name);
39334 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39335 cleanAttr(a.name,a.value); // fixme..
39338 if (a.name == 'style') {
39339 cleanStyle(a.name,a.value);
39341 /// clean up MS crap..
39342 if (a.name == 'class') {
39343 if (a.value.match(/^Mso/)) {
39344 node.className = '';
39354 this.cleanUpChildren(node);
39360 // hide stuff that is not compatible
39374 * @event specialkey
39378 * @cfg {String} fieldClass @hide
39381 * @cfg {String} focusClass @hide
39384 * @cfg {String} autoCreate @hide
39387 * @cfg {String} inputType @hide
39390 * @cfg {String} invalidClass @hide
39393 * @cfg {String} invalidText @hide
39396 * @cfg {String} msgFx @hide
39399 * @cfg {String} validateOnBlur @hide
39403 Roo.form.HtmlEditor.white = [
39404 'area', 'br', 'img', 'input', 'hr', 'wbr',
39406 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39407 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39408 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39409 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39410 'table', 'ul', 'xmp',
39412 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39415 'dir', 'menu', 'ol', 'ul', 'dl',
39421 Roo.form.HtmlEditor.black = [
39422 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39424 'base', 'basefont', 'bgsound', 'blink', 'body',
39425 'frame', 'frameset', 'head', 'html', 'ilayer',
39426 'iframe', 'layer', 'link', 'meta', 'object',
39427 'script', 'style' ,'title', 'xml' // clean later..
39429 Roo.form.HtmlEditor.clean = [
39430 'script', 'style', 'title', 'xml'
39435 Roo.form.HtmlEditor.ablack = [
39439 Roo.form.HtmlEditor.aclean = [
39440 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39444 Roo.form.HtmlEditor.pwhite= [
39445 'http', 'https', 'mailto'
39448 Roo.form.HtmlEditor.cwhite= [
39453 // <script type="text/javascript">
39456 * Ext JS Library 1.1.1
39457 * Copyright(c) 2006-2007, Ext JS, LLC.
39463 * @class Roo.form.HtmlEditorToolbar1
39468 new Roo.form.HtmlEditor({
39471 new Roo.form.HtmlEditorToolbar1({
39472 disable : { fonts: 1 , format: 1, ..., ... , ...],
39478 * @cfg {Object} disable List of elements to disable..
39479 * @cfg {Array} btns List of additional buttons.
39483 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39486 Roo.form.HtmlEditor.ToolbarStandard = function(config)
39489 Roo.apply(this, config);
39490 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39491 // dont call parent... till later.
39494 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
39502 * @cfg {Object} disable List of toolbar elements to disable
39507 * @cfg {Array} fontFamilies An array of available font families
39525 // "á" , ?? a acute?
39530 "°" // , // degrees
39532 // "é" , // e ecute
39533 // "ú" , // u ecute?
39536 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
39537 "input:submit", "input:button", "select", "textarea", "label" ],
39540 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
39542 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39545 * @cfg {String} defaultFont default font to use.
39547 defaultFont: 'tahoma',
39549 fontSelect : false,
39552 formatCombo : false,
39554 init : function(editor)
39556 this.editor = editor;
39559 var fid = editor.frameId;
39561 function btn(id, toggle, handler){
39562 var xid = fid + '-'+ id ;
39566 cls : 'x-btn-icon x-edit-'+id,
39567 enableToggle:toggle !== false,
39568 scope: editor, // was editor...
39569 handler:handler||editor.relayBtnCmd,
39570 clickEvent:'mousedown',
39571 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39578 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
39580 // stop form submits
39581 tb.el.on('click', function(e){
39582 e.preventDefault(); // what does this do?
39585 if(!this.disable.font && !Roo.isSafari){
39586 /* why no safari for fonts
39587 editor.fontSelect = tb.el.createChild({
39590 cls:'x-font-select',
39591 html: editor.createFontOptions()
39593 editor.fontSelect.on('change', function(){
39594 var font = editor.fontSelect.dom.value;
39595 editor.relayCmd('fontname', font);
39596 editor.deferFocus();
39599 editor.fontSelect.dom,
39604 if(!this.disable.formats){
39605 this.formatCombo = new Roo.form.ComboBox({
39606 store: new Roo.data.SimpleStore({
39609 data : this.formats // from states.js
39612 //autoCreate : {tag: "div", size: "20"},
39613 displayField:'tag',
39617 triggerAction: 'all',
39618 emptyText:'Add tag',
39619 selectOnFocus:true,
39622 'select': function(c, r, i) {
39623 editor.insertTag(r.get('tag'));
39629 tb.addField(this.formatCombo);
39633 if(!this.disable.format){
39640 if(!this.disable.fontSize){
39645 btn('increasefontsize', false, editor.adjustFont),
39646 btn('decreasefontsize', false, editor.adjustFont)
39651 if(this.disable.colors){
39654 id:editor.frameId +'-forecolor',
39655 cls:'x-btn-icon x-edit-forecolor',
39656 clickEvent:'mousedown',
39657 tooltip: this.buttonTips['forecolor'] || undefined,
39659 menu : new Roo.menu.ColorMenu({
39660 allowReselect: true,
39661 focus: Roo.emptyFn,
39664 selectHandler: function(cp, color){
39665 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
39666 editor.deferFocus();
39669 clickEvent:'mousedown'
39672 id:editor.frameId +'backcolor',
39673 cls:'x-btn-icon x-edit-backcolor',
39674 clickEvent:'mousedown',
39675 tooltip: this.buttonTips['backcolor'] || undefined,
39677 menu : new Roo.menu.ColorMenu({
39678 focus: Roo.emptyFn,
39681 allowReselect: true,
39682 selectHandler: function(cp, color){
39684 editor.execCmd('useCSS', false);
39685 editor.execCmd('hilitecolor', color);
39686 editor.execCmd('useCSS', true);
39687 editor.deferFocus();
39689 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
39690 Roo.isSafari || Roo.isIE ? '#'+color : color);
39691 editor.deferFocus();
39695 clickEvent:'mousedown'
39700 // now add all the items...
39703 if(!this.disable.alignments){
39706 btn('justifyleft'),
39707 btn('justifycenter'),
39708 btn('justifyright')
39712 //if(!Roo.isSafari){
39713 if(!this.disable.links){
39716 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
39720 if(!this.disable.lists){
39723 btn('insertorderedlist'),
39724 btn('insertunorderedlist')
39727 if(!this.disable.sourceEdit){
39730 btn('sourceedit', true, function(btn){
39731 this.toggleSourceEdit(btn.pressed);
39738 // special menu.. - needs to be tidied up..
39739 if (!this.disable.special) {
39742 cls: 'x-edit-none',
39747 for (var i =0; i < this.specialChars.length; i++) {
39748 smenu.menu.items.push({
39750 html: this.specialChars[i],
39751 handler: function(a,b) {
39752 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
39765 for(var i =0; i< this.btns.length;i++) {
39766 var b = this.btns[i];
39767 b.cls = 'x-edit-none';
39776 // disable everything...
39778 this.tb.items.each(function(item){
39779 if(item.id != editor.frameId+ '-sourceedit'){
39783 this.rendered = true;
39785 // the all the btns;
39786 editor.on('editorevent', this.updateToolbar, this);
39787 // other toolbars need to implement this..
39788 //editor.on('editmodechange', this.updateToolbar, this);
39794 * Protected method that will not generally be called directly. It triggers
39795 * a toolbar update by reading the markup state of the current selection in the editor.
39797 updateToolbar: function(){
39799 if(!this.editor.activated){
39800 this.editor.onFirstFocus();
39804 var btns = this.tb.items.map,
39805 doc = this.editor.doc,
39806 frameId = this.editor.frameId;
39808 if(!this.disable.font && !Roo.isSafari){
39810 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39811 if(name != this.fontSelect.dom.value){
39812 this.fontSelect.dom.value = name;
39816 if(!this.disable.format){
39817 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39818 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39819 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39821 if(!this.disable.alignments){
39822 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39823 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39824 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39826 if(!Roo.isSafari && !this.disable.lists){
39827 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39828 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39831 var ans = this.editor.getAllAncestors();
39832 if (this.formatCombo) {
39835 var store = this.formatCombo.store;
39836 this.formatCombo.setValue("");
39837 for (var i =0; i < ans.length;i++) {
39838 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
39840 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39848 // hides menus... - so this cant be on a menu...
39849 Roo.menu.MenuMgr.hideAll();
39851 //this.editorsyncValue();
39855 createFontOptions : function(){
39856 var buf = [], fs = this.fontFamilies, ff, lc;
39857 for(var i = 0, len = fs.length; i< len; i++){
39859 lc = ff.toLowerCase();
39861 '<option value="',lc,'" style="font-family:',ff,';"',
39862 (this.defaultFont == lc ? ' selected="true">' : '>'),
39867 return buf.join('');
39870 toggleSourceEdit : function(sourceEditMode){
39871 if(sourceEditMode === undefined){
39872 sourceEditMode = !this.sourceEditMode;
39874 this.sourceEditMode = sourceEditMode === true;
39875 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39876 // just toggle the button?
39877 if(btn.pressed !== this.editor.sourceEditMode){
39878 btn.toggle(this.editor.sourceEditMode);
39882 if(this.sourceEditMode){
39883 this.tb.items.each(function(item){
39884 if(item.cmd != 'sourceedit'){
39890 if(this.initialized){
39891 this.tb.items.each(function(item){
39897 // tell the editor that it's been pressed..
39898 this.editor.toggleSourceEdit(sourceEditMode);
39902 * Object collection of toolbar tooltips for the buttons in the editor. The key
39903 * is the command id associated with that button and the value is a valid QuickTips object.
39908 title: 'Bold (Ctrl+B)',
39909 text: 'Make the selected text bold.',
39910 cls: 'x-html-editor-tip'
39913 title: 'Italic (Ctrl+I)',
39914 text: 'Make the selected text italic.',
39915 cls: 'x-html-editor-tip'
39923 title: 'Bold (Ctrl+B)',
39924 text: 'Make the selected text bold.',
39925 cls: 'x-html-editor-tip'
39928 title: 'Italic (Ctrl+I)',
39929 text: 'Make the selected text italic.',
39930 cls: 'x-html-editor-tip'
39933 title: 'Underline (Ctrl+U)',
39934 text: 'Underline the selected text.',
39935 cls: 'x-html-editor-tip'
39937 increasefontsize : {
39938 title: 'Grow Text',
39939 text: 'Increase the font size.',
39940 cls: 'x-html-editor-tip'
39942 decreasefontsize : {
39943 title: 'Shrink Text',
39944 text: 'Decrease the font size.',
39945 cls: 'x-html-editor-tip'
39948 title: 'Text Highlight Color',
39949 text: 'Change the background color of the selected text.',
39950 cls: 'x-html-editor-tip'
39953 title: 'Font Color',
39954 text: 'Change the color of the selected text.',
39955 cls: 'x-html-editor-tip'
39958 title: 'Align Text Left',
39959 text: 'Align text to the left.',
39960 cls: 'x-html-editor-tip'
39963 title: 'Center Text',
39964 text: 'Center text in the editor.',
39965 cls: 'x-html-editor-tip'
39968 title: 'Align Text Right',
39969 text: 'Align text to the right.',
39970 cls: 'x-html-editor-tip'
39972 insertunorderedlist : {
39973 title: 'Bullet List',
39974 text: 'Start a bulleted list.',
39975 cls: 'x-html-editor-tip'
39977 insertorderedlist : {
39978 title: 'Numbered List',
39979 text: 'Start a numbered list.',
39980 cls: 'x-html-editor-tip'
39983 title: 'Hyperlink',
39984 text: 'Make the selected text a hyperlink.',
39985 cls: 'x-html-editor-tip'
39988 title: 'Source Edit',
39989 text: 'Switch to source editing mode.',
39990 cls: 'x-html-editor-tip'
39994 onDestroy : function(){
39997 this.tb.items.each(function(item){
39999 item.menu.removeAll();
40001 item.menu.el.destroy();
40009 onFirstFocus: function() {
40010 this.tb.items.each(function(item){
40019 // <script type="text/javascript">
40022 * Ext JS Library 1.1.1
40023 * Copyright(c) 2006-2007, Ext JS, LLC.
40030 * @class Roo.form.HtmlEditor.ToolbarContext
40035 new Roo.form.HtmlEditor({
40038 new Roo.form.HtmlEditor.ToolbarStandard(),
40039 new Roo.form.HtmlEditor.ToolbarContext()
40044 * @config : {Object} disable List of elements to disable.. (not done yet.)
40049 Roo.form.HtmlEditor.ToolbarContext = function(config)
40052 Roo.apply(this, config);
40053 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
40054 // dont call parent... till later.
40056 Roo.form.HtmlEditor.ToolbarContext.types = {
40068 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
40130 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
40135 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40199 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40207 * @cfg {Object} disable List of toolbar elements to disable
40216 init : function(editor)
40218 this.editor = editor;
40221 var fid = editor.frameId;
40223 function btn(id, toggle, handler){
40224 var xid = fid + '-'+ id ;
40228 cls : 'x-btn-icon x-edit-'+id,
40229 enableToggle:toggle !== false,
40230 scope: editor, // was editor...
40231 handler:handler||editor.relayBtnCmd,
40232 clickEvent:'mousedown',
40233 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40237 // create a new element.
40238 var wdiv = editor.wrap.createChild({
40240 }, editor.wrap.dom.firstChild.nextSibling, true);
40242 // can we do this more than once??
40244 // stop form submits
40247 // disable everything...
40248 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40249 this.toolbars = {};
40251 for (var i in ty) {
40253 this.toolbars[i] = this.buildToolbar(ty[i],i);
40255 this.tb = this.toolbars.BODY;
40259 this.rendered = true;
40261 // the all the btns;
40262 editor.on('editorevent', this.updateToolbar, this);
40263 // other toolbars need to implement this..
40264 //editor.on('editmodechange', this.updateToolbar, this);
40270 * Protected method that will not generally be called directly. It triggers
40271 * a toolbar update by reading the markup state of the current selection in the editor.
40273 updateToolbar: function(){
40275 if(!this.editor.activated){
40276 this.editor.onFirstFocus();
40281 var ans = this.editor.getAllAncestors();
40284 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40285 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40286 sel = sel ? sel : this.editor.doc.body;
40287 sel = sel.tagName.length ? sel : this.editor.doc.body;
40288 var tn = sel.tagName.toUpperCase();
40289 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40290 tn = sel.tagName.toUpperCase();
40291 if (this.tb.name == tn) {
40292 return; // no change
40295 ///console.log("show: " + tn);
40296 this.tb = this.toolbars[tn];
40298 this.tb.fields.each(function(e) {
40299 e.setValue(sel.getAttribute(e.name));
40301 this.tb.selectedNode = sel;
40304 Roo.menu.MenuMgr.hideAll();
40306 //this.editorsyncValue();
40311 onDestroy : function(){
40314 this.tb.items.each(function(item){
40316 item.menu.removeAll();
40318 item.menu.el.destroy();
40326 onFirstFocus: function() {
40327 // need to do this for all the toolbars..
40328 this.tb.items.each(function(item){
40332 buildToolbar: function(tlist, nm)
40334 var editor = this.editor;
40335 // create a new element.
40336 var wdiv = editor.wrap.createChild({
40338 }, editor.wrap.dom.firstChild.nextSibling, true);
40341 var tb = new Roo.Toolbar(wdiv);
40342 tb.add(nm+ ": ");
40343 for (var i in tlist) {
40344 var item = tlist[i];
40345 tb.add(item.title + ": ");
40350 tb.addField( new Roo.form.ComboBox({
40351 store: new Roo.data.SimpleStore({
40354 data : item.opts // from states.js
40357 displayField:'val',
40361 triggerAction: 'all',
40362 emptyText:'Select',
40363 selectOnFocus:true,
40364 width: item.width ? item.width : 130,
40366 'select': function(c, r, i) {
40367 tb.selectedNode.setAttribute(c.name, r.get('val'));
40378 tb.addField( new Roo.form.TextField({
40381 //allowBlank:false,
40386 tb.addField( new Roo.form.TextField({
40392 'change' : function(f, nv, ov) {
40393 tb.selectedNode.setAttribute(f.name, nv);
40399 tb.el.on('click', function(e){
40400 e.preventDefault(); // what does this do?
40402 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40405 // dont need to disable them... as they will get hidden
40422 * Ext JS Library 1.1.1
40423 * Copyright(c) 2006-2007, Ext JS, LLC.
40425 * Originally Released Under LGPL - original licence link has changed is not relivant.
40428 * <script type="text/javascript">
40432 * @class Roo.form.BasicForm
40433 * @extends Roo.util.Observable
40434 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
40436 * @param {String/HTMLElement/Roo.Element} el The form element or its id
40437 * @param {Object} config Configuration options
40439 Roo.form.BasicForm = function(el, config){
40440 this.allItems = [];
40441 this.childForms = [];
40442 Roo.apply(this, config);
40444 * The Roo.form.Field items in this form.
40445 * @type MixedCollection
40449 this.items = new Roo.util.MixedCollection(false, function(o){
40450 return o.id || (o.id = Roo.id());
40454 * @event beforeaction
40455 * Fires before any action is performed. Return false to cancel the action.
40456 * @param {Form} this
40457 * @param {Action} action The action to be performed
40459 beforeaction: true,
40461 * @event actionfailed
40462 * Fires when an action fails.
40463 * @param {Form} this
40464 * @param {Action} action The action that failed
40466 actionfailed : true,
40468 * @event actioncomplete
40469 * Fires when an action is completed.
40470 * @param {Form} this
40471 * @param {Action} action The action that completed
40473 actioncomplete : true
40478 Roo.form.BasicForm.superclass.constructor.call(this);
40481 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
40483 * @cfg {String} method
40484 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
40487 * @cfg {DataReader} reader
40488 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
40489 * This is optional as there is built-in support for processing JSON.
40492 * @cfg {DataReader} errorReader
40493 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
40494 * This is completely optional as there is built-in support for processing JSON.
40497 * @cfg {String} url
40498 * The URL to use for form actions if one isn't supplied in the action options.
40501 * @cfg {Boolean} fileUpload
40502 * Set to true if this form is a file upload.
40506 * @cfg {Object} baseParams
40507 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
40512 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
40517 activeAction : null,
40520 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
40521 * or setValues() data instead of when the form was first created.
40523 trackResetOnLoad : false,
40527 * childForms - used for multi-tab forms
40530 childForms : false,
40533 * allItems - full list of fields.
40539 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
40540 * element by passing it or its id or mask the form itself by passing in true.
40543 waitMsgTarget : false,
40546 initEl : function(el){
40547 this.el = Roo.get(el);
40548 this.id = this.el.id || Roo.id();
40549 this.el.on('submit', this.onSubmit, this);
40550 this.el.addClass('x-form');
40554 onSubmit : function(e){
40559 * Returns true if client-side validation on the form is successful.
40562 isValid : function(){
40564 this.items.each(function(f){
40573 * Returns true if any fields in this form have changed since their original load.
40576 isDirty : function(){
40578 this.items.each(function(f){
40588 * Performs a predefined action (submit or load) or custom actions you define on this form.
40589 * @param {String} actionName The name of the action type
40590 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
40591 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
40592 * accept other config options):
40594 Property Type Description
40595 ---------------- --------------- ----------------------------------------------------------------------------------
40596 url String The url for the action (defaults to the form's url)
40597 method String The form method to use (defaults to the form's method, or POST if not defined)
40598 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
40599 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
40600 validate the form on the client (defaults to false)
40602 * @return {BasicForm} this
40604 doAction : function(action, options){
40605 if(typeof action == 'string'){
40606 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
40608 if(this.fireEvent('beforeaction', this, action) !== false){
40609 this.beforeAction(action);
40610 action.run.defer(100, action);
40616 * Shortcut to do a submit action.
40617 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40618 * @return {BasicForm} this
40620 submit : function(options){
40621 this.doAction('submit', options);
40626 * Shortcut to do a load action.
40627 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40628 * @return {BasicForm} this
40630 load : function(options){
40631 this.doAction('load', options);
40636 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
40637 * @param {Record} record The record to edit
40638 * @return {BasicForm} this
40640 updateRecord : function(record){
40641 record.beginEdit();
40642 var fs = record.fields;
40643 fs.each(function(f){
40644 var field = this.findField(f.name);
40646 record.set(f.name, field.getValue());
40654 * Loads an Roo.data.Record into this form.
40655 * @param {Record} record The record to load
40656 * @return {BasicForm} this
40658 loadRecord : function(record){
40659 this.setValues(record.data);
40664 beforeAction : function(action){
40665 var o = action.options;
40668 if(this.waitMsgTarget === true){
40669 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
40670 }else if(this.waitMsgTarget){
40671 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
40672 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
40674 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
40680 afterAction : function(action, success){
40681 this.activeAction = null;
40682 var o = action.options;
40684 if(this.waitMsgTarget === true){
40686 }else if(this.waitMsgTarget){
40687 this.waitMsgTarget.unmask();
40689 Roo.MessageBox.updateProgress(1);
40690 Roo.MessageBox.hide();
40697 Roo.callback(o.success, o.scope, [this, action]);
40698 this.fireEvent('actioncomplete', this, action);
40701 Roo.callback(o.failure, o.scope, [this, action]);
40702 // show an error message if no failed handler is set..
40703 if (!this.hasListener('actionfailed')) {
40704 Roo.MessageBox.alert("Error", "Saving Failed, please check your entries");
40707 this.fireEvent('actionfailed', this, action);
40713 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
40714 * @param {String} id The value to search for
40717 findField : function(id){
40718 var field = this.items.get(id);
40720 this.items.each(function(f){
40721 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
40727 return field || null;
40731 * Add a secondary form to this one,
40732 * Used to provide tabbed forms. One form is primary, with hidden values
40733 * which mirror the elements from the other forms.
40735 * @param {Roo.form.Form} form to add.
40738 addForm : function(form)
40741 if (this.childForms.indexOf(form) > -1) {
40745 this.childForms.push(form);
40747 Roo.each(form.allItems, function (fe) {
40749 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
40750 if (this.findField(n)) { // already added..
40753 var add = new Roo.form.Hidden({
40756 add.render(this.el);
40763 * Mark fields in this form invalid in bulk.
40764 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
40765 * @return {BasicForm} this
40767 markInvalid : function(errors){
40768 if(errors instanceof Array){
40769 for(var i = 0, len = errors.length; i < len; i++){
40770 var fieldError = errors[i];
40771 var f = this.findField(fieldError.id);
40773 f.markInvalid(fieldError.msg);
40779 if(typeof errors[id] != 'function' && (field = this.findField(id))){
40780 field.markInvalid(errors[id]);
40784 Roo.each(this.childForms || [], function (f) {
40785 f.markInvalid(errors);
40792 * Set values for fields in this form in bulk.
40793 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
40794 * @return {BasicForm} this
40796 setValues : function(values){
40797 if(values instanceof Array){ // array of objects
40798 for(var i = 0, len = values.length; i < len; i++){
40800 var f = this.findField(v.id);
40802 f.setValue(v.value);
40803 if(this.trackResetOnLoad){
40804 f.originalValue = f.getValue();
40808 }else{ // object hash
40811 if(typeof values[id] != 'function' && (field = this.findField(id))){
40813 if (field.setFromData &&
40814 field.valueField &&
40815 field.displayField &&
40816 // combos' with local stores can
40817 // be queried via setValue()
40818 // to set their value..
40819 (field.store && !field.store.isLocal)
40823 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40824 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40825 field.setFromData(sd);
40828 field.setValue(values[id]);
40832 if(this.trackResetOnLoad){
40833 field.originalValue = field.getValue();
40839 Roo.each(this.childForms || [], function (f) {
40840 f.setValues(values);
40847 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40848 * they are returned as an array.
40849 * @param {Boolean} asString
40852 getValues : function(asString){
40853 if (this.childForms) {
40854 // copy values from the child forms
40855 Roo.each(this.childForms, function (f) {
40856 this.setValues(f.getValues());
40862 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40863 if(asString === true){
40866 return Roo.urlDecode(fs);
40870 * Returns the fields in this form as an object with key/value pairs.
40871 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
40874 getFieldValues : function()
40876 if (this.childForms) {
40877 // copy values from the child forms
40878 Roo.each(this.childForms, function (f) {
40879 this.setValues(f.getValues());
40884 this.items.each(function(f){
40885 if (!f.getName()) {
40888 var v = f.getValue();
40889 if ((typeof(v) == 'object') && f.getRawValue) {
40890 v = f.getRawValue() ; // dates..
40892 ret[f.getName()] = v;
40899 * Clears all invalid messages in this form.
40900 * @return {BasicForm} this
40902 clearInvalid : function(){
40903 this.items.each(function(f){
40907 Roo.each(this.childForms || [], function (f) {
40916 * Resets this form.
40917 * @return {BasicForm} this
40919 reset : function(){
40920 this.items.each(function(f){
40924 Roo.each(this.childForms || [], function (f) {
40933 * Add Roo.form components to this form.
40934 * @param {Field} field1
40935 * @param {Field} field2 (optional)
40936 * @param {Field} etc (optional)
40937 * @return {BasicForm} this
40940 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40946 * Removes a field from the items collection (does NOT remove its markup).
40947 * @param {Field} field
40948 * @return {BasicForm} this
40950 remove : function(field){
40951 this.items.remove(field);
40956 * Looks at the fields in this form, checks them for an id attribute,
40957 * and calls applyTo on the existing dom element with that id.
40958 * @return {BasicForm} this
40960 render : function(){
40961 this.items.each(function(f){
40962 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40970 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40971 * @param {Object} values
40972 * @return {BasicForm} this
40974 applyToFields : function(o){
40975 this.items.each(function(f){
40982 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40983 * @param {Object} values
40984 * @return {BasicForm} this
40986 applyIfToFields : function(o){
40987 this.items.each(function(f){
40995 Roo.BasicForm = Roo.form.BasicForm;/*
40997 * Ext JS Library 1.1.1
40998 * Copyright(c) 2006-2007, Ext JS, LLC.
41000 * Originally Released Under LGPL - original licence link has changed is not relivant.
41003 * <script type="text/javascript">
41007 * @class Roo.form.Form
41008 * @extends Roo.form.BasicForm
41009 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
41011 * @param {Object} config Configuration options
41013 Roo.form.Form = function(config){
41015 if (config.items) {
41016 xitems = config.items;
41017 delete config.items;
41021 Roo.form.Form.superclass.constructor.call(this, null, config);
41022 this.url = this.url || this.action;
41024 this.root = new Roo.form.Layout(Roo.applyIf({
41028 this.active = this.root;
41030 * Array of all the buttons that have been added to this form via {@link addButton}
41034 this.allItems = [];
41037 * @event clientvalidation
41038 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
41039 * @param {Form} this
41040 * @param {Boolean} valid true if the form has passed client-side validation
41042 clientvalidation: true,
41045 * Fires when the form is rendered
41046 * @param {Roo.form.Form} form
41051 if (this.progressUrl) {
41052 // push a hidden field onto the list of fields..
41056 name : 'UPLOAD_IDENTIFIER'
41061 Roo.each(xitems, this.addxtype, this);
41067 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
41069 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
41072 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
41075 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
41077 buttonAlign:'center',
41080 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
41085 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
41086 * This property cascades to child containers if not set.
41091 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
41092 * fires a looping event with that state. This is required to bind buttons to the valid
41093 * state using the config value formBind:true on the button.
41095 monitorValid : false,
41098 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
41103 * @cfg {String} progressUrl - Url to return progress data
41106 progressUrl : false,
41109 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
41110 * fields are added and the column is closed. If no fields are passed the column remains open
41111 * until end() is called.
41112 * @param {Object} config The config to pass to the column
41113 * @param {Field} field1 (optional)
41114 * @param {Field} field2 (optional)
41115 * @param {Field} etc (optional)
41116 * @return Column The column container object
41118 column : function(c){
41119 var col = new Roo.form.Column(c);
41121 if(arguments.length > 1){ // duplicate code required because of Opera
41122 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41129 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
41130 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
41131 * until end() is called.
41132 * @param {Object} config The config to pass to the fieldset
41133 * @param {Field} field1 (optional)
41134 * @param {Field} field2 (optional)
41135 * @param {Field} etc (optional)
41136 * @return FieldSet The fieldset container object
41138 fieldset : function(c){
41139 var fs = new Roo.form.FieldSet(c);
41141 if(arguments.length > 1){ // duplicate code required because of Opera
41142 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41149 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
41150 * fields are added and the container is closed. If no fields are passed the container remains open
41151 * until end() is called.
41152 * @param {Object} config The config to pass to the Layout
41153 * @param {Field} field1 (optional)
41154 * @param {Field} field2 (optional)
41155 * @param {Field} etc (optional)
41156 * @return Layout The container object
41158 container : function(c){
41159 var l = new Roo.form.Layout(c);
41161 if(arguments.length > 1){ // duplicate code required because of Opera
41162 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41169 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41170 * @param {Object} container A Roo.form.Layout or subclass of Layout
41171 * @return {Form} this
41173 start : function(c){
41174 // cascade label info
41175 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
41176 this.active.stack.push(c);
41177 c.ownerCt = this.active;
41183 * Closes the current open container
41184 * @return {Form} this
41187 if(this.active == this.root){
41190 this.active = this.active.ownerCt;
41195 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
41196 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
41197 * as the label of the field.
41198 * @param {Field} field1
41199 * @param {Field} field2 (optional)
41200 * @param {Field} etc. (optional)
41201 * @return {Form} this
41204 this.active.stack.push.apply(this.active.stack, arguments);
41205 this.allItems.push.apply(this.allItems,arguments);
41207 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
41208 if(a[i].isFormField){
41213 Roo.form.Form.superclass.add.apply(this, r);
41223 * Find any element that has been added to a form, using it's ID or name
41224 * This can include framesets, columns etc. along with regular fields..
41225 * @param {String} id - id or name to find.
41227 * @return {Element} e - or false if nothing found.
41229 findbyId : function(id)
41235 Roo.each(this.allItems, function(f){
41236 if (f.id == id || f.name == id ){
41247 * Render this form into the passed container. This should only be called once!
41248 * @param {String/HTMLElement/Element} container The element this component should be rendered into
41249 * @return {Form} this
41251 render : function(ct)
41257 var o = this.autoCreate || {
41259 method : this.method || 'POST',
41260 id : this.id || Roo.id()
41262 this.initEl(ct.createChild(o));
41264 this.root.render(this.el);
41268 this.items.each(function(f){
41269 f.render('x-form-el-'+f.id);
41272 if(this.buttons.length > 0){
41273 // tables are required to maintain order and for correct IE layout
41274 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
41275 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
41276 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
41278 var tr = tb.getElementsByTagName('tr')[0];
41279 for(var i = 0, len = this.buttons.length; i < len; i++) {
41280 var b = this.buttons[i];
41281 var td = document.createElement('td');
41282 td.className = 'x-form-btn-td';
41283 b.render(tr.appendChild(td));
41286 if(this.monitorValid){ // initialize after render
41287 this.startMonitoring();
41289 this.fireEvent('rendered', this);
41294 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
41295 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
41296 * object or a valid Roo.DomHelper element config
41297 * @param {Function} handler The function called when the button is clicked
41298 * @param {Object} scope (optional) The scope of the handler function
41299 * @return {Roo.Button}
41301 addButton : function(config, handler, scope){
41305 minWidth: this.minButtonWidth,
41308 if(typeof config == "string"){
41311 Roo.apply(bc, config);
41313 var btn = new Roo.Button(null, bc);
41314 this.buttons.push(btn);
41319 * Adds a series of form elements (using the xtype property as the factory method.
41320 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41321 * @param {Object} config
41324 addxtype : function()
41326 var ar = Array.prototype.slice.call(arguments, 0);
41328 for(var i = 0; i < ar.length; i++) {
41330 continue; // skip -- if this happends something invalid got sent, we
41331 // should ignore it, as basically that interface element will not show up
41332 // and that should be pretty obvious!!
41335 if (Roo.form[ar[i].xtype]) {
41337 var fe = Roo.factory(ar[i], Roo.form);
41343 fe.store.form = this;
41348 this.allItems.push(fe);
41349 if (fe.items && fe.addxtype) {
41350 fe.addxtype.apply(fe, fe.items);
41360 // console.log('adding ' + ar[i].xtype);
41362 if (ar[i].xtype == 'Button') {
41363 //console.log('adding button');
41364 //console.log(ar[i]);
41365 this.addButton(ar[i]);
41366 this.allItems.push(fe);
41370 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
41371 alert('end is not supported on xtype any more, use items');
41373 // //console.log('adding end');
41381 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
41382 * option "monitorValid"
41384 startMonitoring : function(){
41387 Roo.TaskMgr.start({
41388 run : this.bindHandler,
41389 interval : this.monitorPoll || 200,
41396 * Stops monitoring of the valid state of this form
41398 stopMonitoring : function(){
41399 this.bound = false;
41403 bindHandler : function(){
41405 return false; // stops binding
41408 this.items.each(function(f){
41409 if(!f.isValid(true)){
41414 for(var i = 0, len = this.buttons.length; i < len; i++){
41415 var btn = this.buttons[i];
41416 if(btn.formBind === true && btn.disabled === valid){
41417 btn.setDisabled(!valid);
41420 this.fireEvent('clientvalidation', this, valid);
41434 Roo.Form = Roo.form.Form;
41437 * Ext JS Library 1.1.1
41438 * Copyright(c) 2006-2007, Ext JS, LLC.
41440 * Originally Released Under LGPL - original licence link has changed is not relivant.
41443 * <script type="text/javascript">
41447 * @class Roo.form.Action
41448 * Internal Class used to handle form actions
41450 * @param {Roo.form.BasicForm} el The form element or its id
41451 * @param {Object} config Configuration options
41455 // define the action interface
41456 Roo.form.Action = function(form, options){
41458 this.options = options || {};
41461 * Client Validation Failed
41464 Roo.form.Action.CLIENT_INVALID = 'client';
41466 * Server Validation Failed
41469 Roo.form.Action.SERVER_INVALID = 'server';
41471 * Connect to Server Failed
41474 Roo.form.Action.CONNECT_FAILURE = 'connect';
41476 * Reading Data from Server Failed
41479 Roo.form.Action.LOAD_FAILURE = 'load';
41481 Roo.form.Action.prototype = {
41483 failureType : undefined,
41484 response : undefined,
41485 result : undefined,
41487 // interface method
41488 run : function(options){
41492 // interface method
41493 success : function(response){
41497 // interface method
41498 handleResponse : function(response){
41502 // default connection failure
41503 failure : function(response){
41505 this.response = response;
41506 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41507 this.form.afterAction(this, false);
41510 processResponse : function(response){
41511 this.response = response;
41512 if(!response.responseText){
41515 this.result = this.handleResponse(response);
41516 return this.result;
41519 // utility functions used internally
41520 getUrl : function(appendParams){
41521 var url = this.options.url || this.form.url || this.form.el.dom.action;
41523 var p = this.getParams();
41525 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
41531 getMethod : function(){
41532 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
41535 getParams : function(){
41536 var bp = this.form.baseParams;
41537 var p = this.options.params;
41539 if(typeof p == "object"){
41540 p = Roo.urlEncode(Roo.applyIf(p, bp));
41541 }else if(typeof p == 'string' && bp){
41542 p += '&' + Roo.urlEncode(bp);
41545 p = Roo.urlEncode(bp);
41550 createCallback : function(){
41552 success: this.success,
41553 failure: this.failure,
41555 timeout: (this.form.timeout*1000),
41556 upload: this.form.fileUpload ? this.success : undefined
41561 Roo.form.Action.Submit = function(form, options){
41562 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
41565 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
41568 haveProgress : false,
41569 uploadComplete : false,
41571 // uploadProgress indicator.
41572 uploadProgress : function()
41574 if (!this.form.progressUrl) {
41578 if (!this.haveProgress) {
41579 Roo.MessageBox.progress("Uploading", "Uploading");
41581 if (this.uploadComplete) {
41582 Roo.MessageBox.hide();
41586 this.haveProgress = true;
41588 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
41590 var c = new Roo.data.Connection();
41592 url : this.form.progressUrl,
41597 success : function(req){
41598 //console.log(data);
41602 rdata = Roo.decode(req.responseText)
41604 Roo.log("Invalid data from server..");
41608 if (!rdata || !rdata.success) {
41612 var data = rdata.data;
41614 if (this.uploadComplete) {
41615 Roo.MessageBox.hide();
41620 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
41621 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
41624 this.uploadProgress.defer(2000,this);
41627 failure: function(data) {
41628 Roo.log('progress url failed ');
41639 // run get Values on the form, so it syncs any secondary forms.
41640 this.form.getValues();
41642 var o = this.options;
41643 var method = this.getMethod();
41644 var isPost = method == 'POST';
41645 if(o.clientValidation === false || this.form.isValid()){
41647 if (this.form.progressUrl) {
41648 this.form.findField('UPLOAD_IDENTIFIER').setValue(
41649 (new Date() * 1) + '' + Math.random());
41654 Roo.Ajax.request(Roo.apply(this.createCallback(), {
41655 form:this.form.el.dom,
41656 url:this.getUrl(!isPost),
41658 params:isPost ? this.getParams() : null,
41659 isUpload: this.form.fileUpload
41662 this.uploadProgress();
41664 }else if (o.clientValidation !== false){ // client validation failed
41665 this.failureType = Roo.form.Action.CLIENT_INVALID;
41666 this.form.afterAction(this, false);
41670 success : function(response)
41672 this.uploadComplete= true;
41673 if (this.haveProgress) {
41674 Roo.MessageBox.hide();
41678 var result = this.processResponse(response);
41679 if(result === true || result.success){
41680 this.form.afterAction(this, true);
41684 this.form.markInvalid(result.errors);
41685 this.failureType = Roo.form.Action.SERVER_INVALID;
41687 this.form.afterAction(this, false);
41689 failure : function(response)
41691 this.uploadComplete= true;
41692 if (this.haveProgress) {
41693 Roo.MessageBox.hide();
41697 this.response = response;
41698 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41699 this.form.afterAction(this, false);
41702 handleResponse : function(response){
41703 if(this.form.errorReader){
41704 var rs = this.form.errorReader.read(response);
41707 for(var i = 0, len = rs.records.length; i < len; i++) {
41708 var r = rs.records[i];
41709 errors[i] = r.data;
41712 if(errors.length < 1){
41716 success : rs.success,
41722 ret = Roo.decode(response.responseText);
41726 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
41736 Roo.form.Action.Load = function(form, options){
41737 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
41738 this.reader = this.form.reader;
41741 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
41746 Roo.Ajax.request(Roo.apply(
41747 this.createCallback(), {
41748 method:this.getMethod(),
41749 url:this.getUrl(false),
41750 params:this.getParams()
41754 success : function(response){
41756 var result = this.processResponse(response);
41757 if(result === true || !result.success || !result.data){
41758 this.failureType = Roo.form.Action.LOAD_FAILURE;
41759 this.form.afterAction(this, false);
41762 this.form.clearInvalid();
41763 this.form.setValues(result.data);
41764 this.form.afterAction(this, true);
41767 handleResponse : function(response){
41768 if(this.form.reader){
41769 var rs = this.form.reader.read(response);
41770 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
41772 success : rs.success,
41776 return Roo.decode(response.responseText);
41780 Roo.form.Action.ACTION_TYPES = {
41781 'load' : Roo.form.Action.Load,
41782 'submit' : Roo.form.Action.Submit
41785 * Ext JS Library 1.1.1
41786 * Copyright(c) 2006-2007, Ext JS, LLC.
41788 * Originally Released Under LGPL - original licence link has changed is not relivant.
41791 * <script type="text/javascript">
41795 * @class Roo.form.Layout
41796 * @extends Roo.Component
41797 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
41799 * @param {Object} config Configuration options
41801 Roo.form.Layout = function(config){
41803 if (config.items) {
41804 xitems = config.items;
41805 delete config.items;
41807 Roo.form.Layout.superclass.constructor.call(this, config);
41809 Roo.each(xitems, this.addxtype, this);
41813 Roo.extend(Roo.form.Layout, Roo.Component, {
41815 * @cfg {String/Object} autoCreate
41816 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
41819 * @cfg {String/Object/Function} style
41820 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
41821 * a function which returns such a specification.
41824 * @cfg {String} labelAlign
41825 * Valid values are "left," "top" and "right" (defaults to "left")
41828 * @cfg {Number} labelWidth
41829 * Fixed width in pixels of all field labels (defaults to undefined)
41832 * @cfg {Boolean} clear
41833 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
41837 * @cfg {String} labelSeparator
41838 * The separator to use after field labels (defaults to ':')
41840 labelSeparator : ':',
41842 * @cfg {Boolean} hideLabels
41843 * True to suppress the display of field labels in this layout (defaults to false)
41845 hideLabels : false,
41848 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
41853 onRender : function(ct, position){
41854 if(this.el){ // from markup
41855 this.el = Roo.get(this.el);
41856 }else { // generate
41857 var cfg = this.getAutoCreate();
41858 this.el = ct.createChild(cfg, position);
41861 this.el.applyStyles(this.style);
41863 if(this.labelAlign){
41864 this.el.addClass('x-form-label-'+this.labelAlign);
41866 if(this.hideLabels){
41867 this.labelStyle = "display:none";
41868 this.elementStyle = "padding-left:0;";
41870 if(typeof this.labelWidth == 'number'){
41871 this.labelStyle = "width:"+this.labelWidth+"px;";
41872 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
41874 if(this.labelAlign == 'top'){
41875 this.labelStyle = "width:auto;";
41876 this.elementStyle = "padding-left:0;";
41879 var stack = this.stack;
41880 var slen = stack.length;
41882 if(!this.fieldTpl){
41883 var t = new Roo.Template(
41884 '<div class="x-form-item {5}">',
41885 '<label for="{0}" style="{2}">{1}{4}</label>',
41886 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41888 '</div><div class="x-form-clear-left"></div>'
41890 t.disableFormats = true;
41892 Roo.form.Layout.prototype.fieldTpl = t;
41894 for(var i = 0; i < slen; i++) {
41895 if(stack[i].isFormField){
41896 this.renderField(stack[i]);
41898 this.renderComponent(stack[i]);
41903 this.el.createChild({cls:'x-form-clear'});
41908 renderField : function(f){
41909 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
41912 f.labelStyle||this.labelStyle||'', //2
41913 this.elementStyle||'', //3
41914 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
41915 f.itemCls||this.itemCls||'' //5
41916 ], true).getPrevSibling());
41920 renderComponent : function(c){
41921 c.render(c.isLayout ? this.el : this.el.createChild());
41924 * Adds a object form elements (using the xtype property as the factory method.)
41925 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
41926 * @param {Object} config
41928 addxtype : function(o)
41930 // create the lement.
41931 o.form = this.form;
41932 var fe = Roo.factory(o, Roo.form);
41933 this.form.allItems.push(fe);
41934 this.stack.push(fe);
41936 if (fe.isFormField) {
41937 this.form.items.add(fe);
41945 * @class Roo.form.Column
41946 * @extends Roo.form.Layout
41947 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
41949 * @param {Object} config Configuration options
41951 Roo.form.Column = function(config){
41952 Roo.form.Column.superclass.constructor.call(this, config);
41955 Roo.extend(Roo.form.Column, Roo.form.Layout, {
41957 * @cfg {Number/String} width
41958 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41961 * @cfg {String/Object} autoCreate
41962 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41966 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41969 onRender : function(ct, position){
41970 Roo.form.Column.superclass.onRender.call(this, ct, position);
41972 this.el.setWidth(this.width);
41979 * @class Roo.form.Row
41980 * @extends Roo.form.Layout
41981 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41983 * @param {Object} config Configuration options
41987 Roo.form.Row = function(config){
41988 Roo.form.Row.superclass.constructor.call(this, config);
41991 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41993 * @cfg {Number/String} width
41994 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41997 * @cfg {Number/String} height
41998 * The fixed height of the column in pixels or CSS value (defaults to "auto")
42000 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
42004 onRender : function(ct, position){
42005 //console.log('row render');
42007 var t = new Roo.Template(
42008 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
42009 '<label for="{0}" style="{2}">{1}{4}</label>',
42010 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
42014 t.disableFormats = true;
42016 Roo.form.Layout.prototype.rowTpl = t;
42018 this.fieldTpl = this.rowTpl;
42020 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
42021 var labelWidth = 100;
42023 if ((this.labelAlign != 'top')) {
42024 if (typeof this.labelWidth == 'number') {
42025 labelWidth = this.labelWidth
42027 this.padWidth = 20 + labelWidth;
42031 Roo.form.Column.superclass.onRender.call(this, ct, position);
42033 this.el.setWidth(this.width);
42036 this.el.setHeight(this.height);
42041 renderField : function(f){
42042 f.fieldEl = this.fieldTpl.append(this.el, [
42043 f.id, f.fieldLabel,
42044 f.labelStyle||this.labelStyle||'',
42045 this.elementStyle||'',
42046 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
42047 f.itemCls||this.itemCls||'',
42048 f.width ? f.width + this.padWidth : 160 + this.padWidth
42055 * @class Roo.form.FieldSet
42056 * @extends Roo.form.Layout
42057 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
42059 * @param {Object} config Configuration options
42061 Roo.form.FieldSet = function(config){
42062 Roo.form.FieldSet.superclass.constructor.call(this, config);
42065 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
42067 * @cfg {String} legend
42068 * The text to display as the legend for the FieldSet (defaults to '')
42071 * @cfg {String/Object} autoCreate
42072 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
42076 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
42079 onRender : function(ct, position){
42080 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
42082 this.setLegend(this.legend);
42087 setLegend : function(text){
42089 this.el.child('legend').update(text);
42094 * Ext JS Library 1.1.1
42095 * Copyright(c) 2006-2007, Ext JS, LLC.
42097 * Originally Released Under LGPL - original licence link has changed is not relivant.
42100 * <script type="text/javascript">
42103 * @class Roo.form.VTypes
42104 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
42107 Roo.form.VTypes = function(){
42108 // closure these in so they are only created once.
42109 var alpha = /^[a-zA-Z_]+$/;
42110 var alphanum = /^[a-zA-Z0-9_]+$/;
42111 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
42112 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
42114 // All these messages and functions are configurable
42117 * The function used to validate email addresses
42118 * @param {String} value The email address
42120 'email' : function(v){
42121 return email.test(v);
42124 * The error text to display when the email validation function returns false
42127 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
42129 * The keystroke filter mask to be applied on email input
42132 'emailMask' : /[a-z0-9_\.\-@]/i,
42135 * The function used to validate URLs
42136 * @param {String} value The URL
42138 'url' : function(v){
42139 return url.test(v);
42142 * The error text to display when the url validation function returns false
42145 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
42148 * The function used to validate alpha values
42149 * @param {String} value The value
42151 'alpha' : function(v){
42152 return alpha.test(v);
42155 * The error text to display when the alpha validation function returns false
42158 'alphaText' : 'This field should only contain letters and _',
42160 * The keystroke filter mask to be applied on alpha input
42163 'alphaMask' : /[a-z_]/i,
42166 * The function used to validate alphanumeric values
42167 * @param {String} value The value
42169 'alphanum' : function(v){
42170 return alphanum.test(v);
42173 * The error text to display when the alphanumeric validation function returns false
42176 'alphanumText' : 'This field should only contain letters, numbers and _',
42178 * The keystroke filter mask to be applied on alphanumeric input
42181 'alphanumMask' : /[a-z0-9_]/i
42183 }();//<script type="text/javascript">
42186 * @class Roo.form.FCKeditor
42187 * @extends Roo.form.TextArea
42188 * Wrapper around the FCKEditor http://www.fckeditor.net
42190 * Creates a new FCKeditor
42191 * @param {Object} config Configuration options
42193 Roo.form.FCKeditor = function(config){
42194 Roo.form.FCKeditor.superclass.constructor.call(this, config);
42197 * @event editorinit
42198 * Fired when the editor is initialized - you can add extra handlers here..
42199 * @param {FCKeditor} this
42200 * @param {Object} the FCK object.
42207 Roo.form.FCKeditor.editors = { };
42208 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
42210 //defaultAutoCreate : {
42211 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
42215 * @cfg {Object} fck options - see fck manual for details.
42220 * @cfg {Object} fck toolbar set (Basic or Default)
42222 toolbarSet : 'Basic',
42224 * @cfg {Object} fck BasePath
42226 basePath : '/fckeditor/',
42234 onRender : function(ct, position)
42237 this.defaultAutoCreate = {
42239 style:"width:300px;height:60px;",
42240 autocomplete: "off"
42243 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
42246 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
42247 if(this.preventScrollbars){
42248 this.el.setStyle("overflow", "hidden");
42250 this.el.setHeight(this.growMin);
42253 //console.log('onrender' + this.getId() );
42254 Roo.form.FCKeditor.editors[this.getId()] = this;
42257 this.replaceTextarea() ;
42261 getEditor : function() {
42262 return this.fckEditor;
42265 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
42266 * @param {Mixed} value The value to set
42270 setValue : function(value)
42272 //console.log('setValue: ' + value);
42274 if(typeof(value) == 'undefined') { // not sure why this is happending...
42277 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42279 //if(!this.el || !this.getEditor()) {
42280 // this.value = value;
42281 //this.setValue.defer(100,this,[value]);
42285 if(!this.getEditor()) {
42289 this.getEditor().SetData(value);
42296 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
42297 * @return {Mixed} value The field value
42299 getValue : function()
42302 if (this.frame && this.frame.dom.style.display == 'none') {
42303 return Roo.form.FCKeditor.superclass.getValue.call(this);
42306 if(!this.el || !this.getEditor()) {
42308 // this.getValue.defer(100,this);
42313 var value=this.getEditor().GetData();
42314 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42315 return Roo.form.FCKeditor.superclass.getValue.call(this);
42321 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
42322 * @return {Mixed} value The field value
42324 getRawValue : function()
42326 if (this.frame && this.frame.dom.style.display == 'none') {
42327 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42330 if(!this.el || !this.getEditor()) {
42331 //this.getRawValue.defer(100,this);
42338 var value=this.getEditor().GetData();
42339 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
42340 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42344 setSize : function(w,h) {
42348 //if (this.frame && this.frame.dom.style.display == 'none') {
42349 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42352 //if(!this.el || !this.getEditor()) {
42353 // this.setSize.defer(100,this, [w,h]);
42359 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42361 this.frame.dom.setAttribute('width', w);
42362 this.frame.dom.setAttribute('height', h);
42363 this.frame.setSize(w,h);
42367 toggleSourceEdit : function(value) {
42371 this.el.dom.style.display = value ? '' : 'none';
42372 this.frame.dom.style.display = value ? 'none' : '';
42377 focus: function(tag)
42379 if (this.frame.dom.style.display == 'none') {
42380 return Roo.form.FCKeditor.superclass.focus.call(this);
42382 if(!this.el || !this.getEditor()) {
42383 this.focus.defer(100,this, [tag]);
42390 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
42391 this.getEditor().Focus();
42393 if (!this.getEditor().Selection.GetSelection()) {
42394 this.focus.defer(100,this, [tag]);
42399 var r = this.getEditor().EditorDocument.createRange();
42400 r.setStart(tgs[0],0);
42401 r.setEnd(tgs[0],0);
42402 this.getEditor().Selection.GetSelection().removeAllRanges();
42403 this.getEditor().Selection.GetSelection().addRange(r);
42404 this.getEditor().Focus();
42411 replaceTextarea : function()
42413 if ( document.getElementById( this.getId() + '___Frame' ) )
42415 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
42417 // We must check the elements firstly using the Id and then the name.
42418 var oTextarea = document.getElementById( this.getId() );
42420 var colElementsByName = document.getElementsByName( this.getId() ) ;
42422 oTextarea.style.display = 'none' ;
42424 if ( oTextarea.tabIndex ) {
42425 this.TabIndex = oTextarea.tabIndex ;
42428 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
42429 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
42430 this.frame = Roo.get(this.getId() + '___Frame')
42433 _getConfigHtml : function()
42437 for ( var o in this.fckconfig ) {
42438 sConfig += sConfig.length > 0 ? '&' : '';
42439 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
42442 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
42446 _getIFrameHtml : function()
42448 var sFile = 'fckeditor.html' ;
42449 /* no idea what this is about..
42452 if ( (/fcksource=true/i).test( window.top.location.search ) )
42453 sFile = 'fckeditor.original.html' ;
42458 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
42459 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
42462 var html = '<iframe id="' + this.getId() +
42463 '___Frame" src="' + sLink +
42464 '" width="' + this.width +
42465 '" height="' + this.height + '"' +
42466 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
42467 ' frameborder="0" scrolling="no"></iframe>' ;
42472 _insertHtmlBefore : function( html, element )
42474 if ( element.insertAdjacentHTML ) {
42476 element.insertAdjacentHTML( 'beforeBegin', html ) ;
42478 var oRange = document.createRange() ;
42479 oRange.setStartBefore( element ) ;
42480 var oFragment = oRange.createContextualFragment( html );
42481 element.parentNode.insertBefore( oFragment, element ) ;
42494 //Roo.reg('fckeditor', Roo.form.FCKeditor);
42496 function FCKeditor_OnComplete(editorInstance){
42497 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
42498 f.fckEditor = editorInstance;
42499 //console.log("loaded");
42500 f.fireEvent('editorinit', f, editorInstance);
42520 //<script type="text/javascript">
42522 * @class Roo.form.GridField
42523 * @extends Roo.form.Field
42524 * Embed a grid (or editable grid into a form)
42527 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
42529 * xgrid.store = Roo.data.Store
42530 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
42531 * xgrid.store.reader = Roo.data.JsonReader
42535 * Creates a new GridField
42536 * @param {Object} config Configuration options
42538 Roo.form.GridField = function(config){
42539 Roo.form.GridField.superclass.constructor.call(this, config);
42543 Roo.extend(Roo.form.GridField, Roo.form.Field, {
42545 * @cfg {Number} width - used to restrict width of grid..
42549 * @cfg {Number} height - used to restrict height of grid..
42553 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
42559 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42560 * {tag: "input", type: "checkbox", autocomplete: "off"})
42562 // defaultAutoCreate : { tag: 'div' },
42563 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42565 * @cfg {String} addTitle Text to include for adding a title.
42569 onResize : function(){
42570 Roo.form.Field.superclass.onResize.apply(this, arguments);
42573 initEvents : function(){
42574 // Roo.form.Checkbox.superclass.initEvents.call(this);
42575 // has no events...
42580 getResizeEl : function(){
42584 getPositionEl : function(){
42589 onRender : function(ct, position){
42591 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
42592 var style = this.style;
42595 Roo.form.GridField.superclass.onRender.call(this, ct, position);
42596 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
42597 this.viewEl = this.wrap.createChild({ tag: 'div' });
42599 this.viewEl.applyStyles(style);
42602 this.viewEl.setWidth(this.width);
42605 this.viewEl.setHeight(this.height);
42607 //if(this.inputValue !== undefined){
42608 //this.setValue(this.value);
42611 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
42614 this.grid.render();
42615 this.grid.getDataSource().on('remove', this.refreshValue, this);
42616 this.grid.getDataSource().on('update', this.refreshValue, this);
42617 this.grid.on('afteredit', this.refreshValue, this);
42623 * Sets the value of the item.
42624 * @param {String} either an object or a string..
42626 setValue : function(v){
42628 v = v || []; // empty set..
42629 // this does not seem smart - it really only affects memoryproxy grids..
42630 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
42631 var ds = this.grid.getDataSource();
42632 // assumes a json reader..
42634 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
42635 ds.loadData( data);
42637 Roo.form.GridField.superclass.setValue.call(this, v);
42638 this.refreshValue();
42639 // should load data in the grid really....
42643 refreshValue: function() {
42645 this.grid.getDataSource().each(function(r) {
42648 this.el.dom.value = Roo.encode(val);
42656 * Ext JS Library 1.1.1
42657 * Copyright(c) 2006-2007, Ext JS, LLC.
42659 * Originally Released Under LGPL - original licence link has changed is not relivant.
42662 * <script type="text/javascript">
42665 * @class Roo.form.DisplayField
42666 * @extends Roo.form.Field
42667 * A generic Field to display non-editable data.
42669 * Creates a new Display Field item.
42670 * @param {Object} config Configuration options
42672 Roo.form.DisplayField = function(config){
42673 Roo.form.DisplayField.superclass.constructor.call(this, config);
42677 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
42678 inputType: 'hidden',
42684 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42686 focusClass : undefined,
42688 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42690 fieldClass: 'x-form-field',
42693 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
42695 valueRenderer: undefined,
42699 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42700 * {tag: "input", type: "checkbox", autocomplete: "off"})
42703 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42705 onResize : function(){
42706 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
42710 initEvents : function(){
42711 // Roo.form.Checkbox.superclass.initEvents.call(this);
42712 // has no events...
42717 getResizeEl : function(){
42721 getPositionEl : function(){
42726 onRender : function(ct, position){
42728 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
42729 //if(this.inputValue !== undefined){
42730 this.wrap = this.el.wrap();
42732 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
42734 if (this.bodyStyle) {
42735 this.viewEl.applyStyles(this.bodyStyle);
42737 //this.viewEl.setStyle('padding', '2px');
42739 this.setValue(this.value);
42744 initValue : Roo.emptyFn,
42749 onClick : function(){
42754 * Sets the checked state of the checkbox.
42755 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
42757 setValue : function(v){
42759 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
42760 // this might be called before we have a dom element..
42761 if (!this.viewEl) {
42764 this.viewEl.dom.innerHTML = html;
42765 Roo.form.DisplayField.superclass.setValue.call(this, v);
42775 * @class Roo.form.DayPicker
42776 * @extends Roo.form.Field
42777 * A Day picker show [M] [T] [W] ....
42779 * Creates a new Day Picker
42780 * @param {Object} config Configuration options
42782 Roo.form.DayPicker= function(config){
42783 Roo.form.DayPicker.superclass.constructor.call(this, config);
42787 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
42789 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42791 focusClass : undefined,
42793 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42795 fieldClass: "x-form-field",
42798 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42799 * {tag: "input", type: "checkbox", autocomplete: "off"})
42801 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42804 actionMode : 'viewEl',
42808 inputType : 'hidden',
42811 inputElement: false, // real input element?
42812 basedOn: false, // ????
42814 isFormField: true, // not sure where this is needed!!!!
42816 onResize : function(){
42817 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42818 if(!this.boxLabel){
42819 this.el.alignTo(this.wrap, 'c-c');
42823 initEvents : function(){
42824 Roo.form.Checkbox.superclass.initEvents.call(this);
42825 this.el.on("click", this.onClick, this);
42826 this.el.on("change", this.onClick, this);
42830 getResizeEl : function(){
42834 getPositionEl : function(){
42840 onRender : function(ct, position){
42841 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42843 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
42845 var r1 = '<table><tr>';
42846 var r2 = '<tr class="x-form-daypick-icons">';
42847 for (var i=0; i < 7; i++) {
42848 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
42849 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
42852 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
42853 viewEl.select('img').on('click', this.onClick, this);
42854 this.viewEl = viewEl;
42857 // this will not work on Chrome!!!
42858 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42859 this.el.on('propertychange', this.setFromHidden, this); //ie
42867 initValue : Roo.emptyFn,
42870 * Returns the checked state of the checkbox.
42871 * @return {Boolean} True if checked, else false
42873 getValue : function(){
42874 return this.el.dom.value;
42879 onClick : function(e){
42880 //this.setChecked(!this.checked);
42881 Roo.get(e.target).toggleClass('x-menu-item-checked');
42882 this.refreshValue();
42883 //if(this.el.dom.checked != this.checked){
42884 // this.setValue(this.el.dom.checked);
42889 refreshValue : function()
42892 this.viewEl.select('img',true).each(function(e,i,n) {
42893 val += e.is(".x-menu-item-checked") ? String(n) : '';
42895 this.setValue(val, true);
42899 * Sets the checked state of the checkbox.
42900 * On is always based on a string comparison between inputValue and the param.
42901 * @param {Boolean/String} value - the value to set
42902 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42904 setValue : function(v,suppressEvent){
42905 if (!this.el.dom) {
42908 var old = this.el.dom.value ;
42909 this.el.dom.value = v;
42910 if (suppressEvent) {
42914 // update display..
42915 this.viewEl.select('img',true).each(function(e,i,n) {
42917 var on = e.is(".x-menu-item-checked");
42918 var newv = v.indexOf(String(n)) > -1;
42920 e.toggleClass('x-menu-item-checked');
42926 this.fireEvent('change', this, v, old);
42931 // handle setting of hidden value by some other method!!?!?
42932 setFromHidden: function()
42937 //console.log("SET FROM HIDDEN");
42938 //alert('setFrom hidden');
42939 this.setValue(this.el.dom.value);
42942 onDestroy : function()
42945 Roo.get(this.viewEl).remove();
42948 Roo.form.DayPicker.superclass.onDestroy.call(this);
42951 });//<script type="text/javasscript">
42955 * @class Roo.DDView
42956 * A DnD enabled version of Roo.View.
42957 * @param {Element/String} container The Element in which to create the View.
42958 * @param {String} tpl The template string used to create the markup for each element of the View
42959 * @param {Object} config The configuration properties. These include all the config options of
42960 * {@link Roo.View} plus some specific to this class.<br>
42962 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
42963 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
42965 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
42966 .x-view-drag-insert-above {
42967 border-top:1px dotted #3366cc;
42969 .x-view-drag-insert-below {
42970 border-bottom:1px dotted #3366cc;
42976 Roo.DDView = function(container, tpl, config) {
42977 Roo.DDView.superclass.constructor.apply(this, arguments);
42978 this.getEl().setStyle("outline", "0px none");
42979 this.getEl().unselectable();
42980 if (this.dragGroup) {
42981 this.setDraggable(this.dragGroup.split(","));
42983 if (this.dropGroup) {
42984 this.setDroppable(this.dropGroup.split(","));
42986 if (this.deletable) {
42987 this.setDeletable();
42989 this.isDirtyFlag = false;
42995 Roo.extend(Roo.DDView, Roo.View, {
42996 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
42997 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
42998 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
42999 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
43003 reset: Roo.emptyFn,
43005 clearInvalid: Roo.form.Field.prototype.clearInvalid,
43007 validate: function() {
43011 destroy: function() {
43012 this.purgeListeners();
43013 this.getEl.removeAllListeners();
43014 this.getEl().remove();
43015 if (this.dragZone) {
43016 if (this.dragZone.destroy) {
43017 this.dragZone.destroy();
43020 if (this.dropZone) {
43021 if (this.dropZone.destroy) {
43022 this.dropZone.destroy();
43027 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
43028 getName: function() {
43032 /** Loads the View from a JSON string representing the Records to put into the Store. */
43033 setValue: function(v) {
43035 throw "DDView.setValue(). DDView must be constructed with a valid Store";
43038 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
43039 this.store.proxy = new Roo.data.MemoryProxy(data);
43043 /** @return {String} a parenthesised list of the ids of the Records in the View. */
43044 getValue: function() {
43046 this.store.each(function(rec) {
43047 result += rec.id + ',';
43049 return result.substr(0, result.length - 1) + ')';
43052 getIds: function() {
43053 var i = 0, result = new Array(this.store.getCount());
43054 this.store.each(function(rec) {
43055 result[i++] = rec.id;
43060 isDirty: function() {
43061 return this.isDirtyFlag;
43065 * Part of the Roo.dd.DropZone interface. If no target node is found, the
43066 * whole Element becomes the target, and this causes the drop gesture to append.
43068 getTargetFromEvent : function(e) {
43069 var target = e.getTarget();
43070 while ((target !== null) && (target.parentNode != this.el.dom)) {
43071 target = target.parentNode;
43074 target = this.el.dom.lastChild || this.el.dom;
43080 * Create the drag data which consists of an object which has the property "ddel" as
43081 * the drag proxy element.
43083 getDragData : function(e) {
43084 var target = this.findItemFromChild(e.getTarget());
43086 this.handleSelection(e);
43087 var selNodes = this.getSelectedNodes();
43090 copy: this.copy || (this.allowCopy && e.ctrlKey),
43094 var selectedIndices = this.getSelectedIndexes();
43095 for (var i = 0; i < selectedIndices.length; i++) {
43096 dragData.records.push(this.store.getAt(selectedIndices[i]));
43098 if (selNodes.length == 1) {
43099 dragData.ddel = target.cloneNode(true); // the div element
43101 var div = document.createElement('div'); // create the multi element drag "ghost"
43102 div.className = 'multi-proxy';
43103 for (var i = 0, len = selNodes.length; i < len; i++) {
43104 div.appendChild(selNodes[i].cloneNode(true));
43106 dragData.ddel = div;
43108 //console.log(dragData)
43109 //console.log(dragData.ddel.innerHTML)
43112 //console.log('nodragData')
43116 /** Specify to which ddGroup items in this DDView may be dragged. */
43117 setDraggable: function(ddGroup) {
43118 if (ddGroup instanceof Array) {
43119 Roo.each(ddGroup, this.setDraggable, this);
43122 if (this.dragZone) {
43123 this.dragZone.addToGroup(ddGroup);
43125 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
43126 containerScroll: true,
43130 // Draggability implies selection. DragZone's mousedown selects the element.
43131 if (!this.multiSelect) { this.singleSelect = true; }
43133 // Wire the DragZone's handlers up to methods in *this*
43134 this.dragZone.getDragData = this.getDragData.createDelegate(this);
43138 /** Specify from which ddGroup this DDView accepts drops. */
43139 setDroppable: function(ddGroup) {
43140 if (ddGroup instanceof Array) {
43141 Roo.each(ddGroup, this.setDroppable, this);
43144 if (this.dropZone) {
43145 this.dropZone.addToGroup(ddGroup);
43147 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
43148 containerScroll: true,
43152 // Wire the DropZone's handlers up to methods in *this*
43153 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
43154 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
43155 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
43156 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
43157 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
43161 /** Decide whether to drop above or below a View node. */
43162 getDropPoint : function(e, n, dd){
43163 if (n == this.el.dom) { return "above"; }
43164 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
43165 var c = t + (b - t) / 2;
43166 var y = Roo.lib.Event.getPageY(e);
43174 onNodeEnter : function(n, dd, e, data){
43178 onNodeOver : function(n, dd, e, data){
43179 var pt = this.getDropPoint(e, n, dd);
43180 // set the insert point style on the target node
43181 var dragElClass = this.dropNotAllowed;
43184 if (pt == "above"){
43185 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
43186 targetElClass = "x-view-drag-insert-above";
43188 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
43189 targetElClass = "x-view-drag-insert-below";
43191 if (this.lastInsertClass != targetElClass){
43192 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
43193 this.lastInsertClass = targetElClass;
43196 return dragElClass;
43199 onNodeOut : function(n, dd, e, data){
43200 this.removeDropIndicators(n);
43203 onNodeDrop : function(n, dd, e, data){
43204 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
43207 var pt = this.getDropPoint(e, n, dd);
43208 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
43209 if (pt == "below") { insertAt++; }
43210 for (var i = 0; i < data.records.length; i++) {
43211 var r = data.records[i];
43212 var dup = this.store.getById(r.id);
43213 if (dup && (dd != this.dragZone)) {
43214 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
43217 this.store.insert(insertAt++, r.copy());
43219 data.source.isDirtyFlag = true;
43221 this.store.insert(insertAt++, r);
43223 this.isDirtyFlag = true;
43226 this.dragZone.cachedTarget = null;
43230 removeDropIndicators : function(n){
43232 Roo.fly(n).removeClass([
43233 "x-view-drag-insert-above",
43234 "x-view-drag-insert-below"]);
43235 this.lastInsertClass = "_noclass";
43240 * Utility method. Add a delete option to the DDView's context menu.
43241 * @param {String} imageUrl The URL of the "delete" icon image.
43243 setDeletable: function(imageUrl) {
43244 if (!this.singleSelect && !this.multiSelect) {
43245 this.singleSelect = true;
43247 var c = this.getContextMenu();
43248 this.contextMenu.on("itemclick", function(item) {
43251 this.remove(this.getSelectedIndexes());
43255 this.contextMenu.add({
43262 /** Return the context menu for this DDView. */
43263 getContextMenu: function() {
43264 if (!this.contextMenu) {
43265 // Create the View's context menu
43266 this.contextMenu = new Roo.menu.Menu({
43267 id: this.id + "-contextmenu"
43269 this.el.on("contextmenu", this.showContextMenu, this);
43271 return this.contextMenu;
43274 disableContextMenu: function() {
43275 if (this.contextMenu) {
43276 this.el.un("contextmenu", this.showContextMenu, this);
43280 showContextMenu: function(e, item) {
43281 item = this.findItemFromChild(e.getTarget());
43284 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
43285 this.contextMenu.showAt(e.getXY());
43290 * Remove {@link Roo.data.Record}s at the specified indices.
43291 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
43293 remove: function(selectedIndices) {
43294 selectedIndices = [].concat(selectedIndices);
43295 for (var i = 0; i < selectedIndices.length; i++) {
43296 var rec = this.store.getAt(selectedIndices[i]);
43297 this.store.remove(rec);
43302 * Double click fires the event, but also, if this is draggable, and there is only one other
43303 * related DropZone, it transfers the selected node.
43305 onDblClick : function(e){
43306 var item = this.findItemFromChild(e.getTarget());
43308 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
43311 if (this.dragGroup) {
43312 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
43313 while (targets.indexOf(this.dropZone) > -1) {
43314 targets.remove(this.dropZone);
43316 if (targets.length == 1) {
43317 this.dragZone.cachedTarget = null;
43318 var el = Roo.get(targets[0].getEl());
43319 var box = el.getBox(true);
43320 targets[0].onNodeDrop(el.dom, {
43322 xy: [box.x, box.y + box.height - 1]
43323 }, null, this.getDragData(e));
43329 handleSelection: function(e) {
43330 this.dragZone.cachedTarget = null;
43331 var item = this.findItemFromChild(e.getTarget());
43333 this.clearSelections(true);
43336 if (item && (this.multiSelect || this.singleSelect)){
43337 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
43338 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
43339 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
43340 this.unselect(item);
43342 this.select(item, this.multiSelect && e.ctrlKey);
43343 this.lastSelection = item;
43348 onItemClick : function(item, index, e){
43349 if(this.fireEvent("beforeclick", this, index, item, e) === false){
43355 unselect : function(nodeInfo, suppressEvent){
43356 var node = this.getNode(nodeInfo);
43357 if(node && this.isSelected(node)){
43358 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
43359 Roo.fly(node).removeClass(this.selectedClass);
43360 this.selections.remove(node);
43361 if(!suppressEvent){
43362 this.fireEvent("selectionchange", this, this.selections);
43370 * Ext JS Library 1.1.1
43371 * Copyright(c) 2006-2007, Ext JS, LLC.
43373 * Originally Released Under LGPL - original licence link has changed is not relivant.
43376 * <script type="text/javascript">
43380 * @class Roo.LayoutManager
43381 * @extends Roo.util.Observable
43382 * Base class for layout managers.
43384 Roo.LayoutManager = function(container, config){
43385 Roo.LayoutManager.superclass.constructor.call(this);
43386 this.el = Roo.get(container);
43387 // ie scrollbar fix
43388 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
43389 document.body.scroll = "no";
43390 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
43391 this.el.position('relative');
43393 this.id = this.el.id;
43394 this.el.addClass("x-layout-container");
43395 /** false to disable window resize monitoring @type Boolean */
43396 this.monitorWindowResize = true;
43401 * Fires when a layout is performed.
43402 * @param {Roo.LayoutManager} this
43406 * @event regionresized
43407 * Fires when the user resizes a region.
43408 * @param {Roo.LayoutRegion} region The resized region
43409 * @param {Number} newSize The new size (width for east/west, height for north/south)
43411 "regionresized" : true,
43413 * @event regioncollapsed
43414 * Fires when a region is collapsed.
43415 * @param {Roo.LayoutRegion} region The collapsed region
43417 "regioncollapsed" : true,
43419 * @event regionexpanded
43420 * Fires when a region is expanded.
43421 * @param {Roo.LayoutRegion} region The expanded region
43423 "regionexpanded" : true
43425 this.updating = false;
43426 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
43429 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
43431 * Returns true if this layout is currently being updated
43432 * @return {Boolean}
43434 isUpdating : function(){
43435 return this.updating;
43439 * Suspend the LayoutManager from doing auto-layouts while
43440 * making multiple add or remove calls
43442 beginUpdate : function(){
43443 this.updating = true;
43447 * Restore auto-layouts and optionally disable the manager from performing a layout
43448 * @param {Boolean} noLayout true to disable a layout update
43450 endUpdate : function(noLayout){
43451 this.updating = false;
43457 layout: function(){
43461 onRegionResized : function(region, newSize){
43462 this.fireEvent("regionresized", region, newSize);
43466 onRegionCollapsed : function(region){
43467 this.fireEvent("regioncollapsed", region);
43470 onRegionExpanded : function(region){
43471 this.fireEvent("regionexpanded", region);
43475 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
43476 * performs box-model adjustments.
43477 * @return {Object} The size as an object {width: (the width), height: (the height)}
43479 getViewSize : function(){
43481 if(this.el.dom != document.body){
43482 size = this.el.getSize();
43484 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
43486 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
43487 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
43492 * Returns the Element this layout is bound to.
43493 * @return {Roo.Element}
43495 getEl : function(){
43500 * Returns the specified region.
43501 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
43502 * @return {Roo.LayoutRegion}
43504 getRegion : function(target){
43505 return this.regions[target.toLowerCase()];
43508 onWindowResize : function(){
43509 if(this.monitorWindowResize){
43515 * Ext JS Library 1.1.1
43516 * Copyright(c) 2006-2007, Ext JS, LLC.
43518 * Originally Released Under LGPL - original licence link has changed is not relivant.
43521 * <script type="text/javascript">
43524 * @class Roo.BorderLayout
43525 * @extends Roo.LayoutManager
43526 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
43527 * please see: <br><br>
43528 * <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>
43529 * <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>
43532 var layout = new Roo.BorderLayout(document.body, {
43566 preferredTabWidth: 150
43571 var CP = Roo.ContentPanel;
43573 layout.beginUpdate();
43574 layout.add("north", new CP("north", "North"));
43575 layout.add("south", new CP("south", {title: "South", closable: true}));
43576 layout.add("west", new CP("west", {title: "West"}));
43577 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
43578 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
43579 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
43580 layout.getRegion("center").showPanel("center1");
43581 layout.endUpdate();
43584 <b>The container the layout is rendered into can be either the body element or any other element.
43585 If it is not the body element, the container needs to either be an absolute positioned element,
43586 or you will need to add "position:relative" to the css of the container. You will also need to specify
43587 the container size if it is not the body element.</b>
43590 * Create a new BorderLayout
43591 * @param {String/HTMLElement/Element} container The container this layout is bound to
43592 * @param {Object} config Configuration options
43594 Roo.BorderLayout = function(container, config){
43595 config = config || {};
43596 Roo.BorderLayout.superclass.constructor.call(this, container, config);
43597 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
43598 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
43599 var target = this.factory.validRegions[i];
43600 if(config[target]){
43601 this.addRegion(target, config[target]);
43606 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
43608 * Creates and adds a new region if it doesn't already exist.
43609 * @param {String} target The target region key (north, south, east, west or center).
43610 * @param {Object} config The regions config object
43611 * @return {BorderLayoutRegion} The new region
43613 addRegion : function(target, config){
43614 if(!this.regions[target]){
43615 var r = this.factory.create(target, this, config);
43616 this.bindRegion(target, r);
43618 return this.regions[target];
43622 bindRegion : function(name, r){
43623 this.regions[name] = r;
43624 r.on("visibilitychange", this.layout, this);
43625 r.on("paneladded", this.layout, this);
43626 r.on("panelremoved", this.layout, this);
43627 r.on("invalidated", this.layout, this);
43628 r.on("resized", this.onRegionResized, this);
43629 r.on("collapsed", this.onRegionCollapsed, this);
43630 r.on("expanded", this.onRegionExpanded, this);
43634 * Performs a layout update.
43636 layout : function(){
43637 if(this.updating) return;
43638 var size = this.getViewSize();
43639 var w = size.width;
43640 var h = size.height;
43645 //var x = 0, y = 0;
43647 var rs = this.regions;
43648 var north = rs["north"];
43649 var south = rs["south"];
43650 var west = rs["west"];
43651 var east = rs["east"];
43652 var center = rs["center"];
43653 //if(this.hideOnLayout){ // not supported anymore
43654 //c.el.setStyle("display", "none");
43656 if(north && north.isVisible()){
43657 var b = north.getBox();
43658 var m = north.getMargins();
43659 b.width = w - (m.left+m.right);
43662 centerY = b.height + b.y + m.bottom;
43663 centerH -= centerY;
43664 north.updateBox(this.safeBox(b));
43666 if(south && south.isVisible()){
43667 var b = south.getBox();
43668 var m = south.getMargins();
43669 b.width = w - (m.left+m.right);
43671 var totalHeight = (b.height + m.top + m.bottom);
43672 b.y = h - totalHeight + m.top;
43673 centerH -= totalHeight;
43674 south.updateBox(this.safeBox(b));
43676 if(west && west.isVisible()){
43677 var b = west.getBox();
43678 var m = west.getMargins();
43679 b.height = centerH - (m.top+m.bottom);
43681 b.y = centerY + m.top;
43682 var totalWidth = (b.width + m.left + m.right);
43683 centerX += totalWidth;
43684 centerW -= totalWidth;
43685 west.updateBox(this.safeBox(b));
43687 if(east && east.isVisible()){
43688 var b = east.getBox();
43689 var m = east.getMargins();
43690 b.height = centerH - (m.top+m.bottom);
43691 var totalWidth = (b.width + m.left + m.right);
43692 b.x = w - totalWidth + m.left;
43693 b.y = centerY + m.top;
43694 centerW -= totalWidth;
43695 east.updateBox(this.safeBox(b));
43698 var m = center.getMargins();
43700 x: centerX + m.left,
43701 y: centerY + m.top,
43702 width: centerW - (m.left+m.right),
43703 height: centerH - (m.top+m.bottom)
43705 //if(this.hideOnLayout){
43706 //center.el.setStyle("display", "block");
43708 center.updateBox(this.safeBox(centerBox));
43711 this.fireEvent("layout", this);
43715 safeBox : function(box){
43716 box.width = Math.max(0, box.width);
43717 box.height = Math.max(0, box.height);
43722 * Adds a ContentPanel (or subclass) to this layout.
43723 * @param {String} target The target region key (north, south, east, west or center).
43724 * @param {Roo.ContentPanel} panel The panel to add
43725 * @return {Roo.ContentPanel} The added panel
43727 add : function(target, panel){
43729 target = target.toLowerCase();
43730 return this.regions[target].add(panel);
43734 * Remove a ContentPanel (or subclass) to this layout.
43735 * @param {String} target The target region key (north, south, east, west or center).
43736 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
43737 * @return {Roo.ContentPanel} The removed panel
43739 remove : function(target, panel){
43740 target = target.toLowerCase();
43741 return this.regions[target].remove(panel);
43745 * Searches all regions for a panel with the specified id
43746 * @param {String} panelId
43747 * @return {Roo.ContentPanel} The panel or null if it wasn't found
43749 findPanel : function(panelId){
43750 var rs = this.regions;
43751 for(var target in rs){
43752 if(typeof rs[target] != "function"){
43753 var p = rs[target].getPanel(panelId);
43763 * Searches all regions for a panel with the specified id and activates (shows) it.
43764 * @param {String/ContentPanel} panelId The panels id or the panel itself
43765 * @return {Roo.ContentPanel} The shown panel or null
43767 showPanel : function(panelId) {
43768 var rs = this.regions;
43769 for(var target in rs){
43770 var r = rs[target];
43771 if(typeof r != "function"){
43772 if(r.hasPanel(panelId)){
43773 return r.showPanel(panelId);
43781 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
43782 * @param {Roo.state.Provider} provider (optional) An alternate state provider
43784 restoreState : function(provider){
43786 provider = Roo.state.Manager;
43788 var sm = new Roo.LayoutStateManager();
43789 sm.init(this, provider);
43793 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
43794 * object should contain properties for each region to add ContentPanels to, and each property's value should be
43795 * a valid ContentPanel config object. Example:
43797 // Create the main layout
43798 var layout = new Roo.BorderLayout('main-ct', {
43809 // Create and add multiple ContentPanels at once via configs
43812 id: 'source-files',
43814 title:'Ext Source Files',
43827 * @param {Object} regions An object containing ContentPanel configs by region name
43829 batchAdd : function(regions){
43830 this.beginUpdate();
43831 for(var rname in regions){
43832 var lr = this.regions[rname];
43834 this.addTypedPanels(lr, regions[rname]);
43841 addTypedPanels : function(lr, ps){
43842 if(typeof ps == 'string'){
43843 lr.add(new Roo.ContentPanel(ps));
43845 else if(ps instanceof Array){
43846 for(var i =0, len = ps.length; i < len; i++){
43847 this.addTypedPanels(lr, ps[i]);
43850 else if(!ps.events){ // raw config?
43852 delete ps.el; // prevent conflict
43853 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
43855 else { // panel object assumed!
43860 * Adds a xtype elements to the layout.
43864 xtype : 'ContentPanel',
43871 xtype : 'NestedLayoutPanel',
43877 items : [ ... list of content panels or nested layout panels.. ]
43881 * @param {Object} cfg Xtype definition of item to add.
43883 addxtype : function(cfg)
43885 // basically accepts a pannel...
43886 // can accept a layout region..!?!?
43887 // console.log('BorderLayout add ' + cfg.xtype)
43889 if (!cfg.xtype.match(/Panel$/)) {
43893 var region = cfg.region;
43899 xitems = cfg.items;
43906 case 'ContentPanel': // ContentPanel (el, cfg)
43907 case 'ScrollPanel': // ContentPanel (el, cfg)
43908 if(cfg.autoCreate) {
43909 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43911 var el = this.el.createChild();
43912 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
43915 this.add(region, ret);
43919 case 'TreePanel': // our new panel!
43920 cfg.el = this.el.createChild();
43921 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43922 this.add(region, ret);
43925 case 'NestedLayoutPanel':
43926 // create a new Layout (which is a Border Layout...
43927 var el = this.el.createChild();
43928 var clayout = cfg.layout;
43930 clayout.items = clayout.items || [];
43931 // replace this exitems with the clayout ones..
43932 xitems = clayout.items;
43935 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
43936 cfg.background = false;
43938 var layout = new Roo.BorderLayout(el, clayout);
43940 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
43941 //console.log('adding nested layout panel ' + cfg.toSource());
43942 this.add(region, ret);
43948 // needs grid and region
43950 //var el = this.getRegion(region).el.createChild();
43951 var el = this.el.createChild();
43952 // create the grid first...
43954 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
43956 if (region == 'center' && this.active ) {
43957 cfg.background = false;
43959 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
43961 this.add(region, ret);
43962 if (cfg.background) {
43963 ret.on('activate', function(gp) {
43964 if (!gp.grid.rendered) {
43977 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
43979 // GridPanel (grid, cfg)
43982 this.beginUpdate();
43984 Roo.each(xitems, function(i) {
43994 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
43995 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
43996 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
43997 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
44000 var CP = Roo.ContentPanel;
44002 var layout = Roo.BorderLayout.create({
44006 panels: [new CP("north", "North")]
44015 panels: [new CP("west", {title: "West"})]
44024 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
44033 panels: [new CP("south", {title: "South", closable: true})]
44040 preferredTabWidth: 150,
44042 new CP("center1", {title: "Close Me", closable: true}),
44043 new CP("center2", {title: "Center Panel", closable: false})
44048 layout.getRegion("center").showPanel("center1");
44053 Roo.BorderLayout.create = function(config, targetEl){
44054 var layout = new Roo.BorderLayout(targetEl || document.body, config);
44055 layout.beginUpdate();
44056 var regions = Roo.BorderLayout.RegionFactory.validRegions;
44057 for(var j = 0, jlen = regions.length; j < jlen; j++){
44058 var lr = regions[j];
44059 if(layout.regions[lr] && config[lr].panels){
44060 var r = layout.regions[lr];
44061 var ps = config[lr].panels;
44062 layout.addTypedPanels(r, ps);
44065 layout.endUpdate();
44070 Roo.BorderLayout.RegionFactory = {
44072 validRegions : ["north","south","east","west","center"],
44075 create : function(target, mgr, config){
44076 target = target.toLowerCase();
44077 if(config.lightweight || config.basic){
44078 return new Roo.BasicLayoutRegion(mgr, config, target);
44082 return new Roo.NorthLayoutRegion(mgr, config);
44084 return new Roo.SouthLayoutRegion(mgr, config);
44086 return new Roo.EastLayoutRegion(mgr, config);
44088 return new Roo.WestLayoutRegion(mgr, config);
44090 return new Roo.CenterLayoutRegion(mgr, config);
44092 throw 'Layout region "'+target+'" not supported.';
44096 * Ext JS Library 1.1.1
44097 * Copyright(c) 2006-2007, Ext JS, LLC.
44099 * Originally Released Under LGPL - original licence link has changed is not relivant.
44102 * <script type="text/javascript">
44106 * @class Roo.BasicLayoutRegion
44107 * @extends Roo.util.Observable
44108 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
44109 * and does not have a titlebar, tabs or any other features. All it does is size and position
44110 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
44112 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
44114 this.position = pos;
44117 * @scope Roo.BasicLayoutRegion
44121 * @event beforeremove
44122 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
44123 * @param {Roo.LayoutRegion} this
44124 * @param {Roo.ContentPanel} panel The panel
44125 * @param {Object} e The cancel event object
44127 "beforeremove" : true,
44129 * @event invalidated
44130 * Fires when the layout for this region is changed.
44131 * @param {Roo.LayoutRegion} this
44133 "invalidated" : true,
44135 * @event visibilitychange
44136 * Fires when this region is shown or hidden
44137 * @param {Roo.LayoutRegion} this
44138 * @param {Boolean} visibility true or false
44140 "visibilitychange" : true,
44142 * @event paneladded
44143 * Fires when a panel is added.
44144 * @param {Roo.LayoutRegion} this
44145 * @param {Roo.ContentPanel} panel The panel
44147 "paneladded" : true,
44149 * @event panelremoved
44150 * Fires when a panel is removed.
44151 * @param {Roo.LayoutRegion} this
44152 * @param {Roo.ContentPanel} panel The panel
44154 "panelremoved" : true,
44157 * Fires when this region is collapsed.
44158 * @param {Roo.LayoutRegion} this
44160 "collapsed" : true,
44163 * Fires when this region is expanded.
44164 * @param {Roo.LayoutRegion} this
44169 * Fires when this region is slid into view.
44170 * @param {Roo.LayoutRegion} this
44172 "slideshow" : true,
44175 * Fires when this region slides out of view.
44176 * @param {Roo.LayoutRegion} this
44178 "slidehide" : true,
44180 * @event panelactivated
44181 * Fires when a panel is activated.
44182 * @param {Roo.LayoutRegion} this
44183 * @param {Roo.ContentPanel} panel The activated panel
44185 "panelactivated" : true,
44188 * Fires when the user resizes this region.
44189 * @param {Roo.LayoutRegion} this
44190 * @param {Number} newSize The new size (width for east/west, height for north/south)
44194 /** A collection of panels in this region. @type Roo.util.MixedCollection */
44195 this.panels = new Roo.util.MixedCollection();
44196 this.panels.getKey = this.getPanelId.createDelegate(this);
44198 this.activePanel = null;
44199 // ensure listeners are added...
44201 if (config.listeners || config.events) {
44202 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
44203 listeners : config.listeners || {},
44204 events : config.events || {}
44208 if(skipConfig !== true){
44209 this.applyConfig(config);
44213 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
44214 getPanelId : function(p){
44218 applyConfig : function(config){
44219 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44220 this.config = config;
44225 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
44226 * the width, for horizontal (north, south) the height.
44227 * @param {Number} newSize The new width or height
44229 resizeTo : function(newSize){
44230 var el = this.el ? this.el :
44231 (this.activePanel ? this.activePanel.getEl() : null);
44233 switch(this.position){
44236 el.setWidth(newSize);
44237 this.fireEvent("resized", this, newSize);
44241 el.setHeight(newSize);
44242 this.fireEvent("resized", this, newSize);
44248 getBox : function(){
44249 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
44252 getMargins : function(){
44253 return this.margins;
44256 updateBox : function(box){
44258 var el = this.activePanel.getEl();
44259 el.dom.style.left = box.x + "px";
44260 el.dom.style.top = box.y + "px";
44261 this.activePanel.setSize(box.width, box.height);
44265 * Returns the container element for this region.
44266 * @return {Roo.Element}
44268 getEl : function(){
44269 return this.activePanel;
44273 * Returns true if this region is currently visible.
44274 * @return {Boolean}
44276 isVisible : function(){
44277 return this.activePanel ? true : false;
44280 setActivePanel : function(panel){
44281 panel = this.getPanel(panel);
44282 if(this.activePanel && this.activePanel != panel){
44283 this.activePanel.setActiveState(false);
44284 this.activePanel.getEl().setLeftTop(-10000,-10000);
44286 this.activePanel = panel;
44287 panel.setActiveState(true);
44289 panel.setSize(this.box.width, this.box.height);
44291 this.fireEvent("panelactivated", this, panel);
44292 this.fireEvent("invalidated");
44296 * Show the specified panel.
44297 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
44298 * @return {Roo.ContentPanel} The shown panel or null
44300 showPanel : function(panel){
44301 if(panel = this.getPanel(panel)){
44302 this.setActivePanel(panel);
44308 * Get the active panel for this region.
44309 * @return {Roo.ContentPanel} The active panel or null
44311 getActivePanel : function(){
44312 return this.activePanel;
44316 * Add the passed ContentPanel(s)
44317 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44318 * @return {Roo.ContentPanel} The panel added (if only one was added)
44320 add : function(panel){
44321 if(arguments.length > 1){
44322 for(var i = 0, len = arguments.length; i < len; i++) {
44323 this.add(arguments[i]);
44327 if(this.hasPanel(panel)){
44328 this.showPanel(panel);
44331 var el = panel.getEl();
44332 if(el.dom.parentNode != this.mgr.el.dom){
44333 this.mgr.el.dom.appendChild(el.dom);
44335 if(panel.setRegion){
44336 panel.setRegion(this);
44338 this.panels.add(panel);
44339 el.setStyle("position", "absolute");
44340 if(!panel.background){
44341 this.setActivePanel(panel);
44342 if(this.config.initialSize && this.panels.getCount()==1){
44343 this.resizeTo(this.config.initialSize);
44346 this.fireEvent("paneladded", this, panel);
44351 * Returns true if the panel is in this region.
44352 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44353 * @return {Boolean}
44355 hasPanel : function(panel){
44356 if(typeof panel == "object"){ // must be panel obj
44357 panel = panel.getId();
44359 return this.getPanel(panel) ? true : false;
44363 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44364 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44365 * @param {Boolean} preservePanel Overrides the config preservePanel option
44366 * @return {Roo.ContentPanel} The panel that was removed
44368 remove : function(panel, preservePanel){
44369 panel = this.getPanel(panel);
44374 this.fireEvent("beforeremove", this, panel, e);
44375 if(e.cancel === true){
44378 var panelId = panel.getId();
44379 this.panels.removeKey(panelId);
44384 * Returns the panel specified or null if it's not in this region.
44385 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44386 * @return {Roo.ContentPanel}
44388 getPanel : function(id){
44389 if(typeof id == "object"){ // must be panel obj
44392 return this.panels.get(id);
44396 * Returns this regions position (north/south/east/west/center).
44399 getPosition: function(){
44400 return this.position;
44404 * Ext JS Library 1.1.1
44405 * Copyright(c) 2006-2007, Ext JS, LLC.
44407 * Originally Released Under LGPL - original licence link has changed is not relivant.
44410 * <script type="text/javascript">
44414 * @class Roo.LayoutRegion
44415 * @extends Roo.BasicLayoutRegion
44416 * This class represents a region in a layout manager.
44417 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
44418 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
44419 * @cfg {Boolean} floatable False to disable floating (defaults to true)
44420 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
44421 * @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})
44422 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
44423 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
44424 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
44425 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
44426 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
44427 * @cfg {String} title The title for the region (overrides panel titles)
44428 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
44429 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
44430 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
44431 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
44432 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
44433 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
44434 * the space available, similar to FireFox 1.5 tabs (defaults to false)
44435 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
44436 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
44437 * @cfg {Boolean} showPin True to show a pin button
44438 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
44439 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
44440 * @cfg {Boolean} disableTabTips True to disable tab tooltips
44441 * @cfg {Number} width For East/West panels
44442 * @cfg {Number} height For North/South panels
44443 * @cfg {Boolean} split To show the splitter
44444 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
44446 Roo.LayoutRegion = function(mgr, config, pos){
44447 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
44448 var dh = Roo.DomHelper;
44449 /** This region's container element
44450 * @type Roo.Element */
44451 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
44452 /** This region's title element
44453 * @type Roo.Element */
44455 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
44456 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
44457 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
44459 this.titleEl.enableDisplayMode();
44460 /** This region's title text element
44461 * @type HTMLElement */
44462 this.titleTextEl = this.titleEl.dom.firstChild;
44463 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
44464 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
44465 this.closeBtn.enableDisplayMode();
44466 this.closeBtn.on("click", this.closeClicked, this);
44467 this.closeBtn.hide();
44469 this.createBody(config);
44470 this.visible = true;
44471 this.collapsed = false;
44473 if(config.hideWhenEmpty){
44475 this.on("paneladded", this.validateVisibility, this);
44476 this.on("panelremoved", this.validateVisibility, this);
44478 this.applyConfig(config);
44481 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
44483 createBody : function(){
44484 /** This region's body element
44485 * @type Roo.Element */
44486 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
44489 applyConfig : function(c){
44490 if(c.collapsible && this.position != "center" && !this.collapsedEl){
44491 var dh = Roo.DomHelper;
44492 if(c.titlebar !== false){
44493 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
44494 this.collapseBtn.on("click", this.collapse, this);
44495 this.collapseBtn.enableDisplayMode();
44497 if(c.showPin === true || this.showPin){
44498 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
44499 this.stickBtn.enableDisplayMode();
44500 this.stickBtn.on("click", this.expand, this);
44501 this.stickBtn.hide();
44504 /** This region's collapsed element
44505 * @type Roo.Element */
44506 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
44507 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
44509 if(c.floatable !== false){
44510 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
44511 this.collapsedEl.on("click", this.collapseClick, this);
44514 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
44515 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
44516 id: "message", unselectable: "on", style:{"float":"left"}});
44517 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
44519 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
44520 this.expandBtn.on("click", this.expand, this);
44522 if(this.collapseBtn){
44523 this.collapseBtn.setVisible(c.collapsible == true);
44525 this.cmargins = c.cmargins || this.cmargins ||
44526 (this.position == "west" || this.position == "east" ?
44527 {top: 0, left: 2, right:2, bottom: 0} :
44528 {top: 2, left: 0, right:0, bottom: 2});
44529 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44530 this.bottomTabs = c.tabPosition != "top";
44531 this.autoScroll = c.autoScroll || false;
44532 if(this.autoScroll){
44533 this.bodyEl.setStyle("overflow", "auto");
44535 this.bodyEl.setStyle("overflow", "hidden");
44537 //if(c.titlebar !== false){
44538 if((!c.titlebar && !c.title) || c.titlebar === false){
44539 this.titleEl.hide();
44541 this.titleEl.show();
44543 this.titleTextEl.innerHTML = c.title;
44547 this.duration = c.duration || .30;
44548 this.slideDuration = c.slideDuration || .45;
44551 this.collapse(true);
44558 * Returns true if this region is currently visible.
44559 * @return {Boolean}
44561 isVisible : function(){
44562 return this.visible;
44566 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
44567 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
44569 setCollapsedTitle : function(title){
44570 title = title || " ";
44571 if(this.collapsedTitleTextEl){
44572 this.collapsedTitleTextEl.innerHTML = title;
44576 getBox : function(){
44578 if(!this.collapsed){
44579 b = this.el.getBox(false, true);
44581 b = this.collapsedEl.getBox(false, true);
44586 getMargins : function(){
44587 return this.collapsed ? this.cmargins : this.margins;
44590 highlight : function(){
44591 this.el.addClass("x-layout-panel-dragover");
44594 unhighlight : function(){
44595 this.el.removeClass("x-layout-panel-dragover");
44598 updateBox : function(box){
44600 if(!this.collapsed){
44601 this.el.dom.style.left = box.x + "px";
44602 this.el.dom.style.top = box.y + "px";
44603 this.updateBody(box.width, box.height);
44605 this.collapsedEl.dom.style.left = box.x + "px";
44606 this.collapsedEl.dom.style.top = box.y + "px";
44607 this.collapsedEl.setSize(box.width, box.height);
44610 this.tabs.autoSizeTabs();
44614 updateBody : function(w, h){
44616 this.el.setWidth(w);
44617 w -= this.el.getBorderWidth("rl");
44618 if(this.config.adjustments){
44619 w += this.config.adjustments[0];
44623 this.el.setHeight(h);
44624 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
44625 h -= this.el.getBorderWidth("tb");
44626 if(this.config.adjustments){
44627 h += this.config.adjustments[1];
44629 this.bodyEl.setHeight(h);
44631 h = this.tabs.syncHeight(h);
44634 if(this.panelSize){
44635 w = w !== null ? w : this.panelSize.width;
44636 h = h !== null ? h : this.panelSize.height;
44638 if(this.activePanel){
44639 var el = this.activePanel.getEl();
44640 w = w !== null ? w : el.getWidth();
44641 h = h !== null ? h : el.getHeight();
44642 this.panelSize = {width: w, height: h};
44643 this.activePanel.setSize(w, h);
44645 if(Roo.isIE && this.tabs){
44646 this.tabs.el.repaint();
44651 * Returns the container element for this region.
44652 * @return {Roo.Element}
44654 getEl : function(){
44659 * Hides this region.
44662 if(!this.collapsed){
44663 this.el.dom.style.left = "-2000px";
44666 this.collapsedEl.dom.style.left = "-2000px";
44667 this.collapsedEl.hide();
44669 this.visible = false;
44670 this.fireEvent("visibilitychange", this, false);
44674 * Shows this region if it was previously hidden.
44677 if(!this.collapsed){
44680 this.collapsedEl.show();
44682 this.visible = true;
44683 this.fireEvent("visibilitychange", this, true);
44686 closeClicked : function(){
44687 if(this.activePanel){
44688 this.remove(this.activePanel);
44692 collapseClick : function(e){
44694 e.stopPropagation();
44697 e.stopPropagation();
44703 * Collapses this region.
44704 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
44706 collapse : function(skipAnim){
44707 if(this.collapsed) return;
44708 this.collapsed = true;
44710 this.split.el.hide();
44712 if(this.config.animate && skipAnim !== true){
44713 this.fireEvent("invalidated", this);
44714 this.animateCollapse();
44716 this.el.setLocation(-20000,-20000);
44718 this.collapsedEl.show();
44719 this.fireEvent("collapsed", this);
44720 this.fireEvent("invalidated", this);
44724 animateCollapse : function(){
44729 * Expands this region if it was previously collapsed.
44730 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
44731 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
44733 expand : function(e, skipAnim){
44734 if(e) e.stopPropagation();
44735 if(!this.collapsed || this.el.hasActiveFx()) return;
44737 this.afterSlideIn();
44740 this.collapsed = false;
44741 if(this.config.animate && skipAnim !== true){
44742 this.animateExpand();
44746 this.split.el.show();
44748 this.collapsedEl.setLocation(-2000,-2000);
44749 this.collapsedEl.hide();
44750 this.fireEvent("invalidated", this);
44751 this.fireEvent("expanded", this);
44755 animateExpand : function(){
44759 initTabs : function()
44761 this.bodyEl.setStyle("overflow", "hidden");
44762 var ts = new Roo.TabPanel(
44765 tabPosition: this.bottomTabs ? 'bottom' : 'top',
44766 disableTooltips: this.config.disableTabTips,
44767 toolbar : this.config.toolbar
44770 if(this.config.hideTabs){
44771 ts.stripWrap.setDisplayed(false);
44774 ts.resizeTabs = this.config.resizeTabs === true;
44775 ts.minTabWidth = this.config.minTabWidth || 40;
44776 ts.maxTabWidth = this.config.maxTabWidth || 250;
44777 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
44778 ts.monitorResize = false;
44779 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44780 ts.bodyEl.addClass('x-layout-tabs-body');
44781 this.panels.each(this.initPanelAsTab, this);
44784 initPanelAsTab : function(panel){
44785 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
44786 this.config.closeOnTab && panel.isClosable());
44787 if(panel.tabTip !== undefined){
44788 ti.setTooltip(panel.tabTip);
44790 ti.on("activate", function(){
44791 this.setActivePanel(panel);
44793 if(this.config.closeOnTab){
44794 ti.on("beforeclose", function(t, e){
44796 this.remove(panel);
44802 updatePanelTitle : function(panel, title){
44803 if(this.activePanel == panel){
44804 this.updateTitle(title);
44807 var ti = this.tabs.getTab(panel.getEl().id);
44809 if(panel.tabTip !== undefined){
44810 ti.setTooltip(panel.tabTip);
44815 updateTitle : function(title){
44816 if(this.titleTextEl && !this.config.title){
44817 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
44821 setActivePanel : function(panel){
44822 panel = this.getPanel(panel);
44823 if(this.activePanel && this.activePanel != panel){
44824 this.activePanel.setActiveState(false);
44826 this.activePanel = panel;
44827 panel.setActiveState(true);
44828 if(this.panelSize){
44829 panel.setSize(this.panelSize.width, this.panelSize.height);
44832 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
44834 this.updateTitle(panel.getTitle());
44836 this.fireEvent("invalidated", this);
44838 this.fireEvent("panelactivated", this, panel);
44842 * Shows the specified panel.
44843 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
44844 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
44846 showPanel : function(panel){
44847 if(panel = this.getPanel(panel)){
44849 var tab = this.tabs.getTab(panel.getEl().id);
44850 if(tab.isHidden()){
44851 this.tabs.unhideTab(tab.id);
44855 this.setActivePanel(panel);
44862 * Get the active panel for this region.
44863 * @return {Roo.ContentPanel} The active panel or null
44865 getActivePanel : function(){
44866 return this.activePanel;
44869 validateVisibility : function(){
44870 if(this.panels.getCount() < 1){
44871 this.updateTitle(" ");
44872 this.closeBtn.hide();
44875 if(!this.isVisible()){
44882 * Adds the passed ContentPanel(s) to this region.
44883 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44884 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
44886 add : function(panel){
44887 if(arguments.length > 1){
44888 for(var i = 0, len = arguments.length; i < len; i++) {
44889 this.add(arguments[i]);
44893 if(this.hasPanel(panel)){
44894 this.showPanel(panel);
44897 panel.setRegion(this);
44898 this.panels.add(panel);
44899 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
44900 this.bodyEl.dom.appendChild(panel.getEl().dom);
44901 if(panel.background !== true){
44902 this.setActivePanel(panel);
44904 this.fireEvent("paneladded", this, panel);
44910 this.initPanelAsTab(panel);
44912 if(panel.background !== true){
44913 this.tabs.activate(panel.getEl().id);
44915 this.fireEvent("paneladded", this, panel);
44920 * Hides the tab for the specified panel.
44921 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44923 hidePanel : function(panel){
44924 if(this.tabs && (panel = this.getPanel(panel))){
44925 this.tabs.hideTab(panel.getEl().id);
44930 * Unhides the tab for a previously hidden panel.
44931 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44933 unhidePanel : function(panel){
44934 if(this.tabs && (panel = this.getPanel(panel))){
44935 this.tabs.unhideTab(panel.getEl().id);
44939 clearPanels : function(){
44940 while(this.panels.getCount() > 0){
44941 this.remove(this.panels.first());
44946 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44947 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44948 * @param {Boolean} preservePanel Overrides the config preservePanel option
44949 * @return {Roo.ContentPanel} The panel that was removed
44951 remove : function(panel, preservePanel){
44952 panel = this.getPanel(panel);
44957 this.fireEvent("beforeremove", this, panel, e);
44958 if(e.cancel === true){
44961 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
44962 var panelId = panel.getId();
44963 this.panels.removeKey(panelId);
44965 document.body.appendChild(panel.getEl().dom);
44968 this.tabs.removeTab(panel.getEl().id);
44969 }else if (!preservePanel){
44970 this.bodyEl.dom.removeChild(panel.getEl().dom);
44972 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
44973 var p = this.panels.first();
44974 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
44975 tempEl.appendChild(p.getEl().dom);
44976 this.bodyEl.update("");
44977 this.bodyEl.dom.appendChild(p.getEl().dom);
44979 this.updateTitle(p.getTitle());
44981 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44982 this.setActivePanel(p);
44984 panel.setRegion(null);
44985 if(this.activePanel == panel){
44986 this.activePanel = null;
44988 if(this.config.autoDestroy !== false && preservePanel !== true){
44989 try{panel.destroy();}catch(e){}
44991 this.fireEvent("panelremoved", this, panel);
44996 * Returns the TabPanel component used by this region
44997 * @return {Roo.TabPanel}
44999 getTabs : function(){
45003 createTool : function(parentEl, className){
45004 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
45005 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
45006 btn.addClassOnOver("x-layout-tools-button-over");
45011 * Ext JS Library 1.1.1
45012 * Copyright(c) 2006-2007, Ext JS, LLC.
45014 * Originally Released Under LGPL - original licence link has changed is not relivant.
45017 * <script type="text/javascript">
45023 * @class Roo.SplitLayoutRegion
45024 * @extends Roo.LayoutRegion
45025 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
45027 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
45028 this.cursor = cursor;
45029 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
45032 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
45033 splitTip : "Drag to resize.",
45034 collapsibleSplitTip : "Drag to resize. Double click to hide.",
45035 useSplitTips : false,
45037 applyConfig : function(config){
45038 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
45041 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
45042 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
45043 /** The SplitBar for this region
45044 * @type Roo.SplitBar */
45045 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
45046 this.split.on("moved", this.onSplitMove, this);
45047 this.split.useShim = config.useShim === true;
45048 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
45049 if(this.useSplitTips){
45050 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
45052 if(config.collapsible){
45053 this.split.el.on("dblclick", this.collapse, this);
45056 if(typeof config.minSize != "undefined"){
45057 this.split.minSize = config.minSize;
45059 if(typeof config.maxSize != "undefined"){
45060 this.split.maxSize = config.maxSize;
45062 if(config.hideWhenEmpty || config.hidden || config.collapsed){
45063 this.hideSplitter();
45068 getHMaxSize : function(){
45069 var cmax = this.config.maxSize || 10000;
45070 var center = this.mgr.getRegion("center");
45071 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
45074 getVMaxSize : function(){
45075 var cmax = this.config.maxSize || 10000;
45076 var center = this.mgr.getRegion("center");
45077 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
45080 onSplitMove : function(split, newSize){
45081 this.fireEvent("resized", this, newSize);
45085 * Returns the {@link Roo.SplitBar} for this region.
45086 * @return {Roo.SplitBar}
45088 getSplitBar : function(){
45093 this.hideSplitter();
45094 Roo.SplitLayoutRegion.superclass.hide.call(this);
45097 hideSplitter : function(){
45099 this.split.el.setLocation(-2000,-2000);
45100 this.split.el.hide();
45106 this.split.el.show();
45108 Roo.SplitLayoutRegion.superclass.show.call(this);
45111 beforeSlide: function(){
45112 if(Roo.isGecko){// firefox overflow auto bug workaround
45113 this.bodyEl.clip();
45114 if(this.tabs) this.tabs.bodyEl.clip();
45115 if(this.activePanel){
45116 this.activePanel.getEl().clip();
45118 if(this.activePanel.beforeSlide){
45119 this.activePanel.beforeSlide();
45125 afterSlide : function(){
45126 if(Roo.isGecko){// firefox overflow auto bug workaround
45127 this.bodyEl.unclip();
45128 if(this.tabs) this.tabs.bodyEl.unclip();
45129 if(this.activePanel){
45130 this.activePanel.getEl().unclip();
45131 if(this.activePanel.afterSlide){
45132 this.activePanel.afterSlide();
45138 initAutoHide : function(){
45139 if(this.autoHide !== false){
45140 if(!this.autoHideHd){
45141 var st = new Roo.util.DelayedTask(this.slideIn, this);
45142 this.autoHideHd = {
45143 "mouseout": function(e){
45144 if(!e.within(this.el, true)){
45148 "mouseover" : function(e){
45154 this.el.on(this.autoHideHd);
45158 clearAutoHide : function(){
45159 if(this.autoHide !== false){
45160 this.el.un("mouseout", this.autoHideHd.mouseout);
45161 this.el.un("mouseover", this.autoHideHd.mouseover);
45165 clearMonitor : function(){
45166 Roo.get(document).un("click", this.slideInIf, this);
45169 // these names are backwards but not changed for compat
45170 slideOut : function(){
45171 if(this.isSlid || this.el.hasActiveFx()){
45174 this.isSlid = true;
45175 if(this.collapseBtn){
45176 this.collapseBtn.hide();
45178 this.closeBtnState = this.closeBtn.getStyle('display');
45179 this.closeBtn.hide();
45181 this.stickBtn.show();
45184 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
45185 this.beforeSlide();
45186 this.el.setStyle("z-index", 10001);
45187 this.el.slideIn(this.getSlideAnchor(), {
45188 callback: function(){
45190 this.initAutoHide();
45191 Roo.get(document).on("click", this.slideInIf, this);
45192 this.fireEvent("slideshow", this);
45199 afterSlideIn : function(){
45200 this.clearAutoHide();
45201 this.isSlid = false;
45202 this.clearMonitor();
45203 this.el.setStyle("z-index", "");
45204 if(this.collapseBtn){
45205 this.collapseBtn.show();
45207 this.closeBtn.setStyle('display', this.closeBtnState);
45209 this.stickBtn.hide();
45211 this.fireEvent("slidehide", this);
45214 slideIn : function(cb){
45215 if(!this.isSlid || this.el.hasActiveFx()){
45219 this.isSlid = false;
45220 this.beforeSlide();
45221 this.el.slideOut(this.getSlideAnchor(), {
45222 callback: function(){
45223 this.el.setLeftTop(-10000, -10000);
45225 this.afterSlideIn();
45233 slideInIf : function(e){
45234 if(!e.within(this.el)){
45239 animateCollapse : function(){
45240 this.beforeSlide();
45241 this.el.setStyle("z-index", 20000);
45242 var anchor = this.getSlideAnchor();
45243 this.el.slideOut(anchor, {
45244 callback : function(){
45245 this.el.setStyle("z-index", "");
45246 this.collapsedEl.slideIn(anchor, {duration:.3});
45248 this.el.setLocation(-10000,-10000);
45250 this.fireEvent("collapsed", this);
45257 animateExpand : function(){
45258 this.beforeSlide();
45259 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
45260 this.el.setStyle("z-index", 20000);
45261 this.collapsedEl.hide({
45264 this.el.slideIn(this.getSlideAnchor(), {
45265 callback : function(){
45266 this.el.setStyle("z-index", "");
45269 this.split.el.show();
45271 this.fireEvent("invalidated", this);
45272 this.fireEvent("expanded", this);
45300 getAnchor : function(){
45301 return this.anchors[this.position];
45304 getCollapseAnchor : function(){
45305 return this.canchors[this.position];
45308 getSlideAnchor : function(){
45309 return this.sanchors[this.position];
45312 getAlignAdj : function(){
45313 var cm = this.cmargins;
45314 switch(this.position){
45330 getExpandAdj : function(){
45331 var c = this.collapsedEl, cm = this.cmargins;
45332 switch(this.position){
45334 return [-(cm.right+c.getWidth()+cm.left), 0];
45337 return [cm.right+c.getWidth()+cm.left, 0];
45340 return [0, -(cm.top+cm.bottom+c.getHeight())];
45343 return [0, cm.top+cm.bottom+c.getHeight()];
45349 * Ext JS Library 1.1.1
45350 * Copyright(c) 2006-2007, Ext JS, LLC.
45352 * Originally Released Under LGPL - original licence link has changed is not relivant.
45355 * <script type="text/javascript">
45358 * These classes are private internal classes
45360 Roo.CenterLayoutRegion = function(mgr, config){
45361 Roo.LayoutRegion.call(this, mgr, config, "center");
45362 this.visible = true;
45363 this.minWidth = config.minWidth || 20;
45364 this.minHeight = config.minHeight || 20;
45367 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
45369 // center panel can't be hidden
45373 // center panel can't be hidden
45376 getMinWidth: function(){
45377 return this.minWidth;
45380 getMinHeight: function(){
45381 return this.minHeight;
45386 Roo.NorthLayoutRegion = function(mgr, config){
45387 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
45389 this.split.placement = Roo.SplitBar.TOP;
45390 this.split.orientation = Roo.SplitBar.VERTICAL;
45391 this.split.el.addClass("x-layout-split-v");
45393 var size = config.initialSize || config.height;
45394 if(typeof size != "undefined"){
45395 this.el.setHeight(size);
45398 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
45399 orientation: Roo.SplitBar.VERTICAL,
45400 getBox : function(){
45401 if(this.collapsed){
45402 return this.collapsedEl.getBox();
45404 var box = this.el.getBox();
45406 box.height += this.split.el.getHeight();
45411 updateBox : function(box){
45412 if(this.split && !this.collapsed){
45413 box.height -= this.split.el.getHeight();
45414 this.split.el.setLeft(box.x);
45415 this.split.el.setTop(box.y+box.height);
45416 this.split.el.setWidth(box.width);
45418 if(this.collapsed){
45419 this.updateBody(box.width, null);
45421 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45425 Roo.SouthLayoutRegion = function(mgr, config){
45426 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
45428 this.split.placement = Roo.SplitBar.BOTTOM;
45429 this.split.orientation = Roo.SplitBar.VERTICAL;
45430 this.split.el.addClass("x-layout-split-v");
45432 var size = config.initialSize || config.height;
45433 if(typeof size != "undefined"){
45434 this.el.setHeight(size);
45437 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
45438 orientation: Roo.SplitBar.VERTICAL,
45439 getBox : function(){
45440 if(this.collapsed){
45441 return this.collapsedEl.getBox();
45443 var box = this.el.getBox();
45445 var sh = this.split.el.getHeight();
45452 updateBox : function(box){
45453 if(this.split && !this.collapsed){
45454 var sh = this.split.el.getHeight();
45457 this.split.el.setLeft(box.x);
45458 this.split.el.setTop(box.y-sh);
45459 this.split.el.setWidth(box.width);
45461 if(this.collapsed){
45462 this.updateBody(box.width, null);
45464 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45468 Roo.EastLayoutRegion = function(mgr, config){
45469 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
45471 this.split.placement = Roo.SplitBar.RIGHT;
45472 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45473 this.split.el.addClass("x-layout-split-h");
45475 var size = config.initialSize || config.width;
45476 if(typeof size != "undefined"){
45477 this.el.setWidth(size);
45480 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
45481 orientation: Roo.SplitBar.HORIZONTAL,
45482 getBox : function(){
45483 if(this.collapsed){
45484 return this.collapsedEl.getBox();
45486 var box = this.el.getBox();
45488 var sw = this.split.el.getWidth();
45495 updateBox : function(box){
45496 if(this.split && !this.collapsed){
45497 var sw = this.split.el.getWidth();
45499 this.split.el.setLeft(box.x);
45500 this.split.el.setTop(box.y);
45501 this.split.el.setHeight(box.height);
45504 if(this.collapsed){
45505 this.updateBody(null, box.height);
45507 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45511 Roo.WestLayoutRegion = function(mgr, config){
45512 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
45514 this.split.placement = Roo.SplitBar.LEFT;
45515 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45516 this.split.el.addClass("x-layout-split-h");
45518 var size = config.initialSize || config.width;
45519 if(typeof size != "undefined"){
45520 this.el.setWidth(size);
45523 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
45524 orientation: Roo.SplitBar.HORIZONTAL,
45525 getBox : function(){
45526 if(this.collapsed){
45527 return this.collapsedEl.getBox();
45529 var box = this.el.getBox();
45531 box.width += this.split.el.getWidth();
45536 updateBox : function(box){
45537 if(this.split && !this.collapsed){
45538 var sw = this.split.el.getWidth();
45540 this.split.el.setLeft(box.x+box.width);
45541 this.split.el.setTop(box.y);
45542 this.split.el.setHeight(box.height);
45544 if(this.collapsed){
45545 this.updateBody(null, box.height);
45547 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45552 * Ext JS Library 1.1.1
45553 * Copyright(c) 2006-2007, Ext JS, LLC.
45555 * Originally Released Under LGPL - original licence link has changed is not relivant.
45558 * <script type="text/javascript">
45563 * Private internal class for reading and applying state
45565 Roo.LayoutStateManager = function(layout){
45566 // default empty state
45575 Roo.LayoutStateManager.prototype = {
45576 init : function(layout, provider){
45577 this.provider = provider;
45578 var state = provider.get(layout.id+"-layout-state");
45580 var wasUpdating = layout.isUpdating();
45582 layout.beginUpdate();
45584 for(var key in state){
45585 if(typeof state[key] != "function"){
45586 var rstate = state[key];
45587 var r = layout.getRegion(key);
45590 r.resizeTo(rstate.size);
45592 if(rstate.collapsed == true){
45595 r.expand(null, true);
45601 layout.endUpdate();
45603 this.state = state;
45605 this.layout = layout;
45606 layout.on("regionresized", this.onRegionResized, this);
45607 layout.on("regioncollapsed", this.onRegionCollapsed, this);
45608 layout.on("regionexpanded", this.onRegionExpanded, this);
45611 storeState : function(){
45612 this.provider.set(this.layout.id+"-layout-state", this.state);
45615 onRegionResized : function(region, newSize){
45616 this.state[region.getPosition()].size = newSize;
45620 onRegionCollapsed : function(region){
45621 this.state[region.getPosition()].collapsed = true;
45625 onRegionExpanded : function(region){
45626 this.state[region.getPosition()].collapsed = false;
45631 * Ext JS Library 1.1.1
45632 * Copyright(c) 2006-2007, Ext JS, LLC.
45634 * Originally Released Under LGPL - original licence link has changed is not relivant.
45637 * <script type="text/javascript">
45640 * @class Roo.ContentPanel
45641 * @extends Roo.util.Observable
45642 * A basic ContentPanel element.
45643 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
45644 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
45645 * @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
45646 * @cfg {Boolean} closable True if the panel can be closed/removed
45647 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
45648 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
45649 * @cfg {Toolbar} toolbar A toolbar for this panel
45650 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
45651 * @cfg {String} title The title for this panel
45652 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
45653 * @cfg {String} url Calls {@link #setUrl} with this value
45654 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
45655 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
45656 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
45657 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
45660 * Create a new ContentPanel.
45661 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
45662 * @param {String/Object} config A string to set only the title or a config object
45663 * @param {String} content (optional) Set the HTML content for this panel
45664 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
45666 Roo.ContentPanel = function(el, config, content){
45670 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
45674 if (config && config.parentLayout) {
45675 el = config.parentLayout.el.createChild();
45678 if(el.autoCreate){ // xtype is available if this is called from factory
45682 this.el = Roo.get(el);
45683 if(!this.el && config && config.autoCreate){
45684 if(typeof config.autoCreate == "object"){
45685 if(!config.autoCreate.id){
45686 config.autoCreate.id = config.id||el;
45688 this.el = Roo.DomHelper.append(document.body,
45689 config.autoCreate, true);
45691 this.el = Roo.DomHelper.append(document.body,
45692 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
45695 this.closable = false;
45696 this.loaded = false;
45697 this.active = false;
45698 if(typeof config == "string"){
45699 this.title = config;
45701 Roo.apply(this, config);
45704 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
45705 this.wrapEl = this.el.wrap();
45706 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
45713 this.resizeEl = Roo.get(this.resizeEl, true);
45715 this.resizeEl = this.el;
45720 * Fires when this panel is activated.
45721 * @param {Roo.ContentPanel} this
45725 * @event deactivate
45726 * Fires when this panel is activated.
45727 * @param {Roo.ContentPanel} this
45729 "deactivate" : true,
45733 * Fires when this panel is resized if fitToFrame is true.
45734 * @param {Roo.ContentPanel} this
45735 * @param {Number} width The width after any component adjustments
45736 * @param {Number} height The height after any component adjustments
45740 if(this.autoScroll){
45741 this.resizeEl.setStyle("overflow", "auto");
45743 // fix randome scrolling
45744 this.el.on('scroll', function() {
45745 Roo.log('fix random scolling');
45746 this.scrollTo('top',0);
45749 content = content || this.content;
45751 this.setContent(content);
45753 if(config && config.url){
45754 this.setUrl(this.url, this.params, this.loadOnce);
45759 Roo.ContentPanel.superclass.constructor.call(this);
45762 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
45764 setRegion : function(region){
45765 this.region = region;
45767 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
45769 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
45774 * Returns the toolbar for this Panel if one was configured.
45775 * @return {Roo.Toolbar}
45777 getToolbar : function(){
45778 return this.toolbar;
45781 setActiveState : function(active){
45782 this.active = active;
45784 this.fireEvent("deactivate", this);
45786 this.fireEvent("activate", this);
45790 * Updates this panel's element
45791 * @param {String} content The new content
45792 * @param {Boolean} loadScripts (optional) true to look for and process scripts
45794 setContent : function(content, loadScripts){
45795 this.el.update(content, loadScripts);
45798 ignoreResize : function(w, h){
45799 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
45802 this.lastSize = {width: w, height: h};
45807 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
45808 * @return {Roo.UpdateManager} The UpdateManager
45810 getUpdateManager : function(){
45811 return this.el.getUpdateManager();
45814 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
45815 * @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:
45818 url: "your-url.php",
45819 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
45820 callback: yourFunction,
45821 scope: yourObject, //(optional scope)
45824 text: "Loading...",
45829 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
45830 * 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.
45831 * @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}
45832 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
45833 * @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.
45834 * @return {Roo.ContentPanel} this
45837 var um = this.el.getUpdateManager();
45838 um.update.apply(um, arguments);
45844 * 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.
45845 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
45846 * @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)
45847 * @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)
45848 * @return {Roo.UpdateManager} The UpdateManager
45850 setUrl : function(url, params, loadOnce){
45851 if(this.refreshDelegate){
45852 this.removeListener("activate", this.refreshDelegate);
45854 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
45855 this.on("activate", this.refreshDelegate);
45856 return this.el.getUpdateManager();
45859 _handleRefresh : function(url, params, loadOnce){
45860 if(!loadOnce || !this.loaded){
45861 var updater = this.el.getUpdateManager();
45862 updater.update(url, params, this._setLoaded.createDelegate(this));
45866 _setLoaded : function(){
45867 this.loaded = true;
45871 * Returns this panel's id
45874 getId : function(){
45879 * Returns this panel's element - used by regiosn to add.
45880 * @return {Roo.Element}
45882 getEl : function(){
45883 return this.wrapEl || this.el;
45886 adjustForComponents : function(width, height){
45887 if(this.resizeEl != this.el){
45888 width -= this.el.getFrameWidth('lr');
45889 height -= this.el.getFrameWidth('tb');
45892 var te = this.toolbar.getEl();
45893 height -= te.getHeight();
45894 te.setWidth(width);
45896 if(this.adjustments){
45897 width += this.adjustments[0];
45898 height += this.adjustments[1];
45900 return {"width": width, "height": height};
45903 setSize : function(width, height){
45904 if(this.fitToFrame && !this.ignoreResize(width, height)){
45905 if(this.fitContainer && this.resizeEl != this.el){
45906 this.el.setSize(width, height);
45908 var size = this.adjustForComponents(width, height);
45909 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
45910 this.fireEvent('resize', this, size.width, size.height);
45915 * Returns this panel's title
45918 getTitle : function(){
45923 * Set this panel's title
45924 * @param {String} title
45926 setTitle : function(title){
45927 this.title = title;
45929 this.region.updatePanelTitle(this, title);
45934 * Returns true is this panel was configured to be closable
45935 * @return {Boolean}
45937 isClosable : function(){
45938 return this.closable;
45941 beforeSlide : function(){
45943 this.resizeEl.clip();
45946 afterSlide : function(){
45948 this.resizeEl.unclip();
45952 * Force a content refresh from the URL specified in the {@link #setUrl} method.
45953 * Will fail silently if the {@link #setUrl} method has not been called.
45954 * This does not activate the panel, just updates its content.
45956 refresh : function(){
45957 if(this.refreshDelegate){
45958 this.loaded = false;
45959 this.refreshDelegate();
45964 * Destroys this panel
45966 destroy : function(){
45967 this.el.removeAllListeners();
45968 var tempEl = document.createElement("span");
45969 tempEl.appendChild(this.el.dom);
45970 tempEl.innerHTML = "";
45976 * form - if the content panel contains a form - this is a reference to it.
45977 * @type {Roo.form.Form}
45981 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
45982 * This contains a reference to it.
45988 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
45998 * @param {Object} cfg Xtype definition of item to add.
46001 addxtype : function(cfg) {
46003 if (cfg.xtype.match(/^Form$/)) {
46004 var el = this.el.createChild();
46006 this.form = new Roo.form.Form(cfg);
46009 if ( this.form.allItems.length) this.form.render(el.dom);
46012 // should only have one of theses..
46013 if (['View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
46015 cfg.el = this.el.appendChild(document.createElement("div"));
46017 var ret = new Roo[cfg.xtype](cfg);
46018 ret.render && ret.render(false, ''); // render blank..
46027 * @class Roo.GridPanel
46028 * @extends Roo.ContentPanel
46030 * Create a new GridPanel.
46031 * @param {Roo.grid.Grid} grid The grid for this panel
46032 * @param {String/Object} config A string to set only the panel's title, or a config object
46034 Roo.GridPanel = function(grid, config){
46037 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
46038 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
46040 this.wrapper.dom.appendChild(grid.getGridEl().dom);
46042 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
46045 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
46047 // xtype created footer. - not sure if will work as we normally have to render first..
46048 if (this.footer && !this.footer.el && this.footer.xtype) {
46050 this.footer.container = this.grid.getView().getFooterPanel(true);
46051 this.footer.dataSource = this.grid.dataSource;
46052 this.footer = Roo.factory(this.footer, Roo);
46056 grid.monitorWindowResize = false; // turn off autosizing
46057 grid.autoHeight = false;
46058 grid.autoWidth = false;
46060 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
46063 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
46064 getId : function(){
46065 return this.grid.id;
46069 * Returns the grid for this panel
46070 * @return {Roo.grid.Grid}
46072 getGrid : function(){
46076 setSize : function(width, height){
46077 if(!this.ignoreResize(width, height)){
46078 var grid = this.grid;
46079 var size = this.adjustForComponents(width, height);
46080 grid.getGridEl().setSize(size.width, size.height);
46085 beforeSlide : function(){
46086 this.grid.getView().scroller.clip();
46089 afterSlide : function(){
46090 this.grid.getView().scroller.unclip();
46093 destroy : function(){
46094 this.grid.destroy();
46096 Roo.GridPanel.superclass.destroy.call(this);
46102 * @class Roo.NestedLayoutPanel
46103 * @extends Roo.ContentPanel
46105 * Create a new NestedLayoutPanel.
46108 * @param {Roo.BorderLayout} layout The layout for this panel
46109 * @param {String/Object} config A string to set only the title or a config object
46111 Roo.NestedLayoutPanel = function(layout, config)
46113 // construct with only one argument..
46114 /* FIXME - implement nicer consturctors
46115 if (layout.layout) {
46117 layout = config.layout;
46118 delete config.layout;
46120 if (layout.xtype && !layout.getEl) {
46121 // then layout needs constructing..
46122 layout = Roo.factory(layout, Roo);
46127 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
46129 layout.monitorWindowResize = false; // turn off autosizing
46130 this.layout = layout;
46131 this.layout.getEl().addClass("x-layout-nested-layout");
46138 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
46140 setSize : function(width, height){
46141 if(!this.ignoreResize(width, height)){
46142 var size = this.adjustForComponents(width, height);
46143 var el = this.layout.getEl();
46144 el.setSize(size.width, size.height);
46145 var touch = el.dom.offsetWidth;
46146 this.layout.layout();
46147 // ie requires a double layout on the first pass
46148 if(Roo.isIE && !this.initialized){
46149 this.initialized = true;
46150 this.layout.layout();
46155 // activate all subpanels if not currently active..
46157 setActiveState : function(active){
46158 this.active = active;
46160 this.fireEvent("deactivate", this);
46164 this.fireEvent("activate", this);
46165 // not sure if this should happen before or after..
46166 if (!this.layout) {
46167 return; // should not happen..
46170 for (var r in this.layout.regions) {
46171 reg = this.layout.getRegion(r);
46172 if (reg.getActivePanel()) {
46173 //reg.showPanel(reg.getActivePanel()); // force it to activate..
46174 reg.setActivePanel(reg.getActivePanel());
46177 if (!reg.panels.length) {
46180 reg.showPanel(reg.getPanel(0));
46189 * Returns the nested BorderLayout for this panel
46190 * @return {Roo.BorderLayout}
46192 getLayout : function(){
46193 return this.layout;
46197 * Adds a xtype elements to the layout of the nested panel
46201 xtype : 'ContentPanel',
46208 xtype : 'NestedLayoutPanel',
46214 items : [ ... list of content panels or nested layout panels.. ]
46218 * @param {Object} cfg Xtype definition of item to add.
46220 addxtype : function(cfg) {
46221 return this.layout.addxtype(cfg);
46226 Roo.ScrollPanel = function(el, config, content){
46227 config = config || {};
46228 config.fitToFrame = true;
46229 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
46231 this.el.dom.style.overflow = "hidden";
46232 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
46233 this.el.removeClass("x-layout-inactive-content");
46234 this.el.on("mousewheel", this.onWheel, this);
46236 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
46237 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
46238 up.unselectable(); down.unselectable();
46239 up.on("click", this.scrollUp, this);
46240 down.on("click", this.scrollDown, this);
46241 up.addClassOnOver("x-scroller-btn-over");
46242 down.addClassOnOver("x-scroller-btn-over");
46243 up.addClassOnClick("x-scroller-btn-click");
46244 down.addClassOnClick("x-scroller-btn-click");
46245 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
46247 this.resizeEl = this.el;
46248 this.el = wrap; this.up = up; this.down = down;
46251 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
46253 wheelIncrement : 5,
46254 scrollUp : function(){
46255 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
46258 scrollDown : function(){
46259 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
46262 afterScroll : function(){
46263 var el = this.resizeEl;
46264 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
46265 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
46266 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
46269 setSize : function(){
46270 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
46271 this.afterScroll();
46274 onWheel : function(e){
46275 var d = e.getWheelDelta();
46276 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
46277 this.afterScroll();
46281 setContent : function(content, loadScripts){
46282 this.resizeEl.update(content, loadScripts);
46296 * @class Roo.TreePanel
46297 * @extends Roo.ContentPanel
46299 * Create a new TreePanel. - defaults to fit/scoll contents.
46300 * @param {String/Object} config A string to set only the panel's title, or a config object
46301 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
46303 Roo.TreePanel = function(config){
46304 var el = config.el;
46305 var tree = config.tree;
46306 delete config.tree;
46307 delete config.el; // hopefull!
46309 // wrapper for IE7 strict & safari scroll issue
46311 var treeEl = el.createChild();
46312 config.resizeEl = treeEl;
46316 Roo.TreePanel.superclass.constructor.call(this, el, config);
46319 this.tree = new Roo.tree.TreePanel(treeEl , tree);
46320 //console.log(tree);
46321 this.on('activate', function()
46323 if (this.tree.rendered) {
46326 //console.log('render tree');
46327 this.tree.render();
46330 this.on('resize', function (cp, w, h) {
46331 this.tree.innerCt.setWidth(w);
46332 this.tree.innerCt.setHeight(h);
46333 this.tree.innerCt.setStyle('overflow-y', 'auto');
46340 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
46357 * Ext JS Library 1.1.1
46358 * Copyright(c) 2006-2007, Ext JS, LLC.
46360 * Originally Released Under LGPL - original licence link has changed is not relivant.
46363 * <script type="text/javascript">
46368 * @class Roo.ReaderLayout
46369 * @extends Roo.BorderLayout
46370 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
46371 * center region containing two nested regions (a top one for a list view and one for item preview below),
46372 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
46373 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
46374 * expedites the setup of the overall layout and regions for this common application style.
46377 var reader = new Roo.ReaderLayout();
46378 var CP = Roo.ContentPanel; // shortcut for adding
46380 reader.beginUpdate();
46381 reader.add("north", new CP("north", "North"));
46382 reader.add("west", new CP("west", {title: "West"}));
46383 reader.add("east", new CP("east", {title: "East"}));
46385 reader.regions.listView.add(new CP("listView", "List"));
46386 reader.regions.preview.add(new CP("preview", "Preview"));
46387 reader.endUpdate();
46390 * Create a new ReaderLayout
46391 * @param {Object} config Configuration options
46392 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
46393 * document.body if omitted)
46395 Roo.ReaderLayout = function(config, renderTo){
46396 var c = config || {size:{}};
46397 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
46398 north: c.north !== false ? Roo.apply({
46402 }, c.north) : false,
46403 west: c.west !== false ? Roo.apply({
46411 margins:{left:5,right:0,bottom:5,top:5},
46412 cmargins:{left:5,right:5,bottom:5,top:5}
46413 }, c.west) : false,
46414 east: c.east !== false ? Roo.apply({
46422 margins:{left:0,right:5,bottom:5,top:5},
46423 cmargins:{left:5,right:5,bottom:5,top:5}
46424 }, c.east) : false,
46425 center: Roo.apply({
46426 tabPosition: 'top',
46430 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
46434 this.el.addClass('x-reader');
46436 this.beginUpdate();
46438 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
46439 south: c.preview !== false ? Roo.apply({
46446 cmargins:{top:5,left:0, right:0, bottom:0}
46447 }, c.preview) : false,
46448 center: Roo.apply({
46454 this.add('center', new Roo.NestedLayoutPanel(inner,
46455 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
46459 this.regions.preview = inner.getRegion('south');
46460 this.regions.listView = inner.getRegion('center');
46463 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
46465 * Ext JS Library 1.1.1
46466 * Copyright(c) 2006-2007, Ext JS, LLC.
46468 * Originally Released Under LGPL - original licence link has changed is not relivant.
46471 * <script type="text/javascript">
46475 * @class Roo.grid.Grid
46476 * @extends Roo.util.Observable
46477 * This class represents the primary interface of a component based grid control.
46478 * <br><br>Usage:<pre><code>
46479 var grid = new Roo.grid.Grid("my-container-id", {
46482 selModel: mySelectionModel,
46483 autoSizeColumns: true,
46484 monitorWindowResize: false,
46485 trackMouseOver: true
46490 * <b>Common Problems:</b><br/>
46491 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
46492 * element will correct this<br/>
46493 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
46494 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
46495 * are unpredictable.<br/>
46496 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
46497 * grid to calculate dimensions/offsets.<br/>
46499 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
46500 * The container MUST have some type of size defined for the grid to fill. The container will be
46501 * automatically set to position relative if it isn't already.
46502 * @param {Object} config A config object that sets properties on this grid.
46504 Roo.grid.Grid = function(container, config){
46505 // initialize the container
46506 this.container = Roo.get(container);
46507 this.container.update("");
46508 this.container.setStyle("overflow", "hidden");
46509 this.container.addClass('x-grid-container');
46511 this.id = this.container.id;
46513 Roo.apply(this, config);
46514 // check and correct shorthanded configs
46516 this.dataSource = this.ds;
46520 this.colModel = this.cm;
46524 this.selModel = this.sm;
46528 if (this.selModel) {
46529 this.selModel = Roo.factory(this.selModel, Roo.grid);
46530 this.sm = this.selModel;
46531 this.sm.xmodule = this.xmodule || false;
46533 if (typeof(this.colModel.config) == 'undefined') {
46534 this.colModel = new Roo.grid.ColumnModel(this.colModel);
46535 this.cm = this.colModel;
46536 this.cm.xmodule = this.xmodule || false;
46538 if (this.dataSource) {
46539 this.dataSource= Roo.factory(this.dataSource, Roo.data);
46540 this.ds = this.dataSource;
46541 this.ds.xmodule = this.xmodule || false;
46548 this.container.setWidth(this.width);
46552 this.container.setHeight(this.height);
46559 * The raw click event for the entire grid.
46560 * @param {Roo.EventObject} e
46565 * The raw dblclick event for the entire grid.
46566 * @param {Roo.EventObject} e
46570 * @event contextmenu
46571 * The raw contextmenu event for the entire grid.
46572 * @param {Roo.EventObject} e
46574 "contextmenu" : true,
46577 * The raw mousedown event for the entire grid.
46578 * @param {Roo.EventObject} e
46580 "mousedown" : true,
46583 * The raw mouseup event for the entire grid.
46584 * @param {Roo.EventObject} e
46589 * The raw mouseover event for the entire grid.
46590 * @param {Roo.EventObject} e
46592 "mouseover" : true,
46595 * The raw mouseout event for the entire grid.
46596 * @param {Roo.EventObject} e
46601 * The raw keypress event for the entire grid.
46602 * @param {Roo.EventObject} e
46607 * The raw keydown event for the entire grid.
46608 * @param {Roo.EventObject} e
46616 * Fires when a cell is clicked
46617 * @param {Grid} this
46618 * @param {Number} rowIndex
46619 * @param {Number} columnIndex
46620 * @param {Roo.EventObject} e
46622 "cellclick" : true,
46624 * @event celldblclick
46625 * Fires when a cell is double clicked
46626 * @param {Grid} this
46627 * @param {Number} rowIndex
46628 * @param {Number} columnIndex
46629 * @param {Roo.EventObject} e
46631 "celldblclick" : true,
46634 * Fires when a row is clicked
46635 * @param {Grid} this
46636 * @param {Number} rowIndex
46637 * @param {Roo.EventObject} e
46641 * @event rowdblclick
46642 * Fires when a row is double clicked
46643 * @param {Grid} this
46644 * @param {Number} rowIndex
46645 * @param {Roo.EventObject} e
46647 "rowdblclick" : true,
46649 * @event headerclick
46650 * Fires when a header is clicked
46651 * @param {Grid} this
46652 * @param {Number} columnIndex
46653 * @param {Roo.EventObject} e
46655 "headerclick" : true,
46657 * @event headerdblclick
46658 * Fires when a header cell is double clicked
46659 * @param {Grid} this
46660 * @param {Number} columnIndex
46661 * @param {Roo.EventObject} e
46663 "headerdblclick" : true,
46665 * @event rowcontextmenu
46666 * Fires when a row is right clicked
46667 * @param {Grid} this
46668 * @param {Number} rowIndex
46669 * @param {Roo.EventObject} e
46671 "rowcontextmenu" : true,
46673 * @event cellcontextmenu
46674 * Fires when a cell is right clicked
46675 * @param {Grid} this
46676 * @param {Number} rowIndex
46677 * @param {Number} cellIndex
46678 * @param {Roo.EventObject} e
46680 "cellcontextmenu" : true,
46682 * @event headercontextmenu
46683 * Fires when a header is right clicked
46684 * @param {Grid} this
46685 * @param {Number} columnIndex
46686 * @param {Roo.EventObject} e
46688 "headercontextmenu" : true,
46690 * @event bodyscroll
46691 * Fires when the body element is scrolled
46692 * @param {Number} scrollLeft
46693 * @param {Number} scrollTop
46695 "bodyscroll" : true,
46697 * @event columnresize
46698 * Fires when the user resizes a column
46699 * @param {Number} columnIndex
46700 * @param {Number} newSize
46702 "columnresize" : true,
46704 * @event columnmove
46705 * Fires when the user moves a column
46706 * @param {Number} oldIndex
46707 * @param {Number} newIndex
46709 "columnmove" : true,
46712 * Fires when row(s) start being dragged
46713 * @param {Grid} this
46714 * @param {Roo.GridDD} dd The drag drop object
46715 * @param {event} e The raw browser event
46717 "startdrag" : true,
46720 * Fires when a drag operation is complete
46721 * @param {Grid} this
46722 * @param {Roo.GridDD} dd The drag drop object
46723 * @param {event} e The raw browser event
46728 * Fires when dragged row(s) are dropped on a valid DD target
46729 * @param {Grid} this
46730 * @param {Roo.GridDD} dd The drag drop object
46731 * @param {String} targetId The target drag drop object
46732 * @param {event} e The raw browser event
46737 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
46738 * @param {Grid} this
46739 * @param {Roo.GridDD} dd The drag drop object
46740 * @param {String} targetId The target drag drop object
46741 * @param {event} e The raw browser event
46746 * Fires when the dragged row(s) first cross another DD target while being dragged
46747 * @param {Grid} this
46748 * @param {Roo.GridDD} dd The drag drop object
46749 * @param {String} targetId The target drag drop object
46750 * @param {event} e The raw browser event
46752 "dragenter" : true,
46755 * Fires when the dragged row(s) leave another DD target while being dragged
46756 * @param {Grid} this
46757 * @param {Roo.GridDD} dd The drag drop object
46758 * @param {String} targetId The target drag drop object
46759 * @param {event} e The raw browser event
46764 * Fires when a row is rendered, so you can change add a style to it.
46765 * @param {GridView} gridview The grid view
46766 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
46772 * Fires when the grid is rendered
46773 * @param {Grid} grid
46778 Roo.grid.Grid.superclass.constructor.call(this);
46780 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
46783 * @cfg {String} ddGroup - drag drop group.
46787 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
46789 minColumnWidth : 25,
46792 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
46793 * <b>on initial render.</b> It is more efficient to explicitly size the columns
46794 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
46796 autoSizeColumns : false,
46799 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
46801 autoSizeHeaders : true,
46804 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
46806 monitorWindowResize : true,
46809 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
46810 * rows measured to get a columns size. Default is 0 (all rows).
46812 maxRowsToMeasure : 0,
46815 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
46817 trackMouseOver : true,
46820 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
46824 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
46826 enableDragDrop : false,
46829 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
46831 enableColumnMove : true,
46834 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
46836 enableColumnHide : true,
46839 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
46841 enableRowHeightSync : false,
46844 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
46849 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
46851 autoHeight : false,
46854 * @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.
46856 autoExpandColumn : false,
46859 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
46862 autoExpandMin : 50,
46865 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
46867 autoExpandMax : 1000,
46870 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
46875 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
46879 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
46889 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
46890 * of a fixed width. Default is false.
46893 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
46896 * Called once after all setup has been completed and the grid is ready to be rendered.
46897 * @return {Roo.grid.Grid} this
46899 render : function()
46901 var c = this.container;
46902 // try to detect autoHeight/width mode
46903 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
46904 this.autoHeight = true;
46906 var view = this.getView();
46909 c.on("click", this.onClick, this);
46910 c.on("dblclick", this.onDblClick, this);
46911 c.on("contextmenu", this.onContextMenu, this);
46912 c.on("keydown", this.onKeyDown, this);
46914 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
46916 this.getSelectionModel().init(this);
46921 this.loadMask = new Roo.LoadMask(this.container,
46922 Roo.apply({store:this.dataSource}, this.loadMask));
46926 if (this.toolbar && this.toolbar.xtype) {
46927 this.toolbar.container = this.getView().getHeaderPanel(true);
46928 this.toolbar = new Roo.Toolbar(this.toolbar);
46930 if (this.footer && this.footer.xtype) {
46931 this.footer.dataSource = this.getDataSource();
46932 this.footer.container = this.getView().getFooterPanel(true);
46933 this.footer = Roo.factory(this.footer, Roo);
46935 if (this.dropTarget && this.dropTarget.xtype) {
46936 delete this.dropTarget.xtype;
46937 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
46941 this.rendered = true;
46942 this.fireEvent('render', this);
46947 * Reconfigures the grid to use a different Store and Column Model.
46948 * The View will be bound to the new objects and refreshed.
46949 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
46950 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
46952 reconfigure : function(dataSource, colModel){
46954 this.loadMask.destroy();
46955 this.loadMask = new Roo.LoadMask(this.container,
46956 Roo.apply({store:dataSource}, this.loadMask));
46958 this.view.bind(dataSource, colModel);
46959 this.dataSource = dataSource;
46960 this.colModel = colModel;
46961 this.view.refresh(true);
46965 onKeyDown : function(e){
46966 this.fireEvent("keydown", e);
46970 * Destroy this grid.
46971 * @param {Boolean} removeEl True to remove the element
46973 destroy : function(removeEl, keepListeners){
46975 this.loadMask.destroy();
46977 var c = this.container;
46978 c.removeAllListeners();
46979 this.view.destroy();
46980 this.colModel.purgeListeners();
46981 if(!keepListeners){
46982 this.purgeListeners();
46985 if(removeEl === true){
46991 processEvent : function(name, e){
46992 this.fireEvent(name, e);
46993 var t = e.getTarget();
46995 var header = v.findHeaderIndex(t);
46996 if(header !== false){
46997 this.fireEvent("header" + name, this, header, e);
46999 var row = v.findRowIndex(t);
47000 var cell = v.findCellIndex(t);
47002 this.fireEvent("row" + name, this, row, e);
47003 if(cell !== false){
47004 this.fireEvent("cell" + name, this, row, cell, e);
47011 onClick : function(e){
47012 this.processEvent("click", e);
47016 onContextMenu : function(e, t){
47017 this.processEvent("contextmenu", e);
47021 onDblClick : function(e){
47022 this.processEvent("dblclick", e);
47026 walkCells : function(row, col, step, fn, scope){
47027 var cm = this.colModel, clen = cm.getColumnCount();
47028 var ds = this.dataSource, rlen = ds.getCount(), first = true;
47040 if(fn.call(scope || this, row, col, cm) === true){
47058 if(fn.call(scope || this, row, col, cm) === true){
47070 getSelections : function(){
47071 return this.selModel.getSelections();
47075 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
47076 * but if manual update is required this method will initiate it.
47078 autoSize : function(){
47080 this.view.layout();
47081 if(this.view.adjustForScroll){
47082 this.view.adjustForScroll();
47088 * Returns the grid's underlying element.
47089 * @return {Element} The element
47091 getGridEl : function(){
47092 return this.container;
47095 // private for compatibility, overridden by editor grid
47096 stopEditing : function(){},
47099 * Returns the grid's SelectionModel.
47100 * @return {SelectionModel}
47102 getSelectionModel : function(){
47103 if(!this.selModel){
47104 this.selModel = new Roo.grid.RowSelectionModel();
47106 return this.selModel;
47110 * Returns the grid's DataSource.
47111 * @return {DataSource}
47113 getDataSource : function(){
47114 return this.dataSource;
47118 * Returns the grid's ColumnModel.
47119 * @return {ColumnModel}
47121 getColumnModel : function(){
47122 return this.colModel;
47126 * Returns the grid's GridView object.
47127 * @return {GridView}
47129 getView : function(){
47131 this.view = new Roo.grid.GridView(this.viewConfig);
47136 * Called to get grid's drag proxy text, by default returns this.ddText.
47139 getDragDropText : function(){
47140 var count = this.selModel.getCount();
47141 return String.format(this.ddText, count, count == 1 ? '' : 's');
47145 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
47146 * %0 is replaced with the number of selected rows.
47149 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
47151 * Ext JS Library 1.1.1
47152 * Copyright(c) 2006-2007, Ext JS, LLC.
47154 * Originally Released Under LGPL - original licence link has changed is not relivant.
47157 * <script type="text/javascript">
47160 Roo.grid.AbstractGridView = function(){
47164 "beforerowremoved" : true,
47165 "beforerowsinserted" : true,
47166 "beforerefresh" : true,
47167 "rowremoved" : true,
47168 "rowsinserted" : true,
47169 "rowupdated" : true,
47172 Roo.grid.AbstractGridView.superclass.constructor.call(this);
47175 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
47176 rowClass : "x-grid-row",
47177 cellClass : "x-grid-cell",
47178 tdClass : "x-grid-td",
47179 hdClass : "x-grid-hd",
47180 splitClass : "x-grid-hd-split",
47182 init: function(grid){
47184 var cid = this.grid.getGridEl().id;
47185 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
47186 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
47187 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
47188 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
47191 getColumnRenderers : function(){
47192 var renderers = [];
47193 var cm = this.grid.colModel;
47194 var colCount = cm.getColumnCount();
47195 for(var i = 0; i < colCount; i++){
47196 renderers[i] = cm.getRenderer(i);
47201 getColumnIds : function(){
47203 var cm = this.grid.colModel;
47204 var colCount = cm.getColumnCount();
47205 for(var i = 0; i < colCount; i++){
47206 ids[i] = cm.getColumnId(i);
47211 getDataIndexes : function(){
47212 if(!this.indexMap){
47213 this.indexMap = this.buildIndexMap();
47215 return this.indexMap.colToData;
47218 getColumnIndexByDataIndex : function(dataIndex){
47219 if(!this.indexMap){
47220 this.indexMap = this.buildIndexMap();
47222 return this.indexMap.dataToCol[dataIndex];
47226 * Set a css style for a column dynamically.
47227 * @param {Number} colIndex The index of the column
47228 * @param {String} name The css property name
47229 * @param {String} value The css value
47231 setCSSStyle : function(colIndex, name, value){
47232 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
47233 Roo.util.CSS.updateRule(selector, name, value);
47236 generateRules : function(cm){
47237 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
47238 Roo.util.CSS.removeStyleSheet(rulesId);
47239 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47240 var cid = cm.getColumnId(i);
47241 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
47242 this.tdSelector, cid, " {\n}\n",
47243 this.hdSelector, cid, " {\n}\n",
47244 this.splitSelector, cid, " {\n}\n");
47246 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
47250 * Ext JS Library 1.1.1
47251 * Copyright(c) 2006-2007, Ext JS, LLC.
47253 * Originally Released Under LGPL - original licence link has changed is not relivant.
47256 * <script type="text/javascript">
47260 // This is a support class used internally by the Grid components
47261 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
47263 this.view = grid.getView();
47264 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
47265 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
47267 this.setHandleElId(Roo.id(hd));
47268 this.setOuterHandleElId(Roo.id(hd2));
47270 this.scroll = false;
47272 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
47274 getDragData : function(e){
47275 var t = Roo.lib.Event.getTarget(e);
47276 var h = this.view.findHeaderCell(t);
47278 return {ddel: h.firstChild, header:h};
47283 onInitDrag : function(e){
47284 this.view.headersDisabled = true;
47285 var clone = this.dragData.ddel.cloneNode(true);
47286 clone.id = Roo.id();
47287 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
47288 this.proxy.update(clone);
47292 afterValidDrop : function(){
47294 setTimeout(function(){
47295 v.headersDisabled = false;
47299 afterInvalidDrop : function(){
47301 setTimeout(function(){
47302 v.headersDisabled = false;
47308 * Ext JS Library 1.1.1
47309 * Copyright(c) 2006-2007, Ext JS, LLC.
47311 * Originally Released Under LGPL - original licence link has changed is not relivant.
47314 * <script type="text/javascript">
47317 // This is a support class used internally by the Grid components
47318 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
47320 this.view = grid.getView();
47321 // split the proxies so they don't interfere with mouse events
47322 this.proxyTop = Roo.DomHelper.append(document.body, {
47323 cls:"col-move-top", html:" "
47325 this.proxyBottom = Roo.DomHelper.append(document.body, {
47326 cls:"col-move-bottom", html:" "
47328 this.proxyTop.hide = this.proxyBottom.hide = function(){
47329 this.setLeftTop(-100,-100);
47330 this.setStyle("visibility", "hidden");
47332 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
47333 // temporarily disabled
47334 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
47335 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
47337 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
47338 proxyOffsets : [-4, -9],
47339 fly: Roo.Element.fly,
47341 getTargetFromEvent : function(e){
47342 var t = Roo.lib.Event.getTarget(e);
47343 var cindex = this.view.findCellIndex(t);
47344 if(cindex !== false){
47345 return this.view.getHeaderCell(cindex);
47350 nextVisible : function(h){
47351 var v = this.view, cm = this.grid.colModel;
47354 if(!cm.isHidden(v.getCellIndex(h))){
47362 prevVisible : function(h){
47363 var v = this.view, cm = this.grid.colModel;
47366 if(!cm.isHidden(v.getCellIndex(h))){
47374 positionIndicator : function(h, n, e){
47375 var x = Roo.lib.Event.getPageX(e);
47376 var r = Roo.lib.Dom.getRegion(n.firstChild);
47377 var px, pt, py = r.top + this.proxyOffsets[1];
47378 if((r.right - x) <= (r.right-r.left)/2){
47379 px = r.right+this.view.borderWidth;
47385 var oldIndex = this.view.getCellIndex(h);
47386 var newIndex = this.view.getCellIndex(n);
47388 if(this.grid.colModel.isFixed(newIndex)){
47392 var locked = this.grid.colModel.isLocked(newIndex);
47397 if(oldIndex < newIndex){
47400 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
47403 px += this.proxyOffsets[0];
47404 this.proxyTop.setLeftTop(px, py);
47405 this.proxyTop.show();
47406 if(!this.bottomOffset){
47407 this.bottomOffset = this.view.mainHd.getHeight();
47409 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
47410 this.proxyBottom.show();
47414 onNodeEnter : function(n, dd, e, data){
47415 if(data.header != n){
47416 this.positionIndicator(data.header, n, e);
47420 onNodeOver : function(n, dd, e, data){
47421 var result = false;
47422 if(data.header != n){
47423 result = this.positionIndicator(data.header, n, e);
47426 this.proxyTop.hide();
47427 this.proxyBottom.hide();
47429 return result ? this.dropAllowed : this.dropNotAllowed;
47432 onNodeOut : function(n, dd, e, data){
47433 this.proxyTop.hide();
47434 this.proxyBottom.hide();
47437 onNodeDrop : function(n, dd, e, data){
47438 var h = data.header;
47440 var cm = this.grid.colModel;
47441 var x = Roo.lib.Event.getPageX(e);
47442 var r = Roo.lib.Dom.getRegion(n.firstChild);
47443 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
47444 var oldIndex = this.view.getCellIndex(h);
47445 var newIndex = this.view.getCellIndex(n);
47446 var locked = cm.isLocked(newIndex);
47450 if(oldIndex < newIndex){
47453 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
47456 cm.setLocked(oldIndex, locked, true);
47457 cm.moveColumn(oldIndex, newIndex);
47458 this.grid.fireEvent("columnmove", oldIndex, newIndex);
47466 * Ext JS Library 1.1.1
47467 * Copyright(c) 2006-2007, Ext JS, LLC.
47469 * Originally Released Under LGPL - original licence link has changed is not relivant.
47472 * <script type="text/javascript">
47476 * @class Roo.grid.GridView
47477 * @extends Roo.util.Observable
47480 * @param {Object} config
47482 Roo.grid.GridView = function(config){
47483 Roo.grid.GridView.superclass.constructor.call(this);
47486 Roo.apply(this, config);
47489 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
47492 * Override this function to apply custom css classes to rows during rendering
47493 * @param {Record} record The record
47494 * @param {Number} index
47495 * @method getRowClass
47497 rowClass : "x-grid-row",
47499 cellClass : "x-grid-col",
47501 tdClass : "x-grid-td",
47503 hdClass : "x-grid-hd",
47505 splitClass : "x-grid-split",
47507 sortClasses : ["sort-asc", "sort-desc"],
47509 enableMoveAnim : false,
47513 dh : Roo.DomHelper,
47515 fly : Roo.Element.fly,
47517 css : Roo.util.CSS,
47523 scrollIncrement : 22,
47525 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
47527 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
47529 bind : function(ds, cm){
47531 this.ds.un("load", this.onLoad, this);
47532 this.ds.un("datachanged", this.onDataChange, this);
47533 this.ds.un("add", this.onAdd, this);
47534 this.ds.un("remove", this.onRemove, this);
47535 this.ds.un("update", this.onUpdate, this);
47536 this.ds.un("clear", this.onClear, this);
47539 ds.on("load", this.onLoad, this);
47540 ds.on("datachanged", this.onDataChange, this);
47541 ds.on("add", this.onAdd, this);
47542 ds.on("remove", this.onRemove, this);
47543 ds.on("update", this.onUpdate, this);
47544 ds.on("clear", this.onClear, this);
47549 this.cm.un("widthchange", this.onColWidthChange, this);
47550 this.cm.un("headerchange", this.onHeaderChange, this);
47551 this.cm.un("hiddenchange", this.onHiddenChange, this);
47552 this.cm.un("columnmoved", this.onColumnMove, this);
47553 this.cm.un("columnlockchange", this.onColumnLock, this);
47556 this.generateRules(cm);
47557 cm.on("widthchange", this.onColWidthChange, this);
47558 cm.on("headerchange", this.onHeaderChange, this);
47559 cm.on("hiddenchange", this.onHiddenChange, this);
47560 cm.on("columnmoved", this.onColumnMove, this);
47561 cm.on("columnlockchange", this.onColumnLock, this);
47566 init: function(grid){
47567 Roo.grid.GridView.superclass.init.call(this, grid);
47569 this.bind(grid.dataSource, grid.colModel);
47571 grid.on("headerclick", this.handleHeaderClick, this);
47573 if(grid.trackMouseOver){
47574 grid.on("mouseover", this.onRowOver, this);
47575 grid.on("mouseout", this.onRowOut, this);
47577 grid.cancelTextSelection = function(){};
47578 this.gridId = grid.id;
47580 var tpls = this.templates || {};
47583 tpls.master = new Roo.Template(
47584 '<div class="x-grid" hidefocus="true">',
47585 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
47586 '<div class="x-grid-topbar"></div>',
47587 '<div class="x-grid-scroller"><div></div></div>',
47588 '<div class="x-grid-locked">',
47589 '<div class="x-grid-header">{lockedHeader}</div>',
47590 '<div class="x-grid-body">{lockedBody}</div>',
47592 '<div class="x-grid-viewport">',
47593 '<div class="x-grid-header">{header}</div>',
47594 '<div class="x-grid-body">{body}</div>',
47596 '<div class="x-grid-bottombar"></div>',
47598 '<div class="x-grid-resize-proxy"> </div>',
47601 tpls.master.disableformats = true;
47605 tpls.header = new Roo.Template(
47606 '<table border="0" cellspacing="0" cellpadding="0">',
47607 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
47610 tpls.header.disableformats = true;
47612 tpls.header.compile();
47615 tpls.hcell = new Roo.Template(
47616 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
47617 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
47620 tpls.hcell.disableFormats = true;
47622 tpls.hcell.compile();
47625 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
47626 tpls.hsplit.disableFormats = true;
47628 tpls.hsplit.compile();
47631 tpls.body = new Roo.Template(
47632 '<table border="0" cellspacing="0" cellpadding="0">',
47633 "<tbody>{rows}</tbody>",
47636 tpls.body.disableFormats = true;
47638 tpls.body.compile();
47641 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
47642 tpls.row.disableFormats = true;
47644 tpls.row.compile();
47647 tpls.cell = new Roo.Template(
47648 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
47649 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
47652 tpls.cell.disableFormats = true;
47654 tpls.cell.compile();
47656 this.templates = tpls;
47659 // remap these for backwards compat
47660 onColWidthChange : function(){
47661 this.updateColumns.apply(this, arguments);
47663 onHeaderChange : function(){
47664 this.updateHeaders.apply(this, arguments);
47666 onHiddenChange : function(){
47667 this.handleHiddenChange.apply(this, arguments);
47669 onColumnMove : function(){
47670 this.handleColumnMove.apply(this, arguments);
47672 onColumnLock : function(){
47673 this.handleLockChange.apply(this, arguments);
47676 onDataChange : function(){
47678 this.updateHeaderSortState();
47681 onClear : function(){
47685 onUpdate : function(ds, record){
47686 this.refreshRow(record);
47689 refreshRow : function(record){
47690 var ds = this.ds, index;
47691 if(typeof record == 'number'){
47693 record = ds.getAt(index);
47695 index = ds.indexOf(record);
47697 this.insertRows(ds, index, index, true);
47698 this.onRemove(ds, record, index+1, true);
47699 this.syncRowHeights(index, index);
47701 this.fireEvent("rowupdated", this, index, record);
47704 onAdd : function(ds, records, index){
47705 this.insertRows(ds, index, index + (records.length-1));
47708 onRemove : function(ds, record, index, isUpdate){
47709 if(isUpdate !== true){
47710 this.fireEvent("beforerowremoved", this, index, record);
47712 var bt = this.getBodyTable(), lt = this.getLockedTable();
47713 if(bt.rows[index]){
47714 bt.firstChild.removeChild(bt.rows[index]);
47716 if(lt.rows[index]){
47717 lt.firstChild.removeChild(lt.rows[index]);
47719 if(isUpdate !== true){
47720 this.stripeRows(index);
47721 this.syncRowHeights(index, index);
47723 this.fireEvent("rowremoved", this, index, record);
47727 onLoad : function(){
47728 this.scrollToTop();
47732 * Scrolls the grid to the top
47734 scrollToTop : function(){
47736 this.scroller.dom.scrollTop = 0;
47742 * Gets a panel in the header of the grid that can be used for toolbars etc.
47743 * After modifying the contents of this panel a call to grid.autoSize() may be
47744 * required to register any changes in size.
47745 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
47746 * @return Roo.Element
47748 getHeaderPanel : function(doShow){
47750 this.headerPanel.show();
47752 return this.headerPanel;
47756 * Gets a panel in the footer of the grid that can be used for toolbars etc.
47757 * After modifying the contents of this panel a call to grid.autoSize() may be
47758 * required to register any changes in size.
47759 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
47760 * @return Roo.Element
47762 getFooterPanel : function(doShow){
47764 this.footerPanel.show();
47766 return this.footerPanel;
47769 initElements : function(){
47770 var E = Roo.Element;
47771 var el = this.grid.getGridEl().dom.firstChild;
47772 var cs = el.childNodes;
47774 this.el = new E(el);
47776 this.focusEl = new E(el.firstChild);
47777 this.focusEl.swallowEvent("click", true);
47779 this.headerPanel = new E(cs[1]);
47780 this.headerPanel.enableDisplayMode("block");
47782 this.scroller = new E(cs[2]);
47783 this.scrollSizer = new E(this.scroller.dom.firstChild);
47785 this.lockedWrap = new E(cs[3]);
47786 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
47787 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
47789 this.mainWrap = new E(cs[4]);
47790 this.mainHd = new E(this.mainWrap.dom.firstChild);
47791 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
47793 this.footerPanel = new E(cs[5]);
47794 this.footerPanel.enableDisplayMode("block");
47796 this.resizeProxy = new E(cs[6]);
47798 this.headerSelector = String.format(
47799 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
47800 this.lockedHd.id, this.mainHd.id
47803 this.splitterSelector = String.format(
47804 '#{0} div.x-grid-split, #{1} div.x-grid-split',
47805 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
47808 idToCssName : function(s)
47810 return s.replace(/[^a-z0-9]+/ig, '-');
47813 getHeaderCell : function(index){
47814 return Roo.DomQuery.select(this.headerSelector)[index];
47817 getHeaderCellMeasure : function(index){
47818 return this.getHeaderCell(index).firstChild;
47821 getHeaderCellText : function(index){
47822 return this.getHeaderCell(index).firstChild.firstChild;
47825 getLockedTable : function(){
47826 return this.lockedBody.dom.firstChild;
47829 getBodyTable : function(){
47830 return this.mainBody.dom.firstChild;
47833 getLockedRow : function(index){
47834 return this.getLockedTable().rows[index];
47837 getRow : function(index){
47838 return this.getBodyTable().rows[index];
47841 getRowComposite : function(index){
47843 this.rowEl = new Roo.CompositeElementLite();
47845 var els = [], lrow, mrow;
47846 if(lrow = this.getLockedRow(index)){
47849 if(mrow = this.getRow(index)){
47852 this.rowEl.elements = els;
47856 getCell : function(rowIndex, colIndex){
47857 var locked = this.cm.getLockedCount();
47859 if(colIndex < locked){
47860 source = this.lockedBody.dom.firstChild;
47862 source = this.mainBody.dom.firstChild;
47863 colIndex -= locked;
47865 return source.rows[rowIndex].childNodes[colIndex];
47868 getCellText : function(rowIndex, colIndex){
47869 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
47872 getCellBox : function(cell){
47873 var b = this.fly(cell).getBox();
47874 if(Roo.isOpera){ // opera fails to report the Y
47875 b.y = cell.offsetTop + this.mainBody.getY();
47880 getCellIndex : function(cell){
47881 var id = String(cell.className).match(this.cellRE);
47883 return parseInt(id[1], 10);
47888 findHeaderIndex : function(n){
47889 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47890 return r ? this.getCellIndex(r) : false;
47893 findHeaderCell : function(n){
47894 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47895 return r ? r : false;
47898 findRowIndex : function(n){
47902 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
47903 return r ? r.rowIndex : false;
47906 findCellIndex : function(node){
47907 var stop = this.el.dom;
47908 while(node && node != stop){
47909 if(this.findRE.test(node.className)){
47910 return this.getCellIndex(node);
47912 node = node.parentNode;
47917 getColumnId : function(index){
47918 return this.cm.getColumnId(index);
47921 getSplitters : function()
47923 if(this.splitterSelector){
47924 return Roo.DomQuery.select(this.splitterSelector);
47930 getSplitter : function(index){
47931 return this.getSplitters()[index];
47934 onRowOver : function(e, t){
47936 if((row = this.findRowIndex(t)) !== false){
47937 this.getRowComposite(row).addClass("x-grid-row-over");
47941 onRowOut : function(e, t){
47943 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
47944 this.getRowComposite(row).removeClass("x-grid-row-over");
47948 renderHeaders : function(){
47950 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
47951 var cb = [], lb = [], sb = [], lsb = [], p = {};
47952 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47953 p.cellId = "x-grid-hd-0-" + i;
47954 p.splitId = "x-grid-csplit-0-" + i;
47955 p.id = cm.getColumnId(i);
47956 p.title = cm.getColumnTooltip(i) || "";
47957 p.value = cm.getColumnHeader(i) || "";
47958 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
47959 if(!cm.isLocked(i)){
47960 cb[cb.length] = ct.apply(p);
47961 sb[sb.length] = st.apply(p);
47963 lb[lb.length] = ct.apply(p);
47964 lsb[lsb.length] = st.apply(p);
47967 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
47968 ht.apply({cells: cb.join(""), splits:sb.join("")})];
47971 updateHeaders : function(){
47972 var html = this.renderHeaders();
47973 this.lockedHd.update(html[0]);
47974 this.mainHd.update(html[1]);
47978 * Focuses the specified row.
47979 * @param {Number} row The row index
47981 focusRow : function(row)
47983 //Roo.log('GridView.focusRow');
47984 var x = this.scroller.dom.scrollLeft;
47985 this.focusCell(row, 0, false);
47986 this.scroller.dom.scrollLeft = x;
47990 * Focuses the specified cell.
47991 * @param {Number} row The row index
47992 * @param {Number} col The column index
47993 * @param {Boolean} hscroll false to disable horizontal scrolling
47995 focusCell : function(row, col, hscroll)
47997 //Roo.log('GridView.focusCell');
47998 var el = this.ensureVisible(row, col, hscroll);
47999 this.focusEl.alignTo(el, "tl-tl");
48001 this.focusEl.focus();
48003 this.focusEl.focus.defer(1, this.focusEl);
48008 * Scrolls the specified cell into view
48009 * @param {Number} row The row index
48010 * @param {Number} col The column index
48011 * @param {Boolean} hscroll false to disable horizontal scrolling
48013 ensureVisible : function(row, col, hscroll)
48015 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
48016 //return null; //disable for testing.
48017 if(typeof row != "number"){
48018 row = row.rowIndex;
48020 if(row < 0 && row >= this.ds.getCount()){
48023 col = (col !== undefined ? col : 0);
48024 var cm = this.grid.colModel;
48025 while(cm.isHidden(col)){
48029 var el = this.getCell(row, col);
48033 var c = this.scroller.dom;
48035 var ctop = parseInt(el.offsetTop, 10);
48036 var cleft = parseInt(el.offsetLeft, 10);
48037 var cbot = ctop + el.offsetHeight;
48038 var cright = cleft + el.offsetWidth;
48040 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
48041 var stop = parseInt(c.scrollTop, 10);
48042 var sleft = parseInt(c.scrollLeft, 10);
48043 var sbot = stop + ch;
48044 var sright = sleft + c.clientWidth;
48046 Roo.log('GridView.ensureVisible:' +
48048 ' c.clientHeight:' + c.clientHeight +
48049 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
48057 c.scrollTop = ctop;
48058 //Roo.log("set scrolltop to ctop DISABLE?");
48059 }else if(cbot > sbot){
48060 //Roo.log("set scrolltop to cbot-ch");
48061 c.scrollTop = cbot-ch;
48064 if(hscroll !== false){
48066 c.scrollLeft = cleft;
48067 }else if(cright > sright){
48068 c.scrollLeft = cright-c.clientWidth;
48075 updateColumns : function(){
48076 this.grid.stopEditing();
48077 var cm = this.grid.colModel, colIds = this.getColumnIds();
48078 //var totalWidth = cm.getTotalWidth();
48080 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48081 //if(cm.isHidden(i)) continue;
48082 var w = cm.getColumnWidth(i);
48083 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48084 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48086 this.updateSplitters();
48089 generateRules : function(cm){
48090 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
48091 Roo.util.CSS.removeStyleSheet(rulesId);
48092 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48093 var cid = cm.getColumnId(i);
48095 if(cm.config[i].align){
48096 align = 'text-align:'+cm.config[i].align+';';
48099 if(cm.isHidden(i)){
48100 hidden = 'display:none;';
48102 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
48104 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
48105 this.hdSelector, cid, " {\n", align, width, "}\n",
48106 this.tdSelector, cid, " {\n",hidden,"\n}\n",
48107 this.splitSelector, cid, " {\n", hidden , "\n}\n");
48109 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
48112 updateSplitters : function(){
48113 var cm = this.cm, s = this.getSplitters();
48114 if(s){ // splitters not created yet
48115 var pos = 0, locked = true;
48116 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48117 if(cm.isHidden(i)) continue;
48118 var w = cm.getColumnWidth(i); // make sure it's a number
48119 if(!cm.isLocked(i) && locked){
48124 s[i].style.left = (pos-this.splitOffset) + "px";
48129 handleHiddenChange : function(colModel, colIndex, hidden){
48131 this.hideColumn(colIndex);
48133 this.unhideColumn(colIndex);
48137 hideColumn : function(colIndex){
48138 var cid = this.getColumnId(colIndex);
48139 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
48140 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
48142 this.updateHeaders();
48144 this.updateSplitters();
48148 unhideColumn : function(colIndex){
48149 var cid = this.getColumnId(colIndex);
48150 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
48151 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
48154 this.updateHeaders();
48156 this.updateSplitters();
48160 insertRows : function(dm, firstRow, lastRow, isUpdate){
48161 if(firstRow == 0 && lastRow == dm.getCount()-1){
48165 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
48167 var s = this.getScrollState();
48168 var markup = this.renderRows(firstRow, lastRow);
48169 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
48170 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
48171 this.restoreScroll(s);
48173 this.fireEvent("rowsinserted", this, firstRow, lastRow);
48174 this.syncRowHeights(firstRow, lastRow);
48175 this.stripeRows(firstRow);
48181 bufferRows : function(markup, target, index){
48182 var before = null, trows = target.rows, tbody = target.tBodies[0];
48183 if(index < trows.length){
48184 before = trows[index];
48186 var b = document.createElement("div");
48187 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
48188 var rows = b.firstChild.rows;
48189 for(var i = 0, len = rows.length; i < len; i++){
48191 tbody.insertBefore(rows[0], before);
48193 tbody.appendChild(rows[0]);
48200 deleteRows : function(dm, firstRow, lastRow){
48201 if(dm.getRowCount()<1){
48202 this.fireEvent("beforerefresh", this);
48203 this.mainBody.update("");
48204 this.lockedBody.update("");
48205 this.fireEvent("refresh", this);
48207 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
48208 var bt = this.getBodyTable();
48209 var tbody = bt.firstChild;
48210 var rows = bt.rows;
48211 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
48212 tbody.removeChild(rows[firstRow]);
48214 this.stripeRows(firstRow);
48215 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
48219 updateRows : function(dataSource, firstRow, lastRow){
48220 var s = this.getScrollState();
48222 this.restoreScroll(s);
48225 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
48229 this.updateHeaderSortState();
48232 getScrollState : function(){
48234 var sb = this.scroller.dom;
48235 return {left: sb.scrollLeft, top: sb.scrollTop};
48238 stripeRows : function(startRow){
48239 if(!this.grid.stripeRows || this.ds.getCount() < 1){
48242 startRow = startRow || 0;
48243 var rows = this.getBodyTable().rows;
48244 var lrows = this.getLockedTable().rows;
48245 var cls = ' x-grid-row-alt ';
48246 for(var i = startRow, len = rows.length; i < len; i++){
48247 var row = rows[i], lrow = lrows[i];
48248 var isAlt = ((i+1) % 2 == 0);
48249 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
48250 if(isAlt == hasAlt){
48254 row.className += " x-grid-row-alt";
48256 row.className = row.className.replace("x-grid-row-alt", "");
48259 lrow.className = row.className;
48264 restoreScroll : function(state){
48265 //Roo.log('GridView.restoreScroll');
48266 var sb = this.scroller.dom;
48267 sb.scrollLeft = state.left;
48268 sb.scrollTop = state.top;
48272 syncScroll : function(){
48273 //Roo.log('GridView.syncScroll');
48274 var sb = this.scroller.dom;
48275 var sh = this.mainHd.dom;
48276 var bs = this.mainBody.dom;
48277 var lv = this.lockedBody.dom;
48278 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
48279 lv.scrollTop = bs.scrollTop = sb.scrollTop;
48282 handleScroll : function(e){
48284 var sb = this.scroller.dom;
48285 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
48289 handleWheel : function(e){
48290 var d = e.getWheelDelta();
48291 this.scroller.dom.scrollTop -= d*22;
48292 // set this here to prevent jumpy scrolling on large tables
48293 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
48297 renderRows : function(startRow, endRow){
48298 // pull in all the crap needed to render rows
48299 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
48300 var colCount = cm.getColumnCount();
48302 if(ds.getCount() < 1){
48306 // build a map for all the columns
48308 for(var i = 0; i < colCount; i++){
48309 var name = cm.getDataIndex(i);
48311 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
48312 renderer : cm.getRenderer(i),
48313 id : cm.getColumnId(i),
48314 locked : cm.isLocked(i)
48318 startRow = startRow || 0;
48319 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
48321 // records to render
48322 var rs = ds.getRange(startRow, endRow);
48324 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
48327 // As much as I hate to duplicate code, this was branched because FireFox really hates
48328 // [].join("") on strings. The performance difference was substantial enough to
48329 // branch this function
48330 doRender : Roo.isGecko ?
48331 function(cs, rs, ds, startRow, colCount, stripe){
48332 var ts = this.templates, ct = ts.cell, rt = ts.row;
48334 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
48336 var hasListener = this.grid.hasListener('rowclass');
48338 for(var j = 0, len = rs.length; j < len; j++){
48339 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
48340 for(var i = 0; i < colCount; i++){
48342 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
48344 p.css = p.attr = "";
48345 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
48346 if(p.value == undefined || p.value === "") p.value = " ";
48347 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
48348 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
48350 var markup = ct.apply(p);
48358 if(stripe && ((rowIndex+1) % 2 == 0)){
48359 alt.push("x-grid-row-alt")
48362 alt.push( " x-grid-dirty-row");
48365 if(this.getRowClass){
48366 alt.push(this.getRowClass(r, rowIndex));
48372 rowIndex : rowIndex,
48375 this.grid.fireEvent('rowclass', this, rowcfg);
48376 alt.push(rowcfg.rowClass);
48378 rp.alt = alt.join(" ");
48379 lbuf+= rt.apply(rp);
48381 buf+= rt.apply(rp);
48383 return [lbuf, buf];
48385 function(cs, rs, ds, startRow, colCount, stripe){
48386 var ts = this.templates, ct = ts.cell, rt = ts.row;
48388 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
48389 var hasListener = this.grid.hasListener('rowclass');
48391 for(var j = 0, len = rs.length; j < len; j++){
48392 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
48393 for(var i = 0; i < colCount; i++){
48395 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
48397 p.css = p.attr = "";
48398 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
48399 if(p.value == undefined || p.value === "") p.value = " ";
48400 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
48401 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
48403 var markup = ct.apply(p);
48405 cb[cb.length] = markup;
48407 lcb[lcb.length] = markup;
48411 if(stripe && ((rowIndex+1) % 2 == 0)){
48412 alt.push( "x-grid-row-alt");
48415 alt.push(" x-grid-dirty-row");
48418 if(this.getRowClass){
48419 alt.push( this.getRowClass(r, rowIndex));
48425 rowIndex : rowIndex,
48428 this.grid.fireEvent('rowclass', this, rowcfg);
48429 alt.push(rowcfg.rowClass);
48431 rp.alt = alt.join(" ");
48432 rp.cells = lcb.join("");
48433 lbuf[lbuf.length] = rt.apply(rp);
48434 rp.cells = cb.join("");
48435 buf[buf.length] = rt.apply(rp);
48437 return [lbuf.join(""), buf.join("")];
48440 renderBody : function(){
48441 var markup = this.renderRows();
48442 var bt = this.templates.body;
48443 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
48447 * Refreshes the grid
48448 * @param {Boolean} headersToo
48450 refresh : function(headersToo){
48451 this.fireEvent("beforerefresh", this);
48452 this.grid.stopEditing();
48453 var result = this.renderBody();
48454 this.lockedBody.update(result[0]);
48455 this.mainBody.update(result[1]);
48456 if(headersToo === true){
48457 this.updateHeaders();
48458 this.updateColumns();
48459 this.updateSplitters();
48460 this.updateHeaderSortState();
48462 this.syncRowHeights();
48464 this.fireEvent("refresh", this);
48467 handleColumnMove : function(cm, oldIndex, newIndex){
48468 this.indexMap = null;
48469 var s = this.getScrollState();
48470 this.refresh(true);
48471 this.restoreScroll(s);
48472 this.afterMove(newIndex);
48475 afterMove : function(colIndex){
48476 if(this.enableMoveAnim && Roo.enableFx){
48477 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
48479 // if multisort - fix sortOrder, and reload..
48480 if (this.grid.dataSource.multiSort) {
48481 // the we can call sort again..
48482 var dm = this.grid.dataSource;
48483 var cm = this.grid.colModel;
48485 for(var i = 0; i < cm.config.length; i++ ) {
48487 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
48488 continue; // dont' bother, it's not in sort list or being set.
48491 so.push(cm.config[i].dataIndex);
48494 dm.load(dm.lastOptions);
48501 updateCell : function(dm, rowIndex, dataIndex){
48502 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
48503 if(typeof colIndex == "undefined"){ // not present in grid
48506 var cm = this.grid.colModel;
48507 var cell = this.getCell(rowIndex, colIndex);
48508 var cellText = this.getCellText(rowIndex, colIndex);
48511 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
48512 id : cm.getColumnId(colIndex),
48513 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
48515 var renderer = cm.getRenderer(colIndex);
48516 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
48517 if(typeof val == "undefined" || val === "") val = " ";
48518 cellText.innerHTML = val;
48519 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
48520 this.syncRowHeights(rowIndex, rowIndex);
48523 calcColumnWidth : function(colIndex, maxRowsToMeasure){
48525 if(this.grid.autoSizeHeaders){
48526 var h = this.getHeaderCellMeasure(colIndex);
48527 maxWidth = Math.max(maxWidth, h.scrollWidth);
48530 if(this.cm.isLocked(colIndex)){
48531 tb = this.getLockedTable();
48534 tb = this.getBodyTable();
48535 index = colIndex - this.cm.getLockedCount();
48538 var rows = tb.rows;
48539 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
48540 for(var i = 0; i < stopIndex; i++){
48541 var cell = rows[i].childNodes[index].firstChild;
48542 maxWidth = Math.max(maxWidth, cell.scrollWidth);
48545 return maxWidth + /*margin for error in IE*/ 5;
48548 * Autofit a column to its content.
48549 * @param {Number} colIndex
48550 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
48552 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
48553 if(this.cm.isHidden(colIndex)){
48554 return; // can't calc a hidden column
48557 var cid = this.cm.getColumnId(colIndex);
48558 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
48559 if(this.grid.autoSizeHeaders){
48560 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
48563 var newWidth = this.calcColumnWidth(colIndex);
48564 this.cm.setColumnWidth(colIndex,
48565 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
48566 if(!suppressEvent){
48567 this.grid.fireEvent("columnresize", colIndex, newWidth);
48572 * Autofits all columns to their content and then expands to fit any extra space in the grid
48574 autoSizeColumns : function(){
48575 var cm = this.grid.colModel;
48576 var colCount = cm.getColumnCount();
48577 for(var i = 0; i < colCount; i++){
48578 this.autoSizeColumn(i, true, true);
48580 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
48583 this.updateColumns();
48589 * Autofits all columns to the grid's width proportionate with their current size
48590 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
48592 fitColumns : function(reserveScrollSpace){
48593 var cm = this.grid.colModel;
48594 var colCount = cm.getColumnCount();
48598 for (i = 0; i < colCount; i++){
48599 if(!cm.isHidden(i) && !cm.isFixed(i)){
48600 w = cm.getColumnWidth(i);
48606 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
48607 if(reserveScrollSpace){
48610 var frac = (avail - cm.getTotalWidth())/width;
48611 while (cols.length){
48614 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
48616 this.updateColumns();
48620 onRowSelect : function(rowIndex){
48621 var row = this.getRowComposite(rowIndex);
48622 row.addClass("x-grid-row-selected");
48625 onRowDeselect : function(rowIndex){
48626 var row = this.getRowComposite(rowIndex);
48627 row.removeClass("x-grid-row-selected");
48630 onCellSelect : function(row, col){
48631 var cell = this.getCell(row, col);
48633 Roo.fly(cell).addClass("x-grid-cell-selected");
48637 onCellDeselect : function(row, col){
48638 var cell = this.getCell(row, col);
48640 Roo.fly(cell).removeClass("x-grid-cell-selected");
48644 updateHeaderSortState : function(){
48646 // sort state can be single { field: xxx, direction : yyy}
48647 // or { xxx=>ASC , yyy : DESC ..... }
48650 if (!this.ds.multiSort) {
48651 var state = this.ds.getSortState();
48655 mstate[state.field] = state.direction;
48656 // FIXME... - this is not used here.. but might be elsewhere..
48657 this.sortState = state;
48660 mstate = this.ds.sortToggle;
48662 //remove existing sort classes..
48664 var sc = this.sortClasses;
48665 var hds = this.el.select(this.headerSelector).removeClass(sc);
48667 for(var f in mstate) {
48669 var sortColumn = this.cm.findColumnIndex(f);
48671 if(sortColumn != -1){
48672 var sortDir = mstate[f];
48673 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
48682 handleHeaderClick : function(g, index){
48683 if(this.headersDisabled){
48686 var dm = g.dataSource, cm = g.colModel;
48687 if(!cm.isSortable(index)){
48692 if (dm.multiSort) {
48693 // update the sortOrder
48695 for(var i = 0; i < cm.config.length; i++ ) {
48697 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
48698 continue; // dont' bother, it's not in sort list or being set.
48701 so.push(cm.config[i].dataIndex);
48707 dm.sort(cm.getDataIndex(index));
48711 destroy : function(){
48713 this.colMenu.removeAll();
48714 Roo.menu.MenuMgr.unregister(this.colMenu);
48715 this.colMenu.getEl().remove();
48716 delete this.colMenu;
48719 this.hmenu.removeAll();
48720 Roo.menu.MenuMgr.unregister(this.hmenu);
48721 this.hmenu.getEl().remove();
48724 if(this.grid.enableColumnMove){
48725 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48727 for(var dd in dds){
48728 if(!dds[dd].config.isTarget && dds[dd].dragElId){
48729 var elid = dds[dd].dragElId;
48731 Roo.get(elid).remove();
48732 } else if(dds[dd].config.isTarget){
48733 dds[dd].proxyTop.remove();
48734 dds[dd].proxyBottom.remove();
48737 if(Roo.dd.DDM.locationCache[dd]){
48738 delete Roo.dd.DDM.locationCache[dd];
48741 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48744 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
48745 this.bind(null, null);
48746 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
48749 handleLockChange : function(){
48750 this.refresh(true);
48753 onDenyColumnLock : function(){
48757 onDenyColumnHide : function(){
48761 handleHdMenuClick : function(item){
48762 var index = this.hdCtxIndex;
48763 var cm = this.cm, ds = this.ds;
48766 ds.sort(cm.getDataIndex(index), "ASC");
48769 ds.sort(cm.getDataIndex(index), "DESC");
48772 var lc = cm.getLockedCount();
48773 if(cm.getColumnCount(true) <= lc+1){
48774 this.onDenyColumnLock();
48778 cm.setLocked(index, true, true);
48779 cm.moveColumn(index, lc);
48780 this.grid.fireEvent("columnmove", index, lc);
48782 cm.setLocked(index, true);
48786 var lc = cm.getLockedCount();
48787 if((lc-1) != index){
48788 cm.setLocked(index, false, true);
48789 cm.moveColumn(index, lc-1);
48790 this.grid.fireEvent("columnmove", index, lc-1);
48792 cm.setLocked(index, false);
48796 index = cm.getIndexById(item.id.substr(4));
48798 if(item.checked && cm.getColumnCount(true) <= 1){
48799 this.onDenyColumnHide();
48802 cm.setHidden(index, item.checked);
48808 beforeColMenuShow : function(){
48809 var cm = this.cm, colCount = cm.getColumnCount();
48810 this.colMenu.removeAll();
48811 for(var i = 0; i < colCount; i++){
48812 this.colMenu.add(new Roo.menu.CheckItem({
48813 id: "col-"+cm.getColumnId(i),
48814 text: cm.getColumnHeader(i),
48815 checked: !cm.isHidden(i),
48821 handleHdCtx : function(g, index, e){
48823 var hd = this.getHeaderCell(index);
48824 this.hdCtxIndex = index;
48825 var ms = this.hmenu.items, cm = this.cm;
48826 ms.get("asc").setDisabled(!cm.isSortable(index));
48827 ms.get("desc").setDisabled(!cm.isSortable(index));
48828 if(this.grid.enableColLock !== false){
48829 ms.get("lock").setDisabled(cm.isLocked(index));
48830 ms.get("unlock").setDisabled(!cm.isLocked(index));
48832 this.hmenu.show(hd, "tl-bl");
48835 handleHdOver : function(e){
48836 var hd = this.findHeaderCell(e.getTarget());
48837 if(hd && !this.headersDisabled){
48838 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
48839 this.fly(hd).addClass("x-grid-hd-over");
48844 handleHdOut : function(e){
48845 var hd = this.findHeaderCell(e.getTarget());
48847 this.fly(hd).removeClass("x-grid-hd-over");
48851 handleSplitDblClick : function(e, t){
48852 var i = this.getCellIndex(t);
48853 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
48854 this.autoSizeColumn(i, true);
48859 render : function(){
48862 var colCount = cm.getColumnCount();
48864 if(this.grid.monitorWindowResize === true){
48865 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48867 var header = this.renderHeaders();
48868 var body = this.templates.body.apply({rows:""});
48869 var html = this.templates.master.apply({
48872 lockedHeader: header[0],
48876 //this.updateColumns();
48878 this.grid.getGridEl().dom.innerHTML = html;
48880 this.initElements();
48882 // a kludge to fix the random scolling effect in webkit
48883 this.el.on("scroll", function() {
48884 this.el.dom.scrollTop=0; // hopefully not recursive..
48887 this.scroller.on("scroll", this.handleScroll, this);
48888 this.lockedBody.on("mousewheel", this.handleWheel, this);
48889 this.mainBody.on("mousewheel", this.handleWheel, this);
48891 this.mainHd.on("mouseover", this.handleHdOver, this);
48892 this.mainHd.on("mouseout", this.handleHdOut, this);
48893 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
48894 {delegate: "."+this.splitClass});
48896 this.lockedHd.on("mouseover", this.handleHdOver, this);
48897 this.lockedHd.on("mouseout", this.handleHdOut, this);
48898 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
48899 {delegate: "."+this.splitClass});
48901 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
48902 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48905 this.updateSplitters();
48907 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
48908 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48909 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48912 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
48913 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
48915 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
48916 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
48918 if(this.grid.enableColLock !== false){
48919 this.hmenu.add('-',
48920 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
48921 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
48924 if(this.grid.enableColumnHide !== false){
48926 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
48927 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
48928 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
48930 this.hmenu.add('-',
48931 {id:"columns", text: this.columnsText, menu: this.colMenu}
48934 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
48936 this.grid.on("headercontextmenu", this.handleHdCtx, this);
48939 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
48940 this.dd = new Roo.grid.GridDragZone(this.grid, {
48941 ddGroup : this.grid.ddGroup || 'GridDD'
48946 for(var i = 0; i < colCount; i++){
48947 if(cm.isHidden(i)){
48948 this.hideColumn(i);
48950 if(cm.config[i].align){
48951 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
48952 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
48956 this.updateHeaderSortState();
48958 this.beforeInitialResize();
48961 // two part rendering gives faster view to the user
48962 this.renderPhase2.defer(1, this);
48965 renderPhase2 : function(){
48966 // render the rows now
48968 if(this.grid.autoSizeColumns){
48969 this.autoSizeColumns();
48973 beforeInitialResize : function(){
48977 onColumnSplitterMoved : function(i, w){
48978 this.userResized = true;
48979 var cm = this.grid.colModel;
48980 cm.setColumnWidth(i, w, true);
48981 var cid = cm.getColumnId(i);
48982 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48983 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48984 this.updateSplitters();
48986 this.grid.fireEvent("columnresize", i, w);
48989 syncRowHeights : function(startIndex, endIndex){
48990 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
48991 startIndex = startIndex || 0;
48992 var mrows = this.getBodyTable().rows;
48993 var lrows = this.getLockedTable().rows;
48994 var len = mrows.length-1;
48995 endIndex = Math.min(endIndex || len, len);
48996 for(var i = startIndex; i <= endIndex; i++){
48997 var m = mrows[i], l = lrows[i];
48998 var h = Math.max(m.offsetHeight, l.offsetHeight);
48999 m.style.height = l.style.height = h + "px";
49004 layout : function(initialRender, is2ndPass){
49006 var auto = g.autoHeight;
49007 var scrollOffset = 16;
49008 var c = g.getGridEl(), cm = this.cm,
49009 expandCol = g.autoExpandColumn,
49011 //c.beginMeasure();
49013 if(!c.dom.offsetWidth){ // display:none?
49015 this.lockedWrap.show();
49016 this.mainWrap.show();
49021 var hasLock = this.cm.isLocked(0);
49023 var tbh = this.headerPanel.getHeight();
49024 var bbh = this.footerPanel.getHeight();
49027 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
49028 var newHeight = ch + c.getBorderWidth("tb");
49030 newHeight = Math.min(g.maxHeight, newHeight);
49032 c.setHeight(newHeight);
49036 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
49039 var s = this.scroller;
49041 var csize = c.getSize(true);
49043 this.el.setSize(csize.width, csize.height);
49045 this.headerPanel.setWidth(csize.width);
49046 this.footerPanel.setWidth(csize.width);
49048 var hdHeight = this.mainHd.getHeight();
49049 var vw = csize.width;
49050 var vh = csize.height - (tbh + bbh);
49054 var bt = this.getBodyTable();
49055 var ltWidth = hasLock ?
49056 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
49058 var scrollHeight = bt.offsetHeight;
49059 var scrollWidth = ltWidth + bt.offsetWidth;
49060 var vscroll = false, hscroll = false;
49062 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
49064 var lw = this.lockedWrap, mw = this.mainWrap;
49065 var lb = this.lockedBody, mb = this.mainBody;
49067 setTimeout(function(){
49068 var t = s.dom.offsetTop;
49069 var w = s.dom.clientWidth,
49070 h = s.dom.clientHeight;
49073 lw.setSize(ltWidth, h);
49075 mw.setLeftTop(ltWidth, t);
49076 mw.setSize(w-ltWidth, h);
49078 lb.setHeight(h-hdHeight);
49079 mb.setHeight(h-hdHeight);
49081 if(is2ndPass !== true && !gv.userResized && expandCol){
49082 // high speed resize without full column calculation
49084 var ci = cm.getIndexById(expandCol);
49086 ci = cm.findColumnIndex(expandCol);
49088 ci = Math.max(0, ci); // make sure it's got at least the first col.
49089 var expandId = cm.getColumnId(ci);
49090 var tw = cm.getTotalWidth(false);
49091 var currentWidth = cm.getColumnWidth(ci);
49092 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
49093 if(currentWidth != cw){
49094 cm.setColumnWidth(ci, cw, true);
49095 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
49096 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
49097 gv.updateSplitters();
49098 gv.layout(false, true);
49110 onWindowResize : function(){
49111 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
49117 appendFooter : function(parentEl){
49121 sortAscText : "Sort Ascending",
49122 sortDescText : "Sort Descending",
49123 lockText : "Lock Column",
49124 unlockText : "Unlock Column",
49125 columnsText : "Columns"
49129 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
49130 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
49131 this.proxy.el.addClass('x-grid3-col-dd');
49134 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
49135 handleMouseDown : function(e){
49139 callHandleMouseDown : function(e){
49140 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
49145 * Ext JS Library 1.1.1
49146 * Copyright(c) 2006-2007, Ext JS, LLC.
49148 * Originally Released Under LGPL - original licence link has changed is not relivant.
49151 * <script type="text/javascript">
49155 // This is a support class used internally by the Grid components
49156 Roo.grid.SplitDragZone = function(grid, hd, hd2){
49158 this.view = grid.getView();
49159 this.proxy = this.view.resizeProxy;
49160 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
49161 "gridSplitters" + this.grid.getGridEl().id, {
49162 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
49164 this.setHandleElId(Roo.id(hd));
49165 this.setOuterHandleElId(Roo.id(hd2));
49166 this.scroll = false;
49168 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
49169 fly: Roo.Element.fly,
49171 b4StartDrag : function(x, y){
49172 this.view.headersDisabled = true;
49173 this.proxy.setHeight(this.view.mainWrap.getHeight());
49174 var w = this.cm.getColumnWidth(this.cellIndex);
49175 var minw = Math.max(w-this.grid.minColumnWidth, 0);
49176 this.resetConstraints();
49177 this.setXConstraint(minw, 1000);
49178 this.setYConstraint(0, 0);
49179 this.minX = x - minw;
49180 this.maxX = x + 1000;
49182 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
49186 handleMouseDown : function(e){
49187 ev = Roo.EventObject.setEvent(e);
49188 var t = this.fly(ev.getTarget());
49189 if(t.hasClass("x-grid-split")){
49190 this.cellIndex = this.view.getCellIndex(t.dom);
49191 this.split = t.dom;
49192 this.cm = this.grid.colModel;
49193 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
49194 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
49199 endDrag : function(e){
49200 this.view.headersDisabled = false;
49201 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
49202 var diff = endX - this.startPos;
49203 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
49206 autoOffset : function(){
49207 this.setDelta(0,0);
49211 * Ext JS Library 1.1.1
49212 * Copyright(c) 2006-2007, Ext JS, LLC.
49214 * Originally Released Under LGPL - original licence link has changed is not relivant.
49217 * <script type="text/javascript">
49221 // This is a support class used internally by the Grid components
49222 Roo.grid.GridDragZone = function(grid, config){
49223 this.view = grid.getView();
49224 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
49225 if(this.view.lockedBody){
49226 this.setHandleElId(Roo.id(this.view.mainBody.dom));
49227 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
49229 this.scroll = false;
49231 this.ddel = document.createElement('div');
49232 this.ddel.className = 'x-grid-dd-wrap';
49235 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
49236 ddGroup : "GridDD",
49238 getDragData : function(e){
49239 var t = Roo.lib.Event.getTarget(e);
49240 var rowIndex = this.view.findRowIndex(t);
49241 if(rowIndex !== false){
49242 var sm = this.grid.selModel;
49243 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
49244 // sm.mouseDown(e, t);
49246 if (e.hasModifier()){
49247 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
49249 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
49254 onInitDrag : function(e){
49255 var data = this.dragData;
49256 this.ddel.innerHTML = this.grid.getDragDropText();
49257 this.proxy.update(this.ddel);
49258 // fire start drag?
49261 afterRepair : function(){
49262 this.dragging = false;
49265 getRepairXY : function(e, data){
49269 onEndDrag : function(data, e){
49273 onValidDrop : function(dd, e, id){
49278 beforeInvalidDrop : function(e, id){
49283 * Ext JS Library 1.1.1
49284 * Copyright(c) 2006-2007, Ext JS, LLC.
49286 * Originally Released Under LGPL - original licence link has changed is not relivant.
49289 * <script type="text/javascript">
49294 * @class Roo.grid.ColumnModel
49295 * @extends Roo.util.Observable
49296 * This is the default implementation of a ColumnModel used by the Grid. It defines
49297 * the columns in the grid.
49300 var colModel = new Roo.grid.ColumnModel([
49301 {header: "Ticker", width: 60, sortable: true, locked: true},
49302 {header: "Company Name", width: 150, sortable: true},
49303 {header: "Market Cap.", width: 100, sortable: true},
49304 {header: "$ Sales", width: 100, sortable: true, renderer: money},
49305 {header: "Employees", width: 100, sortable: true, resizable: false}
49310 * The config options listed for this class are options which may appear in each
49311 * individual column definition.
49312 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
49314 * @param {Object} config An Array of column config objects. See this class's
49315 * config objects for details.
49317 Roo.grid.ColumnModel = function(config){
49319 * The config passed into the constructor
49321 this.config = config;
49324 // if no id, create one
49325 // if the column does not have a dataIndex mapping,
49326 // map it to the order it is in the config
49327 for(var i = 0, len = config.length; i < len; i++){
49329 if(typeof c.dataIndex == "undefined"){
49332 if(typeof c.renderer == "string"){
49333 c.renderer = Roo.util.Format[c.renderer];
49335 if(typeof c.id == "undefined"){
49338 if(c.editor && c.editor.xtype){
49339 c.editor = Roo.factory(c.editor, Roo.grid);
49341 if(c.editor && c.editor.isFormField){
49342 c.editor = new Roo.grid.GridEditor(c.editor);
49344 this.lookup[c.id] = c;
49348 * The width of columns which have no width specified (defaults to 100)
49351 this.defaultWidth = 100;
49354 * Default sortable of columns which have no sortable specified (defaults to false)
49357 this.defaultSortable = false;
49361 * @event widthchange
49362 * Fires when the width of a column changes.
49363 * @param {ColumnModel} this
49364 * @param {Number} columnIndex The column index
49365 * @param {Number} newWidth The new width
49367 "widthchange": true,
49369 * @event headerchange
49370 * Fires when the text of a header changes.
49371 * @param {ColumnModel} this
49372 * @param {Number} columnIndex The column index
49373 * @param {Number} newText The new header text
49375 "headerchange": true,
49377 * @event hiddenchange
49378 * Fires when a column is hidden or "unhidden".
49379 * @param {ColumnModel} this
49380 * @param {Number} columnIndex The column index
49381 * @param {Boolean} hidden true if hidden, false otherwise
49383 "hiddenchange": true,
49385 * @event columnmoved
49386 * Fires when a column is moved.
49387 * @param {ColumnModel} this
49388 * @param {Number} oldIndex
49389 * @param {Number} newIndex
49391 "columnmoved" : true,
49393 * @event columlockchange
49394 * Fires when a column's locked state is changed
49395 * @param {ColumnModel} this
49396 * @param {Number} colIndex
49397 * @param {Boolean} locked true if locked
49399 "columnlockchange" : true
49401 Roo.grid.ColumnModel.superclass.constructor.call(this);
49403 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
49405 * @cfg {String} header The header text to display in the Grid view.
49408 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
49409 * {@link Roo.data.Record} definition from which to draw the column's value. If not
49410 * specified, the column's index is used as an index into the Record's data Array.
49413 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
49414 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
49417 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
49418 * Defaults to the value of the {@link #defaultSortable} property.
49419 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
49422 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
49425 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
49428 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
49431 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
49434 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
49435 * given the cell's data value. See {@link #setRenderer}. If not specified, the
49436 * default renderer uses the raw data value.
49439 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
49442 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
49446 * Returns the id of the column at the specified index.
49447 * @param {Number} index The column index
49448 * @return {String} the id
49450 getColumnId : function(index){
49451 return this.config[index].id;
49455 * Returns the column for a specified id.
49456 * @param {String} id The column id
49457 * @return {Object} the column
49459 getColumnById : function(id){
49460 return this.lookup[id];
49465 * Returns the column for a specified dataIndex.
49466 * @param {String} dataIndex The column dataIndex
49467 * @return {Object|Boolean} the column or false if not found
49469 getColumnByDataIndex: function(dataIndex){
49470 var index = this.findColumnIndex(dataIndex);
49471 return index > -1 ? this.config[index] : false;
49475 * Returns the index for a specified column id.
49476 * @param {String} id The column id
49477 * @return {Number} the index, or -1 if not found
49479 getIndexById : function(id){
49480 for(var i = 0, len = this.config.length; i < len; i++){
49481 if(this.config[i].id == id){
49489 * Returns the index for a specified column dataIndex.
49490 * @param {String} dataIndex The column dataIndex
49491 * @return {Number} the index, or -1 if not found
49494 findColumnIndex : function(dataIndex){
49495 for(var i = 0, len = this.config.length; i < len; i++){
49496 if(this.config[i].dataIndex == dataIndex){
49504 moveColumn : function(oldIndex, newIndex){
49505 var c = this.config[oldIndex];
49506 this.config.splice(oldIndex, 1);
49507 this.config.splice(newIndex, 0, c);
49508 this.dataMap = null;
49509 this.fireEvent("columnmoved", this, oldIndex, newIndex);
49512 isLocked : function(colIndex){
49513 return this.config[colIndex].locked === true;
49516 setLocked : function(colIndex, value, suppressEvent){
49517 if(this.isLocked(colIndex) == value){
49520 this.config[colIndex].locked = value;
49521 if(!suppressEvent){
49522 this.fireEvent("columnlockchange", this, colIndex, value);
49526 getTotalLockedWidth : function(){
49527 var totalWidth = 0;
49528 for(var i = 0; i < this.config.length; i++){
49529 if(this.isLocked(i) && !this.isHidden(i)){
49530 this.totalWidth += this.getColumnWidth(i);
49536 getLockedCount : function(){
49537 for(var i = 0, len = this.config.length; i < len; i++){
49538 if(!this.isLocked(i)){
49545 * Returns the number of columns.
49548 getColumnCount : function(visibleOnly){
49549 if(visibleOnly === true){
49551 for(var i = 0, len = this.config.length; i < len; i++){
49552 if(!this.isHidden(i)){
49558 return this.config.length;
49562 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
49563 * @param {Function} fn
49564 * @param {Object} scope (optional)
49565 * @return {Array} result
49567 getColumnsBy : function(fn, scope){
49569 for(var i = 0, len = this.config.length; i < len; i++){
49570 var c = this.config[i];
49571 if(fn.call(scope||this, c, i) === true){
49579 * Returns true if the specified column is sortable.
49580 * @param {Number} col The column index
49581 * @return {Boolean}
49583 isSortable : function(col){
49584 if(typeof this.config[col].sortable == "undefined"){
49585 return this.defaultSortable;
49587 return this.config[col].sortable;
49591 * Returns the rendering (formatting) function defined for the column.
49592 * @param {Number} col The column index.
49593 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
49595 getRenderer : function(col){
49596 if(!this.config[col].renderer){
49597 return Roo.grid.ColumnModel.defaultRenderer;
49599 return this.config[col].renderer;
49603 * Sets the rendering (formatting) function for a column.
49604 * @param {Number} col The column index
49605 * @param {Function} fn The function to use to process the cell's raw data
49606 * to return HTML markup for the grid view. The render function is called with
49607 * the following parameters:<ul>
49608 * <li>Data value.</li>
49609 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
49610 * <li>css A CSS style string to apply to the table cell.</li>
49611 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
49612 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
49613 * <li>Row index</li>
49614 * <li>Column index</li>
49615 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
49617 setRenderer : function(col, fn){
49618 this.config[col].renderer = fn;
49622 * Returns the width for the specified column.
49623 * @param {Number} col The column index
49626 getColumnWidth : function(col){
49627 return this.config[col].width * 1 || this.defaultWidth;
49631 * Sets the width for a column.
49632 * @param {Number} col The column index
49633 * @param {Number} width The new width
49635 setColumnWidth : function(col, width, suppressEvent){
49636 this.config[col].width = width;
49637 this.totalWidth = null;
49638 if(!suppressEvent){
49639 this.fireEvent("widthchange", this, col, width);
49644 * Returns the total width of all columns.
49645 * @param {Boolean} includeHidden True to include hidden column widths
49648 getTotalWidth : function(includeHidden){
49649 if(!this.totalWidth){
49650 this.totalWidth = 0;
49651 for(var i = 0, len = this.config.length; i < len; i++){
49652 if(includeHidden || !this.isHidden(i)){
49653 this.totalWidth += this.getColumnWidth(i);
49657 return this.totalWidth;
49661 * Returns the header for the specified column.
49662 * @param {Number} col The column index
49665 getColumnHeader : function(col){
49666 return this.config[col].header;
49670 * Sets the header for a column.
49671 * @param {Number} col The column index
49672 * @param {String} header The new header
49674 setColumnHeader : function(col, header){
49675 this.config[col].header = header;
49676 this.fireEvent("headerchange", this, col, header);
49680 * Returns the tooltip for the specified column.
49681 * @param {Number} col The column index
49684 getColumnTooltip : function(col){
49685 return this.config[col].tooltip;
49688 * Sets the tooltip for a column.
49689 * @param {Number} col The column index
49690 * @param {String} tooltip The new tooltip
49692 setColumnTooltip : function(col, tooltip){
49693 this.config[col].tooltip = tooltip;
49697 * Returns the dataIndex for the specified column.
49698 * @param {Number} col The column index
49701 getDataIndex : function(col){
49702 return this.config[col].dataIndex;
49706 * Sets the dataIndex for a column.
49707 * @param {Number} col The column index
49708 * @param {Number} dataIndex The new dataIndex
49710 setDataIndex : function(col, dataIndex){
49711 this.config[col].dataIndex = dataIndex;
49717 * Returns true if the cell is editable.
49718 * @param {Number} colIndex The column index
49719 * @param {Number} rowIndex The row index
49720 * @return {Boolean}
49722 isCellEditable : function(colIndex, rowIndex){
49723 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
49727 * Returns the editor defined for the cell/column.
49728 * return false or null to disable editing.
49729 * @param {Number} colIndex The column index
49730 * @param {Number} rowIndex The row index
49733 getCellEditor : function(colIndex, rowIndex){
49734 return this.config[colIndex].editor;
49738 * Sets if a column is editable.
49739 * @param {Number} col The column index
49740 * @param {Boolean} editable True if the column is editable
49742 setEditable : function(col, editable){
49743 this.config[col].editable = editable;
49748 * Returns true if the column is hidden.
49749 * @param {Number} colIndex The column index
49750 * @return {Boolean}
49752 isHidden : function(colIndex){
49753 return this.config[colIndex].hidden;
49758 * Returns true if the column width cannot be changed
49760 isFixed : function(colIndex){
49761 return this.config[colIndex].fixed;
49765 * Returns true if the column can be resized
49766 * @return {Boolean}
49768 isResizable : function(colIndex){
49769 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
49772 * Sets if a column is hidden.
49773 * @param {Number} colIndex The column index
49774 * @param {Boolean} hidden True if the column is hidden
49776 setHidden : function(colIndex, hidden){
49777 this.config[colIndex].hidden = hidden;
49778 this.totalWidth = null;
49779 this.fireEvent("hiddenchange", this, colIndex, hidden);
49783 * Sets the editor for a column.
49784 * @param {Number} col The column index
49785 * @param {Object} editor The editor object
49787 setEditor : function(col, editor){
49788 this.config[col].editor = editor;
49792 Roo.grid.ColumnModel.defaultRenderer = function(value){
49793 if(typeof value == "string" && value.length < 1){
49799 // Alias for backwards compatibility
49800 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
49803 * Ext JS Library 1.1.1
49804 * Copyright(c) 2006-2007, Ext JS, LLC.
49806 * Originally Released Under LGPL - original licence link has changed is not relivant.
49809 * <script type="text/javascript">
49813 * @class Roo.grid.AbstractSelectionModel
49814 * @extends Roo.util.Observable
49815 * Abstract base class for grid SelectionModels. It provides the interface that should be
49816 * implemented by descendant classes. This class should not be directly instantiated.
49819 Roo.grid.AbstractSelectionModel = function(){
49820 this.locked = false;
49821 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
49824 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
49825 /** @ignore Called by the grid automatically. Do not call directly. */
49826 init : function(grid){
49832 * Locks the selections.
49835 this.locked = true;
49839 * Unlocks the selections.
49841 unlock : function(){
49842 this.locked = false;
49846 * Returns true if the selections are locked.
49847 * @return {Boolean}
49849 isLocked : function(){
49850 return this.locked;
49854 * Ext JS Library 1.1.1
49855 * Copyright(c) 2006-2007, Ext JS, LLC.
49857 * Originally Released Under LGPL - original licence link has changed is not relivant.
49860 * <script type="text/javascript">
49863 * @extends Roo.grid.AbstractSelectionModel
49864 * @class Roo.grid.RowSelectionModel
49865 * The default SelectionModel used by {@link Roo.grid.Grid}.
49866 * It supports multiple selections and keyboard selection/navigation.
49868 * @param {Object} config
49870 Roo.grid.RowSelectionModel = function(config){
49871 Roo.apply(this, config);
49872 this.selections = new Roo.util.MixedCollection(false, function(o){
49877 this.lastActive = false;
49881 * @event selectionchange
49882 * Fires when the selection changes
49883 * @param {SelectionModel} this
49885 "selectionchange" : true,
49887 * @event afterselectionchange
49888 * Fires after the selection changes (eg. by key press or clicking)
49889 * @param {SelectionModel} this
49891 "afterselectionchange" : true,
49893 * @event beforerowselect
49894 * Fires when a row is selected being selected, return false to cancel.
49895 * @param {SelectionModel} this
49896 * @param {Number} rowIndex The selected index
49897 * @param {Boolean} keepExisting False if other selections will be cleared
49899 "beforerowselect" : true,
49902 * Fires when a row is selected.
49903 * @param {SelectionModel} this
49904 * @param {Number} rowIndex The selected index
49905 * @param {Roo.data.Record} r The record
49907 "rowselect" : true,
49909 * @event rowdeselect
49910 * Fires when a row is deselected.
49911 * @param {SelectionModel} this
49912 * @param {Number} rowIndex The selected index
49914 "rowdeselect" : true
49916 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
49917 this.locked = false;
49920 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
49922 * @cfg {Boolean} singleSelect
49923 * True to allow selection of only one row at a time (defaults to false)
49925 singleSelect : false,
49928 initEvents : function(){
49930 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
49931 this.grid.on("mousedown", this.handleMouseDown, this);
49932 }else{ // allow click to work like normal
49933 this.grid.on("rowclick", this.handleDragableRowClick, this);
49936 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
49937 "up" : function(e){
49939 this.selectPrevious(e.shiftKey);
49940 }else if(this.last !== false && this.lastActive !== false){
49941 var last = this.last;
49942 this.selectRange(this.last, this.lastActive-1);
49943 this.grid.getView().focusRow(this.lastActive);
49944 if(last !== false){
49948 this.selectFirstRow();
49950 this.fireEvent("afterselectionchange", this);
49952 "down" : function(e){
49954 this.selectNext(e.shiftKey);
49955 }else if(this.last !== false && this.lastActive !== false){
49956 var last = this.last;
49957 this.selectRange(this.last, this.lastActive+1);
49958 this.grid.getView().focusRow(this.lastActive);
49959 if(last !== false){
49963 this.selectFirstRow();
49965 this.fireEvent("afterselectionchange", this);
49970 var view = this.grid.view;
49971 view.on("refresh", this.onRefresh, this);
49972 view.on("rowupdated", this.onRowUpdated, this);
49973 view.on("rowremoved", this.onRemove, this);
49977 onRefresh : function(){
49978 var ds = this.grid.dataSource, i, v = this.grid.view;
49979 var s = this.selections;
49980 s.each(function(r){
49981 if((i = ds.indexOfId(r.id)) != -1){
49990 onRemove : function(v, index, r){
49991 this.selections.remove(r);
49995 onRowUpdated : function(v, index, r){
49996 if(this.isSelected(r)){
49997 v.onRowSelect(index);
50003 * @param {Array} records The records to select
50004 * @param {Boolean} keepExisting (optional) True to keep existing selections
50006 selectRecords : function(records, keepExisting){
50008 this.clearSelections();
50010 var ds = this.grid.dataSource;
50011 for(var i = 0, len = records.length; i < len; i++){
50012 this.selectRow(ds.indexOf(records[i]), true);
50017 * Gets the number of selected rows.
50020 getCount : function(){
50021 return this.selections.length;
50025 * Selects the first row in the grid.
50027 selectFirstRow : function(){
50032 * Select the last row.
50033 * @param {Boolean} keepExisting (optional) True to keep existing selections
50035 selectLastRow : function(keepExisting){
50036 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
50040 * Selects the row immediately following the last selected row.
50041 * @param {Boolean} keepExisting (optional) True to keep existing selections
50043 selectNext : function(keepExisting){
50044 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
50045 this.selectRow(this.last+1, keepExisting);
50046 this.grid.getView().focusRow(this.last);
50051 * Selects the row that precedes the last selected row.
50052 * @param {Boolean} keepExisting (optional) True to keep existing selections
50054 selectPrevious : function(keepExisting){
50056 this.selectRow(this.last-1, keepExisting);
50057 this.grid.getView().focusRow(this.last);
50062 * Returns the selected records
50063 * @return {Array} Array of selected records
50065 getSelections : function(){
50066 return [].concat(this.selections.items);
50070 * Returns the first selected record.
50073 getSelected : function(){
50074 return this.selections.itemAt(0);
50079 * Clears all selections.
50081 clearSelections : function(fast){
50082 if(this.locked) return;
50084 var ds = this.grid.dataSource;
50085 var s = this.selections;
50086 s.each(function(r){
50087 this.deselectRow(ds.indexOfId(r.id));
50091 this.selections.clear();
50098 * Selects all rows.
50100 selectAll : function(){
50101 if(this.locked) return;
50102 this.selections.clear();
50103 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
50104 this.selectRow(i, true);
50109 * Returns True if there is a selection.
50110 * @return {Boolean}
50112 hasSelection : function(){
50113 return this.selections.length > 0;
50117 * Returns True if the specified row is selected.
50118 * @param {Number/Record} record The record or index of the record to check
50119 * @return {Boolean}
50121 isSelected : function(index){
50122 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
50123 return (r && this.selections.key(r.id) ? true : false);
50127 * Returns True if the specified record id is selected.
50128 * @param {String} id The id of record to check
50129 * @return {Boolean}
50131 isIdSelected : function(id){
50132 return (this.selections.key(id) ? true : false);
50136 handleMouseDown : function(e, t){
50137 var view = this.grid.getView(), rowIndex;
50138 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
50141 if(e.shiftKey && this.last !== false){
50142 var last = this.last;
50143 this.selectRange(last, rowIndex, e.ctrlKey);
50144 this.last = last; // reset the last
50145 view.focusRow(rowIndex);
50147 var isSelected = this.isSelected(rowIndex);
50148 if(e.button !== 0 && isSelected){
50149 view.focusRow(rowIndex);
50150 }else if(e.ctrlKey && isSelected){
50151 this.deselectRow(rowIndex);
50152 }else if(!isSelected){
50153 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
50154 view.focusRow(rowIndex);
50157 this.fireEvent("afterselectionchange", this);
50160 handleDragableRowClick : function(grid, rowIndex, e)
50162 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
50163 this.selectRow(rowIndex, false);
50164 grid.view.focusRow(rowIndex);
50165 this.fireEvent("afterselectionchange", this);
50170 * Selects multiple rows.
50171 * @param {Array} rows Array of the indexes of the row to select
50172 * @param {Boolean} keepExisting (optional) True to keep existing selections
50174 selectRows : function(rows, keepExisting){
50176 this.clearSelections();
50178 for(var i = 0, len = rows.length; i < len; i++){
50179 this.selectRow(rows[i], true);
50184 * Selects a range of rows. All rows in between startRow and endRow are also selected.
50185 * @param {Number} startRow The index of the first row in the range
50186 * @param {Number} endRow The index of the last row in the range
50187 * @param {Boolean} keepExisting (optional) True to retain existing selections
50189 selectRange : function(startRow, endRow, keepExisting){
50190 if(this.locked) return;
50192 this.clearSelections();
50194 if(startRow <= endRow){
50195 for(var i = startRow; i <= endRow; i++){
50196 this.selectRow(i, true);
50199 for(var i = startRow; i >= endRow; i--){
50200 this.selectRow(i, true);
50206 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
50207 * @param {Number} startRow The index of the first row in the range
50208 * @param {Number} endRow The index of the last row in the range
50210 deselectRange : function(startRow, endRow, preventViewNotify){
50211 if(this.locked) return;
50212 for(var i = startRow; i <= endRow; i++){
50213 this.deselectRow(i, preventViewNotify);
50219 * @param {Number} row The index of the row to select
50220 * @param {Boolean} keepExisting (optional) True to keep existing selections
50222 selectRow : function(index, keepExisting, preventViewNotify){
50223 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
50224 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
50225 if(!keepExisting || this.singleSelect){
50226 this.clearSelections();
50228 var r = this.grid.dataSource.getAt(index);
50229 this.selections.add(r);
50230 this.last = this.lastActive = index;
50231 if(!preventViewNotify){
50232 this.grid.getView().onRowSelect(index);
50234 this.fireEvent("rowselect", this, index, r);
50235 this.fireEvent("selectionchange", this);
50241 * @param {Number} row The index of the row to deselect
50243 deselectRow : function(index, preventViewNotify){
50244 if(this.locked) return;
50245 if(this.last == index){
50248 if(this.lastActive == index){
50249 this.lastActive = false;
50251 var r = this.grid.dataSource.getAt(index);
50252 this.selections.remove(r);
50253 if(!preventViewNotify){
50254 this.grid.getView().onRowDeselect(index);
50256 this.fireEvent("rowdeselect", this, index);
50257 this.fireEvent("selectionchange", this);
50261 restoreLast : function(){
50263 this.last = this._last;
50268 acceptsNav : function(row, col, cm){
50269 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50273 onEditorKey : function(field, e){
50274 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50279 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50281 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50283 }else if(k == e.ENTER && !e.ctrlKey){
50287 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
50289 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
50291 }else if(k == e.ESC){
50295 g.startEditing(newCell[0], newCell[1]);
50300 * Ext JS Library 1.1.1
50301 * Copyright(c) 2006-2007, Ext JS, LLC.
50303 * Originally Released Under LGPL - original licence link has changed is not relivant.
50306 * <script type="text/javascript">
50309 * @class Roo.grid.CellSelectionModel
50310 * @extends Roo.grid.AbstractSelectionModel
50311 * This class provides the basic implementation for cell selection in a grid.
50313 * @param {Object} config The object containing the configuration of this model.
50315 Roo.grid.CellSelectionModel = function(config){
50316 Roo.apply(this, config);
50318 this.selection = null;
50322 * @event beforerowselect
50323 * Fires before a cell is selected.
50324 * @param {SelectionModel} this
50325 * @param {Number} rowIndex The selected row index
50326 * @param {Number} colIndex The selected cell index
50328 "beforecellselect" : true,
50330 * @event cellselect
50331 * Fires when a cell is selected.
50332 * @param {SelectionModel} this
50333 * @param {Number} rowIndex The selected row index
50334 * @param {Number} colIndex The selected cell index
50336 "cellselect" : true,
50338 * @event selectionchange
50339 * Fires when the active selection changes.
50340 * @param {SelectionModel} this
50341 * @param {Object} selection null for no selection or an object (o) with two properties
50343 <li>o.record: the record object for the row the selection is in</li>
50344 <li>o.cell: An array of [rowIndex, columnIndex]</li>
50347 "selectionchange" : true
50349 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
50352 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
50355 initEvents : function(){
50356 this.grid.on("mousedown", this.handleMouseDown, this);
50357 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
50358 var view = this.grid.view;
50359 view.on("refresh", this.onViewChange, this);
50360 view.on("rowupdated", this.onRowUpdated, this);
50361 view.on("beforerowremoved", this.clearSelections, this);
50362 view.on("beforerowsinserted", this.clearSelections, this);
50363 if(this.grid.isEditor){
50364 this.grid.on("beforeedit", this.beforeEdit, this);
50369 beforeEdit : function(e){
50370 this.select(e.row, e.column, false, true, e.record);
50374 onRowUpdated : function(v, index, r){
50375 if(this.selection && this.selection.record == r){
50376 v.onCellSelect(index, this.selection.cell[1]);
50381 onViewChange : function(){
50382 this.clearSelections(true);
50386 * Returns the currently selected cell,.
50387 * @return {Array} The selected cell (row, column) or null if none selected.
50389 getSelectedCell : function(){
50390 return this.selection ? this.selection.cell : null;
50394 * Clears all selections.
50395 * @param {Boolean} true to prevent the gridview from being notified about the change.
50397 clearSelections : function(preventNotify){
50398 var s = this.selection;
50400 if(preventNotify !== true){
50401 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
50403 this.selection = null;
50404 this.fireEvent("selectionchange", this, null);
50409 * Returns true if there is a selection.
50410 * @return {Boolean}
50412 hasSelection : function(){
50413 return this.selection ? true : false;
50417 handleMouseDown : function(e, t){
50418 var v = this.grid.getView();
50419 if(this.isLocked()){
50422 var row = v.findRowIndex(t);
50423 var cell = v.findCellIndex(t);
50424 if(row !== false && cell !== false){
50425 this.select(row, cell);
50431 * @param {Number} rowIndex
50432 * @param {Number} collIndex
50434 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
50435 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
50436 this.clearSelections();
50437 r = r || this.grid.dataSource.getAt(rowIndex);
50440 cell : [rowIndex, colIndex]
50442 if(!preventViewNotify){
50443 var v = this.grid.getView();
50444 v.onCellSelect(rowIndex, colIndex);
50445 if(preventFocus !== true){
50446 v.focusCell(rowIndex, colIndex);
50449 this.fireEvent("cellselect", this, rowIndex, colIndex);
50450 this.fireEvent("selectionchange", this, this.selection);
50455 isSelectable : function(rowIndex, colIndex, cm){
50456 return !cm.isHidden(colIndex);
50460 handleKeyDown : function(e){
50461 Roo.log('Cell Sel Model handleKeyDown');
50462 if(!e.isNavKeyPress()){
50465 var g = this.grid, s = this.selection;
50468 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
50470 this.select(cell[0], cell[1]);
50475 var walk = function(row, col, step){
50476 return g.walkCells(row, col, step, sm.isSelectable, sm);
50478 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
50483 // handled by onEditorKey
50484 if (g.isEditor && g.editing) {
50488 newCell = walk(r, c-1, -1);
50490 newCell = walk(r, c+1, 1);
50494 newCell = walk(r+1, c, 1);
50497 newCell = walk(r-1, c, -1);
50500 newCell = walk(r, c+1, 1);
50503 newCell = walk(r, c-1, -1);
50506 if(g.isEditor && !g.editing){
50507 g.startEditing(r, c);
50514 this.select(newCell[0], newCell[1]);
50519 acceptsNav : function(row, col, cm){
50520 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50523 onEditorKey : function(field, e){
50525 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50526 ///Roo.log('onEditorKey' + k);
50530 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50532 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50535 }else if(k == e.ENTER && !e.ctrlKey){
50538 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50539 }else if(k == e.ESC){
50545 //Roo.log('next cell after edit');
50546 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
50551 * Ext JS Library 1.1.1
50552 * Copyright(c) 2006-2007, Ext JS, LLC.
50554 * Originally Released Under LGPL - original licence link has changed is not relivant.
50557 * <script type="text/javascript">
50561 * @class Roo.grid.EditorGrid
50562 * @extends Roo.grid.Grid
50563 * Class for creating and editable grid.
50564 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50565 * The container MUST have some type of size defined for the grid to fill. The container will be
50566 * automatically set to position relative if it isn't already.
50567 * @param {Object} dataSource The data model to bind to
50568 * @param {Object} colModel The column model with info about this grid's columns
50570 Roo.grid.EditorGrid = function(container, config){
50571 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
50572 this.getGridEl().addClass("xedit-grid");
50574 if(!this.selModel){
50575 this.selModel = new Roo.grid.CellSelectionModel();
50578 this.activeEditor = null;
50582 * @event beforeedit
50583 * Fires before cell editing is triggered. The edit event object has the following properties <br />
50584 * <ul style="padding:5px;padding-left:16px;">
50585 * <li>grid - This grid</li>
50586 * <li>record - The record being edited</li>
50587 * <li>field - The field name being edited</li>
50588 * <li>value - The value for the field being edited.</li>
50589 * <li>row - The grid row index</li>
50590 * <li>column - The grid column index</li>
50591 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50593 * @param {Object} e An edit event (see above for description)
50595 "beforeedit" : true,
50598 * Fires after a cell is edited. <br />
50599 * <ul style="padding:5px;padding-left:16px;">
50600 * <li>grid - This grid</li>
50601 * <li>record - The record being edited</li>
50602 * <li>field - The field name being edited</li>
50603 * <li>value - The value being set</li>
50604 * <li>originalValue - The original value for the field, before the edit.</li>
50605 * <li>row - The grid row index</li>
50606 * <li>column - The grid column index</li>
50608 * @param {Object} e An edit event (see above for description)
50610 "afteredit" : true,
50612 * @event validateedit
50613 * Fires after a cell is edited, but before the value is set in the record.
50614 * You can use this to modify the value being set in the field, Return false
50615 * to cancel the change. The edit event object has the following properties <br />
50616 * <ul style="padding:5px;padding-left:16px;">
50617 * <li>editor - This editor</li>
50618 * <li>grid - This grid</li>
50619 * <li>record - The record being edited</li>
50620 * <li>field - The field name being edited</li>
50621 * <li>value - The value being set</li>
50622 * <li>originalValue - The original value for the field, before the edit.</li>
50623 * <li>row - The grid row index</li>
50624 * <li>column - The grid column index</li>
50625 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50627 * @param {Object} e An edit event (see above for description)
50629 "validateedit" : true
50631 this.on("bodyscroll", this.stopEditing, this);
50632 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
50635 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
50637 * @cfg {Number} clicksToEdit
50638 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
50645 trackMouseOver: false, // causes very odd FF errors
50647 onCellDblClick : function(g, row, col){
50648 this.startEditing(row, col);
50651 onEditComplete : function(ed, value, startValue){
50652 this.editing = false;
50653 this.activeEditor = null;
50654 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
50656 var field = this.colModel.getDataIndex(ed.col);
50661 originalValue: startValue,
50668 if(String(value) !== String(startValue)){
50670 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
50671 r.set(field, e.value);
50672 // if we are dealing with a combo box..
50673 // then we also set the 'name' colum to be the displayField
50674 if (ed.field.displayField && ed.field.name) {
50675 r.set(ed.field.name, ed.field.el.dom.value);
50678 delete e.cancel; //?? why!!!
50679 this.fireEvent("afteredit", e);
50682 this.fireEvent("afteredit", e); // always fire it!
50684 this.view.focusCell(ed.row, ed.col);
50688 * Starts editing the specified for the specified row/column
50689 * @param {Number} rowIndex
50690 * @param {Number} colIndex
50692 startEditing : function(row, col){
50693 this.stopEditing();
50694 if(this.colModel.isCellEditable(col, row)){
50695 this.view.ensureVisible(row, col, true);
50696 var r = this.dataSource.getAt(row);
50697 var field = this.colModel.getDataIndex(col);
50702 value: r.data[field],
50707 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
50708 this.editing = true;
50709 var ed = this.colModel.getCellEditor(col, row);
50715 ed.render(ed.parentEl || document.body);
50718 (function(){ // complex but required for focus issues in safari, ie and opera
50722 ed.on("complete", this.onEditComplete, this, {single: true});
50723 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
50724 this.activeEditor = ed;
50725 var v = r.data[field];
50726 ed.startEdit(this.view.getCell(row, col), v);
50727 // combo's with 'displayField and name set
50728 if (ed.field.displayField && ed.field.name) {
50729 ed.field.el.dom.value = r.data[ed.field.name];
50733 }).defer(50, this);
50739 * Stops any active editing
50741 stopEditing : function(){
50742 if(this.activeEditor){
50743 this.activeEditor.completeEdit();
50745 this.activeEditor = null;
50749 * Ext JS Library 1.1.1
50750 * Copyright(c) 2006-2007, Ext JS, LLC.
50752 * Originally Released Under LGPL - original licence link has changed is not relivant.
50755 * <script type="text/javascript">
50758 // private - not really -- you end up using it !
50759 // This is a support class used internally by the Grid components
50762 * @class Roo.grid.GridEditor
50763 * @extends Roo.Editor
50764 * Class for creating and editable grid elements.
50765 * @param {Object} config any settings (must include field)
50767 Roo.grid.GridEditor = function(field, config){
50768 if (!config && field.field) {
50770 field = Roo.factory(config.field, Roo.form);
50772 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
50773 field.monitorTab = false;
50776 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
50779 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
50782 alignment: "tl-tl",
50785 cls: "x-small-editor x-grid-editor",
50790 * Ext JS Library 1.1.1
50791 * Copyright(c) 2006-2007, Ext JS, LLC.
50793 * Originally Released Under LGPL - original licence link has changed is not relivant.
50796 * <script type="text/javascript">
50801 Roo.grid.PropertyRecord = Roo.data.Record.create([
50802 {name:'name',type:'string'}, 'value'
50806 Roo.grid.PropertyStore = function(grid, source){
50808 this.store = new Roo.data.Store({
50809 recordType : Roo.grid.PropertyRecord
50811 this.store.on('update', this.onUpdate, this);
50813 this.setSource(source);
50815 Roo.grid.PropertyStore.superclass.constructor.call(this);
50820 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
50821 setSource : function(o){
50823 this.store.removeAll();
50826 if(this.isEditableValue(o[k])){
50827 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
50830 this.store.loadRecords({records: data}, {}, true);
50833 onUpdate : function(ds, record, type){
50834 if(type == Roo.data.Record.EDIT){
50835 var v = record.data['value'];
50836 var oldValue = record.modified['value'];
50837 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
50838 this.source[record.id] = v;
50840 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
50847 getProperty : function(row){
50848 return this.store.getAt(row);
50851 isEditableValue: function(val){
50852 if(val && val instanceof Date){
50854 }else if(typeof val == 'object' || typeof val == 'function'){
50860 setValue : function(prop, value){
50861 this.source[prop] = value;
50862 this.store.getById(prop).set('value', value);
50865 getSource : function(){
50866 return this.source;
50870 Roo.grid.PropertyColumnModel = function(grid, store){
50873 g.PropertyColumnModel.superclass.constructor.call(this, [
50874 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
50875 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
50877 this.store = store;
50878 this.bselect = Roo.DomHelper.append(document.body, {
50879 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
50880 {tag: 'option', value: 'true', html: 'true'},
50881 {tag: 'option', value: 'false', html: 'false'}
50884 Roo.id(this.bselect);
50887 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
50888 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
50889 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
50890 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
50891 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
50893 this.renderCellDelegate = this.renderCell.createDelegate(this);
50894 this.renderPropDelegate = this.renderProp.createDelegate(this);
50897 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
50901 valueText : 'Value',
50903 dateFormat : 'm/j/Y',
50906 renderDate : function(dateVal){
50907 return dateVal.dateFormat(this.dateFormat);
50910 renderBool : function(bVal){
50911 return bVal ? 'true' : 'false';
50914 isCellEditable : function(colIndex, rowIndex){
50915 return colIndex == 1;
50918 getRenderer : function(col){
50920 this.renderCellDelegate : this.renderPropDelegate;
50923 renderProp : function(v){
50924 return this.getPropertyName(v);
50927 renderCell : function(val){
50929 if(val instanceof Date){
50930 rv = this.renderDate(val);
50931 }else if(typeof val == 'boolean'){
50932 rv = this.renderBool(val);
50934 return Roo.util.Format.htmlEncode(rv);
50937 getPropertyName : function(name){
50938 var pn = this.grid.propertyNames;
50939 return pn && pn[name] ? pn[name] : name;
50942 getCellEditor : function(colIndex, rowIndex){
50943 var p = this.store.getProperty(rowIndex);
50944 var n = p.data['name'], val = p.data['value'];
50946 if(typeof(this.grid.customEditors[n]) == 'string'){
50947 return this.editors[this.grid.customEditors[n]];
50949 if(typeof(this.grid.customEditors[n]) != 'undefined'){
50950 return this.grid.customEditors[n];
50952 if(val instanceof Date){
50953 return this.editors['date'];
50954 }else if(typeof val == 'number'){
50955 return this.editors['number'];
50956 }else if(typeof val == 'boolean'){
50957 return this.editors['boolean'];
50959 return this.editors['string'];
50965 * @class Roo.grid.PropertyGrid
50966 * @extends Roo.grid.EditorGrid
50967 * This class represents the interface of a component based property grid control.
50968 * <br><br>Usage:<pre><code>
50969 var grid = new Roo.grid.PropertyGrid("my-container-id", {
50977 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50978 * The container MUST have some type of size defined for the grid to fill. The container will be
50979 * automatically set to position relative if it isn't already.
50980 * @param {Object} config A config object that sets properties on this grid.
50982 Roo.grid.PropertyGrid = function(container, config){
50983 config = config || {};
50984 var store = new Roo.grid.PropertyStore(this);
50985 this.store = store;
50986 var cm = new Roo.grid.PropertyColumnModel(this, store);
50987 store.store.sort('name', 'ASC');
50988 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
50991 enableColLock:false,
50992 enableColumnMove:false,
50994 trackMouseOver: false,
50997 this.getGridEl().addClass('x-props-grid');
50998 this.lastEditRow = null;
50999 this.on('columnresize', this.onColumnResize, this);
51002 * @event beforepropertychange
51003 * Fires before a property changes (return false to stop?)
51004 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
51005 * @param {String} id Record Id
51006 * @param {String} newval New Value
51007 * @param {String} oldval Old Value
51009 "beforepropertychange": true,
51011 * @event propertychange
51012 * Fires after a property changes
51013 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
51014 * @param {String} id Record Id
51015 * @param {String} newval New Value
51016 * @param {String} oldval Old Value
51018 "propertychange": true
51020 this.customEditors = this.customEditors || {};
51022 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
51025 * @cfg {Object} customEditors map of colnames=> custom editors.
51026 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
51027 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
51028 * false disables editing of the field.
51032 * @cfg {Object} propertyNames map of property Names to their displayed value
51035 render : function(){
51036 Roo.grid.PropertyGrid.superclass.render.call(this);
51037 this.autoSize.defer(100, this);
51040 autoSize : function(){
51041 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
51043 this.view.fitColumns();
51047 onColumnResize : function(){
51048 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
51052 * Sets the data for the Grid
51053 * accepts a Key => Value object of all the elements avaiable.
51054 * @param {Object} data to appear in grid.
51056 setSource : function(source){
51057 this.store.setSource(source);
51061 * Gets all the data from the grid.
51062 * @return {Object} data data stored in grid
51064 getSource : function(){
51065 return this.store.getSource();
51069 * Ext JS Library 1.1.1
51070 * Copyright(c) 2006-2007, Ext JS, LLC.
51072 * Originally Released Under LGPL - original licence link has changed is not relivant.
51075 * <script type="text/javascript">
51079 * @class Roo.LoadMask
51080 * A simple utility class for generically masking elements while loading data. If the element being masked has
51081 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
51082 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
51083 * element's UpdateManager load indicator and will be destroyed after the initial load.
51085 * Create a new LoadMask
51086 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
51087 * @param {Object} config The config object
51089 Roo.LoadMask = function(el, config){
51090 this.el = Roo.get(el);
51091 Roo.apply(this, config);
51093 this.store.on('beforeload', this.onBeforeLoad, this);
51094 this.store.on('load', this.onLoad, this);
51095 this.store.on('loadexception', this.onLoad, this);
51096 this.removeMask = false;
51098 var um = this.el.getUpdateManager();
51099 um.showLoadIndicator = false; // disable the default indicator
51100 um.on('beforeupdate', this.onBeforeLoad, this);
51101 um.on('update', this.onLoad, this);
51102 um.on('failure', this.onLoad, this);
51103 this.removeMask = true;
51107 Roo.LoadMask.prototype = {
51109 * @cfg {Boolean} removeMask
51110 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
51111 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
51114 * @cfg {String} msg
51115 * The text to display in a centered loading message box (defaults to 'Loading...')
51117 msg : 'Loading...',
51119 * @cfg {String} msgCls
51120 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
51122 msgCls : 'x-mask-loading',
51125 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
51131 * Disables the mask to prevent it from being displayed
51133 disable : function(){
51134 this.disabled = true;
51138 * Enables the mask so that it can be displayed
51140 enable : function(){
51141 this.disabled = false;
51145 onLoad : function(){
51146 this.el.unmask(this.removeMask);
51150 onBeforeLoad : function(){
51151 if(!this.disabled){
51152 this.el.mask(this.msg, this.msgCls);
51157 destroy : function(){
51159 this.store.un('beforeload', this.onBeforeLoad, this);
51160 this.store.un('load', this.onLoad, this);
51161 this.store.un('loadexception', this.onLoad, this);
51163 var um = this.el.getUpdateManager();
51164 um.un('beforeupdate', this.onBeforeLoad, this);
51165 um.un('update', this.onLoad, this);
51166 um.un('failure', this.onLoad, this);
51171 * Ext JS Library 1.1.1
51172 * Copyright(c) 2006-2007, Ext JS, LLC.
51174 * Originally Released Under LGPL - original licence link has changed is not relivant.
51177 * <script type="text/javascript">
51179 Roo.XTemplate = function(){
51180 Roo.XTemplate.superclass.constructor.apply(this, arguments);
51183 s = ['<tpl>', s, '</tpl>'].join('');
51185 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
51187 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
51188 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
51189 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
51193 while(m = s.match(re)){
51194 var m2 = m[0].match(nameRe);
51195 var m3 = m[0].match(ifRe);
51196 var m4 = m[0].match(execRe);
51197 var exp = null, fn = null, exec = null;
51198 var name = m2 && m2[1] ? m2[1] : '';
51200 exp = m3 && m3[1] ? m3[1] : null;
51202 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
51206 exp = m4 && m4[1] ? m4[1] : null;
51208 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
51213 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
51214 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
51215 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
51225 s = s.replace(m[0], '{xtpl'+ id + '}');
51228 for(var i = tpls.length-1; i >= 0; --i){
51229 this.compileTpl(tpls[i]);
51231 this.master = tpls[tpls.length-1];
51234 Roo.extend(Roo.XTemplate, Roo.Template, {
51236 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
51238 applySubTemplate : function(id, values, parent){
51239 var t = this.tpls[id];
51240 if(t.test && !t.test.call(this, values, parent)){
51243 if(t.exec && t.exec.call(this, values, parent)){
51246 var vs = t.target ? t.target.call(this, values, parent) : values;
51247 parent = t.target ? values : parent;
51248 if(t.target && vs instanceof Array){
51250 for(var i = 0, len = vs.length; i < len; i++){
51251 buf[buf.length] = t.compiled.call(this, vs[i], parent);
51253 return buf.join('');
51255 return t.compiled.call(this, vs, parent);
51258 compileTpl : function(tpl){
51259 var fm = Roo.util.Format;
51260 var useF = this.disableFormats !== true;
51261 var sep = Roo.isGecko ? "+" : ",";
51262 var fn = function(m, name, format, args){
51263 if(name.substr(0, 4) == 'xtpl'){
51264 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
51267 if(name.indexOf('.') != -1){
51270 v = "values['" + name + "']";
51272 if(format && useF){
51273 args = args ? ',' + args : "";
51274 if(format.substr(0, 5) != "this."){
51275 format = "fm." + format + '(';
51277 format = 'this.call("'+ format.substr(5) + '", ';
51281 args= ''; format = "("+v+" === undefined ? '' : ";
51283 return "'"+ sep + format + v + args + ")"+sep+"'";
51286 // branched to use + in gecko and [].join() in others
51288 body = "tpl.compiled = function(values, parent){ return '" +
51289 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
51292 body = ["tpl.compiled = function(values, parent){ return ['"];
51293 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
51294 body.push("'].join('');};");
51295 body = body.join('');
51297 /** eval:var:zzzzzzz */
51302 applyTemplate : function(values){
51303 return this.master.compiled.call(this, values, {});
51307 apply : function(){
51308 return this.applyTemplate.apply(this, arguments);
51311 compile : function(){return this;}
51314 Roo.XTemplate.from = function(el){
51315 el = Roo.getDom(el);
51316 return new Roo.XTemplate(el.value || el.innerHTML);
51318 * Original code for Roojs - LGPL
51319 * <script type="text/javascript">
51323 * @class Roo.XComponent
51324 * A delayed Element creator...
51325 * Or a way to group chunks of interface together.
51327 * Mypart.xyx = new Roo.XComponent({
51329 parent : 'Mypart.xyz', // empty == document.element.!!
51333 disabled : function() {}
51335 tree : function() { // return an tree of xtype declared components
51339 xtype : 'NestedLayoutPanel',
51346 * It can be used to build a big heiracy, with parent etc.
51347 * or you can just use this to render a single compoent to a dom element
51348 * MYPART.render(Roo.Element | String(id) | dom_element )
51350 * @extends Roo.util.Observable
51352 * @param cfg {Object} configuration of component
51355 Roo.XComponent = function(cfg) {
51356 Roo.apply(this, cfg);
51360 * Fires when this the componnt is built
51361 * @param {Roo.XComponent} c the component
51365 * @event buildcomplete
51366 * Fires on the top level element when all elements have been built
51367 * @param {Roo.XComponent} c the top level component.
51369 'buildcomplete' : true
51372 this.region = this.region || 'center'; // default..
51373 Roo.XComponent.register(this);
51374 this.modules = false;
51375 this.el = false; // where the layout goes..
51379 Roo.extend(Roo.XComponent, Roo.util.Observable, {
51382 * The created element (with Roo.factory())
51383 * @type {Roo.Layout}
51389 * for BC - use el in new code
51390 * @type {Roo.Layout}
51396 * for BC - use el in new code
51397 * @type {Roo.Layout}
51402 * @cfg {Function|boolean} disabled
51403 * If this module is disabled by some rule, return true from the funtion
51408 * @cfg {String} parent
51409 * Name of parent element which it get xtype added to..
51414 * @cfg {String} order
51415 * Used to set the order in which elements are created (usefull for multiple tabs)
51420 * @cfg {String} name
51421 * String to display while loading.
51425 * @cfg {String} region
51426 * Region to render component to (defaults to center)
51431 * @cfg {Array} items
51432 * A single item array - the first element is the root of the tree..
51433 * It's done this way to stay compatible with the Xtype system...
51440 * render element to dom or tree
51441 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
51444 render : function(el)
51448 var hp = this.parent ? 1 : 0;
51450 if (!el && typeof(this.parent) == 'string' && this.parent[0] == '#') {
51451 // if parent is a '#.....' string, then let's use that..
51452 var ename = this.parent.substr(1)
51453 this.parent = false;
51454 el = Roo.get(ename);
51456 Roo.log("Warning - element can not be found :#" + ename );
51462 if (!this.parent) {
51464 el = el ? Roo.get(el) : false;
51466 // it's a top level one..
51468 el : new Roo.BorderLayout(el || document.body, {
51474 tabPosition: 'top',
51475 //resizeTabs: true,
51476 alwaysShowTabs: el && hp? false : true,
51477 hideTabs: el || !hp ? true : false,
51486 var tree = this.tree();
51487 tree.region = tree.region || this.region;
51488 this.el = this.parent.el.addxtype(tree);
51489 this.fireEvent('built', this);
51491 this.panel = this.el;
51492 this.layout = this.panel.layout;
51498 Roo.apply(Roo.XComponent, {
51501 * @property buildCompleted
51502 * True when the builder has completed building the interface.
51505 buildCompleted : false,
51508 * @property topModule
51509 * the upper most module - uses document.element as it's constructor.
51516 * @property modules
51517 * array of modules to be created by registration system.
51518 * @type {Array} of Roo.XComponent
51523 * @property elmodules
51524 * array of modules to be created by which use #ID
51525 * @type {Array} of Roo.XComponent
51532 * Register components to be built later.
51534 * This solves the following issues
51535 * - Building is not done on page load, but after an authentication process has occured.
51536 * - Interface elements are registered on page load
51537 * - Parent Interface elements may not be loaded before child, so this handles that..
51544 module : 'Pman.Tab.projectMgr',
51546 parent : 'Pman.layout',
51547 disabled : false, // or use a function..
51550 * * @param {Object} details about module
51552 register : function(obj) {
51553 this.modules.push(obj);
51557 * convert a string to an object..
51558 * eg. 'AAA.BBB' -> finds AAA.BBB
51562 toObject : function(str)
51564 if (!str || typeof(str) == 'object') {
51571 var ar = str.split('.');
51575 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
51577 throw "Module not found : " + str;
51579 Roo.each(ar, function(e) {
51580 if (typeof(o[e]) == 'undefined') {
51581 throw "Module not found : " + str;
51592 * move modules into their correct place in the tree..
51595 preBuild : function ()
51598 Roo.each(this.modules , function (obj)
51600 var opar = obj.parent;
51601 obj.parent = this.toObject(opar);
51604 this.topModule = obj;
51607 if (typeof(obj.parent) == 'string') {
51608 this.elmodules.push(obj);
51611 if (obj.parent.constructor != Roo.XComponent) {
51612 Roo.log("Object Parent is not instance of XComponent:" + obj.name)
51614 if (!obj.parent.modules) {
51615 obj.parent.modules = new Roo.util.MixedCollection(false,
51616 function(o) { return o.order + '' }
51620 obj.parent.modules.add(obj);
51625 * make a list of modules to build.
51626 * @return {Array} list of modules.
51629 buildOrder : function()
51632 var cmp = function(a,b) {
51633 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
51635 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
51636 throw "No top level modules to build";
51639 // make a flat list in order of modules to build.
51640 var mods = this.topModule ? [ this.topModule ] : [];
51641 Roo.each(this.elmodules,function(e) { mods.push(e) });
51644 // add modules to their parents..
51645 var addMod = function(m) {
51646 // Roo.debug && Roo.log(m.modKey);
51650 m.modules.keySort('ASC', cmp );
51651 m.modules.each(addMod);
51653 // not sure if this is used any more..
51655 m.finalize.name = m.name + " (clean up) ";
51656 mods.push(m.finalize);
51660 if (this.topModule) {
51661 this.topModule.modules.keySort('ASC', cmp );
51662 this.topModule.modules.each(addMod);
51668 * Build the registered modules.
51669 * @param {Object} parent element.
51670 * @param {Function} optional method to call after module has been added.
51678 var mods = this.buildOrder();
51680 //this.allmods = mods;
51681 //Roo.debug && Roo.log(mods);
51683 if (!mods.length) { // should not happen
51684 throw "NO modules!!!";
51689 // flash it up as modal - so we store the mask!?
51690 Roo.MessageBox.show({ title: 'loading' });
51691 Roo.MessageBox.show({
51692 title: "Please wait...",
51693 msg: "Building Interface...",
51700 var total = mods.length;
51703 var progressRun = function() {
51704 if (!mods.length) {
51705 Roo.debug && Roo.log('hide?');
51706 Roo.MessageBox.hide();
51707 if (_this.topModule) {
51708 _this.topModule.fireEvent('buildcomplete', _this.topModule);
51714 var m = mods.shift();
51717 Roo.debug && Roo.log(m);
51718 // not sure if this is supported any more.. - modules that are are just function
51719 if (typeof(m) == 'function') {
51721 return progressRun.defer(10, _this);
51726 Roo.MessageBox.updateProgress(
51727 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
51729 (m.name ? (' - ' + m.name) : '')
51733 // is the module disabled?
51734 var disabled = (typeof(m.disabled) == 'function') ?
51735 m.disabled.call(m.module.disabled) : m.disabled;
51739 return progressRun(); // we do not update the display!
51745 // it's 10 on top level, and 1 on others??? why...
51746 return progressRun.defer(10, _this);
51749 progressRun.defer(1, _this);
51760 //<script type="text/javascript">
51765 * @extends Roo.LayoutDialog
51766 * A generic Login Dialog..... - only one needed in theory!?!?
51768 * Fires XComponent builder on success...
51771 * username,password, lang = for login actions.
51772 * check = 1 for periodic checking that sesion is valid.
51773 * passwordRequest = email request password
51774 * logout = 1 = to logout
51776 * Affects: (this id="????" elements)
51777 * loading (removed) (used to indicate application is loading)
51778 * loading-mask (hides) (used to hide application when it's building loading)
51784 * Myapp.login = Roo.Login({
51800 Roo.Login = function(cfg)
51806 Roo.apply(this,cfg);
51808 Roo.onReady(function() {
51814 Roo.Login.superclass.constructor.call(this, this);
51815 //this.addxtype(this.items[0]);
51821 Roo.extend(Roo.Login, Roo.LayoutDialog, {
51824 * @cfg {String} method
51825 * Method used to query for login details.
51830 * @cfg {String} url
51831 * URL to query login data. - eg. baseURL + '/Login.php'
51837 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
51842 * @property checkFails
51843 * Number of times we have attempted to get authentication check, and failed.
51848 * @property intervalID
51849 * The window interval that does the constant login checking.
51855 onLoad : function() // called on page load...
51859 if (Roo.get('loading')) { // clear any loading indicator..
51860 Roo.get('loading').remove();
51863 //this.switchLang('en'); // set the language to english..
51866 success: function(response, opts) { // check successfull...
51868 var res = this.processResponse(response);
51869 this.checkFails =0;
51870 if (!res.success) { // error!
51871 this.checkFails = 5;
51872 //console.log('call failure');
51873 return this.failure(response,opts);
51876 if (!res.data.id) { // id=0 == login failure.
51877 return this.show();
51881 //console.log(success);
51882 this.fillAuth(res.data);
51883 this.checkFails =0;
51884 Roo.XComponent.build();
51886 failure : this.show
51892 check: function(cfg) // called every so often to refresh cookie etc..
51894 if (cfg.again) { // could be undefined..
51897 this.checkFails = 0;
51900 if (this.sending) {
51901 if ( this.checkFails > 4) {
51902 Roo.MessageBox.alert("Error",
51903 "Error getting authentication status. - try reloading, or wait a while", function() {
51904 _this.sending = false;
51909 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
51912 this.sending = true;
51919 method: this.method,
51920 success: cfg.success || this.success,
51921 failure : cfg.failure || this.failure,
51931 window.onbeforeunload = function() { }; // false does not work for IE..
51941 failure : function() {
51942 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
51943 document.location = document.location.toString() + '?ts=' + Math.random();
51947 success : function() {
51948 _this.user = false;
51949 this.checkFails =0;
51951 document.location = document.location.toString() + '?ts=' + Math.random();
51958 processResponse : function (response)
51962 res = Roo.decode(response.responseText);
51964 if (typeof(res) != 'object') {
51965 res = { success : false, errorMsg : res, errors : true };
51967 if (typeof(res.success) == 'undefined') {
51968 res.success = false;
51972 res = { success : false, errorMsg : response.responseText, errors : true };
51977 success : function(response, opts) // check successfull...
51979 this.sending = false;
51980 var res = this.processResponse(response);
51981 if (!res.success) {
51982 return this.failure(response, opts);
51984 if (!res.data || !res.data.id) {
51985 return this.failure(response,opts);
51987 //console.log(res);
51988 this.fillAuth(res.data);
51990 this.checkFails =0;
51995 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
51997 this.authUser = -1;
51998 this.sending = false;
51999 var res = this.processResponse(response);
52000 //console.log(res);
52001 if ( this.checkFails > 2) {
52003 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
52004 "Error getting authentication status. - try reloading");
52007 opts.callCfg.again = true;
52008 this.check.defer(1000, this, [ opts.callCfg ]);
52014 fillAuth: function(au) {
52015 this.startAuthCheck();
52016 this.authUserId = au.id;
52017 this.authUser = au;
52018 this.lastChecked = new Date();
52019 this.fireEvent('refreshed', au);
52020 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
52021 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
52022 au.lang = au.lang || 'en';
52023 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
52024 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
52025 this.switchLang(au.lang );
52028 // open system... - -on setyp..
52029 if (this.authUserId < 0) {
52030 Roo.MessageBox.alert("Warning",
52031 "This is an open system - please set up a admin user with a password.");
52034 //Pman.onload(); // which should do nothing if it's a re-auth result...
52039 startAuthCheck : function() // starter for timeout checking..
52041 if (this.intervalID) { // timer already in place...
52045 this.intervalID = window.setInterval(function() {
52046 _this.check(false);
52047 }, 120000); // every 120 secs = 2mins..
52053 switchLang : function (lang)
52055 _T = typeof(_T) == 'undefined' ? false : _T;
52056 if (!_T || !lang.length) {
52060 if (!_T && lang != 'en') {
52061 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
52065 if (typeof(_T.en) == 'undefined') {
52067 Roo.apply(_T.en, _T);
52070 if (typeof(_T[lang]) == 'undefined') {
52071 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
52076 Roo.apply(_T, _T[lang]);
52077 // just need to set the text values for everything...
52079 /* this will not work ...
52083 function formLabel(name, val) {
52084 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
52087 formLabel('password', "Password"+':');
52088 formLabel('username', "Email Address"+':');
52089 formLabel('lang', "Language"+':');
52090 this.dialog.setTitle("Login");
52091 this.dialog.buttons[0].setText("Forgot Password");
52092 this.dialog.buttons[1].setText("Login");
52111 collapsible: false,
52113 center: { // needed??
52116 // tabPosition: 'top',
52119 alwaysShowTabs: false
52123 show : function(dlg)
52125 //console.log(this);
52126 this.form = this.layout.getRegion('center').activePanel.form;
52127 this.form.dialog = dlg;
52128 this.buttons[0].form = this.form;
52129 this.buttons[0].dialog = dlg;
52130 this.buttons[1].form = this.form;
52131 this.buttons[1].dialog = dlg;
52133 //this.resizeToLogo.defer(1000,this);
52134 // this is all related to resizing for logos..
52135 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
52137 // this.resizeToLogo.defer(1000,this);
52140 //var w = Ext.lib.Dom.getViewWidth() - 100;
52141 //var h = Ext.lib.Dom.getViewHeight() - 100;
52142 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
52144 if (this.disabled) {
52149 if (this.user.id < 0) { // used for inital setup situations.
52153 if (this.intervalID) {
52154 // remove the timer
52155 window.clearInterval(this.intervalID);
52156 this.intervalID = false;
52160 if (Roo.get('loading')) {
52161 Roo.get('loading').remove();
52163 if (Roo.get('loading-mask')) {
52164 Roo.get('loading-mask').hide();
52167 //incomming._node = tnode;
52169 //this.dialog.modal = !modal;
52170 //this.dialog.show();
52174 this.form.setValues({
52175 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
52176 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
52179 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
52180 if (this.form.findField('username').getValue().length > 0 ){
52181 this.form.findField('password').focus();
52183 this.form.findField('username').focus();
52191 xtype : 'ContentPanel',
52203 style : 'margin: 10px;',
52206 actionfailed : function(f, act) {
52207 // form can return { errors: .... }
52209 //act.result.errors // invalid form element list...
52210 //act.result.errorMsg// invalid form element list...
52212 this.dialog.el.unmask();
52213 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
52214 "Login failed - communication error - try again.");
52217 actioncomplete: function(re, act) {
52219 Roo.state.Manager.set(
52220 this.dialog.realm + '.username',
52221 this.findField('username').getValue()
52223 Roo.state.Manager.set(
52224 this.dialog.realm + '.lang',
52225 this.findField('lang').getValue()
52228 this.dialog.fillAuth(act.result.data);
52230 this.dialog.hide();
52232 if (Roo.get('loading-mask')) {
52233 Roo.get('loading-mask').show();
52235 Roo.XComponent.build();
52243 xtype : 'TextField',
52245 fieldLabel: "Email Address",
52248 autoCreate : {tag: "input", type: "text", size: "20"}
52251 xtype : 'TextField',
52253 fieldLabel: "Password",
52254 inputType: 'password',
52257 autoCreate : {tag: "input", type: "text", size: "20"},
52259 specialkey : function(e,ev) {
52260 if (ev.keyCode == 13) {
52261 this.form.dialog.el.mask("Logging in");
52262 this.form.doAction('submit', {
52263 url: this.form.dialog.url,
52264 method: this.form.dialog.method
52271 xtype : 'ComboBox',
52273 fieldLabel: "Language",
52276 xtype : 'SimpleStore',
52277 fields: ['lang', 'ldisp'],
52279 [ 'en', 'English' ],
52280 [ 'zh_HK' , '\u7E41\u4E2D' ],
52281 [ 'zh_CN', '\u7C21\u4E2D' ]
52285 valueField : 'lang',
52286 hiddenName: 'lang',
52288 displayField:'ldisp',
52292 triggerAction: 'all',
52293 emptyText:'Select a Language...',
52294 selectOnFocus:true,
52296 select : function(cb, rec, ix) {
52297 this.form.switchLang(rec.data.lang);
52313 text : "Forgot Password",
52315 click : function() {
52316 //console.log(this);
52317 var n = this.form.findField('username').getValue();
52319 Roo.MessageBox.alert("Error", "Fill in your email address");
52323 url: this.dialog.url,
52327 method: this.dialog.method,
52328 success: function(response, opts) { // check successfull...
52330 var res = this.dialog.processResponse(response);
52331 if (!res.success) { // error!
52332 Roo.MessageBox.alert("Error" ,
52333 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
52336 Roo.MessageBox.alert("Notice" ,
52337 "Please check you email for the Password Reset message");
52339 failure : function() {
52340 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
52353 click : function () {
52355 this.dialog.el.mask("Logging in");
52356 this.form.doAction('submit', {
52357 url: this.dialog.url,
52358 method: this.dialog.method