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">
4031 * @class Roo.DomHelper
4032 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4033 * 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>.
4036 Roo.DomHelper = function(){
4037 var tempTableEl = null;
4038 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4039 var tableRe = /^table|tbody|tr|td$/i;
4041 // build as innerHTML where available
4043 var createHtml = function(o){
4044 if(typeof o == 'string'){
4053 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4054 if(attr == "style"){
4056 if(typeof s == "function"){
4059 if(typeof s == "string"){
4060 b += ' style="' + s + '"';
4061 }else if(typeof s == "object"){
4064 if(typeof s[key] != "function"){
4065 b += key + ":" + s[key] + ";";
4072 b += ' class="' + o["cls"] + '"';
4073 }else if(attr == "htmlFor"){
4074 b += ' for="' + o["htmlFor"] + '"';
4076 b += " " + attr + '="' + o[attr] + '"';
4080 if(emptyTags.test(o.tag)){
4084 var cn = o.children || o.cn;
4086 //http://bugs.kde.org/show_bug.cgi?id=71506
4087 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4088 for(var i = 0, len = cn.length; i < len; i++) {
4089 b += createHtml(cn[i], b);
4092 b += createHtml(cn, b);
4098 b += "</" + o.tag + ">";
4105 var createDom = function(o, parentNode){
4107 // defininition craeted..
4109 if (o.ns && o.ns != 'html') {
4111 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4112 xmlns[o.ns] = o.xmlns;
4115 if (typeof(xmlns[o.ns]) == 'undefined') {
4116 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4122 if (typeof(o) == 'string') {
4123 return parentNode.appendChild(document.createTextNode(o));
4125 o.tag = o.tag || div;
4126 if (o.ns && Roo.isIE) {
4128 o.tag = o.ns + ':' + o.tag;
4131 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4132 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4135 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4136 attr == "style" || typeof o[attr] == "function") continue;
4138 if(attr=="cls" && Roo.isIE){
4139 el.className = o["cls"];
4141 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4142 else el[attr] = o[attr];
4145 Roo.DomHelper.applyStyles(el, o.style);
4146 var cn = o.children || o.cn;
4148 //http://bugs.kde.org/show_bug.cgi?id=71506
4149 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4150 for(var i = 0, len = cn.length; i < len; i++) {
4151 createDom(cn[i], el);
4158 el.innerHTML = o.html;
4161 parentNode.appendChild(el);
4166 var ieTable = function(depth, s, h, e){
4167 tempTableEl.innerHTML = [s, h, e].join('');
4168 var i = -1, el = tempTableEl;
4175 // kill repeat to save bytes
4179 tbe = '</tbody>'+te,
4185 * Nasty code for IE's broken table implementation
4187 var insertIntoTable = function(tag, where, el, html){
4189 tempTableEl = document.createElement('div');
4194 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4197 if(where == 'beforebegin'){
4201 before = el.nextSibling;
4204 node = ieTable(4, trs, html, tre);
4206 else if(tag == 'tr'){
4207 if(where == 'beforebegin'){
4210 node = ieTable(3, tbs, html, tbe);
4211 } else if(where == 'afterend'){
4212 before = el.nextSibling;
4214 node = ieTable(3, tbs, html, tbe);
4215 } else{ // INTO a TR
4216 if(where == 'afterbegin'){
4217 before = el.firstChild;
4219 node = ieTable(4, trs, html, tre);
4221 } else if(tag == 'tbody'){
4222 if(where == 'beforebegin'){
4225 node = ieTable(2, ts, html, te);
4226 } else if(where == 'afterend'){
4227 before = el.nextSibling;
4229 node = ieTable(2, ts, html, te);
4231 if(where == 'afterbegin'){
4232 before = el.firstChild;
4234 node = ieTable(3, tbs, html, tbe);
4237 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4240 if(where == 'afterbegin'){
4241 before = el.firstChild;
4243 node = ieTable(2, ts, html, te);
4245 el.insertBefore(node, before);
4250 /** True to force the use of DOM instead of html fragments @type Boolean */
4254 * Returns the markup for the passed Element(s) config
4255 * @param {Object} o The Dom object spec (and children)
4258 markup : function(o){
4259 return createHtml(o);
4263 * Applies a style specification to an element
4264 * @param {String/HTMLElement} el The element to apply styles to
4265 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4266 * a function which returns such a specification.
4268 applyStyles : function(el, styles){
4271 if(typeof styles == "string"){
4272 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4274 while ((matches = re.exec(styles)) != null){
4275 el.setStyle(matches[1], matches[2]);
4277 }else if (typeof styles == "object"){
4278 for (var style in styles){
4279 el.setStyle(style, styles[style]);
4281 }else if (typeof styles == "function"){
4282 Roo.DomHelper.applyStyles(el, styles.call());
4288 * Inserts an HTML fragment into the Dom
4289 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4290 * @param {HTMLElement} el The context element
4291 * @param {String} html The HTML fragmenet
4292 * @return {HTMLElement} The new node
4294 insertHtml : function(where, el, html){
4295 where = where.toLowerCase();
4296 if(el.insertAdjacentHTML){
4297 if(tableRe.test(el.tagName)){
4299 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4305 el.insertAdjacentHTML('BeforeBegin', html);
4306 return el.previousSibling;
4308 el.insertAdjacentHTML('AfterBegin', html);
4309 return el.firstChild;
4311 el.insertAdjacentHTML('BeforeEnd', html);
4312 return el.lastChild;
4314 el.insertAdjacentHTML('AfterEnd', html);
4315 return el.nextSibling;
4317 throw 'Illegal insertion point -> "' + where + '"';
4319 var range = el.ownerDocument.createRange();
4323 range.setStartBefore(el);
4324 frag = range.createContextualFragment(html);
4325 el.parentNode.insertBefore(frag, el);
4326 return el.previousSibling;
4329 range.setStartBefore(el.firstChild);
4330 frag = range.createContextualFragment(html);
4331 el.insertBefore(frag, el.firstChild);
4332 return el.firstChild;
4334 el.innerHTML = html;
4335 return el.firstChild;
4339 range.setStartAfter(el.lastChild);
4340 frag = range.createContextualFragment(html);
4341 el.appendChild(frag);
4342 return el.lastChild;
4344 el.innerHTML = html;
4345 return el.lastChild;
4348 range.setStartAfter(el);
4349 frag = range.createContextualFragment(html);
4350 el.parentNode.insertBefore(frag, el.nextSibling);
4351 return el.nextSibling;
4353 throw 'Illegal insertion point -> "' + where + '"';
4357 * Creates new Dom element(s) and inserts them before el
4358 * @param {String/HTMLElement/Element} el The context element
4359 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4360 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4361 * @return {HTMLElement/Roo.Element} The new node
4363 insertBefore : function(el, o, returnElement){
4364 return this.doInsert(el, o, returnElement, "beforeBegin");
4368 * Creates new Dom element(s) and inserts them after el
4369 * @param {String/HTMLElement/Element} el The context element
4370 * @param {Object} o The Dom object spec (and children)
4371 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4372 * @return {HTMLElement/Roo.Element} The new node
4374 insertAfter : function(el, o, returnElement){
4375 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4379 * Creates new Dom element(s) and inserts them as the first child of el
4380 * @param {String/HTMLElement/Element} el The context element
4381 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4382 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4383 * @return {HTMLElement/Roo.Element} The new node
4385 insertFirst : function(el, o, returnElement){
4386 return this.doInsert(el, o, returnElement, "afterBegin");
4390 doInsert : function(el, o, returnElement, pos, sibling){
4391 el = Roo.getDom(el);
4393 if(this.useDom || o.ns){
4394 newNode = createDom(o, null);
4395 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4397 var html = createHtml(o);
4398 newNode = this.insertHtml(pos, el, html);
4400 return returnElement ? Roo.get(newNode, true) : newNode;
4404 * Creates new Dom element(s) and appends them to el
4405 * @param {String/HTMLElement/Element} el The context element
4406 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4407 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4408 * @return {HTMLElement/Roo.Element} The new node
4410 append : function(el, o, returnElement){
4411 el = Roo.getDom(el);
4413 if(this.useDom || o.ns){
4414 newNode = createDom(o, null);
4415 el.appendChild(newNode);
4417 var html = createHtml(o);
4418 newNode = this.insertHtml("beforeEnd", el, html);
4420 return returnElement ? Roo.get(newNode, true) : newNode;
4424 * Creates new Dom element(s) and overwrites the contents of el with them
4425 * @param {String/HTMLElement/Element} el The context element
4426 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4427 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4428 * @return {HTMLElement/Roo.Element} The new node
4430 overwrite : function(el, o, returnElement){
4431 el = Roo.getDom(el);
4434 while (el.childNodes.length) {
4435 el.removeChild(el.firstChild);
4439 el.innerHTML = createHtml(o);
4442 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4446 * Creates a new Roo.DomHelper.Template from the Dom object spec
4447 * @param {Object} o The Dom object spec (and children)
4448 * @return {Roo.DomHelper.Template} The new template
4450 createTemplate : function(o){
4451 var html = createHtml(o);
4452 return new Roo.Template(html);
4458 * Ext JS Library 1.1.1
4459 * Copyright(c) 2006-2007, Ext JS, LLC.
4461 * Originally Released Under LGPL - original licence link has changed is not relivant.
4464 * <script type="text/javascript">
4468 * @class Roo.Template
4469 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4470 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4473 var t = new Roo.Template({
4474 html : '<div name="{id}">' +
4475 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4477 myformat: function (value, allValues) {
4478 return 'XX' + value;
4481 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4483 * 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>.
4485 * @param {Object} cfg - Configuration object.
4487 Roo.Template = function(cfg){
4489 if(cfg instanceof Array){
4491 }else if(arguments.length > 1){
4492 cfg = Array.prototype.join.call(arguments, "");
4496 if (typeof(cfg) == 'object') {
4505 Roo.Template.prototype = {
4508 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4512 * Returns an HTML fragment of this template with the specified values applied.
4513 * @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'})
4514 * @return {String} The HTML fragment
4516 applyTemplate : function(values){
4520 return this.compiled(values);
4522 var useF = this.disableFormats !== true;
4523 var fm = Roo.util.Format, tpl = this;
4524 var fn = function(m, name, format, args){
4526 if(format.substr(0, 5) == "this."){
4527 return tpl.call(format.substr(5), values[name], values);
4530 // quoted values are required for strings in compiled templates,
4531 // but for non compiled we need to strip them
4532 // quoted reversed for jsmin
4533 var re = /^\s*['"](.*)["']\s*$/;
4534 args = args.split(',');
4535 for(var i = 0, len = args.length; i < len; i++){
4536 args[i] = args[i].replace(re, "$1");
4538 args = [values[name]].concat(args);
4540 args = [values[name]];
4542 return fm[format].apply(fm, args);
4545 return values[name] !== undefined ? values[name] : "";
4548 return this.html.replace(this.re, fn);
4557 * Sets the HTML used as the template and optionally compiles it.
4558 * @param {String} html
4559 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4560 * @return {Roo.Template} this
4562 set : function(html, compile){
4564 this.compiled = null;
4572 * True to disable format functions (defaults to false)
4575 disableFormats : false,
4578 * The regular expression used to match template variables
4582 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4585 * Compiles the template into an internal function, eliminating the RegEx overhead.
4586 * @return {Roo.Template} this
4588 compile : function(){
4589 var fm = Roo.util.Format;
4590 var useF = this.disableFormats !== true;
4591 var sep = Roo.isGecko ? "+" : ",";
4592 var fn = function(m, name, format, args){
4594 args = args ? ',' + args : "";
4595 if(format.substr(0, 5) != "this."){
4596 format = "fm." + format + '(';
4598 format = 'this.call("'+ format.substr(5) + '", ';
4602 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4604 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4607 // branched to use + in gecko and [].join() in others
4609 body = "this.compiled = function(values){ return '" +
4610 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4613 body = ["this.compiled = function(values){ return ['"];
4614 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4615 body.push("'].join('');};");
4616 body = body.join('');
4626 // private function used to call members
4627 call : function(fnName, value, allValues){
4628 return this[fnName](value, allValues);
4632 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4633 * @param {String/HTMLElement/Roo.Element} el The context element
4634 * @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'})
4635 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4636 * @return {HTMLElement/Roo.Element} The new node or Element
4638 insertFirst: function(el, values, returnElement){
4639 return this.doInsert('afterBegin', el, values, returnElement);
4643 * Applies the supplied values to the template and inserts the new node(s) before el.
4644 * @param {String/HTMLElement/Roo.Element} el The context element
4645 * @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'})
4646 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4647 * @return {HTMLElement/Roo.Element} The new node or Element
4649 insertBefore: function(el, values, returnElement){
4650 return this.doInsert('beforeBegin', el, values, returnElement);
4654 * Applies the supplied values to the template and inserts the new node(s) after el.
4655 * @param {String/HTMLElement/Roo.Element} el The context element
4656 * @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'})
4657 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4658 * @return {HTMLElement/Roo.Element} The new node or Element
4660 insertAfter : function(el, values, returnElement){
4661 return this.doInsert('afterEnd', el, values, returnElement);
4665 * Applies the supplied values to the template and appends the new node(s) to el.
4666 * @param {String/HTMLElement/Roo.Element} el The context element
4667 * @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'})
4668 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4669 * @return {HTMLElement/Roo.Element} The new node or Element
4671 append : function(el, values, returnElement){
4672 return this.doInsert('beforeEnd', el, values, returnElement);
4675 doInsert : function(where, el, values, returnEl){
4676 el = Roo.getDom(el);
4677 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4678 return returnEl ? Roo.get(newNode, true) : newNode;
4682 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4683 * @param {String/HTMLElement/Roo.Element} el The context element
4684 * @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'})
4685 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4686 * @return {HTMLElement/Roo.Element} The new node or Element
4688 overwrite : function(el, values, returnElement){
4689 el = Roo.getDom(el);
4690 el.innerHTML = this.applyTemplate(values);
4691 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4695 * Alias for {@link #applyTemplate}
4698 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4701 Roo.DomHelper.Template = Roo.Template;
4704 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4705 * @param {String/HTMLElement} el A DOM element or its id
4706 * @returns {Roo.Template} The created template
4709 Roo.Template.from = function(el){
4710 el = Roo.getDom(el);
4711 return new Roo.Template(el.value || el.innerHTML);
4714 * Ext JS Library 1.1.1
4715 * Copyright(c) 2006-2007, Ext JS, LLC.
4717 * Originally Released Under LGPL - original licence link has changed is not relivant.
4720 * <script type="text/javascript">
4725 * This is code is also distributed under MIT license for use
4726 * with jQuery and prototype JavaScript libraries.
4729 * @class Roo.DomQuery
4730 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).
4732 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>
4735 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.
4737 <h4>Element Selectors:</h4>
4739 <li> <b>*</b> any element</li>
4740 <li> <b>E</b> an element with the tag E</li>
4741 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4742 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4743 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4744 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4746 <h4>Attribute Selectors:</h4>
4747 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4749 <li> <b>E[foo]</b> has an attribute "foo"</li>
4750 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4751 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4752 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4753 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4754 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4755 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4757 <h4>Pseudo Classes:</h4>
4759 <li> <b>E:first-child</b> E is the first child of its parent</li>
4760 <li> <b>E:last-child</b> E is the last child of its parent</li>
4761 <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>
4762 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4763 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4764 <li> <b>E:only-child</b> E is the only child of its parent</li>
4765 <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>
4766 <li> <b>E:first</b> the first E in the resultset</li>
4767 <li> <b>E:last</b> the last E in the resultset</li>
4768 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4769 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4770 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4771 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4772 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4773 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4774 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4775 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4776 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4778 <h4>CSS Value Selectors:</h4>
4780 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4781 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4782 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4783 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4784 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4785 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4789 Roo.DomQuery = function(){
4790 var cache = {}, simpleCache = {}, valueCache = {};
4791 var nonSpace = /\S/;
4792 var trimRe = /^\s+|\s+$/g;
4793 var tplRe = /\{(\d+)\}/g;
4794 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4795 var tagTokenRe = /^(#)?([\w-\*]+)/;
4796 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4798 function child(p, index){
4800 var n = p.firstChild;
4802 if(n.nodeType == 1){
4813 while((n = n.nextSibling) && n.nodeType != 1);
4818 while((n = n.previousSibling) && n.nodeType != 1);
4822 function children(d){
4823 var n = d.firstChild, ni = -1;
4825 var nx = n.nextSibling;
4826 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4836 function byClassName(c, a, v){
4840 var r = [], ri = -1, cn;
4841 for(var i = 0, ci; ci = c[i]; i++){
4842 if((' '+ci.className+' ').indexOf(v) != -1){
4849 function attrValue(n, attr){
4850 if(!n.tagName && typeof n.length != "undefined"){
4859 if(attr == "class" || attr == "className"){
4862 return n.getAttribute(attr) || n[attr];
4866 function getNodes(ns, mode, tagName){
4867 var result = [], ri = -1, cs;
4871 tagName = tagName || "*";
4872 if(typeof ns.getElementsByTagName != "undefined"){
4876 for(var i = 0, ni; ni = ns[i]; i++){
4877 cs = ni.getElementsByTagName(tagName);
4878 for(var j = 0, ci; ci = cs[j]; j++){
4882 }else if(mode == "/" || mode == ">"){
4883 var utag = tagName.toUpperCase();
4884 for(var i = 0, ni, cn; ni = ns[i]; i++){
4885 cn = ni.children || ni.childNodes;
4886 for(var j = 0, cj; cj = cn[j]; j++){
4887 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4892 }else if(mode == "+"){
4893 var utag = tagName.toUpperCase();
4894 for(var i = 0, n; n = ns[i]; i++){
4895 while((n = n.nextSibling) && n.nodeType != 1);
4896 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4900 }else if(mode == "~"){
4901 for(var i = 0, n; n = ns[i]; i++){
4902 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4911 function concat(a, b){
4915 for(var i = 0, l = b.length; i < l; i++){
4921 function byTag(cs, tagName){
4922 if(cs.tagName || cs == document){
4928 var r = [], ri = -1;
4929 tagName = tagName.toLowerCase();
4930 for(var i = 0, ci; ci = cs[i]; i++){
4931 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4938 function byId(cs, attr, id){
4939 if(cs.tagName || cs == document){
4945 var r = [], ri = -1;
4946 for(var i = 0,ci; ci = cs[i]; i++){
4947 if(ci && ci.id == id){
4955 function byAttribute(cs, attr, value, op, custom){
4956 var r = [], ri = -1, st = custom=="{";
4957 var f = Roo.DomQuery.operators[op];
4958 for(var i = 0, ci; ci = cs[i]; i++){
4961 a = Roo.DomQuery.getStyle(ci, attr);
4963 else if(attr == "class" || attr == "className"){
4965 }else if(attr == "for"){
4967 }else if(attr == "href"){
4968 a = ci.getAttribute("href", 2);
4970 a = ci.getAttribute(attr);
4972 if((f && f(a, value)) || (!f && a)){
4979 function byPseudo(cs, name, value){
4980 return Roo.DomQuery.pseudos[name](cs, value);
4983 // This is for IE MSXML which does not support expandos.
4984 // IE runs the same speed using setAttribute, however FF slows way down
4985 // and Safari completely fails so they need to continue to use expandos.
4986 var isIE = window.ActiveXObject ? true : false;
4988 // this eval is stop the compressor from
4989 // renaming the variable to something shorter
4991 /** eval:var:batch */
4996 function nodupIEXml(cs){
4998 cs[0].setAttribute("_nodup", d);
5000 for(var i = 1, len = cs.length; i < len; i++){
5002 if(!c.getAttribute("_nodup") != d){
5003 c.setAttribute("_nodup", d);
5007 for(var i = 0, len = cs.length; i < len; i++){
5008 cs[i].removeAttribute("_nodup");
5017 var len = cs.length, c, i, r = cs, cj, ri = -1;
5018 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5021 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5022 return nodupIEXml(cs);
5026 for(i = 1; c = cs[i]; i++){
5031 for(var j = 0; j < i; j++){
5034 for(j = i+1; cj = cs[j]; j++){
5046 function quickDiffIEXml(c1, c2){
5048 for(var i = 0, len = c1.length; i < len; i++){
5049 c1[i].setAttribute("_qdiff", d);
5052 for(var i = 0, len = c2.length; i < len; i++){
5053 if(c2[i].getAttribute("_qdiff") != d){
5054 r[r.length] = c2[i];
5057 for(var i = 0, len = c1.length; i < len; i++){
5058 c1[i].removeAttribute("_qdiff");
5063 function quickDiff(c1, c2){
5064 var len1 = c1.length;
5068 if(isIE && c1[0].selectSingleNode){
5069 return quickDiffIEXml(c1, c2);
5072 for(var i = 0; i < len1; i++){
5076 for(var i = 0, len = c2.length; i < len; i++){
5077 if(c2[i]._qdiff != d){
5078 r[r.length] = c2[i];
5084 function quickId(ns, mode, root, id){
5086 var d = root.ownerDocument || root;
5087 return d.getElementById(id);
5089 ns = getNodes(ns, mode, "*");
5090 return byId(ns, null, id);
5094 getStyle : function(el, name){
5095 return Roo.fly(el).getStyle(name);
5098 * Compiles a selector/xpath query into a reusable function. The returned function
5099 * takes one parameter "root" (optional), which is the context node from where the query should start.
5100 * @param {String} selector The selector/xpath query
5101 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5102 * @return {Function}
5104 compile : function(path, type){
5105 type = type || "select";
5107 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5108 var q = path, mode, lq;
5109 var tk = Roo.DomQuery.matchers;
5110 var tklen = tk.length;
5113 // accept leading mode switch
5114 var lmode = q.match(modeRe);
5115 if(lmode && lmode[1]){
5116 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5117 q = q.replace(lmode[1], "");
5119 // strip leading slashes
5120 while(path.substr(0, 1)=="/"){
5121 path = path.substr(1);
5124 while(q && lq != q){
5126 var tm = q.match(tagTokenRe);
5127 if(type == "select"){
5130 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5132 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5134 q = q.replace(tm[0], "");
5135 }else if(q.substr(0, 1) != '@'){
5136 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5141 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5143 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5145 q = q.replace(tm[0], "");
5148 while(!(mm = q.match(modeRe))){
5149 var matched = false;
5150 for(var j = 0; j < tklen; j++){
5152 var m = q.match(t.re);
5154 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5157 q = q.replace(m[0], "");
5162 // prevent infinite loop on bad selector
5164 throw 'Error parsing selector, parsing failed at "' + q + '"';
5168 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5169 q = q.replace(mm[1], "");
5172 fn[fn.length] = "return nodup(n);\n}";
5175 * list of variables that need from compression as they are used by eval.
5185 * eval:var:byClassName
5187 * eval:var:byAttribute
5188 * eval:var:attrValue
5196 * Selects a group of elements.
5197 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5198 * @param {Node} root (optional) The start of the query (defaults to document).
5201 select : function(path, root, type){
5202 if(!root || root == document){
5205 if(typeof root == "string"){
5206 root = document.getElementById(root);
5208 var paths = path.split(",");
5210 for(var i = 0, len = paths.length; i < len; i++){
5211 var p = paths[i].replace(trimRe, "");
5213 cache[p] = Roo.DomQuery.compile(p);
5215 throw p + " is not a valid selector";
5218 var result = cache[p](root);
5219 if(result && result != document){
5220 results = results.concat(result);
5223 if(paths.length > 1){
5224 return nodup(results);
5230 * Selects a single element.
5231 * @param {String} selector The selector/xpath query
5232 * @param {Node} root (optional) The start of the query (defaults to document).
5235 selectNode : function(path, root){
5236 return Roo.DomQuery.select(path, root)[0];
5240 * Selects the value of a node, optionally replacing null with the defaultValue.
5241 * @param {String} selector The selector/xpath query
5242 * @param {Node} root (optional) The start of the query (defaults to document).
5243 * @param {String} defaultValue
5245 selectValue : function(path, root, defaultValue){
5246 path = path.replace(trimRe, "");
5247 if(!valueCache[path]){
5248 valueCache[path] = Roo.DomQuery.compile(path, "select");
5250 var n = valueCache[path](root);
5251 n = n[0] ? n[0] : n;
5252 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5253 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5257 * Selects the value of a node, parsing integers and floats.
5258 * @param {String} selector The selector/xpath query
5259 * @param {Node} root (optional) The start of the query (defaults to document).
5260 * @param {Number} defaultValue
5263 selectNumber : function(path, root, defaultValue){
5264 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5265 return parseFloat(v);
5269 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5270 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5271 * @param {String} selector The simple selector to test
5274 is : function(el, ss){
5275 if(typeof el == "string"){
5276 el = document.getElementById(el);
5278 var isArray = (el instanceof Array);
5279 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5280 return isArray ? (result.length == el.length) : (result.length > 0);
5284 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5285 * @param {Array} el An array of elements to filter
5286 * @param {String} selector The simple selector to test
5287 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5288 * the selector instead of the ones that match
5291 filter : function(els, ss, nonMatches){
5292 ss = ss.replace(trimRe, "");
5293 if(!simpleCache[ss]){
5294 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5296 var result = simpleCache[ss](els);
5297 return nonMatches ? quickDiff(result, els) : result;
5301 * Collection of matching regular expressions and code snippets.
5305 select: 'n = byClassName(n, null, " {1} ");'
5307 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5308 select: 'n = byPseudo(n, "{1}", "{2}");'
5310 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5311 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5314 select: 'n = byId(n, null, "{1}");'
5317 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5322 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5323 * 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, > <.
5326 "=" : function(a, v){
5329 "!=" : function(a, v){
5332 "^=" : function(a, v){
5333 return a && a.substr(0, v.length) == v;
5335 "$=" : function(a, v){
5336 return a && a.substr(a.length-v.length) == v;
5338 "*=" : function(a, v){
5339 return a && a.indexOf(v) !== -1;
5341 "%=" : function(a, v){
5342 return (a % v) == 0;
5344 "|=" : function(a, v){
5345 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5347 "~=" : function(a, v){
5348 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5353 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5354 * and the argument (if any) supplied in the selector.
5357 "first-child" : function(c){
5358 var r = [], ri = -1, n;
5359 for(var i = 0, ci; ci = n = c[i]; i++){
5360 while((n = n.previousSibling) && n.nodeType != 1);
5368 "last-child" : function(c){
5369 var r = [], ri = -1, n;
5370 for(var i = 0, ci; ci = n = c[i]; i++){
5371 while((n = n.nextSibling) && n.nodeType != 1);
5379 "nth-child" : function(c, a) {
5380 var r = [], ri = -1;
5381 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5382 var f = (m[1] || 1) - 0, l = m[2] - 0;
5383 for(var i = 0, n; n = c[i]; i++){
5384 var pn = n.parentNode;
5385 if (batch != pn._batch) {
5387 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5388 if(cn.nodeType == 1){
5395 if (l == 0 || n.nodeIndex == l){
5398 } else if ((n.nodeIndex + l) % f == 0){
5406 "only-child" : function(c){
5407 var r = [], ri = -1;;
5408 for(var i = 0, ci; ci = c[i]; i++){
5409 if(!prev(ci) && !next(ci)){
5416 "empty" : function(c){
5417 var r = [], ri = -1;
5418 for(var i = 0, ci; ci = c[i]; i++){
5419 var cns = ci.childNodes, j = 0, cn, empty = true;
5422 if(cn.nodeType == 1 || cn.nodeType == 3){
5434 "contains" : function(c, v){
5435 var r = [], ri = -1;
5436 for(var i = 0, ci; ci = c[i]; i++){
5437 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5444 "nodeValue" : function(c, v){
5445 var r = [], ri = -1;
5446 for(var i = 0, ci; ci = c[i]; i++){
5447 if(ci.firstChild && ci.firstChild.nodeValue == v){
5454 "checked" : function(c){
5455 var r = [], ri = -1;
5456 for(var i = 0, ci; ci = c[i]; i++){
5457 if(ci.checked == true){
5464 "not" : function(c, ss){
5465 return Roo.DomQuery.filter(c, ss, true);
5468 "odd" : function(c){
5469 return this["nth-child"](c, "odd");
5472 "even" : function(c){
5473 return this["nth-child"](c, "even");
5476 "nth" : function(c, a){
5477 return c[a-1] || [];
5480 "first" : function(c){
5484 "last" : function(c){
5485 return c[c.length-1] || [];
5488 "has" : function(c, ss){
5489 var s = Roo.DomQuery.select;
5490 var r = [], ri = -1;
5491 for(var i = 0, ci; ci = c[i]; i++){
5492 if(s(ss, ci).length > 0){
5499 "next" : function(c, ss){
5500 var is = Roo.DomQuery.is;
5501 var r = [], ri = -1;
5502 for(var i = 0, ci; ci = c[i]; i++){
5511 "prev" : function(c, ss){
5512 var is = Roo.DomQuery.is;
5513 var r = [], ri = -1;
5514 for(var i = 0, ci; ci = c[i]; i++){
5527 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5528 * @param {String} path The selector/xpath query
5529 * @param {Node} root (optional) The start of the query (defaults to document).
5534 Roo.query = Roo.DomQuery.select;
5537 * Ext JS Library 1.1.1
5538 * Copyright(c) 2006-2007, Ext JS, LLC.
5540 * Originally Released Under LGPL - original licence link has changed is not relivant.
5543 * <script type="text/javascript">
5547 * @class Roo.util.Observable
5548 * Base class that provides a common interface for publishing events. Subclasses are expected to
5549 * to have a property "events" with all the events defined.<br>
5552 Employee = function(name){
5559 Roo.extend(Employee, Roo.util.Observable);
5561 * @param {Object} config properties to use (incuding events / listeners)
5564 Roo.util.Observable = function(cfg){
5567 this.addEvents(cfg.events || {});
5569 delete cfg.events; // make sure
5572 Roo.apply(this, cfg);
5575 this.on(this.listeners);
5576 delete this.listeners;
5579 Roo.util.Observable.prototype = {
5581 * @cfg {Object} listeners list of events and functions to call for this object,
5585 'click' : function(e) {
5595 * Fires the specified event with the passed parameters (minus the event name).
5596 * @param {String} eventName
5597 * @param {Object...} args Variable number of parameters are passed to handlers
5598 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5600 fireEvent : function(){
5601 var ce = this.events[arguments[0].toLowerCase()];
5602 if(typeof ce == "object"){
5603 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5610 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5613 * Appends an event handler to this component
5614 * @param {String} eventName The type of event to listen for
5615 * @param {Function} handler The method the event invokes
5616 * @param {Object} scope (optional) The scope in which to execute the handler
5617 * function. The handler function's "this" context.
5618 * @param {Object} options (optional) An object containing handler configuration
5619 * properties. This may contain any of the following properties:<ul>
5620 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5621 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5622 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5623 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5624 * by the specified number of milliseconds. If the event fires again within that time, the original
5625 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5628 * <b>Combining Options</b><br>
5629 * Using the options argument, it is possible to combine different types of listeners:<br>
5631 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5633 el.on('click', this.onClick, this, {
5640 * <b>Attaching multiple handlers in 1 call</b><br>
5641 * The method also allows for a single argument to be passed which is a config object containing properties
5642 * which specify multiple handlers.
5651 fn: this.onMouseOver,
5655 fn: this.onMouseOut,
5661 * Or a shorthand syntax which passes the same scope object to all handlers:
5664 'click': this.onClick,
5665 'mouseover': this.onMouseOver,
5666 'mouseout': this.onMouseOut,
5671 addListener : function(eventName, fn, scope, o){
5672 if(typeof eventName == "object"){
5675 if(this.filterOptRe.test(e)){
5678 if(typeof o[e] == "function"){
5680 this.addListener(e, o[e], o.scope, o);
5682 // individual options
5683 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5688 o = (!o || typeof o == "boolean") ? {} : o;
5689 eventName = eventName.toLowerCase();
5690 var ce = this.events[eventName] || true;
5691 if(typeof ce == "boolean"){
5692 ce = new Roo.util.Event(this, eventName);
5693 this.events[eventName] = ce;
5695 ce.addListener(fn, scope, o);
5699 * Removes a listener
5700 * @param {String} eventName The type of event to listen for
5701 * @param {Function} handler The handler to remove
5702 * @param {Object} scope (optional) The scope (this object) for the handler
5704 removeListener : function(eventName, fn, scope){
5705 var ce = this.events[eventName.toLowerCase()];
5706 if(typeof ce == "object"){
5707 ce.removeListener(fn, scope);
5712 * Removes all listeners for this object
5714 purgeListeners : function(){
5715 for(var evt in this.events){
5716 if(typeof this.events[evt] == "object"){
5717 this.events[evt].clearListeners();
5722 relayEvents : function(o, events){
5723 var createHandler = function(ename){
5725 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5728 for(var i = 0, len = events.length; i < len; i++){
5729 var ename = events[i];
5730 if(!this.events[ename]){ this.events[ename] = true; };
5731 o.on(ename, createHandler(ename), this);
5736 * Used to define events on this Observable
5737 * @param {Object} object The object with the events defined
5739 addEvents : function(o){
5743 Roo.applyIf(this.events, o);
5747 * Checks to see if this object has any listeners for a specified event
5748 * @param {String} eventName The name of the event to check for
5749 * @return {Boolean} True if the event is being listened for, else false
5751 hasListener : function(eventName){
5752 var e = this.events[eventName];
5753 return typeof e == "object" && e.listeners.length > 0;
5757 * Appends an event handler to this element (shorthand for addListener)
5758 * @param {String} eventName The type of event to listen for
5759 * @param {Function} handler The method the event invokes
5760 * @param {Object} scope (optional) The scope in which to execute the handler
5761 * function. The handler function's "this" context.
5762 * @param {Object} options (optional)
5765 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5767 * Removes a listener (shorthand for removeListener)
5768 * @param {String} eventName The type of event to listen for
5769 * @param {Function} handler The handler to remove
5770 * @param {Object} scope (optional) The scope (this object) for the handler
5773 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5776 * Starts capture on the specified Observable. All events will be passed
5777 * to the supplied function with the event name + standard signature of the event
5778 * <b>before</b> the event is fired. If the supplied function returns false,
5779 * the event will not fire.
5780 * @param {Observable} o The Observable to capture
5781 * @param {Function} fn The function to call
5782 * @param {Object} scope (optional) The scope (this object) for the fn
5785 Roo.util.Observable.capture = function(o, fn, scope){
5786 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5790 * Removes <b>all</b> added captures from the Observable.
5791 * @param {Observable} o The Observable to release
5794 Roo.util.Observable.releaseCapture = function(o){
5795 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5800 var createBuffered = function(h, o, scope){
5801 var task = new Roo.util.DelayedTask();
5803 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5807 var createSingle = function(h, e, fn, scope){
5809 e.removeListener(fn, scope);
5810 return h.apply(scope, arguments);
5814 var createDelayed = function(h, o, scope){
5816 var args = Array.prototype.slice.call(arguments, 0);
5817 setTimeout(function(){
5818 h.apply(scope, args);
5823 Roo.util.Event = function(obj, name){
5826 this.listeners = [];
5829 Roo.util.Event.prototype = {
5830 addListener : function(fn, scope, options){
5831 var o = options || {};
5832 scope = scope || this.obj;
5833 if(!this.isListening(fn, scope)){
5834 var l = {fn: fn, scope: scope, options: o};
5837 h = createDelayed(h, o, scope);
5840 h = createSingle(h, this, fn, scope);
5843 h = createBuffered(h, o, scope);
5846 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5847 this.listeners.push(l);
5849 this.listeners = this.listeners.slice(0);
5850 this.listeners.push(l);
5855 findListener : function(fn, scope){
5856 scope = scope || this.obj;
5857 var ls = this.listeners;
5858 for(var i = 0, len = ls.length; i < len; i++){
5860 if(l.fn == fn && l.scope == scope){
5867 isListening : function(fn, scope){
5868 return this.findListener(fn, scope) != -1;
5871 removeListener : function(fn, scope){
5873 if((index = this.findListener(fn, scope)) != -1){
5875 this.listeners.splice(index, 1);
5877 this.listeners = this.listeners.slice(0);
5878 this.listeners.splice(index, 1);
5885 clearListeners : function(){
5886 this.listeners = [];
5890 var ls = this.listeners, scope, len = ls.length;
5893 var args = Array.prototype.slice.call(arguments, 0);
5894 for(var i = 0; i < len; i++){
5896 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5897 this.firing = false;
5901 this.firing = false;
5908 * Ext JS Library 1.1.1
5909 * Copyright(c) 2006-2007, Ext JS, LLC.
5911 * Originally Released Under LGPL - original licence link has changed is not relivant.
5914 * <script type="text/javascript">
5918 * @class Roo.EventManager
5919 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5920 * several useful events directly.
5921 * See {@link Roo.EventObject} for more details on normalized event objects.
5924 Roo.EventManager = function(){
5925 var docReadyEvent, docReadyProcId, docReadyState = false;
5926 var resizeEvent, resizeTask, textEvent, textSize;
5927 var E = Roo.lib.Event;
5928 var D = Roo.lib.Dom;
5931 var fireDocReady = function(){
5933 docReadyState = true;
5936 clearInterval(docReadyProcId);
5938 if(Roo.isGecko || Roo.isOpera) {
5939 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5942 var defer = document.getElementById("ie-deferred-loader");
5944 defer.onreadystatechange = null;
5945 defer.parentNode.removeChild(defer);
5949 docReadyEvent.fire();
5950 docReadyEvent.clearListeners();
5955 var initDocReady = function(){
5956 docReadyEvent = new Roo.util.Event();
5957 if(Roo.isGecko || Roo.isOpera) {
5958 document.addEventListener("DOMContentLoaded", fireDocReady, false);
5960 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5961 var defer = document.getElementById("ie-deferred-loader");
5962 defer.onreadystatechange = function(){
5963 if(this.readyState == "complete"){
5967 }else if(Roo.isSafari){
5968 docReadyProcId = setInterval(function(){
5969 var rs = document.readyState;
5970 if(rs == "complete") {
5975 // no matter what, make sure it fires on load
5976 E.on(window, "load", fireDocReady);
5979 var createBuffered = function(h, o){
5980 var task = new Roo.util.DelayedTask(h);
5982 // create new event object impl so new events don't wipe out properties
5983 e = new Roo.EventObjectImpl(e);
5984 task.delay(o.buffer, h, null, [e]);
5988 var createSingle = function(h, el, ename, fn){
5990 Roo.EventManager.removeListener(el, ename, fn);
5995 var createDelayed = function(h, o){
5997 // create new event object impl so new events don't wipe out properties
5998 e = new Roo.EventObjectImpl(e);
5999 setTimeout(function(){
6005 var listen = function(element, ename, opt, fn, scope){
6006 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6007 fn = fn || o.fn; scope = scope || o.scope;
6008 var el = Roo.getDom(element);
6010 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6012 var h = function(e){
6013 e = Roo.EventObject.setEvent(e);
6016 t = e.getTarget(o.delegate, el);
6023 if(o.stopEvent === true){
6026 if(o.preventDefault === true){
6029 if(o.stopPropagation === true){
6030 e.stopPropagation();
6033 if(o.normalized === false){
6037 fn.call(scope || el, e, t, o);
6040 h = createDelayed(h, o);
6043 h = createSingle(h, el, ename, fn);
6046 h = createBuffered(h, o);
6048 fn._handlers = fn._handlers || [];
6049 fn._handlers.push([Roo.id(el), ename, h]);
6052 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6053 el.addEventListener("DOMMouseScroll", h, false);
6054 E.on(window, 'unload', function(){
6055 el.removeEventListener("DOMMouseScroll", h, false);
6058 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6059 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6064 var stopListening = function(el, ename, fn){
6065 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6067 for(var i = 0, len = hds.length; i < len; i++){
6069 if(h[0] == id && h[1] == ename){
6076 E.un(el, ename, hd);
6077 el = Roo.getDom(el);
6078 if(ename == "mousewheel" && el.addEventListener){
6079 el.removeEventListener("DOMMouseScroll", hd, false);
6081 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6082 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6086 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6093 * @scope Roo.EventManager
6098 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6099 * object with a Roo.EventObject
6100 * @param {Function} fn The method the event invokes
6101 * @param {Object} scope An object that becomes the scope of the handler
6102 * @param {boolean} override If true, the obj passed in becomes
6103 * the execution scope of the listener
6104 * @return {Function} The wrapped function
6107 wrap : function(fn, scope, override){
6109 Roo.EventObject.setEvent(e);
6110 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6115 * Appends an event handler to an element (shorthand for addListener)
6116 * @param {String/HTMLElement} element The html element or id to assign the
6117 * @param {String} eventName The type of event to listen for
6118 * @param {Function} handler The method the event invokes
6119 * @param {Object} scope (optional) The scope in which to execute the handler
6120 * function. The handler function's "this" context.
6121 * @param {Object} options (optional) An object containing handler configuration
6122 * properties. This may contain any of the following properties:<ul>
6123 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6124 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6125 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6126 * <li>preventDefault {Boolean} True to prevent the default action</li>
6127 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6128 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6129 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6130 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6131 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6132 * by the specified number of milliseconds. If the event fires again within that time, the original
6133 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6136 * <b>Combining Options</b><br>
6137 * Using the options argument, it is possible to combine different types of listeners:<br>
6139 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6141 el.on('click', this.onClick, this, {
6148 * <b>Attaching multiple handlers in 1 call</b><br>
6149 * The method also allows for a single argument to be passed which is a config object containing properties
6150 * which specify multiple handlers.
6160 fn: this.onMouseOver
6169 * Or a shorthand syntax:<br>
6172 'click' : this.onClick,
6173 'mouseover' : this.onMouseOver,
6174 'mouseout' : this.onMouseOut
6178 addListener : function(element, eventName, fn, scope, options){
6179 if(typeof eventName == "object"){
6185 if(typeof o[e] == "function"){
6187 listen(element, e, o, o[e], o.scope);
6189 // individual options
6190 listen(element, e, o[e]);
6195 return listen(element, eventName, options, fn, scope);
6199 * Removes an event handler
6201 * @param {String/HTMLElement} element The id or html element to remove the
6203 * @param {String} eventName The type of event
6204 * @param {Function} fn
6205 * @return {Boolean} True if a listener was actually removed
6207 removeListener : function(element, eventName, fn){
6208 return stopListening(element, eventName, fn);
6212 * Fires when the document is ready (before onload and before images are loaded). Can be
6213 * accessed shorthanded Roo.onReady().
6214 * @param {Function} fn The method the event invokes
6215 * @param {Object} scope An object that becomes the scope of the handler
6216 * @param {boolean} options
6218 onDocumentReady : function(fn, scope, options){
6219 if(docReadyState){ // if it already fired
6220 docReadyEvent.addListener(fn, scope, options);
6221 docReadyEvent.fire();
6222 docReadyEvent.clearListeners();
6228 docReadyEvent.addListener(fn, scope, options);
6232 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6233 * @param {Function} fn The method the event invokes
6234 * @param {Object} scope An object that becomes the scope of the handler
6235 * @param {boolean} options
6237 onWindowResize : function(fn, scope, options){
6239 resizeEvent = new Roo.util.Event();
6240 resizeTask = new Roo.util.DelayedTask(function(){
6241 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6243 E.on(window, "resize", function(){
6245 resizeTask.delay(50);
6247 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6251 resizeEvent.addListener(fn, scope, options);
6255 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6256 * @param {Function} fn The method the event invokes
6257 * @param {Object} scope An object that becomes the scope of the handler
6258 * @param {boolean} options
6260 onTextResize : function(fn, scope, options){
6262 textEvent = new Roo.util.Event();
6263 var textEl = new Roo.Element(document.createElement('div'));
6264 textEl.dom.className = 'x-text-resize';
6265 textEl.dom.innerHTML = 'X';
6266 textEl.appendTo(document.body);
6267 textSize = textEl.dom.offsetHeight;
6268 setInterval(function(){
6269 if(textEl.dom.offsetHeight != textSize){
6270 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6272 }, this.textResizeInterval);
6274 textEvent.addListener(fn, scope, options);
6278 * Removes the passed window resize listener.
6279 * @param {Function} fn The method the event invokes
6280 * @param {Object} scope The scope of handler
6282 removeResizeListener : function(fn, scope){
6284 resizeEvent.removeListener(fn, scope);
6289 fireResize : function(){
6291 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6295 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6299 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6301 textResizeInterval : 50
6306 * @scopeAlias pub=Roo.EventManager
6310 * Appends an event handler to an element (shorthand for addListener)
6311 * @param {String/HTMLElement} element The html element or id to assign the
6312 * @param {String} eventName The type of event to listen for
6313 * @param {Function} handler The method the event invokes
6314 * @param {Object} scope (optional) The scope in which to execute the handler
6315 * function. The handler function's "this" context.
6316 * @param {Object} options (optional) An object containing handler configuration
6317 * properties. This may contain any of the following properties:<ul>
6318 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6319 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6320 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6321 * <li>preventDefault {Boolean} True to prevent the default action</li>
6322 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6323 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6324 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6325 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6326 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6327 * by the specified number of milliseconds. If the event fires again within that time, the original
6328 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6331 * <b>Combining Options</b><br>
6332 * Using the options argument, it is possible to combine different types of listeners:<br>
6334 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6336 el.on('click', this.onClick, this, {
6343 * <b>Attaching multiple handlers in 1 call</b><br>
6344 * The method also allows for a single argument to be passed which is a config object containing properties
6345 * which specify multiple handlers.
6355 fn: this.onMouseOver
6364 * Or a shorthand syntax:<br>
6367 'click' : this.onClick,
6368 'mouseover' : this.onMouseOver,
6369 'mouseout' : this.onMouseOut
6373 pub.on = pub.addListener;
6374 pub.un = pub.removeListener;
6376 pub.stoppedMouseDownEvent = new Roo.util.Event();
6380 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6381 * @param {Function} fn The method the event invokes
6382 * @param {Object} scope An object that becomes the scope of the handler
6383 * @param {boolean} override If true, the obj passed in becomes
6384 * the execution scope of the listener
6388 Roo.onReady = Roo.EventManager.onDocumentReady;
6390 Roo.onReady(function(){
6391 var bd = Roo.get(document.body);
6396 : Roo.isGecko ? "roo-gecko"
6397 : Roo.isOpera ? "roo-opera"
6398 : Roo.isSafari ? "roo-safari" : ""];
6401 cls.push("roo-mac");
6404 cls.push("roo-linux");
6406 if(Roo.isBorderBox){
6407 cls.push('roo-border-box');
6409 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6410 var p = bd.dom.parentNode;
6412 p.className += ' roo-strict';
6415 bd.addClass(cls.join(' '));
6419 * @class Roo.EventObject
6420 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6421 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6424 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6426 var target = e.getTarget();
6429 var myDiv = Roo.get("myDiv");
6430 myDiv.on("click", handleClick);
6432 Roo.EventManager.on("myDiv", 'click', handleClick);
6433 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6437 Roo.EventObject = function(){
6439 var E = Roo.lib.Event;
6441 // safari keypress events for special keys return bad keycodes
6444 63235 : 39, // right
6447 63276 : 33, // page up
6448 63277 : 34, // page down
6449 63272 : 46, // delete
6454 // normalize button clicks
6455 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6456 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6458 Roo.EventObjectImpl = function(e){
6460 this.setEvent(e.browserEvent || e);
6463 Roo.EventObjectImpl.prototype = {
6465 * Used to fix doc tools.
6466 * @scope Roo.EventObject.prototype
6472 /** The normal browser event */
6473 browserEvent : null,
6474 /** The button pressed in a mouse event */
6476 /** True if the shift key was down during the event */
6478 /** True if the control key was down during the event */
6480 /** True if the alt key was down during the event */
6539 setEvent : function(e){
6540 if(e == this || (e && e.browserEvent)){ // already wrapped
6543 this.browserEvent = e;
6545 // normalize buttons
6546 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6547 if(e.type == 'click' && this.button == -1){
6551 this.shiftKey = e.shiftKey;
6552 // mac metaKey behaves like ctrlKey
6553 this.ctrlKey = e.ctrlKey || e.metaKey;
6554 this.altKey = e.altKey;
6555 // in getKey these will be normalized for the mac
6556 this.keyCode = e.keyCode;
6557 // keyup warnings on firefox.
6558 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6559 // cache the target for the delayed and or buffered events
6560 this.target = E.getTarget(e);
6562 this.xy = E.getXY(e);
6565 this.shiftKey = false;
6566 this.ctrlKey = false;
6567 this.altKey = false;
6577 * Stop the event (preventDefault and stopPropagation)
6579 stopEvent : function(){
6580 if(this.browserEvent){
6581 if(this.browserEvent.type == 'mousedown'){
6582 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6584 E.stopEvent(this.browserEvent);
6589 * Prevents the browsers default handling of the event.
6591 preventDefault : function(){
6592 if(this.browserEvent){
6593 E.preventDefault(this.browserEvent);
6598 isNavKeyPress : function(){
6599 var k = this.keyCode;
6600 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6601 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6604 isSpecialKey : function(){
6605 var k = this.keyCode;
6606 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6607 (k == 16) || (k == 17) ||
6608 (k >= 18 && k <= 20) ||
6609 (k >= 33 && k <= 35) ||
6610 (k >= 36 && k <= 39) ||
6611 (k >= 44 && k <= 45);
6614 * Cancels bubbling of the event.
6616 stopPropagation : function(){
6617 if(this.browserEvent){
6618 if(this.type == 'mousedown'){
6619 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6621 E.stopPropagation(this.browserEvent);
6626 * Gets the key code for the event.
6629 getCharCode : function(){
6630 return this.charCode || this.keyCode;
6634 * Returns a normalized keyCode for the event.
6635 * @return {Number} The key code
6637 getKey : function(){
6638 var k = this.keyCode || this.charCode;
6639 return Roo.isSafari ? (safariKeys[k] || k) : k;
6643 * Gets the x coordinate of the event.
6646 getPageX : function(){
6651 * Gets the y coordinate of the event.
6654 getPageY : function(){
6659 * Gets the time of the event.
6662 getTime : function(){
6663 if(this.browserEvent){
6664 return E.getTime(this.browserEvent);
6670 * Gets the page coordinates of the event.
6671 * @return {Array} The xy values like [x, y]
6678 * Gets the target for the event.
6679 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6680 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6681 search as a number or element (defaults to 10 || document.body)
6682 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6683 * @return {HTMLelement}
6685 getTarget : function(selector, maxDepth, returnEl){
6686 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6689 * Gets the related target.
6690 * @return {HTMLElement}
6692 getRelatedTarget : function(){
6693 if(this.browserEvent){
6694 return E.getRelatedTarget(this.browserEvent);
6700 * Normalizes mouse wheel delta across browsers
6701 * @return {Number} The delta
6703 getWheelDelta : function(){
6704 var e = this.browserEvent;
6706 if(e.wheelDelta){ /* IE/Opera. */
6707 delta = e.wheelDelta/120;
6708 }else if(e.detail){ /* Mozilla case. */
6709 delta = -e.detail/3;
6715 * Returns true if the control, meta, shift or alt key was pressed during this event.
6718 hasModifier : function(){
6719 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6723 * Returns true if the target of this event equals el or is a child of el
6724 * @param {String/HTMLElement/Element} el
6725 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6728 within : function(el, related){
6729 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6730 return t && Roo.fly(el).contains(t);
6733 getPoint : function(){
6734 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6738 return new Roo.EventObjectImpl();
6743 * Ext JS Library 1.1.1
6744 * Copyright(c) 2006-2007, Ext JS, LLC.
6746 * Originally Released Under LGPL - original licence link has changed is not relivant.
6749 * <script type="text/javascript">
6753 // was in Composite Element!??!?!
6756 var D = Roo.lib.Dom;
6757 var E = Roo.lib.Event;
6758 var A = Roo.lib.Anim;
6760 // local style camelizing for speed
6762 var camelRe = /(-[a-z])/gi;
6763 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6764 var view = document.defaultView;
6767 * @class Roo.Element
6768 * Represents an Element in the DOM.<br><br>
6771 var el = Roo.get("my-div");
6774 var el = getEl("my-div");
6776 // or with a DOM element
6777 var el = Roo.get(myDivElement);
6779 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6780 * each call instead of constructing a new one.<br><br>
6781 * <b>Animations</b><br />
6782 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6783 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6785 Option Default Description
6786 --------- -------- ---------------------------------------------
6787 duration .35 The duration of the animation in seconds
6788 easing easeOut The YUI easing method
6789 callback none A function to execute when the anim completes
6790 scope this The scope (this) of the callback function
6792 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6793 * manipulate the animation. Here's an example:
6795 var el = Roo.get("my-div");
6800 // default animation
6801 el.setWidth(100, true);
6803 // animation with some options set
6810 // using the "anim" property to get the Anim object
6816 el.setWidth(100, opt);
6818 if(opt.anim.isAnimated()){
6822 * <b> Composite (Collections of) Elements</b><br />
6823 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6824 * @constructor Create a new Element directly.
6825 * @param {String/HTMLElement} element
6826 * @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).
6828 Roo.Element = function(element, forceNew){
6829 var dom = typeof element == "string" ?
6830 document.getElementById(element) : element;
6831 if(!dom){ // invalid id/element
6835 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6836 return Roo.Element.cache[id];
6846 * The DOM element ID
6849 this.id = id || Roo.id(dom);
6852 var El = Roo.Element;
6856 * The element's default display mode (defaults to "")
6859 originalDisplay : "",
6863 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6868 * Sets the element's visibility mode. When setVisible() is called it
6869 * will use this to determine whether to set the visibility or the display property.
6870 * @param visMode Element.VISIBILITY or Element.DISPLAY
6871 * @return {Roo.Element} this
6873 setVisibilityMode : function(visMode){
6874 this.visibilityMode = visMode;
6878 * Convenience method for setVisibilityMode(Element.DISPLAY)
6879 * @param {String} display (optional) What to set display to when visible
6880 * @return {Roo.Element} this
6882 enableDisplayMode : function(display){
6883 this.setVisibilityMode(El.DISPLAY);
6884 if(typeof display != "undefined") this.originalDisplay = display;
6889 * 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)
6890 * @param {String} selector The simple selector to test
6891 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6892 search as a number or element (defaults to 10 || document.body)
6893 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6894 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6896 findParent : function(simpleSelector, maxDepth, returnEl){
6897 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6898 maxDepth = maxDepth || 50;
6899 if(typeof maxDepth != "number"){
6900 stopEl = Roo.getDom(maxDepth);
6903 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6904 if(dq.is(p, simpleSelector)){
6905 return returnEl ? Roo.get(p) : p;
6915 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6916 * @param {String} selector The simple selector to test
6917 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6918 search as a number or element (defaults to 10 || document.body)
6919 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6920 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6922 findParentNode : function(simpleSelector, maxDepth, returnEl){
6923 var p = Roo.fly(this.dom.parentNode, '_internal');
6924 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6928 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6929 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6930 * @param {String} selector The simple selector to test
6931 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6932 search as a number or element (defaults to 10 || document.body)
6933 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6935 up : function(simpleSelector, maxDepth){
6936 return this.findParentNode(simpleSelector, maxDepth, true);
6942 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6943 * @param {String} selector The simple selector to test
6944 * @return {Boolean} True if this element matches the selector, else false
6946 is : function(simpleSelector){
6947 return Roo.DomQuery.is(this.dom, simpleSelector);
6951 * Perform animation on this element.
6952 * @param {Object} args The YUI animation control args
6953 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6954 * @param {Function} onComplete (optional) Function to call when animation completes
6955 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6956 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6957 * @return {Roo.Element} this
6959 animate : function(args, duration, onComplete, easing, animType){
6960 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6965 * @private Internal animation call
6967 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6968 animType = animType || 'run';
6970 var anim = Roo.lib.Anim[animType](
6972 (opt.duration || defaultDur) || .35,
6973 (opt.easing || defaultEase) || 'easeOut',
6975 Roo.callback(cb, this);
6976 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6984 // private legacy anim prep
6985 preanim : function(a, i){
6986 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6990 * Removes worthless text nodes
6991 * @param {Boolean} forceReclean (optional) By default the element
6992 * keeps track if it has been cleaned already so
6993 * you can call this over and over. However, if you update the element and
6994 * need to force a reclean, you can pass true.
6996 clean : function(forceReclean){
6997 if(this.isCleaned && forceReclean !== true){
7001 var d = this.dom, n = d.firstChild, ni = -1;
7003 var nx = n.nextSibling;
7004 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7011 this.isCleaned = true;
7016 calcOffsetsTo : function(el){
7019 var restorePos = false;
7020 if(el.getStyle('position') == 'static'){
7021 el.position('relative');
7026 while(op && op != d && op.tagName != 'HTML'){
7029 op = op.offsetParent;
7032 el.position('static');
7038 * Scrolls this element into view within the passed container.
7039 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7040 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7041 * @return {Roo.Element} this
7043 scrollIntoView : function(container, hscroll){
7044 var c = Roo.getDom(container) || document.body;
7047 var o = this.calcOffsetsTo(c),
7050 b = t+el.offsetHeight,
7051 r = l+el.offsetWidth;
7053 var ch = c.clientHeight;
7054 var ct = parseInt(c.scrollTop, 10);
7055 var cl = parseInt(c.scrollLeft, 10);
7057 var cr = cl + c.clientWidth;
7065 if(hscroll !== false){
7069 c.scrollLeft = r-c.clientWidth;
7076 scrollChildIntoView : function(child, hscroll){
7077 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7081 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7082 * the new height may not be available immediately.
7083 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7084 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7085 * @param {Function} onComplete (optional) Function to call when animation completes
7086 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7087 * @return {Roo.Element} this
7089 autoHeight : function(animate, duration, onComplete, easing){
7090 var oldHeight = this.getHeight();
7092 this.setHeight(1); // force clipping
7093 setTimeout(function(){
7094 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7096 this.setHeight(height);
7098 if(typeof onComplete == "function"){
7102 this.setHeight(oldHeight); // restore original height
7103 this.setHeight(height, animate, duration, function(){
7105 if(typeof onComplete == "function") onComplete();
7106 }.createDelegate(this), easing);
7108 }.createDelegate(this), 0);
7113 * Returns true if this element is an ancestor of the passed element
7114 * @param {HTMLElement/String} el The element to check
7115 * @return {Boolean} True if this element is an ancestor of el, else false
7117 contains : function(el){
7118 if(!el){return false;}
7119 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7123 * Checks whether the element is currently visible using both visibility and display properties.
7124 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7125 * @return {Boolean} True if the element is currently visible, else false
7127 isVisible : function(deep) {
7128 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7129 if(deep !== true || !vis){
7132 var p = this.dom.parentNode;
7133 while(p && p.tagName.toLowerCase() != "body"){
7134 if(!Roo.fly(p, '_isVisible').isVisible()){
7143 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7144 * @param {String} selector The CSS selector
7145 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7146 * @return {CompositeElement/CompositeElementLite} The composite element
7148 select : function(selector, unique){
7149 return El.select(selector, unique, this.dom);
7153 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7154 * @param {String} selector The CSS selector
7155 * @return {Array} An array of the matched nodes
7157 query : function(selector, unique){
7158 return Roo.DomQuery.select(selector, this.dom);
7162 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7163 * @param {String} selector The CSS selector
7164 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7165 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7167 child : function(selector, returnDom){
7168 var n = Roo.DomQuery.selectNode(selector, this.dom);
7169 return returnDom ? n : Roo.get(n);
7173 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7174 * @param {String} selector The CSS selector
7175 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7176 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7178 down : function(selector, returnDom){
7179 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7180 return returnDom ? n : Roo.get(n);
7184 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7185 * @param {String} group The group the DD object is member of
7186 * @param {Object} config The DD config object
7187 * @param {Object} overrides An object containing methods to override/implement on the DD object
7188 * @return {Roo.dd.DD} The DD object
7190 initDD : function(group, config, overrides){
7191 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7192 return Roo.apply(dd, overrides);
7196 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7197 * @param {String} group The group the DDProxy object is member of
7198 * @param {Object} config The DDProxy config object
7199 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7200 * @return {Roo.dd.DDProxy} The DDProxy object
7202 initDDProxy : function(group, config, overrides){
7203 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7204 return Roo.apply(dd, overrides);
7208 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7209 * @param {String} group The group the DDTarget object is member of
7210 * @param {Object} config The DDTarget config object
7211 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7212 * @return {Roo.dd.DDTarget} The DDTarget object
7214 initDDTarget : function(group, config, overrides){
7215 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7216 return Roo.apply(dd, overrides);
7220 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7221 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7222 * @param {Boolean} visible Whether the element is visible
7223 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7224 * @return {Roo.Element} this
7226 setVisible : function(visible, animate){
7228 if(this.visibilityMode == El.DISPLAY){
7229 this.setDisplayed(visible);
7232 this.dom.style.visibility = visible ? "visible" : "hidden";
7235 // closure for composites
7237 var visMode = this.visibilityMode;
7239 this.setOpacity(.01);
7240 this.setVisible(true);
7242 this.anim({opacity: { to: (visible?1:0) }},
7243 this.preanim(arguments, 1),
7244 null, .35, 'easeIn', function(){
7246 if(visMode == El.DISPLAY){
7247 dom.style.display = "none";
7249 dom.style.visibility = "hidden";
7251 Roo.get(dom).setOpacity(1);
7259 * Returns true if display is not "none"
7262 isDisplayed : function() {
7263 return this.getStyle("display") != "none";
7267 * Toggles the element's visibility or display, depending on visibility mode.
7268 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7269 * @return {Roo.Element} this
7271 toggle : function(animate){
7272 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7277 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7278 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7279 * @return {Roo.Element} this
7281 setDisplayed : function(value) {
7282 if(typeof value == "boolean"){
7283 value = value ? this.originalDisplay : "none";
7285 this.setStyle("display", value);
7290 * Tries to focus the element. Any exceptions are caught and ignored.
7291 * @return {Roo.Element} this
7293 focus : function() {
7301 * Tries to blur the element. Any exceptions are caught and ignored.
7302 * @return {Roo.Element} this
7312 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7313 * @param {String/Array} className The CSS class to add, or an array of classes
7314 * @return {Roo.Element} this
7316 addClass : function(className){
7317 if(className instanceof Array){
7318 for(var i = 0, len = className.length; i < len; i++) {
7319 this.addClass(className[i]);
7322 if(className && !this.hasClass(className)){
7323 this.dom.className = this.dom.className + " " + className;
7330 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7331 * @param {String/Array} className The CSS class to add, or an array of classes
7332 * @return {Roo.Element} this
7334 radioClass : function(className){
7335 var siblings = this.dom.parentNode.childNodes;
7336 for(var i = 0; i < siblings.length; i++) {
7337 var s = siblings[i];
7338 if(s.nodeType == 1){
7339 Roo.get(s).removeClass(className);
7342 this.addClass(className);
7347 * Removes one or more CSS classes from the element.
7348 * @param {String/Array} className The CSS class to remove, or an array of classes
7349 * @return {Roo.Element} this
7351 removeClass : function(className){
7352 if(!className || !this.dom.className){
7355 if(className instanceof Array){
7356 for(var i = 0, len = className.length; i < len; i++) {
7357 this.removeClass(className[i]);
7360 if(this.hasClass(className)){
7361 var re = this.classReCache[className];
7363 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7364 this.classReCache[className] = re;
7366 this.dom.className =
7367 this.dom.className.replace(re, " ");
7377 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7378 * @param {String} className The CSS class to toggle
7379 * @return {Roo.Element} this
7381 toggleClass : function(className){
7382 if(this.hasClass(className)){
7383 this.removeClass(className);
7385 this.addClass(className);
7391 * Checks if the specified CSS class exists on this element's DOM node.
7392 * @param {String} className The CSS class to check for
7393 * @return {Boolean} True if the class exists, else false
7395 hasClass : function(className){
7396 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7400 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7401 * @param {String} oldClassName The CSS class to replace
7402 * @param {String} newClassName The replacement CSS class
7403 * @return {Roo.Element} this
7405 replaceClass : function(oldClassName, newClassName){
7406 this.removeClass(oldClassName);
7407 this.addClass(newClassName);
7412 * Returns an object with properties matching the styles requested.
7413 * For example, el.getStyles('color', 'font-size', 'width') might return
7414 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7415 * @param {String} style1 A style name
7416 * @param {String} style2 A style name
7417 * @param {String} etc.
7418 * @return {Object} The style object
7420 getStyles : function(){
7421 var a = arguments, len = a.length, r = {};
7422 for(var i = 0; i < len; i++){
7423 r[a[i]] = this.getStyle(a[i]);
7429 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7430 * @param {String} property The style property whose value is returned.
7431 * @return {String} The current value of the style property for this element.
7433 getStyle : function(){
7434 return view && view.getComputedStyle ?
7436 var el = this.dom, v, cs, camel;
7437 if(prop == 'float'){
7440 if(el.style && (v = el.style[prop])){
7443 if(cs = view.getComputedStyle(el, "")){
7444 if(!(camel = propCache[prop])){
7445 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7452 var el = this.dom, v, cs, camel;
7453 if(prop == 'opacity'){
7454 if(typeof el.style.filter == 'string'){
7455 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7457 var fv = parseFloat(m[1]);
7459 return fv ? fv / 100 : 0;
7464 }else if(prop == 'float'){
7465 prop = "styleFloat";
7467 if(!(camel = propCache[prop])){
7468 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7470 if(v = el.style[camel]){
7473 if(cs = el.currentStyle){
7481 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7482 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7483 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7484 * @return {Roo.Element} this
7486 setStyle : function(prop, value){
7487 if(typeof prop == "string"){
7489 if (prop == 'float') {
7490 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7495 if(!(camel = propCache[prop])){
7496 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7499 if(camel == 'opacity') {
7500 this.setOpacity(value);
7502 this.dom.style[camel] = value;
7505 for(var style in prop){
7506 if(typeof prop[style] != "function"){
7507 this.setStyle(style, prop[style]);
7515 * More flexible version of {@link #setStyle} for setting style properties.
7516 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7517 * a function which returns such a specification.
7518 * @return {Roo.Element} this
7520 applyStyles : function(style){
7521 Roo.DomHelper.applyStyles(this.dom, style);
7526 * 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).
7527 * @return {Number} The X position of the element
7530 return D.getX(this.dom);
7534 * 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).
7535 * @return {Number} The Y position of the element
7538 return D.getY(this.dom);
7542 * 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).
7543 * @return {Array} The XY position of the element
7546 return D.getXY(this.dom);
7550 * 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).
7551 * @param {Number} The X position of the element
7552 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7553 * @return {Roo.Element} this
7555 setX : function(x, animate){
7557 D.setX(this.dom, x);
7559 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7565 * 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).
7566 * @param {Number} The Y 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 setY : function(y, animate){
7572 D.setY(this.dom, y);
7574 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7580 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7581 * @param {String} left The left CSS property value
7582 * @return {Roo.Element} this
7584 setLeft : function(left){
7585 this.setStyle("left", this.addUnits(left));
7590 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7591 * @param {String} top The top CSS property value
7592 * @return {Roo.Element} this
7594 setTop : function(top){
7595 this.setStyle("top", this.addUnits(top));
7600 * Sets the element's CSS right style.
7601 * @param {String} right The right CSS property value
7602 * @return {Roo.Element} this
7604 setRight : function(right){
7605 this.setStyle("right", this.addUnits(right));
7610 * Sets the element's CSS bottom style.
7611 * @param {String} bottom The bottom CSS property value
7612 * @return {Roo.Element} this
7614 setBottom : function(bottom){
7615 this.setStyle("bottom", this.addUnits(bottom));
7620 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7621 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7622 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7623 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7624 * @return {Roo.Element} this
7626 setXY : function(pos, animate){
7628 D.setXY(this.dom, pos);
7630 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7636 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7637 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7638 * @param {Number} x X value for new position (coordinates are page-based)
7639 * @param {Number} y Y value for new position (coordinates are page-based)
7640 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7641 * @return {Roo.Element} this
7643 setLocation : function(x, y, animate){
7644 this.setXY([x, y], this.preanim(arguments, 2));
7649 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7650 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7651 * @param {Number} x X value for new position (coordinates are page-based)
7652 * @param {Number} y Y value for new position (coordinates are page-based)
7653 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7654 * @return {Roo.Element} this
7656 moveTo : function(x, y, animate){
7657 this.setXY([x, y], this.preanim(arguments, 2));
7662 * Returns the region of the given element.
7663 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7664 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7666 getRegion : function(){
7667 return D.getRegion(this.dom);
7671 * Returns the offset height of the element
7672 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7673 * @return {Number} The element's height
7675 getHeight : function(contentHeight){
7676 var h = this.dom.offsetHeight || 0;
7677 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7681 * Returns the offset width of the element
7682 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7683 * @return {Number} The element's width
7685 getWidth : function(contentWidth){
7686 var w = this.dom.offsetWidth || 0;
7687 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7691 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7692 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7693 * if a height has not been set using CSS.
7696 getComputedHeight : function(){
7697 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7699 h = parseInt(this.getStyle('height'), 10) || 0;
7700 if(!this.isBorderBox()){
7701 h += this.getFrameWidth('tb');
7708 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7709 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7710 * if a width has not been set using CSS.
7713 getComputedWidth : function(){
7714 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7716 w = parseInt(this.getStyle('width'), 10) || 0;
7717 if(!this.isBorderBox()){
7718 w += this.getFrameWidth('lr');
7725 * Returns the size of the element.
7726 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7727 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7729 getSize : function(contentSize){
7730 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7734 * Returns the width and height of the viewport.
7735 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7737 getViewSize : function(){
7738 var d = this.dom, doc = document, aw = 0, ah = 0;
7739 if(d == doc || d == doc.body){
7740 return {width : D.getViewWidth(), height: D.getViewHeight()};
7743 width : d.clientWidth,
7744 height: d.clientHeight
7750 * Returns the value of the "value" attribute
7751 * @param {Boolean} asNumber true to parse the value as a number
7752 * @return {String/Number}
7754 getValue : function(asNumber){
7755 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7759 adjustWidth : function(width){
7760 if(typeof width == "number"){
7761 if(this.autoBoxAdjust && !this.isBorderBox()){
7762 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7772 adjustHeight : function(height){
7773 if(typeof height == "number"){
7774 if(this.autoBoxAdjust && !this.isBorderBox()){
7775 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7785 * Set the width of the element
7786 * @param {Number} width The new width
7787 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7788 * @return {Roo.Element} this
7790 setWidth : function(width, animate){
7791 width = this.adjustWidth(width);
7793 this.dom.style.width = this.addUnits(width);
7795 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7801 * Set the height of the element
7802 * @param {Number} height The new height
7803 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7804 * @return {Roo.Element} this
7806 setHeight : function(height, animate){
7807 height = this.adjustHeight(height);
7809 this.dom.style.height = this.addUnits(height);
7811 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7817 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7818 * @param {Number} width The new width
7819 * @param {Number} height The new height
7820 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7821 * @return {Roo.Element} this
7823 setSize : function(width, height, animate){
7824 if(typeof width == "object"){ // in case of object from getSize()
7825 height = width.height; width = width.width;
7827 width = this.adjustWidth(width); height = this.adjustHeight(height);
7829 this.dom.style.width = this.addUnits(width);
7830 this.dom.style.height = this.addUnits(height);
7832 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7838 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7839 * @param {Number} x X value for new position (coordinates are page-based)
7840 * @param {Number} y Y value for new position (coordinates are page-based)
7841 * @param {Number} width The new width
7842 * @param {Number} height The new height
7843 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7844 * @return {Roo.Element} this
7846 setBounds : function(x, y, width, height, animate){
7848 this.setSize(width, height);
7849 this.setLocation(x, y);
7851 width = this.adjustWidth(width); height = this.adjustHeight(height);
7852 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7853 this.preanim(arguments, 4), 'motion');
7859 * 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.
7860 * @param {Roo.lib.Region} region The region to fill
7861 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7862 * @return {Roo.Element} this
7864 setRegion : function(region, animate){
7865 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7870 * Appends an event handler
7872 * @param {String} eventName The type of event to append
7873 * @param {Function} fn The method the event invokes
7874 * @param {Object} scope (optional) The scope (this object) of the fn
7875 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7877 addListener : function(eventName, fn, scope, options){
7879 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7884 * Removes an event handler from this element
7885 * @param {String} eventName the type of event to remove
7886 * @param {Function} fn the method the event invokes
7887 * @return {Roo.Element} this
7889 removeListener : function(eventName, fn){
7890 Roo.EventManager.removeListener(this.dom, eventName, fn);
7895 * Removes all previous added listeners from this element
7896 * @return {Roo.Element} this
7898 removeAllListeners : function(){
7899 E.purgeElement(this.dom);
7903 relayEvent : function(eventName, observable){
7904 this.on(eventName, function(e){
7905 observable.fireEvent(eventName, e);
7910 * Set the opacity of the element
7911 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7912 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7913 * @return {Roo.Element} this
7915 setOpacity : function(opacity, animate){
7917 var s = this.dom.style;
7920 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7921 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7923 s.opacity = opacity;
7926 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7932 * Gets the left X coordinate
7933 * @param {Boolean} local True to get the local css position instead of page coordinate
7936 getLeft : function(local){
7940 return parseInt(this.getStyle("left"), 10) || 0;
7945 * Gets the right X coordinate of the element (element X position + element width)
7946 * @param {Boolean} local True to get the local css position instead of page coordinate
7949 getRight : function(local){
7951 return this.getX() + this.getWidth();
7953 return (this.getLeft(true) + this.getWidth()) || 0;
7958 * Gets the top Y coordinate
7959 * @param {Boolean} local True to get the local css position instead of page coordinate
7962 getTop : function(local) {
7966 return parseInt(this.getStyle("top"), 10) || 0;
7971 * Gets the bottom Y coordinate of the element (element Y position + element height)
7972 * @param {Boolean} local True to get the local css position instead of page coordinate
7975 getBottom : function(local){
7977 return this.getY() + this.getHeight();
7979 return (this.getTop(true) + this.getHeight()) || 0;
7984 * Initializes positioning on this element. If a desired position is not passed, it will make the
7985 * the element positioned relative IF it is not already positioned.
7986 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7987 * @param {Number} zIndex (optional) The zIndex to apply
7988 * @param {Number} x (optional) Set the page X position
7989 * @param {Number} y (optional) Set the page Y position
7991 position : function(pos, zIndex, x, y){
7993 if(this.getStyle('position') == 'static'){
7994 this.setStyle('position', 'relative');
7997 this.setStyle("position", pos);
8000 this.setStyle("z-index", zIndex);
8002 if(x !== undefined && y !== undefined){
8004 }else if(x !== undefined){
8006 }else if(y !== undefined){
8012 * Clear positioning back to the default when the document was loaded
8013 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8014 * @return {Roo.Element} this
8016 clearPositioning : function(value){
8024 "position" : "static"
8030 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8031 * snapshot before performing an update and then restoring the element.
8034 getPositioning : function(){
8035 var l = this.getStyle("left");
8036 var t = this.getStyle("top");
8038 "position" : this.getStyle("position"),
8040 "right" : l ? "" : this.getStyle("right"),
8042 "bottom" : t ? "" : this.getStyle("bottom"),
8043 "z-index" : this.getStyle("z-index")
8048 * Gets the width of the border(s) for the specified side(s)
8049 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8050 * passing lr would get the border (l)eft width + the border (r)ight width.
8051 * @return {Number} The width of the sides passed added together
8053 getBorderWidth : function(side){
8054 return this.addStyles(side, El.borders);
8058 * Gets the width of the padding(s) for the specified side(s)
8059 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8060 * passing lr would get the padding (l)eft + the padding (r)ight.
8061 * @return {Number} The padding of the sides passed added together
8063 getPadding : function(side){
8064 return this.addStyles(side, El.paddings);
8068 * Set positioning with an object returned by getPositioning().
8069 * @param {Object} posCfg
8070 * @return {Roo.Element} this
8072 setPositioning : function(pc){
8073 this.applyStyles(pc);
8074 if(pc.right == "auto"){
8075 this.dom.style.right = "";
8077 if(pc.bottom == "auto"){
8078 this.dom.style.bottom = "";
8084 fixDisplay : function(){
8085 if(this.getStyle("display") == "none"){
8086 this.setStyle("visibility", "hidden");
8087 this.setStyle("display", this.originalDisplay); // first try reverting to default
8088 if(this.getStyle("display") == "none"){ // if that fails, default to block
8089 this.setStyle("display", "block");
8095 * Quick set left and top adding default units
8096 * @param {String} left The left CSS property value
8097 * @param {String} top The top CSS property value
8098 * @return {Roo.Element} this
8100 setLeftTop : function(left, top){
8101 this.dom.style.left = this.addUnits(left);
8102 this.dom.style.top = this.addUnits(top);
8107 * Move this element relative to its current position.
8108 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8109 * @param {Number} distance How far to move the element in pixels
8110 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8111 * @return {Roo.Element} this
8113 move : function(direction, distance, animate){
8114 var xy = this.getXY();
8115 direction = direction.toLowerCase();
8119 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8123 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8128 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8133 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8140 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8141 * @return {Roo.Element} this
8144 if(!this.isClipped){
8145 this.isClipped = true;
8146 this.originalClip = {
8147 "o": this.getStyle("overflow"),
8148 "x": this.getStyle("overflow-x"),
8149 "y": this.getStyle("overflow-y")
8151 this.setStyle("overflow", "hidden");
8152 this.setStyle("overflow-x", "hidden");
8153 this.setStyle("overflow-y", "hidden");
8159 * Return clipping (overflow) to original clipping before clip() was called
8160 * @return {Roo.Element} this
8162 unclip : function(){
8164 this.isClipped = false;
8165 var o = this.originalClip;
8166 if(o.o){this.setStyle("overflow", o.o);}
8167 if(o.x){this.setStyle("overflow-x", o.x);}
8168 if(o.y){this.setStyle("overflow-y", o.y);}
8175 * Gets the x,y coordinates specified by the anchor position on the element.
8176 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8177 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8178 * {width: (target width), height: (target height)} (defaults to the element's current size)
8179 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8180 * @return {Array} [x, y] An array containing the element's x and y coordinates
8182 getAnchorXY : function(anchor, local, s){
8183 //Passing a different size is useful for pre-calculating anchors,
8184 //especially for anchored animations that change the el size.
8186 var w, h, vp = false;
8189 if(d == document.body || d == document){
8191 w = D.getViewWidth(); h = D.getViewHeight();
8193 w = this.getWidth(); h = this.getHeight();
8196 w = s.width; h = s.height;
8198 var x = 0, y = 0, r = Math.round;
8199 switch((anchor || "tl").toLowerCase()){
8241 var sc = this.getScroll();
8242 return [x + sc.left, y + sc.top];
8244 //Add the element's offset xy
8245 var o = this.getXY();
8246 return [x+o[0], y+o[1]];
8250 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8251 * supported position values.
8252 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8253 * @param {String} position The position to align to.
8254 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8255 * @return {Array} [x, y]
8257 getAlignToXY : function(el, p, o){
8261 throw "Element.alignTo with an element that doesn't exist";
8263 var c = false; //constrain to viewport
8264 var p1 = "", p2 = "";
8271 }else if(p.indexOf("-") == -1){
8274 p = p.toLowerCase();
8275 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8277 throw "Element.alignTo with an invalid alignment " + p;
8279 p1 = m[1]; p2 = m[2]; c = !!m[3];
8281 //Subtract the aligned el's internal xy from the target's offset xy
8282 //plus custom offset to get the aligned el's new offset xy
8283 var a1 = this.getAnchorXY(p1, true);
8284 var a2 = el.getAnchorXY(p2, false);
8285 var x = a2[0] - a1[0] + o[0];
8286 var y = a2[1] - a1[1] + o[1];
8288 //constrain the aligned el to viewport if necessary
8289 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8290 // 5px of margin for ie
8291 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8293 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8294 //perpendicular to the vp border, allow the aligned el to slide on that border,
8295 //otherwise swap the aligned el to the opposite border of the target.
8296 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8297 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8298 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8299 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8302 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8303 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8305 if((x+w) > dw + scrollX){
8306 x = swapX ? r.left-w : dw+scrollX-w;
8309 x = swapX ? r.right : scrollX;
8311 if((y+h) > dh + scrollY){
8312 y = swapY ? r.top-h : dh+scrollY-h;
8315 y = swapY ? r.bottom : scrollY;
8322 getConstrainToXY : function(){
8323 var os = {top:0, left:0, bottom:0, right: 0};
8325 return function(el, local, offsets, proposedXY){
8327 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8329 var vw, vh, vx = 0, vy = 0;
8330 if(el.dom == document.body || el.dom == document){
8331 vw = Roo.lib.Dom.getViewWidth();
8332 vh = Roo.lib.Dom.getViewHeight();
8334 vw = el.dom.clientWidth;
8335 vh = el.dom.clientHeight;
8337 var vxy = el.getXY();
8343 var s = el.getScroll();
8345 vx += offsets.left + s.left;
8346 vy += offsets.top + s.top;
8348 vw -= offsets.right;
8349 vh -= offsets.bottom;
8354 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8355 var x = xy[0], y = xy[1];
8356 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8358 // only move it if it needs it
8361 // first validate right/bottom
8370 // then make sure top/left isn't negative
8379 return moved ? [x, y] : false;
8384 adjustForConstraints : function(xy, parent, offsets){
8385 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8389 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8390 * document it aligns it to the viewport.
8391 * The position parameter is optional, and can be specified in any one of the following formats:
8393 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8394 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8395 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8396 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8397 * <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
8398 * element's anchor point, and the second value is used as the target's anchor point.</li>
8400 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8401 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8402 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8403 * that specified in order to enforce the viewport constraints.
8404 * Following are all of the supported anchor positions:
8407 ----- -----------------------------
8408 tl The top left corner (default)
8409 t The center of the top edge
8410 tr The top right corner
8411 l The center of the left edge
8412 c In the center of the element
8413 r The center of the right edge
8414 bl The bottom left corner
8415 b The center of the bottom edge
8416 br The bottom right corner
8420 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8421 el.alignTo("other-el");
8423 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8424 el.alignTo("other-el", "tr?");
8426 // align the bottom right corner of el with the center left edge of other-el
8427 el.alignTo("other-el", "br-l?");
8429 // align the center of el with the bottom left corner of other-el and
8430 // adjust the x position by -6 pixels (and the y position by 0)
8431 el.alignTo("other-el", "c-bl", [-6, 0]);
8433 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8434 * @param {String} position The position to align to.
8435 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8436 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8437 * @return {Roo.Element} this
8439 alignTo : function(element, position, offsets, animate){
8440 var xy = this.getAlignToXY(element, position, offsets);
8441 this.setXY(xy, this.preanim(arguments, 3));
8446 * Anchors an element to another element and realigns it when the window is resized.
8447 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8448 * @param {String} position The position to align to.
8449 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8450 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8451 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8452 * is a number, it is used as the buffer delay (defaults to 50ms).
8453 * @param {Function} callback The function to call after the animation finishes
8454 * @return {Roo.Element} this
8456 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8457 var action = function(){
8458 this.alignTo(el, alignment, offsets, animate);
8459 Roo.callback(callback, this);
8461 Roo.EventManager.onWindowResize(action, this);
8462 var tm = typeof monitorScroll;
8463 if(tm != 'undefined'){
8464 Roo.EventManager.on(window, 'scroll', action, this,
8465 {buffer: tm == 'number' ? monitorScroll : 50});
8467 action.call(this); // align immediately
8471 * Clears any opacity settings from this element. Required in some cases for IE.
8472 * @return {Roo.Element} this
8474 clearOpacity : function(){
8475 if (window.ActiveXObject) {
8476 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8477 this.dom.style.filter = "";
8480 this.dom.style.opacity = "";
8481 this.dom.style["-moz-opacity"] = "";
8482 this.dom.style["-khtml-opacity"] = "";
8488 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8489 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8490 * @return {Roo.Element} this
8492 hide : function(animate){
8493 this.setVisible(false, this.preanim(arguments, 0));
8498 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8499 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8500 * @return {Roo.Element} this
8502 show : function(animate){
8503 this.setVisible(true, this.preanim(arguments, 0));
8508 * @private Test if size has a unit, otherwise appends the default
8510 addUnits : function(size){
8511 return Roo.Element.addUnits(size, this.defaultUnit);
8515 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8516 * @return {Roo.Element} this
8518 beginMeasure : function(){
8520 if(el.offsetWidth || el.offsetHeight){
8521 return this; // offsets work already
8524 var p = this.dom, b = document.body; // start with this element
8525 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8526 var pe = Roo.get(p);
8527 if(pe.getStyle('display') == 'none'){
8528 changed.push({el: p, visibility: pe.getStyle("visibility")});
8529 p.style.visibility = "hidden";
8530 p.style.display = "block";
8534 this._measureChanged = changed;
8540 * Restores displays to before beginMeasure was called
8541 * @return {Roo.Element} this
8543 endMeasure : function(){
8544 var changed = this._measureChanged;
8546 for(var i = 0, len = changed.length; i < len; i++) {
8548 r.el.style.visibility = r.visibility;
8549 r.el.style.display = "none";
8551 this._measureChanged = null;
8557 * Update the innerHTML of this element, optionally searching for and processing scripts
8558 * @param {String} html The new HTML
8559 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8560 * @param {Function} callback For async script loading you can be noticed when the update completes
8561 * @return {Roo.Element} this
8563 update : function(html, loadScripts, callback){
8564 if(typeof html == "undefined"){
8567 if(loadScripts !== true){
8568 this.dom.innerHTML = html;
8569 if(typeof callback == "function"){
8577 html += '<span id="' + id + '"></span>';
8579 E.onAvailable(id, function(){
8580 var hd = document.getElementsByTagName("head")[0];
8581 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8582 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8583 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8586 while(match = re.exec(html)){
8587 var attrs = match[1];
8588 var srcMatch = attrs ? attrs.match(srcRe) : false;
8589 if(srcMatch && srcMatch[2]){
8590 var s = document.createElement("script");
8591 s.src = srcMatch[2];
8592 var typeMatch = attrs.match(typeRe);
8593 if(typeMatch && typeMatch[2]){
8594 s.type = typeMatch[2];
8597 }else if(match[2] && match[2].length > 0){
8598 if(window.execScript) {
8599 window.execScript(match[2]);
8607 window.eval(match[2]);
8611 var el = document.getElementById(id);
8612 if(el){el.parentNode.removeChild(el);}
8613 if(typeof callback == "function"){
8617 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8622 * Direct access to the UpdateManager update() method (takes the same parameters).
8623 * @param {String/Function} url The url for this request or a function to call to get the url
8624 * @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}
8625 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8626 * @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.
8627 * @return {Roo.Element} this
8630 var um = this.getUpdateManager();
8631 um.update.apply(um, arguments);
8636 * Gets this element's UpdateManager
8637 * @return {Roo.UpdateManager} The UpdateManager
8639 getUpdateManager : function(){
8640 if(!this.updateManager){
8641 this.updateManager = new Roo.UpdateManager(this);
8643 return this.updateManager;
8647 * Disables text selection for this element (normalized across browsers)
8648 * @return {Roo.Element} this
8650 unselectable : function(){
8651 this.dom.unselectable = "on";
8652 this.swallowEvent("selectstart", true);
8653 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8654 this.addClass("x-unselectable");
8659 * Calculates the x, y to center this element on the screen
8660 * @return {Array} The x, y values [x, y]
8662 getCenterXY : function(){
8663 return this.getAlignToXY(document, 'c-c');
8667 * Centers the Element in either the viewport, or another Element.
8668 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8670 center : function(centerIn){
8671 this.alignTo(centerIn || document, 'c-c');
8676 * Tests various css rules/browsers to determine if this element uses a border box
8679 isBorderBox : function(){
8680 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8684 * Return a box {x, y, width, height} that can be used to set another elements
8685 * size/location to match this element.
8686 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8687 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8688 * @return {Object} box An object in the format {x, y, width, height}
8690 getBox : function(contentBox, local){
8695 var left = parseInt(this.getStyle("left"), 10) || 0;
8696 var top = parseInt(this.getStyle("top"), 10) || 0;
8699 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8701 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8703 var l = this.getBorderWidth("l")+this.getPadding("l");
8704 var r = this.getBorderWidth("r")+this.getPadding("r");
8705 var t = this.getBorderWidth("t")+this.getPadding("t");
8706 var b = this.getBorderWidth("b")+this.getPadding("b");
8707 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)};
8709 bx.right = bx.x + bx.width;
8710 bx.bottom = bx.y + bx.height;
8715 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8716 for more information about the sides.
8717 * @param {String} sides
8720 getFrameWidth : function(sides, onlyContentBox){
8721 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8725 * 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.
8726 * @param {Object} box The box to fill {x, y, width, height}
8727 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8728 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8729 * @return {Roo.Element} this
8731 setBox : function(box, adjust, animate){
8732 var w = box.width, h = box.height;
8733 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8734 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8735 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8737 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8742 * Forces the browser to repaint this element
8743 * @return {Roo.Element} this
8745 repaint : function(){
8747 this.addClass("x-repaint");
8748 setTimeout(function(){
8749 Roo.get(dom).removeClass("x-repaint");
8755 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8756 * then it returns the calculated width of the sides (see getPadding)
8757 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8758 * @return {Object/Number}
8760 getMargins : function(side){
8763 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8764 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8765 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8766 right: parseInt(this.getStyle("margin-right"), 10) || 0
8769 return this.addStyles(side, El.margins);
8774 addStyles : function(sides, styles){
8776 for(var i = 0, len = sides.length; i < len; i++){
8777 v = this.getStyle(styles[sides.charAt(i)]);
8779 w = parseInt(v, 10);
8787 * Creates a proxy element of this element
8788 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8789 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8790 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8791 * @return {Roo.Element} The new proxy element
8793 createProxy : function(config, renderTo, matchBox){
8795 renderTo = Roo.getDom(renderTo);
8797 renderTo = document.body;
8799 config = typeof config == "object" ?
8800 config : {tag : "div", cls: config};
8801 var proxy = Roo.DomHelper.append(renderTo, config, true);
8803 proxy.setBox(this.getBox());
8809 * Puts a mask over this element to disable user interaction. Requires core.css.
8810 * This method can only be applied to elements which accept child nodes.
8811 * @param {String} msg (optional) A message to display in the mask
8812 * @param {String} msgCls (optional) A css class to apply to the msg element
8813 * @return {Element} The mask element
8815 mask : function(msg, msgCls){
8816 if(this.getStyle("position") == "static"){
8817 this.setStyle("position", "relative");
8820 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8822 this.addClass("x-masked");
8823 this._mask.setDisplayed(true);
8824 if(typeof msg == 'string'){
8826 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8828 var mm = this._maskMsg;
8829 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8830 mm.dom.firstChild.innerHTML = msg;
8831 mm.setDisplayed(true);
8834 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8835 this._mask.setHeight(this.getHeight());
8841 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8842 * it is cached for reuse.
8844 unmask : function(removeEl){
8846 if(removeEl === true){
8847 this._mask.remove();
8850 this._maskMsg.remove();
8851 delete this._maskMsg;
8854 this._mask.setDisplayed(false);
8856 this._maskMsg.setDisplayed(false);
8860 this.removeClass("x-masked");
8864 * Returns true if this element is masked
8867 isMasked : function(){
8868 return this._mask && this._mask.isVisible();
8872 * Creates an iframe shim for this element to keep selects and other windowed objects from
8874 * @return {Roo.Element} The new shim element
8876 createShim : function(){
8877 var el = document.createElement('iframe');
8878 el.frameBorder = 'no';
8879 el.className = 'roo-shim';
8880 if(Roo.isIE && Roo.isSecure){
8881 el.src = Roo.SSL_SECURE_URL;
8883 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8884 shim.autoBoxAdjust = false;
8889 * Removes this element from the DOM and deletes it from the cache
8891 remove : function(){
8892 if(this.dom.parentNode){
8893 this.dom.parentNode.removeChild(this.dom);
8895 delete El.cache[this.dom.id];
8899 * Sets up event handlers to add and remove a css class when the mouse is over this element
8900 * @param {String} className
8901 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8902 * mouseout events for children elements
8903 * @return {Roo.Element} this
8905 addClassOnOver : function(className, preventFlicker){
8906 this.on("mouseover", function(){
8907 Roo.fly(this, '_internal').addClass(className);
8909 var removeFn = function(e){
8910 if(preventFlicker !== true || !e.within(this, true)){
8911 Roo.fly(this, '_internal').removeClass(className);
8914 this.on("mouseout", removeFn, this.dom);
8919 * Sets up event handlers to add and remove a css class when this element has the focus
8920 * @param {String} className
8921 * @return {Roo.Element} this
8923 addClassOnFocus : function(className){
8924 this.on("focus", function(){
8925 Roo.fly(this, '_internal').addClass(className);
8927 this.on("blur", function(){
8928 Roo.fly(this, '_internal').removeClass(className);
8933 * 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)
8934 * @param {String} className
8935 * @return {Roo.Element} this
8937 addClassOnClick : function(className){
8939 this.on("mousedown", function(){
8940 Roo.fly(dom, '_internal').addClass(className);
8941 var d = Roo.get(document);
8942 var fn = function(){
8943 Roo.fly(dom, '_internal').removeClass(className);
8944 d.removeListener("mouseup", fn);
8946 d.on("mouseup", fn);
8952 * Stops the specified event from bubbling and optionally prevents the default action
8953 * @param {String} eventName
8954 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8955 * @return {Roo.Element} this
8957 swallowEvent : function(eventName, preventDefault){
8958 var fn = function(e){
8959 e.stopPropagation();
8964 if(eventName instanceof Array){
8965 for(var i = 0, len = eventName.length; i < len; i++){
8966 this.on(eventName[i], fn);
8970 this.on(eventName, fn);
8977 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8980 * Sizes this element to its parent element's dimensions performing
8981 * neccessary box adjustments.
8982 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8983 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8984 * @return {Roo.Element} this
8986 fitToParent : function(monitorResize, targetParent) {
8987 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8988 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8989 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8992 var p = Roo.get(targetParent || this.dom.parentNode);
8993 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8994 if (monitorResize === true) {
8995 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8996 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9002 * Gets the next sibling, skipping text nodes
9003 * @return {HTMLElement} The next sibling or null
9005 getNextSibling : function(){
9006 var n = this.dom.nextSibling;
9007 while(n && n.nodeType != 1){
9014 * Gets the previous sibling, skipping text nodes
9015 * @return {HTMLElement} The previous sibling or null
9017 getPrevSibling : function(){
9018 var n = this.dom.previousSibling;
9019 while(n && n.nodeType != 1){
9020 n = n.previousSibling;
9027 * Appends the passed element(s) to this element
9028 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9029 * @return {Roo.Element} this
9031 appendChild: function(el){
9038 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9039 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9040 * automatically generated with the specified attributes.
9041 * @param {HTMLElement} insertBefore (optional) a child element of this element
9042 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9043 * @return {Roo.Element} The new child element
9045 createChild: function(config, insertBefore, returnDom){
9046 config = config || {tag:'div'};
9048 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9050 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9054 * Appends this element to the passed element
9055 * @param {String/HTMLElement/Element} el The new parent element
9056 * @return {Roo.Element} this
9058 appendTo: function(el){
9059 el = Roo.getDom(el);
9060 el.appendChild(this.dom);
9065 * Inserts this element before the passed element in the DOM
9066 * @param {String/HTMLElement/Element} el The element to insert before
9067 * @return {Roo.Element} this
9069 insertBefore: function(el){
9070 el = Roo.getDom(el);
9071 el.parentNode.insertBefore(this.dom, el);
9076 * Inserts this element after the passed element in the DOM
9077 * @param {String/HTMLElement/Element} el The element to insert after
9078 * @return {Roo.Element} this
9080 insertAfter: function(el){
9081 el = Roo.getDom(el);
9082 el.parentNode.insertBefore(this.dom, el.nextSibling);
9087 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9088 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9089 * @return {Roo.Element} The new child
9091 insertFirst: function(el, returnDom){
9093 if(typeof el == 'object' && !el.nodeType){ // dh config
9094 return this.createChild(el, this.dom.firstChild, returnDom);
9096 el = Roo.getDom(el);
9097 this.dom.insertBefore(el, this.dom.firstChild);
9098 return !returnDom ? Roo.get(el) : el;
9103 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9104 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9105 * @param {String} where (optional) 'before' or 'after' defaults to before
9106 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9107 * @return {Roo.Element} the inserted Element
9109 insertSibling: function(el, where, returnDom){
9110 where = where ? where.toLowerCase() : 'before';
9112 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9114 if(typeof el == 'object' && !el.nodeType){ // dh config
9115 if(where == 'after' && !this.dom.nextSibling){
9116 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9118 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9122 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9123 where == 'before' ? this.dom : this.dom.nextSibling);
9132 * Creates and wraps this element with another element
9133 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9134 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9135 * @return {HTMLElement/Element} The newly created wrapper element
9137 wrap: function(config, returnDom){
9139 config = {tag: "div"};
9141 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9142 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9147 * Replaces the passed element with this element
9148 * @param {String/HTMLElement/Element} el The element to replace
9149 * @return {Roo.Element} this
9151 replace: function(el){
9153 this.insertBefore(el);
9159 * Inserts an html fragment into this element
9160 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9161 * @param {String} html The HTML fragment
9162 * @param {Boolean} returnEl True to return an Roo.Element
9163 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9165 insertHtml : function(where, html, returnEl){
9166 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9167 return returnEl ? Roo.get(el) : el;
9171 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9172 * @param {Object} o The object with the attributes
9173 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9174 * @return {Roo.Element} this
9176 set : function(o, useSet){
9178 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9180 if(attr == "style" || typeof o[attr] == "function") continue;
9182 el.className = o["cls"];
9184 if(useSet) el.setAttribute(attr, o[attr]);
9185 else el[attr] = o[attr];
9189 Roo.DomHelper.applyStyles(el, o.style);
9195 * Convenience method for constructing a KeyMap
9196 * @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:
9197 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9198 * @param {Function} fn The function to call
9199 * @param {Object} scope (optional) The scope of the function
9200 * @return {Roo.KeyMap} The KeyMap created
9202 addKeyListener : function(key, fn, scope){
9204 if(typeof key != "object" || key instanceof Array){
9220 return new Roo.KeyMap(this, config);
9224 * Creates a KeyMap for this element
9225 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9226 * @return {Roo.KeyMap} The KeyMap created
9228 addKeyMap : function(config){
9229 return new Roo.KeyMap(this, config);
9233 * Returns true if this element is scrollable.
9236 isScrollable : function(){
9238 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9242 * 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().
9243 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9244 * @param {Number} value The new scroll value
9245 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9246 * @return {Element} this
9249 scrollTo : function(side, value, animate){
9250 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9252 this.dom[prop] = value;
9254 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9255 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9261 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9262 * within this element's scrollable range.
9263 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9264 * @param {Number} distance How far to scroll the element in pixels
9265 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9266 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9267 * was scrolled as far as it could go.
9269 scroll : function(direction, distance, animate){
9270 if(!this.isScrollable()){
9274 var l = el.scrollLeft, t = el.scrollTop;
9275 var w = el.scrollWidth, h = el.scrollHeight;
9276 var cw = el.clientWidth, ch = el.clientHeight;
9277 direction = direction.toLowerCase();
9278 var scrolled = false;
9279 var a = this.preanim(arguments, 2);
9284 var v = Math.min(l + distance, w-cw);
9285 this.scrollTo("left", v, a);
9292 var v = Math.max(l - distance, 0);
9293 this.scrollTo("left", v, a);
9301 var v = Math.max(t - distance, 0);
9302 this.scrollTo("top", v, a);
9310 var v = Math.min(t + distance, h-ch);
9311 this.scrollTo("top", v, a);
9320 * Translates the passed page coordinates into left/top css values for this element
9321 * @param {Number/Array} x The page x or an array containing [x, y]
9322 * @param {Number} y The page y
9323 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9325 translatePoints : function(x, y){
9326 if(typeof x == 'object' || x instanceof Array){
9329 var p = this.getStyle('position');
9330 var o = this.getXY();
9332 var l = parseInt(this.getStyle('left'), 10);
9333 var t = parseInt(this.getStyle('top'), 10);
9336 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9339 t = (p == "relative") ? 0 : this.dom.offsetTop;
9342 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9346 * Returns the current scroll position of the element.
9347 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9349 getScroll : function(){
9350 var d = this.dom, doc = document;
9351 if(d == doc || d == doc.body){
9352 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9353 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9354 return {left: l, top: t};
9356 return {left: d.scrollLeft, top: d.scrollTop};
9361 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9362 * are convert to standard 6 digit hex color.
9363 * @param {String} attr The css attribute
9364 * @param {String} defaultValue The default value to use when a valid color isn't found
9365 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9368 getColor : function(attr, defaultValue, prefix){
9369 var v = this.getStyle(attr);
9370 if(!v || v == "transparent" || v == "inherit") {
9371 return defaultValue;
9373 var color = typeof prefix == "undefined" ? "#" : prefix;
9374 if(v.substr(0, 4) == "rgb("){
9375 var rvs = v.slice(4, v.length -1).split(",");
9376 for(var i = 0; i < 3; i++){
9377 var h = parseInt(rvs[i]).toString(16);
9384 if(v.substr(0, 1) == "#"){
9386 for(var i = 1; i < 4; i++){
9387 var c = v.charAt(i);
9390 }else if(v.length == 7){
9391 color += v.substr(1);
9395 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9399 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9400 * gradient background, rounded corners and a 4-way shadow.
9401 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9402 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9403 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9404 * @return {Roo.Element} this
9406 boxWrap : function(cls){
9407 cls = cls || 'x-box';
9408 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9409 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9414 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9415 * @param {String} namespace The namespace in which to look for the attribute
9416 * @param {String} name The attribute name
9417 * @return {String} The attribute value
9419 getAttributeNS : Roo.isIE ? function(ns, name){
9421 var type = typeof d[ns+":"+name];
9422 if(type != 'undefined' && type != 'unknown'){
9423 return d[ns+":"+name];
9426 } : function(ns, name){
9428 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9432 var ep = El.prototype;
9435 * Appends an event handler (Shorthand for addListener)
9436 * @param {String} eventName The type of event to append
9437 * @param {Function} fn The method the event invokes
9438 * @param {Object} scope (optional) The scope (this object) of the fn
9439 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9442 ep.on = ep.addListener;
9444 ep.mon = ep.addListener;
9447 * Removes an event handler from this element (shorthand for removeListener)
9448 * @param {String} eventName the type of event to remove
9449 * @param {Function} fn the method the event invokes
9450 * @return {Roo.Element} this
9453 ep.un = ep.removeListener;
9456 * true to automatically adjust width and height settings for box-model issues (default to true)
9458 ep.autoBoxAdjust = true;
9461 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9464 El.addUnits = function(v, defaultUnit){
9465 if(v === "" || v == "auto"){
9468 if(v === undefined){
9471 if(typeof v == "number" || !El.unitPattern.test(v)){
9472 return v + (defaultUnit || 'px');
9477 // special markup used throughout Roo when box wrapping elements
9478 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>';
9480 * Visibility mode constant - Use visibility to hide element
9486 * Visibility mode constant - Use display to hide element
9492 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9493 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9494 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9506 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9507 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9508 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9509 * @return {Element} The Element object
9512 El.get = function(el){
9514 if(!el){ return null; }
9515 if(typeof el == "string"){ // element id
9516 if(!(elm = document.getElementById(el))){
9519 if(ex = El.cache[el]){
9522 ex = El.cache[el] = new El(elm);
9525 }else if(el.tagName){ // dom element
9529 if(ex = El.cache[id]){
9532 ex = El.cache[id] = new El(el);
9535 }else if(el instanceof El){
9537 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9538 // catch case where it hasn't been appended
9539 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9542 }else if(el.isComposite){
9544 }else if(el instanceof Array){
9545 return El.select(el);
9546 }else if(el == document){
9547 // create a bogus element object representing the document object
9549 var f = function(){};
9550 f.prototype = El.prototype;
9552 docEl.dom = document;
9560 El.uncache = function(el){
9561 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9563 delete El.cache[a[i].id || a[i]];
9569 // Garbage collection - uncache elements/purge listeners on orphaned elements
9570 // so we don't hold a reference and cause the browser to retain them
9571 El.garbageCollect = function(){
9572 if(!Roo.enableGarbageCollector){
9573 clearInterval(El.collectorThread);
9576 for(var eid in El.cache){
9577 var el = El.cache[eid], d = el.dom;
9578 // -------------------------------------------------------
9579 // Determining what is garbage:
9580 // -------------------------------------------------------
9582 // dom node is null, definitely garbage
9583 // -------------------------------------------------------
9585 // no parentNode == direct orphan, definitely garbage
9586 // -------------------------------------------------------
9587 // !d.offsetParent && !document.getElementById(eid)
9588 // display none elements have no offsetParent so we will
9589 // also try to look it up by it's id. However, check
9590 // offsetParent first so we don't do unneeded lookups.
9591 // This enables collection of elements that are not orphans
9592 // directly, but somewhere up the line they have an orphan
9594 // -------------------------------------------------------
9595 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9596 delete El.cache[eid];
9597 if(d && Roo.enableListenerCollection){
9603 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9607 El.Flyweight = function(dom){
9610 El.Flyweight.prototype = El.prototype;
9612 El._flyweights = {};
9614 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9615 * the dom node can be overwritten by other code.
9616 * @param {String/HTMLElement} el The dom node or id
9617 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9618 * prevent conflicts (e.g. internally Roo uses "_internal")
9620 * @return {Element} The shared Element object
9622 El.fly = function(el, named){
9623 named = named || '_global';
9624 el = Roo.getDom(el);
9628 if(!El._flyweights[named]){
9629 El._flyweights[named] = new El.Flyweight();
9631 El._flyweights[named].dom = el;
9632 return El._flyweights[named];
9636 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9637 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9638 * Shorthand of {@link Roo.Element#get}
9639 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9640 * @return {Element} The Element object
9646 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9647 * the dom node can be overwritten by other code.
9648 * Shorthand of {@link Roo.Element#fly}
9649 * @param {String/HTMLElement} el The dom node or id
9650 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9651 * prevent conflicts (e.g. internally Roo uses "_internal")
9653 * @return {Element} The shared Element object
9659 // speedy lookup for elements never to box adjust
9660 var noBoxAdjust = Roo.isStrict ? {
9663 input:1, select:1, textarea:1
9665 if(Roo.isIE || Roo.isGecko){
9666 noBoxAdjust['button'] = 1;
9670 Roo.EventManager.on(window, 'unload', function(){
9672 delete El._flyweights;
9680 Roo.Element.selectorFunction = Roo.DomQuery.select;
9683 Roo.Element.select = function(selector, unique, root){
9685 if(typeof selector == "string"){
9686 els = Roo.Element.selectorFunction(selector, root);
9687 }else if(selector.length !== undefined){
9690 throw "Invalid selector";
9692 if(unique === true){
9693 return new Roo.CompositeElement(els);
9695 return new Roo.CompositeElementLite(els);
9699 * Selects elements based on the passed CSS selector to enable working on them as 1.
9700 * @param {String/Array} selector The CSS selector or an array of elements
9701 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9702 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9703 * @return {CompositeElementLite/CompositeElement}
9707 Roo.select = Roo.Element.select;
9724 * Ext JS Library 1.1.1
9725 * Copyright(c) 2006-2007, Ext JS, LLC.
9727 * Originally Released Under LGPL - original licence link has changed is not relivant.
9730 * <script type="text/javascript">
9735 //Notifies Element that fx methods are available
9736 Roo.enableFx = true;
9740 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9741 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9742 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9743 * Element effects to work.</p><br/>
9745 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9746 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9747 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9748 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9749 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9750 * expected results and should be done with care.</p><br/>
9752 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9753 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9756 ----- -----------------------------
9757 tl The top left corner
9758 t The center of the top edge
9759 tr The top right corner
9760 l The center of the left edge
9761 r The center of the right edge
9762 bl The bottom left corner
9763 b The center of the bottom edge
9764 br The bottom right corner
9766 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9767 * below are common options that can be passed to any Fx method.</b>
9768 * @cfg {Function} callback A function called when the effect is finished
9769 * @cfg {Object} scope The scope of the effect function
9770 * @cfg {String} easing A valid Easing value for the effect
9771 * @cfg {String} afterCls A css class to apply after the effect
9772 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9773 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9774 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9775 * effects that end with the element being visually hidden, ignored otherwise)
9776 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9777 * a function which returns such a specification that will be applied to the Element after the effect finishes
9778 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9779 * @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
9780 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9784 * Slides the element into view. An anchor point can be optionally passed to set the point of
9785 * origin for the slide effect. This function automatically handles wrapping the element with
9786 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9789 // default: slide the element in from the top
9792 // custom: slide the element in from the right with a 2-second duration
9793 el.slideIn('r', { duration: 2 });
9795 // common config options shown with default values
9801 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9802 * @param {Object} options (optional) Object literal with any of the Fx config options
9803 * @return {Roo.Element} The Element
9805 slideIn : function(anchor, o){
9806 var el = this.getFxEl();
9809 el.queueFx(o, function(){
9811 anchor = anchor || "t";
9813 // fix display to visibility
9816 // restore values after effect
9817 var r = this.getFxRestore();
9818 var b = this.getBox();
9819 // fixed size for slide
9823 var wrap = this.fxWrap(r.pos, o, "hidden");
9825 var st = this.dom.style;
9826 st.visibility = "visible";
9827 st.position = "absolute";
9829 // clear out temp styles after slide and unwrap
9830 var after = function(){
9831 el.fxUnwrap(wrap, r.pos, o);
9833 st.height = r.height;
9836 // time to calc the positions
9837 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9839 switch(anchor.toLowerCase()){
9841 wrap.setSize(b.width, 0);
9842 st.left = st.bottom = "0";
9846 wrap.setSize(0, b.height);
9847 st.right = st.top = "0";
9851 wrap.setSize(0, b.height);
9853 st.left = st.top = "0";
9854 a = {width: bw, points: pt};
9857 wrap.setSize(b.width, 0);
9858 wrap.setY(b.bottom);
9859 st.left = st.top = "0";
9860 a = {height: bh, points: pt};
9864 st.right = st.bottom = "0";
9865 a = {width: bw, height: bh};
9869 wrap.setY(b.y+b.height);
9870 st.right = st.top = "0";
9871 a = {width: bw, height: bh, points: pt};
9875 wrap.setXY([b.right, b.bottom]);
9876 st.left = st.top = "0";
9877 a = {width: bw, height: bh, points: pt};
9881 wrap.setX(b.x+b.width);
9882 st.left = st.bottom = "0";
9883 a = {width: bw, height: bh, points: pt};
9886 this.dom.style.visibility = "visible";
9889 arguments.callee.anim = wrap.fxanim(a,
9899 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9900 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9901 * 'hidden') but block elements will still take up space in the document. The element must be removed
9902 * from the DOM using the 'remove' config option if desired. This function automatically handles
9903 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9906 // default: slide the element out to the top
9909 // custom: slide the element out to the right with a 2-second duration
9910 el.slideOut('r', { duration: 2 });
9912 // common config options shown with default values
9920 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9921 * @param {Object} options (optional) Object literal with any of the Fx config options
9922 * @return {Roo.Element} The Element
9924 slideOut : function(anchor, o){
9925 var el = this.getFxEl();
9928 el.queueFx(o, function(){
9930 anchor = anchor || "t";
9932 // restore values after effect
9933 var r = this.getFxRestore();
9935 var b = this.getBox();
9936 // fixed size for slide
9940 var wrap = this.fxWrap(r.pos, o, "visible");
9942 var st = this.dom.style;
9943 st.visibility = "visible";
9944 st.position = "absolute";
9948 var after = function(){
9950 el.setDisplayed(false);
9955 el.fxUnwrap(wrap, r.pos, o);
9958 st.height = r.height;
9963 var a, zero = {to: 0};
9964 switch(anchor.toLowerCase()){
9966 st.left = st.bottom = "0";
9970 st.right = st.top = "0";
9974 st.left = st.top = "0";
9975 a = {width: zero, points: {to:[b.right, b.y]}};
9978 st.left = st.top = "0";
9979 a = {height: zero, points: {to:[b.x, b.bottom]}};
9982 st.right = st.bottom = "0";
9983 a = {width: zero, height: zero};
9986 st.right = st.top = "0";
9987 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9990 st.left = st.top = "0";
9991 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9994 st.left = st.bottom = "0";
9995 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9999 arguments.callee.anim = wrap.fxanim(a,
10009 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10010 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10011 * The element must be removed from the DOM using the 'remove' config option if desired.
10017 // common config options shown with default values
10025 * @param {Object} options (optional) Object literal with any of the Fx config options
10026 * @return {Roo.Element} The Element
10028 puff : function(o){
10029 var el = this.getFxEl();
10032 el.queueFx(o, function(){
10033 this.clearOpacity();
10036 // restore values after effect
10037 var r = this.getFxRestore();
10038 var st = this.dom.style;
10040 var after = function(){
10042 el.setDisplayed(false);
10049 el.setPositioning(r.pos);
10050 st.width = r.width;
10051 st.height = r.height;
10056 var width = this.getWidth();
10057 var height = this.getHeight();
10059 arguments.callee.anim = this.fxanim({
10060 width : {to: this.adjustWidth(width * 2)},
10061 height : {to: this.adjustHeight(height * 2)},
10062 points : {by: [-(width * .5), -(height * .5)]},
10064 fontSize: {to:200, unit: "%"}
10075 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10076 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10077 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10083 // all config options shown with default values
10091 * @param {Object} options (optional) Object literal with any of the Fx config options
10092 * @return {Roo.Element} The Element
10094 switchOff : function(o){
10095 var el = this.getFxEl();
10098 el.queueFx(o, function(){
10099 this.clearOpacity();
10102 // restore values after effect
10103 var r = this.getFxRestore();
10104 var st = this.dom.style;
10106 var after = function(){
10108 el.setDisplayed(false);
10114 el.setPositioning(r.pos);
10115 st.width = r.width;
10116 st.height = r.height;
10121 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10122 this.clearOpacity();
10126 points:{by:[0, this.getHeight() * .5]}
10127 }, o, 'motion', 0.3, 'easeIn', after);
10128 }).defer(100, this);
10135 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10136 * changed using the "attr" config option) and then fading back to the original color. If no original
10137 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10140 // default: highlight background to yellow
10143 // custom: highlight foreground text to blue for 2 seconds
10144 el.highlight("0000ff", { attr: 'color', duration: 2 });
10146 // common config options shown with default values
10147 el.highlight("ffff9c", {
10148 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10149 endColor: (current color) or "ffffff",
10154 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10155 * @param {Object} options (optional) Object literal with any of the Fx config options
10156 * @return {Roo.Element} The Element
10158 highlight : function(color, o){
10159 var el = this.getFxEl();
10162 el.queueFx(o, function(){
10163 color = color || "ffff9c";
10164 attr = o.attr || "backgroundColor";
10166 this.clearOpacity();
10169 var origColor = this.getColor(attr);
10170 var restoreColor = this.dom.style[attr];
10171 endColor = (o.endColor || origColor) || "ffffff";
10173 var after = function(){
10174 el.dom.style[attr] = restoreColor;
10179 a[attr] = {from: color, to: endColor};
10180 arguments.callee.anim = this.fxanim(a,
10190 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10193 // default: a single light blue ripple
10196 // custom: 3 red ripples lasting 3 seconds total
10197 el.frame("ff0000", 3, { duration: 3 });
10199 // common config options shown with default values
10200 el.frame("C3DAF9", 1, {
10201 duration: 1 //duration of entire animation (not each individual ripple)
10202 // Note: Easing is not configurable and will be ignored if included
10205 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10206 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10207 * @param {Object} options (optional) Object literal with any of the Fx config options
10208 * @return {Roo.Element} The Element
10210 frame : function(color, count, o){
10211 var el = this.getFxEl();
10214 el.queueFx(o, function(){
10215 color = color || "#C3DAF9";
10216 if(color.length == 6){
10217 color = "#" + color;
10219 count = count || 1;
10220 duration = o.duration || 1;
10223 var b = this.getBox();
10224 var animFn = function(){
10225 var proxy = this.createProxy({
10228 visbility:"hidden",
10229 position:"absolute",
10230 "z-index":"35000", // yee haw
10231 border:"0px solid " + color
10234 var scale = Roo.isBorderBox ? 2 : 1;
10236 top:{from:b.y, to:b.y - 20},
10237 left:{from:b.x, to:b.x - 20},
10238 borderWidth:{from:0, to:10},
10239 opacity:{from:1, to:0},
10240 height:{from:b.height, to:(b.height + (20*scale))},
10241 width:{from:b.width, to:(b.width + (20*scale))}
10242 }, duration, function(){
10246 animFn.defer((duration/2)*1000, this);
10257 * Creates a pause before any subsequent queued effects begin. If there are
10258 * no effects queued after the pause it will have no effect.
10263 * @param {Number} seconds The length of time to pause (in seconds)
10264 * @return {Roo.Element} The Element
10266 pause : function(seconds){
10267 var el = this.getFxEl();
10270 el.queueFx(o, function(){
10271 setTimeout(function(){
10273 }, seconds * 1000);
10279 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10280 * using the "endOpacity" config option.
10283 // default: fade in from opacity 0 to 100%
10286 // custom: fade in from opacity 0 to 75% over 2 seconds
10287 el.fadeIn({ endOpacity: .75, duration: 2});
10289 // common config options shown with default values
10291 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10296 * @param {Object} options (optional) Object literal with any of the Fx config options
10297 * @return {Roo.Element} The Element
10299 fadeIn : function(o){
10300 var el = this.getFxEl();
10302 el.queueFx(o, function(){
10303 this.setOpacity(0);
10305 this.dom.style.visibility = 'visible';
10306 var to = o.endOpacity || 1;
10307 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10308 o, null, .5, "easeOut", function(){
10310 this.clearOpacity();
10319 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10320 * using the "endOpacity" config option.
10323 // default: fade out from the element's current opacity to 0
10326 // custom: fade out from the element's current opacity to 25% over 2 seconds
10327 el.fadeOut({ endOpacity: .25, duration: 2});
10329 // common config options shown with default values
10331 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10338 * @param {Object} options (optional) Object literal with any of the Fx config options
10339 * @return {Roo.Element} The Element
10341 fadeOut : function(o){
10342 var el = this.getFxEl();
10344 el.queueFx(o, function(){
10345 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10346 o, null, .5, "easeOut", function(){
10347 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10348 this.dom.style.display = "none";
10350 this.dom.style.visibility = "hidden";
10352 this.clearOpacity();
10360 * Animates the transition of an element's dimensions from a starting height/width
10361 * to an ending height/width.
10364 // change height and width to 100x100 pixels
10365 el.scale(100, 100);
10367 // common config options shown with default values. The height and width will default to
10368 // the element's existing values if passed as null.
10371 [element's height], {
10376 * @param {Number} width The new width (pass undefined to keep the original width)
10377 * @param {Number} height The new height (pass undefined to keep the original height)
10378 * @param {Object} options (optional) Object literal with any of the Fx config options
10379 * @return {Roo.Element} The Element
10381 scale : function(w, h, o){
10382 this.shift(Roo.apply({}, o, {
10390 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10391 * Any of these properties not specified in the config object will not be changed. This effect
10392 * requires that at least one new dimension, position or opacity setting must be passed in on
10393 * the config object in order for the function to have any effect.
10396 // slide the element horizontally to x position 200 while changing the height and opacity
10397 el.shift({ x: 200, height: 50, opacity: .8 });
10399 // common config options shown with default values.
10401 width: [element's width],
10402 height: [element's height],
10403 x: [element's x position],
10404 y: [element's y position],
10405 opacity: [element's opacity],
10410 * @param {Object} options Object literal with any of the Fx config options
10411 * @return {Roo.Element} The Element
10413 shift : function(o){
10414 var el = this.getFxEl();
10416 el.queueFx(o, function(){
10417 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10418 if(w !== undefined){
10419 a.width = {to: this.adjustWidth(w)};
10421 if(h !== undefined){
10422 a.height = {to: this.adjustHeight(h)};
10424 if(x !== undefined || y !== undefined){
10426 x !== undefined ? x : this.getX(),
10427 y !== undefined ? y : this.getY()
10430 if(op !== undefined){
10431 a.opacity = {to: op};
10433 if(o.xy !== undefined){
10434 a.points = {to: o.xy};
10436 arguments.callee.anim = this.fxanim(a,
10437 o, 'motion', .35, "easeOut", function(){
10445 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10446 * ending point of the effect.
10449 // default: slide the element downward while fading out
10452 // custom: slide the element out to the right with a 2-second duration
10453 el.ghost('r', { duration: 2 });
10455 // common config options shown with default values
10463 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10464 * @param {Object} options (optional) Object literal with any of the Fx config options
10465 * @return {Roo.Element} The Element
10467 ghost : function(anchor, o){
10468 var el = this.getFxEl();
10471 el.queueFx(o, function(){
10472 anchor = anchor || "b";
10474 // restore values after effect
10475 var r = this.getFxRestore();
10476 var w = this.getWidth(),
10477 h = this.getHeight();
10479 var st = this.dom.style;
10481 var after = function(){
10483 el.setDisplayed(false);
10489 el.setPositioning(r.pos);
10490 st.width = r.width;
10491 st.height = r.height;
10496 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10497 switch(anchor.toLowerCase()){
10524 arguments.callee.anim = this.fxanim(a,
10534 * Ensures that all effects queued after syncFx is called on the element are
10535 * run concurrently. This is the opposite of {@link #sequenceFx}.
10536 * @return {Roo.Element} The Element
10538 syncFx : function(){
10539 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10548 * Ensures that all effects queued after sequenceFx is called on the element are
10549 * run in sequence. This is the opposite of {@link #syncFx}.
10550 * @return {Roo.Element} The Element
10552 sequenceFx : function(){
10553 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10555 concurrent : false,
10562 nextFx : function(){
10563 var ef = this.fxQueue[0];
10570 * Returns true if the element has any effects actively running or queued, else returns false.
10571 * @return {Boolean} True if element has active effects, else false
10573 hasActiveFx : function(){
10574 return this.fxQueue && this.fxQueue[0];
10578 * Stops any running effects and clears the element's internal effects queue if it contains
10579 * any additional effects that haven't started yet.
10580 * @return {Roo.Element} The Element
10582 stopFx : function(){
10583 if(this.hasActiveFx()){
10584 var cur = this.fxQueue[0];
10585 if(cur && cur.anim && cur.anim.isAnimated()){
10586 this.fxQueue = [cur]; // clear out others
10587 cur.anim.stop(true);
10594 beforeFx : function(o){
10595 if(this.hasActiveFx() && !o.concurrent){
10606 * Returns true if the element is currently blocking so that no other effect can be queued
10607 * until this effect is finished, else returns false if blocking is not set. This is commonly
10608 * used to ensure that an effect initiated by a user action runs to completion prior to the
10609 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10610 * @return {Boolean} True if blocking, else false
10612 hasFxBlock : function(){
10613 var q = this.fxQueue;
10614 return q && q[0] && q[0].block;
10618 queueFx : function(o, fn){
10622 if(!this.hasFxBlock()){
10623 Roo.applyIf(o, this.fxDefaults);
10625 var run = this.beforeFx(o);
10626 fn.block = o.block;
10627 this.fxQueue.push(fn);
10639 fxWrap : function(pos, o, vis){
10641 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10644 wrapXY = this.getXY();
10646 var div = document.createElement("div");
10647 div.style.visibility = vis;
10648 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10649 wrap.setPositioning(pos);
10650 if(wrap.getStyle("position") == "static"){
10651 wrap.position("relative");
10653 this.clearPositioning('auto');
10655 wrap.dom.appendChild(this.dom);
10657 wrap.setXY(wrapXY);
10664 fxUnwrap : function(wrap, pos, o){
10665 this.clearPositioning();
10666 this.setPositioning(pos);
10668 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10674 getFxRestore : function(){
10675 var st = this.dom.style;
10676 return {pos: this.getPositioning(), width: st.width, height : st.height};
10680 afterFx : function(o){
10682 this.applyStyles(o.afterStyle);
10685 this.addClass(o.afterCls);
10687 if(o.remove === true){
10690 Roo.callback(o.callback, o.scope, [this]);
10692 this.fxQueue.shift();
10698 getFxEl : function(){ // support for composite element fx
10699 return Roo.get(this.dom);
10703 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10704 animType = animType || 'run';
10706 var anim = Roo.lib.Anim[animType](
10708 (opt.duration || defaultDur) || .35,
10709 (opt.easing || defaultEase) || 'easeOut',
10711 Roo.callback(cb, this);
10720 // backwords compat
10721 Roo.Fx.resize = Roo.Fx.scale;
10723 //When included, Roo.Fx is automatically applied to Element so that all basic
10724 //effects are available directly via the Element API
10725 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10727 * Ext JS Library 1.1.1
10728 * Copyright(c) 2006-2007, Ext JS, LLC.
10730 * Originally Released Under LGPL - original licence link has changed is not relivant.
10733 * <script type="text/javascript">
10738 * @class Roo.CompositeElement
10739 * Standard composite class. Creates a Roo.Element for every element in the collection.
10741 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10742 * actions will be performed on all the elements in this collection.</b>
10744 * All methods return <i>this</i> and can be chained.
10746 var els = Roo.select("#some-el div.some-class", true);
10747 // or select directly from an existing element
10748 var el = Roo.get('some-el');
10749 el.select('div.some-class', true);
10751 els.setWidth(100); // all elements become 100 width
10752 els.hide(true); // all elements fade out and hide
10754 els.setWidth(100).hide(true);
10757 Roo.CompositeElement = function(els){
10758 this.elements = [];
10759 this.addElements(els);
10761 Roo.CompositeElement.prototype = {
10763 addElements : function(els){
10764 if(!els) return this;
10765 if(typeof els == "string"){
10766 els = Roo.Element.selectorFunction(els);
10768 var yels = this.elements;
10769 var index = yels.length-1;
10770 for(var i = 0, len = els.length; i < len; i++) {
10771 yels[++index] = Roo.get(els[i]);
10777 * Clears this composite and adds the elements returned by the passed selector.
10778 * @param {String/Array} els A string CSS selector, an array of elements or an element
10779 * @return {CompositeElement} this
10781 fill : function(els){
10782 this.elements = [];
10788 * Filters this composite to only elements that match the passed selector.
10789 * @param {String} selector A string CSS selector
10790 * @return {CompositeElement} this
10792 filter : function(selector){
10794 this.each(function(el){
10795 if(el.is(selector)){
10796 els[els.length] = el.dom;
10803 invoke : function(fn, args){
10804 var els = this.elements;
10805 for(var i = 0, len = els.length; i < len; i++) {
10806 Roo.Element.prototype[fn].apply(els[i], args);
10811 * Adds elements to this composite.
10812 * @param {String/Array} els A string CSS selector, an array of elements or an element
10813 * @return {CompositeElement} this
10815 add : function(els){
10816 if(typeof els == "string"){
10817 this.addElements(Roo.Element.selectorFunction(els));
10818 }else if(els.length !== undefined){
10819 this.addElements(els);
10821 this.addElements([els]);
10826 * Calls the passed function passing (el, this, index) for each element in this composite.
10827 * @param {Function} fn The function to call
10828 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10829 * @return {CompositeElement} this
10831 each : function(fn, scope){
10832 var els = this.elements;
10833 for(var i = 0, len = els.length; i < len; i++){
10834 if(fn.call(scope || els[i], els[i], this, i) === false) {
10842 * Returns the Element object at the specified index
10843 * @param {Number} index
10844 * @return {Roo.Element}
10846 item : function(index){
10847 return this.elements[index] || null;
10851 * Returns the first Element
10852 * @return {Roo.Element}
10854 first : function(){
10855 return this.item(0);
10859 * Returns the last Element
10860 * @return {Roo.Element}
10863 return this.item(this.elements.length-1);
10867 * Returns the number of elements in this composite
10870 getCount : function(){
10871 return this.elements.length;
10875 * Returns true if this composite contains the passed element
10878 contains : function(el){
10879 return this.indexOf(el) !== -1;
10883 * Returns true if this composite contains the passed element
10886 indexOf : function(el){
10887 return this.elements.indexOf(Roo.get(el));
10892 * Removes the specified element(s).
10893 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10894 * or an array of any of those.
10895 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10896 * @return {CompositeElement} this
10898 removeElement : function(el, removeDom){
10899 if(el instanceof Array){
10900 for(var i = 0, len = el.length; i < len; i++){
10901 this.removeElement(el[i]);
10905 var index = typeof el == 'number' ? el : this.indexOf(el);
10908 var d = this.elements[index];
10912 d.parentNode.removeChild(d);
10915 this.elements.splice(index, 1);
10921 * Replaces the specified element with the passed element.
10922 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10924 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10925 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10926 * @return {CompositeElement} this
10928 replaceElement : function(el, replacement, domReplace){
10929 var index = typeof el == 'number' ? el : this.indexOf(el);
10932 this.elements[index].replaceWith(replacement);
10934 this.elements.splice(index, 1, Roo.get(replacement))
10941 * Removes all elements.
10943 clear : function(){
10944 this.elements = [];
10948 Roo.CompositeElement.createCall = function(proto, fnName){
10949 if(!proto[fnName]){
10950 proto[fnName] = function(){
10951 return this.invoke(fnName, arguments);
10955 for(var fnName in Roo.Element.prototype){
10956 if(typeof Roo.Element.prototype[fnName] == "function"){
10957 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10963 * Ext JS Library 1.1.1
10964 * Copyright(c) 2006-2007, Ext JS, LLC.
10966 * Originally Released Under LGPL - original licence link has changed is not relivant.
10969 * <script type="text/javascript">
10973 * @class Roo.CompositeElementLite
10974 * @extends Roo.CompositeElement
10975 * Flyweight composite class. Reuses the same Roo.Element for element operations.
10977 var els = Roo.select("#some-el div.some-class");
10978 // or select directly from an existing element
10979 var el = Roo.get('some-el');
10980 el.select('div.some-class');
10982 els.setWidth(100); // all elements become 100 width
10983 els.hide(true); // all elements fade out and hide
10985 els.setWidth(100).hide(true);
10986 </code></pre><br><br>
10987 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10988 * actions will be performed on all the elements in this collection.</b>
10990 Roo.CompositeElementLite = function(els){
10991 Roo.CompositeElementLite.superclass.constructor.call(this, els);
10992 this.el = new Roo.Element.Flyweight();
10994 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10995 addElements : function(els){
10997 if(els instanceof Array){
10998 this.elements = this.elements.concat(els);
11000 var yels = this.elements;
11001 var index = yels.length-1;
11002 for(var i = 0, len = els.length; i < len; i++) {
11003 yels[++index] = els[i];
11009 invoke : function(fn, args){
11010 var els = this.elements;
11012 for(var i = 0, len = els.length; i < len; i++) {
11014 Roo.Element.prototype[fn].apply(el, args);
11019 * Returns a flyweight Element of the dom element object at the specified index
11020 * @param {Number} index
11021 * @return {Roo.Element}
11023 item : function(index){
11024 if(!this.elements[index]){
11027 this.el.dom = this.elements[index];
11031 // fixes scope with flyweight
11032 addListener : function(eventName, handler, scope, opt){
11033 var els = this.elements;
11034 for(var i = 0, len = els.length; i < len; i++) {
11035 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11041 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11042 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11043 * a reference to the dom node, use el.dom.</b>
11044 * @param {Function} fn The function to call
11045 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11046 * @return {CompositeElement} this
11048 each : function(fn, scope){
11049 var els = this.elements;
11051 for(var i = 0, len = els.length; i < len; i++){
11053 if(fn.call(scope || el, el, this, i) === false){
11060 indexOf : function(el){
11061 return this.elements.indexOf(Roo.getDom(el));
11064 replaceElement : function(el, replacement, domReplace){
11065 var index = typeof el == 'number' ? el : this.indexOf(el);
11067 replacement = Roo.getDom(replacement);
11069 var d = this.elements[index];
11070 d.parentNode.insertBefore(replacement, d);
11071 d.parentNode.removeChild(d);
11073 this.elements.splice(index, 1, replacement);
11078 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11082 * Ext JS Library 1.1.1
11083 * Copyright(c) 2006-2007, Ext JS, LLC.
11085 * Originally Released Under LGPL - original licence link has changed is not relivant.
11088 * <script type="text/javascript">
11094 * @class Roo.data.Connection
11095 * @extends Roo.util.Observable
11096 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11097 * either to a configured URL, or to a URL specified at request time.<br><br>
11099 * Requests made by this class are asynchronous, and will return immediately. No data from
11100 * the server will be available to the statement immediately following the {@link #request} call.
11101 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11103 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11104 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11105 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11106 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11107 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11108 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11109 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11110 * standard DOM methods.
11112 * @param {Object} config a configuration object.
11114 Roo.data.Connection = function(config){
11115 Roo.apply(this, config);
11118 * @event beforerequest
11119 * Fires before a network request is made to retrieve a data object.
11120 * @param {Connection} conn This Connection object.
11121 * @param {Object} options The options config object passed to the {@link #request} method.
11123 "beforerequest" : true,
11125 * @event requestcomplete
11126 * Fires if the request was successfully completed.
11127 * @param {Connection} conn This Connection object.
11128 * @param {Object} response The XHR object containing the response data.
11129 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11130 * @param {Object} options The options config object passed to the {@link #request} method.
11132 "requestcomplete" : true,
11134 * @event requestexception
11135 * Fires if an error HTTP status was returned from the server.
11136 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11137 * @param {Connection} conn This Connection object.
11138 * @param {Object} response The XHR object containing the response data.
11139 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11140 * @param {Object} options The options config object passed to the {@link #request} method.
11142 "requestexception" : true
11144 Roo.data.Connection.superclass.constructor.call(this);
11147 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11149 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11152 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11153 * extra parameters to each request made by this object. (defaults to undefined)
11156 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11157 * to each request made by this object. (defaults to undefined)
11160 * @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)
11163 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11167 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11173 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11176 disableCaching: true,
11179 * Sends an HTTP request to a remote server.
11180 * @param {Object} options An object which may contain the following properties:<ul>
11181 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11182 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11183 * request, a url encoded string or a function to call to get either.</li>
11184 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11185 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11186 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11187 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11188 * <li>options {Object} The parameter to the request call.</li>
11189 * <li>success {Boolean} True if the request succeeded.</li>
11190 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11192 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11193 * The callback is passed the following parameters:<ul>
11194 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11195 * <li>options {Object} The parameter to the request call.</li>
11197 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11198 * The callback is passed the following parameters:<ul>
11199 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11200 * <li>options {Object} The parameter to the request call.</li>
11202 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11203 * for the callback function. Defaults to the browser window.</li>
11204 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11205 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11206 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11207 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11208 * params for the post data. Any params will be appended to the URL.</li>
11209 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11211 * @return {Number} transactionId
11213 request : function(o){
11214 if(this.fireEvent("beforerequest", this, o) !== false){
11217 if(typeof p == "function"){
11218 p = p.call(o.scope||window, o);
11220 if(typeof p == "object"){
11221 p = Roo.urlEncode(o.params);
11223 if(this.extraParams){
11224 var extras = Roo.urlEncode(this.extraParams);
11225 p = p ? (p + '&' + extras) : extras;
11228 var url = o.url || this.url;
11229 if(typeof url == 'function'){
11230 url = url.call(o.scope||window, o);
11234 var form = Roo.getDom(o.form);
11235 url = url || form.action;
11237 var enctype = form.getAttribute("enctype");
11238 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11239 return this.doFormUpload(o, p, url);
11241 var f = Roo.lib.Ajax.serializeForm(form);
11242 p = p ? (p + '&' + f) : f;
11245 var hs = o.headers;
11246 if(this.defaultHeaders){
11247 hs = Roo.apply(hs || {}, this.defaultHeaders);
11254 success: this.handleResponse,
11255 failure: this.handleFailure,
11257 argument: {options: o},
11258 timeout : this.timeout
11261 var method = o.method||this.method||(p ? "POST" : "GET");
11263 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11264 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11267 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11271 }else if(this.autoAbort !== false){
11275 if((method == 'GET' && p) || o.xmlData){
11276 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11279 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11280 return this.transId;
11282 Roo.callback(o.callback, o.scope, [o, null, null]);
11288 * Determine whether this object has a request outstanding.
11289 * @param {Number} transactionId (Optional) defaults to the last transaction
11290 * @return {Boolean} True if there is an outstanding request.
11292 isLoading : function(transId){
11294 return Roo.lib.Ajax.isCallInProgress(transId);
11296 return this.transId ? true : false;
11301 * Aborts any outstanding request.
11302 * @param {Number} transactionId (Optional) defaults to the last transaction
11304 abort : function(transId){
11305 if(transId || this.isLoading()){
11306 Roo.lib.Ajax.abort(transId || this.transId);
11311 handleResponse : function(response){
11312 this.transId = false;
11313 var options = response.argument.options;
11314 response.argument = options ? options.argument : null;
11315 this.fireEvent("requestcomplete", this, response, options);
11316 Roo.callback(options.success, options.scope, [response, options]);
11317 Roo.callback(options.callback, options.scope, [options, true, response]);
11321 handleFailure : function(response, e){
11322 this.transId = false;
11323 var options = response.argument.options;
11324 response.argument = options ? options.argument : null;
11325 this.fireEvent("requestexception", this, response, options, e);
11326 Roo.callback(options.failure, options.scope, [response, options]);
11327 Roo.callback(options.callback, options.scope, [options, false, response]);
11331 doFormUpload : function(o, ps, url){
11333 var frame = document.createElement('iframe');
11336 frame.className = 'x-hidden';
11338 frame.src = Roo.SSL_SECURE_URL;
11340 document.body.appendChild(frame);
11343 document.frames[id].name = id;
11346 var form = Roo.getDom(o.form);
11348 form.method = 'POST';
11349 form.enctype = form.encoding = 'multipart/form-data';
11355 if(ps){ // add dynamic params
11357 ps = Roo.urlDecode(ps, false);
11359 if(ps.hasOwnProperty(k)){
11360 hd = document.createElement('input');
11361 hd.type = 'hidden';
11364 form.appendChild(hd);
11371 var r = { // bogus response object
11376 r.argument = o ? o.argument : null;
11381 doc = frame.contentWindow.document;
11383 doc = (frame.contentDocument || window.frames[id].document);
11385 if(doc && doc.body){
11386 r.responseText = doc.body.innerHTML;
11388 if(doc && doc.XMLDocument){
11389 r.responseXML = doc.XMLDocument;
11391 r.responseXML = doc;
11398 Roo.EventManager.removeListener(frame, 'load', cb, this);
11400 this.fireEvent("requestcomplete", this, r, o);
11401 Roo.callback(o.success, o.scope, [r, o]);
11402 Roo.callback(o.callback, o.scope, [o, true, r]);
11404 setTimeout(function(){document.body.removeChild(frame);}, 100);
11407 Roo.EventManager.on(frame, 'load', cb, this);
11410 if(hiddens){ // remove dynamic params
11411 for(var i = 0, len = hiddens.length; i < len; i++){
11412 form.removeChild(hiddens[i]);
11420 * @extends Roo.data.Connection
11421 * Global Ajax request class.
11425 Roo.Ajax = new Roo.data.Connection({
11428 * @cfg {String} url @hide
11431 * @cfg {Object} extraParams @hide
11434 * @cfg {Object} defaultHeaders @hide
11437 * @cfg {String} method (Optional) @hide
11440 * @cfg {Number} timeout (Optional) @hide
11443 * @cfg {Boolean} autoAbort (Optional) @hide
11447 * @cfg {Boolean} disableCaching (Optional) @hide
11451 * @property disableCaching
11452 * True to add a unique cache-buster param to GET requests. (defaults to true)
11457 * The default URL to be used for requests to the server. (defaults to undefined)
11461 * @property extraParams
11462 * An object containing properties which are used as
11463 * extra parameters to each request made by this object. (defaults to undefined)
11467 * @property defaultHeaders
11468 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11473 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11477 * @property timeout
11478 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11483 * @property autoAbort
11484 * Whether a new request should abort any pending requests. (defaults to false)
11490 * Serialize the passed form into a url encoded string
11491 * @param {String/HTMLElement} form
11494 serializeForm : function(form){
11495 return Roo.lib.Ajax.serializeForm(form);
11499 * Ext JS Library 1.1.1
11500 * Copyright(c) 2006-2007, Ext JS, LLC.
11502 * Originally Released Under LGPL - original licence link has changed is not relivant.
11505 * <script type="text/javascript">
11510 * @extends Roo.data.Connection
11511 * Global Ajax request class.
11513 * @instanceOf Roo.data.Connection
11515 Roo.Ajax = new Roo.data.Connection({
11524 * @cfg {String} url @hide
11527 * @cfg {Object} extraParams @hide
11530 * @cfg {Object} defaultHeaders @hide
11533 * @cfg {String} method (Optional) @hide
11536 * @cfg {Number} timeout (Optional) @hide
11539 * @cfg {Boolean} autoAbort (Optional) @hide
11543 * @cfg {Boolean} disableCaching (Optional) @hide
11547 * @property disableCaching
11548 * True to add a unique cache-buster param to GET requests. (defaults to true)
11553 * The default URL to be used for requests to the server. (defaults to undefined)
11557 * @property extraParams
11558 * An object containing properties which are used as
11559 * extra parameters to each request made by this object. (defaults to undefined)
11563 * @property defaultHeaders
11564 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11569 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11573 * @property timeout
11574 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11579 * @property autoAbort
11580 * Whether a new request should abort any pending requests. (defaults to false)
11586 * Serialize the passed form into a url encoded string
11587 * @param {String/HTMLElement} form
11590 serializeForm : function(form){
11591 return Roo.lib.Ajax.serializeForm(form);
11595 * Ext JS Library 1.1.1
11596 * Copyright(c) 2006-2007, Ext JS, LLC.
11598 * Originally Released Under LGPL - original licence link has changed is not relivant.
11601 * <script type="text/javascript">
11606 * @class Roo.UpdateManager
11607 * @extends Roo.util.Observable
11608 * Provides AJAX-style update for Element object.<br><br>
11611 * // Get it from a Roo.Element object
11612 * var el = Roo.get("foo");
11613 * var mgr = el.getUpdateManager();
11614 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11616 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11618 * // or directly (returns the same UpdateManager instance)
11619 * var mgr = new Roo.UpdateManager("myElementId");
11620 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11621 * mgr.on("update", myFcnNeedsToKnow);
11623 // short handed call directly from the element object
11624 Roo.get("foo").load({
11628 text: "Loading Foo..."
11632 * Create new UpdateManager directly.
11633 * @param {String/HTMLElement/Roo.Element} el The element to update
11634 * @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).
11636 Roo.UpdateManager = function(el, forceNew){
11638 if(!forceNew && el.updateManager){
11639 return el.updateManager;
11642 * The Element object
11643 * @type Roo.Element
11647 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11650 this.defaultUrl = null;
11654 * @event beforeupdate
11655 * Fired before an update is made, return false from your handler and the update is cancelled.
11656 * @param {Roo.Element} el
11657 * @param {String/Object/Function} url
11658 * @param {String/Object} params
11660 "beforeupdate": true,
11663 * Fired after successful update is made.
11664 * @param {Roo.Element} el
11665 * @param {Object} oResponseObject The response Object
11670 * Fired on update failure.
11671 * @param {Roo.Element} el
11672 * @param {Object} oResponseObject The response Object
11676 var d = Roo.UpdateManager.defaults;
11678 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11681 this.sslBlankUrl = d.sslBlankUrl;
11683 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11686 this.disableCaching = d.disableCaching;
11688 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11691 this.indicatorText = d.indicatorText;
11693 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11696 this.showLoadIndicator = d.showLoadIndicator;
11698 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11701 this.timeout = d.timeout;
11704 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11707 this.loadScripts = d.loadScripts;
11710 * Transaction object of current executing transaction
11712 this.transaction = null;
11717 this.autoRefreshProcId = null;
11719 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11722 this.refreshDelegate = this.refresh.createDelegate(this);
11724 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11727 this.updateDelegate = this.update.createDelegate(this);
11729 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11732 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11736 this.successDelegate = this.processSuccess.createDelegate(this);
11740 this.failureDelegate = this.processFailure.createDelegate(this);
11742 if(!this.renderer){
11744 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11746 this.renderer = new Roo.UpdateManager.BasicRenderer();
11749 Roo.UpdateManager.superclass.constructor.call(this);
11752 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11754 * Get the Element this UpdateManager is bound to
11755 * @return {Roo.Element} The element
11757 getEl : function(){
11761 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11762 * @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:
11765 url: "your-url.php",<br/>
11766 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11767 callback: yourFunction,<br/>
11768 scope: yourObject, //(optional scope) <br/>
11769 discardUrl: false, <br/>
11770 nocache: false,<br/>
11771 text: "Loading...",<br/>
11773 scripts: false<br/>
11776 * The only required property is url. The optional properties nocache, text and scripts
11777 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11778 * @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}
11779 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11780 * @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.
11782 update : function(url, params, callback, discardUrl){
11783 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11784 var method = this.method, cfg;
11785 if(typeof url == "object"){ // must be config object
11788 params = params || cfg.params;
11789 callback = callback || cfg.callback;
11790 discardUrl = discardUrl || cfg.discardUrl;
11791 if(callback && cfg.scope){
11792 callback = callback.createDelegate(cfg.scope);
11794 if(typeof cfg.method != "undefined"){method = cfg.method;};
11795 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11796 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11797 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11798 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11800 this.showLoading();
11802 this.defaultUrl = url;
11804 if(typeof url == "function"){
11805 url = url.call(this);
11808 method = method || (params ? "POST" : "GET");
11809 if(method == "GET"){
11810 url = this.prepareUrl(url);
11813 var o = Roo.apply(cfg ||{}, {
11816 success: this.successDelegate,
11817 failure: this.failureDelegate,
11818 callback: undefined,
11819 timeout: (this.timeout*1000),
11820 argument: {"url": url, "form": null, "callback": callback, "params": params}
11823 this.transaction = Roo.Ajax.request(o);
11828 * 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.
11829 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11830 * @param {String/HTMLElement} form The form Id or form element
11831 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11832 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11833 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11835 formUpdate : function(form, url, reset, callback){
11836 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11837 if(typeof url == "function"){
11838 url = url.call(this);
11840 form = Roo.getDom(form);
11841 this.transaction = Roo.Ajax.request({
11844 success: this.successDelegate,
11845 failure: this.failureDelegate,
11846 timeout: (this.timeout*1000),
11847 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11849 this.showLoading.defer(1, this);
11854 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11855 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11857 refresh : function(callback){
11858 if(this.defaultUrl == null){
11861 this.update(this.defaultUrl, null, callback, true);
11865 * Set this element to auto refresh.
11866 * @param {Number} interval How often to update (in seconds).
11867 * @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)
11868 * @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}
11869 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11870 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11872 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11874 this.update(url || this.defaultUrl, params, callback, true);
11876 if(this.autoRefreshProcId){
11877 clearInterval(this.autoRefreshProcId);
11879 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11883 * Stop auto refresh on this element.
11885 stopAutoRefresh : function(){
11886 if(this.autoRefreshProcId){
11887 clearInterval(this.autoRefreshProcId);
11888 delete this.autoRefreshProcId;
11892 isAutoRefreshing : function(){
11893 return this.autoRefreshProcId ? true : false;
11896 * Called to update the element to "Loading" state. Override to perform custom action.
11898 showLoading : function(){
11899 if(this.showLoadIndicator){
11900 this.el.update(this.indicatorText);
11905 * Adds unique parameter to query string if disableCaching = true
11908 prepareUrl : function(url){
11909 if(this.disableCaching){
11910 var append = "_dc=" + (new Date().getTime());
11911 if(url.indexOf("?") !== -1){
11912 url += "&" + append;
11914 url += "?" + append;
11923 processSuccess : function(response){
11924 this.transaction = null;
11925 if(response.argument.form && response.argument.reset){
11926 try{ // put in try/catch since some older FF releases had problems with this
11927 response.argument.form.reset();
11930 if(this.loadScripts){
11931 this.renderer.render(this.el, response, this,
11932 this.updateComplete.createDelegate(this, [response]));
11934 this.renderer.render(this.el, response, this);
11935 this.updateComplete(response);
11939 updateComplete : function(response){
11940 this.fireEvent("update", this.el, response);
11941 if(typeof response.argument.callback == "function"){
11942 response.argument.callback(this.el, true, response);
11949 processFailure : function(response){
11950 this.transaction = null;
11951 this.fireEvent("failure", this.el, response);
11952 if(typeof response.argument.callback == "function"){
11953 response.argument.callback(this.el, false, response);
11958 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11959 * @param {Object} renderer The object implementing the render() method
11961 setRenderer : function(renderer){
11962 this.renderer = renderer;
11965 getRenderer : function(){
11966 return this.renderer;
11970 * Set the defaultUrl used for updates
11971 * @param {String/Function} defaultUrl The url or a function to call to get the url
11973 setDefaultUrl : function(defaultUrl){
11974 this.defaultUrl = defaultUrl;
11978 * Aborts the executing transaction
11980 abort : function(){
11981 if(this.transaction){
11982 Roo.Ajax.abort(this.transaction);
11987 * Returns true if an update is in progress
11988 * @return {Boolean}
11990 isUpdating : function(){
11991 if(this.transaction){
11992 return Roo.Ajax.isLoading(this.transaction);
11999 * @class Roo.UpdateManager.defaults
12000 * @static (not really - but it helps the doc tool)
12001 * The defaults collection enables customizing the default properties of UpdateManager
12003 Roo.UpdateManager.defaults = {
12005 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12011 * True to process scripts by default (Defaults to false).
12014 loadScripts : false,
12017 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12020 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12022 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12025 disableCaching : false,
12027 * Whether to show indicatorText when loading (Defaults to true).
12030 showLoadIndicator : true,
12032 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12035 indicatorText : '<div class="loading-indicator">Loading...</div>'
12039 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12041 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12042 * @param {String/HTMLElement/Roo.Element} el The element to update
12043 * @param {String} url The url
12044 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12045 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12048 * @member Roo.UpdateManager
12050 Roo.UpdateManager.updateElement = function(el, url, params, options){
12051 var um = Roo.get(el, true).getUpdateManager();
12052 Roo.apply(um, options);
12053 um.update(url, params, options ? options.callback : null);
12055 // alias for backwards compat
12056 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12058 * @class Roo.UpdateManager.BasicRenderer
12059 * Default Content renderer. Updates the elements innerHTML with the responseText.
12061 Roo.UpdateManager.BasicRenderer = function(){};
12063 Roo.UpdateManager.BasicRenderer.prototype = {
12065 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12066 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12067 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12068 * @param {Roo.Element} el The element being rendered
12069 * @param {Object} response The YUI Connect response object
12070 * @param {UpdateManager} updateManager The calling update manager
12071 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12073 render : function(el, response, updateManager, callback){
12074 el.update(response.responseText, updateManager.loadScripts, callback);
12079 * Ext JS Library 1.1.1
12080 * Copyright(c) 2006-2007, Ext JS, LLC.
12082 * Originally Released Under LGPL - original licence link has changed is not relivant.
12085 * <script type="text/javascript">
12089 * @class Roo.util.DelayedTask
12090 * Provides a convenient method of performing setTimeout where a new
12091 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12092 * You can use this class to buffer
12093 * the keypress events for a certain number of milliseconds, and perform only if they stop
12094 * for that amount of time.
12095 * @constructor The parameters to this constructor serve as defaults and are not required.
12096 * @param {Function} fn (optional) The default function to timeout
12097 * @param {Object} scope (optional) The default scope of that timeout
12098 * @param {Array} args (optional) The default Array of arguments
12100 Roo.util.DelayedTask = function(fn, scope, args){
12101 var id = null, d, t;
12103 var call = function(){
12104 var now = new Date().getTime();
12108 fn.apply(scope, args || []);
12112 * Cancels any pending timeout and queues a new one
12113 * @param {Number} delay The milliseconds to delay
12114 * @param {Function} newFn (optional) Overrides function passed to constructor
12115 * @param {Object} newScope (optional) Overrides scope passed to constructor
12116 * @param {Array} newArgs (optional) Overrides args passed to constructor
12118 this.delay = function(delay, newFn, newScope, newArgs){
12119 if(id && delay != d){
12123 t = new Date().getTime();
12125 scope = newScope || scope;
12126 args = newArgs || args;
12128 id = setInterval(call, d);
12133 * Cancel the last queued timeout
12135 this.cancel = function(){
12143 * Ext JS Library 1.1.1
12144 * Copyright(c) 2006-2007, Ext JS, LLC.
12146 * Originally Released Under LGPL - original licence link has changed is not relivant.
12149 * <script type="text/javascript">
12153 Roo.util.TaskRunner = function(interval){
12154 interval = interval || 10;
12155 var tasks = [], removeQueue = [];
12157 var running = false;
12159 var stopThread = function(){
12165 var startThread = function(){
12168 id = setInterval(runTasks, interval);
12172 var removeTask = function(task){
12173 removeQueue.push(task);
12179 var runTasks = function(){
12180 if(removeQueue.length > 0){
12181 for(var i = 0, len = removeQueue.length; i < len; i++){
12182 tasks.remove(removeQueue[i]);
12185 if(tasks.length < 1){
12190 var now = new Date().getTime();
12191 for(var i = 0, len = tasks.length; i < len; ++i){
12193 var itime = now - t.taskRunTime;
12194 if(t.interval <= itime){
12195 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12196 t.taskRunTime = now;
12197 if(rt === false || t.taskRunCount === t.repeat){
12202 if(t.duration && t.duration <= (now - t.taskStartTime)){
12209 * Queues a new task.
12210 * @param {Object} task
12212 this.start = function(task){
12214 task.taskStartTime = new Date().getTime();
12215 task.taskRunTime = 0;
12216 task.taskRunCount = 0;
12221 this.stop = function(task){
12226 this.stopAll = function(){
12228 for(var i = 0, len = tasks.length; i < len; i++){
12229 if(tasks[i].onStop){
12238 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12240 * Ext JS Library 1.1.1
12241 * Copyright(c) 2006-2007, Ext JS, LLC.
12243 * Originally Released Under LGPL - original licence link has changed is not relivant.
12246 * <script type="text/javascript">
12251 * @class Roo.util.MixedCollection
12252 * @extends Roo.util.Observable
12253 * A Collection class that maintains both numeric indexes and keys and exposes events.
12255 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12256 * collection (defaults to false)
12257 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12258 * and return the key value for that item. This is used when available to look up the key on items that
12259 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12260 * equivalent to providing an implementation for the {@link #getKey} method.
12262 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12270 * Fires when the collection is cleared.
12275 * Fires when an item is added to the collection.
12276 * @param {Number} index The index at which the item was added.
12277 * @param {Object} o The item added.
12278 * @param {String} key The key associated with the added item.
12283 * Fires when an item is replaced in the collection.
12284 * @param {String} key he key associated with the new added.
12285 * @param {Object} old The item being replaced.
12286 * @param {Object} new The new item.
12291 * Fires when an item is removed from the collection.
12292 * @param {Object} o The item being removed.
12293 * @param {String} key (optional) The key associated with the removed item.
12298 this.allowFunctions = allowFunctions === true;
12300 this.getKey = keyFn;
12302 Roo.util.MixedCollection.superclass.constructor.call(this);
12305 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12306 allowFunctions : false,
12309 * Adds an item to the collection.
12310 * @param {String} key The key to associate with the item
12311 * @param {Object} o The item to add.
12312 * @return {Object} The item added.
12314 add : function(key, o){
12315 if(arguments.length == 1){
12317 key = this.getKey(o);
12319 if(typeof key == "undefined" || key === null){
12321 this.items.push(o);
12322 this.keys.push(null);
12324 var old = this.map[key];
12326 return this.replace(key, o);
12329 this.items.push(o);
12331 this.keys.push(key);
12333 this.fireEvent("add", this.length-1, o, key);
12338 * MixedCollection has a generic way to fetch keys if you implement getKey.
12341 var mc = new Roo.util.MixedCollection();
12342 mc.add(someEl.dom.id, someEl);
12343 mc.add(otherEl.dom.id, otherEl);
12347 var mc = new Roo.util.MixedCollection();
12348 mc.getKey = function(el){
12354 // or via the constructor
12355 var mc = new Roo.util.MixedCollection(false, function(el){
12361 * @param o {Object} The item for which to find the key.
12362 * @return {Object} The key for the passed item.
12364 getKey : function(o){
12369 * Replaces an item in the collection.
12370 * @param {String} key The key associated with the item to replace, or the item to replace.
12371 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12372 * @return {Object} The new item.
12374 replace : function(key, o){
12375 if(arguments.length == 1){
12377 key = this.getKey(o);
12379 var old = this.item(key);
12380 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12381 return this.add(key, o);
12383 var index = this.indexOfKey(key);
12384 this.items[index] = o;
12386 this.fireEvent("replace", key, old, o);
12391 * Adds all elements of an Array or an Object to the collection.
12392 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12393 * an Array of values, each of which are added to the collection.
12395 addAll : function(objs){
12396 if(arguments.length > 1 || objs instanceof Array){
12397 var args = arguments.length > 1 ? arguments : objs;
12398 for(var i = 0, len = args.length; i < len; i++){
12402 for(var key in objs){
12403 if(this.allowFunctions || typeof objs[key] != "function"){
12404 this.add(key, objs[key]);
12411 * Executes the specified function once for every item in the collection, passing each
12412 * item as the first and only parameter. returning false from the function will stop the iteration.
12413 * @param {Function} fn The function to execute for each item.
12414 * @param {Object} scope (optional) The scope in which to execute the function.
12416 each : function(fn, scope){
12417 var items = [].concat(this.items); // each safe for removal
12418 for(var i = 0, len = items.length; i < len; i++){
12419 if(fn.call(scope || items[i], items[i], i, len) === false){
12426 * Executes the specified function once for every key in the collection, passing each
12427 * key, and its associated item as the first two parameters.
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 eachKey : function(fn, scope){
12432 for(var i = 0, len = this.keys.length; i < len; i++){
12433 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12438 * Returns the first item in the collection which elicits a true return value from the
12439 * passed selection function.
12440 * @param {Function} fn The selection function to execute for each item.
12441 * @param {Object} scope (optional) The scope in which to execute the function.
12442 * @return {Object} The first item in the collection which returned true from the selection function.
12444 find : function(fn, scope){
12445 for(var i = 0, len = this.items.length; i < len; i++){
12446 if(fn.call(scope || window, this.items[i], this.keys[i])){
12447 return this.items[i];
12454 * Inserts an item at the specified index in the collection.
12455 * @param {Number} index The index to insert the item at.
12456 * @param {String} key The key to associate with the new item, or the item itself.
12457 * @param {Object} o (optional) If the second parameter was a key, the new item.
12458 * @return {Object} The item inserted.
12460 insert : function(index, key, o){
12461 if(arguments.length == 2){
12463 key = this.getKey(o);
12465 if(index >= this.length){
12466 return this.add(key, o);
12469 this.items.splice(index, 0, o);
12470 if(typeof key != "undefined" && key != null){
12473 this.keys.splice(index, 0, key);
12474 this.fireEvent("add", index, o, key);
12479 * Removed an item from the collection.
12480 * @param {Object} o The item to remove.
12481 * @return {Object} The item removed.
12483 remove : function(o){
12484 return this.removeAt(this.indexOf(o));
12488 * Remove an item from a specified index in the collection.
12489 * @param {Number} index The index within the collection of the item to remove.
12491 removeAt : function(index){
12492 if(index < this.length && index >= 0){
12494 var o = this.items[index];
12495 this.items.splice(index, 1);
12496 var key = this.keys[index];
12497 if(typeof key != "undefined"){
12498 delete this.map[key];
12500 this.keys.splice(index, 1);
12501 this.fireEvent("remove", o, key);
12506 * Removed an item associated with the passed key fom the collection.
12507 * @param {String} key The key of the item to remove.
12509 removeKey : function(key){
12510 return this.removeAt(this.indexOfKey(key));
12514 * Returns the number of items in the collection.
12515 * @return {Number} the number of items in the collection.
12517 getCount : function(){
12518 return this.length;
12522 * Returns index within the collection of the passed Object.
12523 * @param {Object} o The item to find the index of.
12524 * @return {Number} index of the item.
12526 indexOf : function(o){
12527 if(!this.items.indexOf){
12528 for(var i = 0, len = this.items.length; i < len; i++){
12529 if(this.items[i] == o) return i;
12533 return this.items.indexOf(o);
12538 * Returns index within the collection of the passed key.
12539 * @param {String} key The key to find the index of.
12540 * @return {Number} index of the key.
12542 indexOfKey : function(key){
12543 if(!this.keys.indexOf){
12544 for(var i = 0, len = this.keys.length; i < len; i++){
12545 if(this.keys[i] == key) return i;
12549 return this.keys.indexOf(key);
12554 * Returns the item associated with the passed key OR index. Key has priority over index.
12555 * @param {String/Number} key The key or index of the item.
12556 * @return {Object} The item associated with the passed key.
12558 item : function(key){
12559 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12560 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12564 * Returns the item at the specified index.
12565 * @param {Number} index The index of the item.
12568 itemAt : function(index){
12569 return this.items[index];
12573 * Returns the item associated with the passed key.
12574 * @param {String/Number} key The key of the item.
12575 * @return {Object} The item associated with the passed key.
12577 key : function(key){
12578 return this.map[key];
12582 * Returns true if the collection contains the passed Object as an item.
12583 * @param {Object} o The Object to look for in the collection.
12584 * @return {Boolean} True if the collection contains the Object as an item.
12586 contains : function(o){
12587 return this.indexOf(o) != -1;
12591 * Returns true if the collection contains the passed Object as a key.
12592 * @param {String} key The key to look for in the collection.
12593 * @return {Boolean} True if the collection contains the Object as a key.
12595 containsKey : function(key){
12596 return typeof this.map[key] != "undefined";
12600 * Removes all items from the collection.
12602 clear : function(){
12607 this.fireEvent("clear");
12611 * Returns the first item in the collection.
12612 * @return {Object} the first item in the collection..
12614 first : function(){
12615 return this.items[0];
12619 * Returns the last item in the collection.
12620 * @return {Object} the last item in the collection..
12623 return this.items[this.length-1];
12626 _sort : function(property, dir, fn){
12627 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12628 fn = fn || function(a, b){
12631 var c = [], k = this.keys, items = this.items;
12632 for(var i = 0, len = items.length; i < len; i++){
12633 c[c.length] = {key: k[i], value: items[i], index: i};
12635 c.sort(function(a, b){
12636 var v = fn(a[property], b[property]) * dsc;
12638 v = (a.index < b.index ? -1 : 1);
12642 for(var i = 0, len = c.length; i < len; i++){
12643 items[i] = c[i].value;
12646 this.fireEvent("sort", this);
12650 * Sorts this collection with the passed comparison function
12651 * @param {String} direction (optional) "ASC" or "DESC"
12652 * @param {Function} fn (optional) comparison function
12654 sort : function(dir, fn){
12655 this._sort("value", dir, fn);
12659 * Sorts this collection by keys
12660 * @param {String} direction (optional) "ASC" or "DESC"
12661 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12663 keySort : function(dir, fn){
12664 this._sort("key", dir, fn || function(a, b){
12665 return String(a).toUpperCase()-String(b).toUpperCase();
12670 * Returns a range of items in this collection
12671 * @param {Number} startIndex (optional) defaults to 0
12672 * @param {Number} endIndex (optional) default to the last item
12673 * @return {Array} An array of items
12675 getRange : function(start, end){
12676 var items = this.items;
12677 if(items.length < 1){
12680 start = start || 0;
12681 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12684 for(var i = start; i <= end; i++) {
12685 r[r.length] = items[i];
12688 for(var i = start; i >= end; i--) {
12689 r[r.length] = items[i];
12696 * Filter the <i>objects</i> in this collection by a specific property.
12697 * Returns a new collection that has been filtered.
12698 * @param {String} property A property on your objects
12699 * @param {String/RegExp} value Either string that the property values
12700 * should start with or a RegExp to test against the property
12701 * @return {MixedCollection} The new filtered collection
12703 filter : function(property, value){
12704 if(!value.exec){ // not a regex
12705 value = String(value);
12706 if(value.length == 0){
12707 return this.clone();
12709 value = new RegExp("^" + Roo.escapeRe(value), "i");
12711 return this.filterBy(function(o){
12712 return o && value.test(o[property]);
12717 * Filter by a function. * Returns a new collection that has been filtered.
12718 * The passed function will be called with each
12719 * object in the collection. If the function returns true, the value is included
12720 * otherwise it is filtered.
12721 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12722 * @param {Object} scope (optional) The scope of the function (defaults to this)
12723 * @return {MixedCollection} The new filtered collection
12725 filterBy : function(fn, scope){
12726 var r = new Roo.util.MixedCollection();
12727 r.getKey = this.getKey;
12728 var k = this.keys, it = this.items;
12729 for(var i = 0, len = it.length; i < len; i++){
12730 if(fn.call(scope||this, it[i], k[i])){
12731 r.add(k[i], it[i]);
12738 * Creates a duplicate of this collection
12739 * @return {MixedCollection}
12741 clone : function(){
12742 var r = new Roo.util.MixedCollection();
12743 var k = this.keys, it = this.items;
12744 for(var i = 0, len = it.length; i < len; i++){
12745 r.add(k[i], it[i]);
12747 r.getKey = this.getKey;
12752 * Returns the item associated with the passed key or index.
12754 * @param {String/Number} key The key or index of the item.
12755 * @return {Object} The item associated with the passed key.
12757 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12759 * Ext JS Library 1.1.1
12760 * Copyright(c) 2006-2007, Ext JS, LLC.
12762 * Originally Released Under LGPL - original licence link has changed is not relivant.
12765 * <script type="text/javascript">
12768 * @class Roo.util.JSON
12769 * Modified version of Douglas Crockford"s json.js that doesn"t
12770 * mess with the Object prototype
12771 * http://www.json.org/js.html
12774 Roo.util.JSON = new (function(){
12775 var useHasOwn = {}.hasOwnProperty ? true : false;
12777 // crashes Safari in some instances
12778 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12780 var pad = function(n) {
12781 return n < 10 ? "0" + n : n;
12794 var encodeString = function(s){
12795 if (/["\\\x00-\x1f]/.test(s)) {
12796 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12801 c = b.charCodeAt();
12803 Math.floor(c / 16).toString(16) +
12804 (c % 16).toString(16);
12807 return '"' + s + '"';
12810 var encodeArray = function(o){
12811 var a = ["["], b, i, l = o.length, v;
12812 for (i = 0; i < l; i += 1) {
12814 switch (typeof v) {
12823 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12831 var encodeDate = function(o){
12832 return '"' + o.getFullYear() + "-" +
12833 pad(o.getMonth() + 1) + "-" +
12834 pad(o.getDate()) + "T" +
12835 pad(o.getHours()) + ":" +
12836 pad(o.getMinutes()) + ":" +
12837 pad(o.getSeconds()) + '"';
12841 * Encodes an Object, Array or other value
12842 * @param {Mixed} o The variable to encode
12843 * @return {String} The JSON string
12845 this.encode = function(o)
12847 // should this be extended to fully wrap stringify..
12849 if(typeof o == "undefined" || o === null){
12851 }else if(o instanceof Array){
12852 return encodeArray(o);
12853 }else if(o instanceof Date){
12854 return encodeDate(o);
12855 }else if(typeof o == "string"){
12856 return encodeString(o);
12857 }else if(typeof o == "number"){
12858 return isFinite(o) ? String(o) : "null";
12859 }else if(typeof o == "boolean"){
12862 var a = ["{"], b, i, v;
12864 if(!useHasOwn || o.hasOwnProperty(i)) {
12866 switch (typeof v) {
12875 a.push(this.encode(i), ":",
12876 v === null ? "null" : this.encode(v));
12887 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12888 * @param {String} json The JSON string
12889 * @return {Object} The resulting object
12891 this.decode = function(json){
12893 return /** eval:var:json */ eval("(" + json + ')');
12897 * Shorthand for {@link Roo.util.JSON#encode}
12898 * @member Roo encode
12900 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12902 * Shorthand for {@link Roo.util.JSON#decode}
12903 * @member Roo decode
12905 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12908 * Ext JS Library 1.1.1
12909 * Copyright(c) 2006-2007, Ext JS, LLC.
12911 * Originally Released Under LGPL - original licence link has changed is not relivant.
12914 * <script type="text/javascript">
12918 * @class Roo.util.Format
12919 * Reusable data formatting functions
12922 Roo.util.Format = function(){
12923 var trimRe = /^\s+|\s+$/g;
12926 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12927 * @param {String} value The string to truncate
12928 * @param {Number} length The maximum length to allow before truncating
12929 * @return {String} The converted text
12931 ellipsis : function(value, len){
12932 if(value && value.length > len){
12933 return value.substr(0, len-3)+"...";
12939 * Checks a reference and converts it to empty string if it is undefined
12940 * @param {Mixed} value Reference to check
12941 * @return {Mixed} Empty string if converted, otherwise the original value
12943 undef : function(value){
12944 return typeof value != "undefined" ? value : "";
12948 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12949 * @param {String} value The string to encode
12950 * @return {String} The encoded text
12952 htmlEncode : function(value){
12953 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12957 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12958 * @param {String} value The string to decode
12959 * @return {String} The decoded text
12961 htmlDecode : function(value){
12962 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12966 * Trims any whitespace from either side of a string
12967 * @param {String} value The text to trim
12968 * @return {String} The trimmed text
12970 trim : function(value){
12971 return String(value).replace(trimRe, "");
12975 * Returns a substring from within an original string
12976 * @param {String} value The original text
12977 * @param {Number} start The start index of the substring
12978 * @param {Number} length The length of the substring
12979 * @return {String} The substring
12981 substr : function(value, start, length){
12982 return String(value).substr(start, length);
12986 * Converts a string to all lower case letters
12987 * @param {String} value The text to convert
12988 * @return {String} The converted text
12990 lowercase : function(value){
12991 return String(value).toLowerCase();
12995 * Converts a string to all upper case letters
12996 * @param {String} value The text to convert
12997 * @return {String} The converted text
12999 uppercase : function(value){
13000 return String(value).toUpperCase();
13004 * Converts the first character only of a string to upper case
13005 * @param {String} value The text to convert
13006 * @return {String} The converted text
13008 capitalize : function(value){
13009 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13013 call : function(value, fn){
13014 if(arguments.length > 2){
13015 var args = Array.prototype.slice.call(arguments, 2);
13016 args.unshift(value);
13018 return /** eval:var:value */ eval(fn).apply(window, args);
13020 /** eval:var:value */
13021 return /** eval:var:value */ eval(fn).call(window, value);
13027 * safer version of Math.toFixed..??/
13028 * @param {Number/String} value The numeric value to format
13029 * @param {Number/String} value Decimal places
13030 * @return {String} The formatted currency string
13032 toFixed : function(v, n)
13034 // why not use to fixed - precision is buggered???
13036 return Math.round(v-0);
13038 var fact = Math.pow(10,n+1);
13039 v = (Math.round((v-0)*fact))/fact;
13040 var z = (''+fact).substring(2);
13041 if (v == Math.floor(v)) {
13042 return Math.floor(v) + '.' + z;
13045 // now just padd decimals..
13046 var ps = String(v).split('.');
13047 var fd = (ps[1] + z);
13048 var r = fd.substring(0,n);
13049 var rm = fd.substring(n);
13051 return ps[0] + '.' + r;
13053 r*=1; // turn it into a number;
13055 if (String(r).length != n) {
13058 r = String(r).substring(1); // chop the end off.
13061 return ps[0] + '.' + r;
13066 * Format a number as US currency
13067 * @param {Number/String} value The numeric value to format
13068 * @return {String} The formatted currency string
13070 usMoney : function(v){
13071 v = (Math.round((v-0)*100))/100;
13072 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13074 var ps = v.split('.');
13076 var sub = ps[1] ? '.'+ ps[1] : '.00';
13077 var r = /(\d+)(\d{3})/;
13078 while (r.test(whole)) {
13079 whole = whole.replace(r, '$1' + ',' + '$2');
13081 return "$" + whole + sub ;
13085 * Parse a value into a formatted date using the specified format pattern.
13086 * @param {Mixed} value The value to format
13087 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13088 * @return {String} The formatted date string
13090 date : function(v, format){
13094 if(!(v instanceof Date)){
13095 v = new Date(Date.parse(v));
13097 return v.dateFormat(format || "m/d/Y");
13101 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13102 * @param {String} format Any valid date format string
13103 * @return {Function} The date formatting function
13105 dateRenderer : function(format){
13106 return function(v){
13107 return Roo.util.Format.date(v, format);
13112 stripTagsRE : /<\/?[^>]+>/gi,
13115 * Strips all HTML tags
13116 * @param {Mixed} value The text from which to strip tags
13117 * @return {String} The stripped text
13119 stripTags : function(v){
13120 return !v ? v : String(v).replace(this.stripTagsRE, "");
13125 * Ext JS Library 1.1.1
13126 * Copyright(c) 2006-2007, Ext JS, LLC.
13128 * Originally Released Under LGPL - original licence link has changed is not relivant.
13131 * <script type="text/javascript">
13138 * @class Roo.MasterTemplate
13139 * @extends Roo.Template
13140 * Provides a template that can have child templates. The syntax is:
13142 var t = new Roo.MasterTemplate(
13143 '<select name="{name}">',
13144 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13147 t.add('options', {value: 'foo', text: 'bar'});
13148 // or you can add multiple child elements in one shot
13149 t.addAll('options', [
13150 {value: 'foo', text: 'bar'},
13151 {value: 'foo2', text: 'bar2'},
13152 {value: 'foo3', text: 'bar3'}
13154 // then append, applying the master template values
13155 t.append('my-form', {name: 'my-select'});
13157 * A name attribute for the child template is not required if you have only one child
13158 * template or you want to refer to them by index.
13160 Roo.MasterTemplate = function(){
13161 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13162 this.originalHtml = this.html;
13164 var m, re = this.subTemplateRe;
13167 while(m = re.exec(this.html)){
13168 var name = m[1], content = m[2];
13173 tpl : new Roo.Template(content)
13176 st[name] = st[subIndex];
13178 st[subIndex].tpl.compile();
13179 st[subIndex].tpl.call = this.call.createDelegate(this);
13182 this.subCount = subIndex;
13185 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13187 * The regular expression used to match sub templates
13191 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13194 * Applies the passed values to a child template.
13195 * @param {String/Number} name (optional) The name or index of the child template
13196 * @param {Array/Object} values The values to be applied to the template
13197 * @return {MasterTemplate} this
13199 add : function(name, values){
13200 if(arguments.length == 1){
13201 values = arguments[0];
13204 var s = this.subs[name];
13205 s.buffer[s.buffer.length] = s.tpl.apply(values);
13210 * Applies all the passed values to a child template.
13211 * @param {String/Number} name (optional) The name or index of the child template
13212 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13213 * @param {Boolean} reset (optional) True to reset the template first
13214 * @return {MasterTemplate} this
13216 fill : function(name, values, reset){
13218 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13226 for(var i = 0, len = values.length; i < len; i++){
13227 this.add(name, values[i]);
13233 * Resets the template for reuse
13234 * @return {MasterTemplate} this
13236 reset : function(){
13238 for(var i = 0; i < this.subCount; i++){
13244 applyTemplate : function(values){
13246 var replaceIndex = -1;
13247 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13248 return s[++replaceIndex].buffer.join("");
13250 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13253 apply : function(){
13254 return this.applyTemplate.apply(this, arguments);
13257 compile : function(){return this;}
13261 * Alias for fill().
13264 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13266 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13267 * var tpl = Roo.MasterTemplate.from('element-id');
13268 * @param {String/HTMLElement} el
13269 * @param {Object} config
13272 Roo.MasterTemplate.from = function(el, config){
13273 el = Roo.getDom(el);
13274 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13277 * Ext JS Library 1.1.1
13278 * Copyright(c) 2006-2007, Ext JS, LLC.
13280 * Originally Released Under LGPL - original licence link has changed is not relivant.
13283 * <script type="text/javascript">
13288 * @class Roo.util.CSS
13289 * Utility class for manipulating CSS rules
13292 Roo.util.CSS = function(){
13294 var doc = document;
13296 var camelRe = /(-[a-z])/gi;
13297 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13301 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13302 * tag and appended to the HEAD of the document.
13303 * @param {String|Object} cssText The text containing the css rules
13304 * @param {String} id An id to add to the stylesheet for later removal
13305 * @return {StyleSheet}
13307 createStyleSheet : function(cssText, id){
13309 var head = doc.getElementsByTagName("head")[0];
13310 var nrules = doc.createElement("style");
13311 nrules.setAttribute("type", "text/css");
13313 nrules.setAttribute("id", id);
13315 if (typeof(cssText) != 'string') {
13316 // support object maps..
13317 // not sure if this a good idea..
13318 // perhaps it should be merged with the general css handling
13319 // and handle js style props.
13320 var cssTextNew = [];
13321 for(var n in cssText) {
13323 for(var k in cssText[n]) {
13324 citems.push( k + ' : ' +cssText[n][k] + ';' );
13326 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13329 cssText = cssTextNew.join("\n");
13335 head.appendChild(nrules);
13336 ss = nrules.styleSheet;
13337 ss.cssText = cssText;
13340 nrules.appendChild(doc.createTextNode(cssText));
13342 nrules.cssText = cssText;
13344 head.appendChild(nrules);
13345 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13347 this.cacheStyleSheet(ss);
13352 * Removes a style or link tag by id
13353 * @param {String} id The id of the tag
13355 removeStyleSheet : function(id){
13356 var existing = doc.getElementById(id);
13358 existing.parentNode.removeChild(existing);
13363 * Dynamically swaps an existing stylesheet reference for a new one
13364 * @param {String} id The id of an existing link tag to remove
13365 * @param {String} url The href of the new stylesheet to include
13367 swapStyleSheet : function(id, url){
13368 this.removeStyleSheet(id);
13369 var ss = doc.createElement("link");
13370 ss.setAttribute("rel", "stylesheet");
13371 ss.setAttribute("type", "text/css");
13372 ss.setAttribute("id", id);
13373 ss.setAttribute("href", url);
13374 doc.getElementsByTagName("head")[0].appendChild(ss);
13378 * Refresh the rule cache if you have dynamically added stylesheets
13379 * @return {Object} An object (hash) of rules indexed by selector
13381 refreshCache : function(){
13382 return this.getRules(true);
13386 cacheStyleSheet : function(stylesheet){
13390 try{// try catch for cross domain access issue
13391 var ssRules = stylesheet.cssRules || stylesheet.rules;
13392 for(var j = ssRules.length-1; j >= 0; --j){
13393 rules[ssRules[j].selectorText] = ssRules[j];
13399 * Gets all css rules for the document
13400 * @param {Boolean} refreshCache true to refresh the internal cache
13401 * @return {Object} An object (hash) of rules indexed by selector
13403 getRules : function(refreshCache){
13404 if(rules == null || refreshCache){
13406 var ds = doc.styleSheets;
13407 for(var i =0, len = ds.length; i < len; i++){
13409 this.cacheStyleSheet(ds[i]);
13417 * Gets an an individual CSS rule by selector(s)
13418 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13419 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13420 * @return {CSSRule} The CSS rule or null if one is not found
13422 getRule : function(selector, refreshCache){
13423 var rs = this.getRules(refreshCache);
13424 if(!(selector instanceof Array)){
13425 return rs[selector];
13427 for(var i = 0; i < selector.length; i++){
13428 if(rs[selector[i]]){
13429 return rs[selector[i]];
13437 * Updates a rule property
13438 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13439 * @param {String} property The css property
13440 * @param {String} value The new value for the property
13441 * @return {Boolean} true If a rule was found and updated
13443 updateRule : function(selector, property, value){
13444 if(!(selector instanceof Array)){
13445 var rule = this.getRule(selector);
13447 rule.style[property.replace(camelRe, camelFn)] = value;
13451 for(var i = 0; i < selector.length; i++){
13452 if(this.updateRule(selector[i], property, value)){
13462 * Ext JS Library 1.1.1
13463 * Copyright(c) 2006-2007, Ext JS, LLC.
13465 * Originally Released Under LGPL - original licence link has changed is not relivant.
13468 * <script type="text/javascript">
13474 * @class Roo.util.ClickRepeater
13475 * @extends Roo.util.Observable
13477 * A wrapper class which can be applied to any element. Fires a "click" event while the
13478 * mouse is pressed. The interval between firings may be specified in the config but
13479 * defaults to 10 milliseconds.
13481 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13483 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13484 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13485 * Similar to an autorepeat key delay.
13486 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13487 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13488 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13489 * "interval" and "delay" are ignored. "immediate" is honored.
13490 * @cfg {Boolean} preventDefault True to prevent the default click event
13491 * @cfg {Boolean} stopDefault True to stop the default click event
13494 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13495 * 2007-02-02 jvs Renamed to ClickRepeater
13496 * 2007-02-03 jvs Modifications for FF Mac and Safari
13499 * @param {String/HTMLElement/Element} el The element to listen on
13500 * @param {Object} config
13502 Roo.util.ClickRepeater = function(el, config)
13504 this.el = Roo.get(el);
13505 this.el.unselectable();
13507 Roo.apply(this, config);
13512 * Fires when the mouse button is depressed.
13513 * @param {Roo.util.ClickRepeater} this
13515 "mousedown" : true,
13518 * Fires on a specified interval during the time the element is pressed.
13519 * @param {Roo.util.ClickRepeater} this
13524 * Fires when the mouse key is released.
13525 * @param {Roo.util.ClickRepeater} this
13530 this.el.on("mousedown", this.handleMouseDown, this);
13531 if(this.preventDefault || this.stopDefault){
13532 this.el.on("click", function(e){
13533 if(this.preventDefault){
13534 e.preventDefault();
13536 if(this.stopDefault){
13542 // allow inline handler
13544 this.on("click", this.handler, this.scope || this);
13547 Roo.util.ClickRepeater.superclass.constructor.call(this);
13550 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13553 preventDefault : true,
13554 stopDefault : false,
13558 handleMouseDown : function(){
13559 clearTimeout(this.timer);
13561 if(this.pressClass){
13562 this.el.addClass(this.pressClass);
13564 this.mousedownTime = new Date();
13566 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13567 this.el.on("mouseout", this.handleMouseOut, this);
13569 this.fireEvent("mousedown", this);
13570 this.fireEvent("click", this);
13572 this.timer = this.click.defer(this.delay || this.interval, this);
13576 click : function(){
13577 this.fireEvent("click", this);
13578 this.timer = this.click.defer(this.getInterval(), this);
13582 getInterval: function(){
13583 if(!this.accelerate){
13584 return this.interval;
13586 var pressTime = this.mousedownTime.getElapsed();
13587 if(pressTime < 500){
13589 }else if(pressTime < 1700){
13591 }else if(pressTime < 2600){
13593 }else if(pressTime < 3500){
13595 }else if(pressTime < 4400){
13597 }else if(pressTime < 5300){
13599 }else if(pressTime < 6200){
13607 handleMouseOut : function(){
13608 clearTimeout(this.timer);
13609 if(this.pressClass){
13610 this.el.removeClass(this.pressClass);
13612 this.el.on("mouseover", this.handleMouseReturn, this);
13616 handleMouseReturn : function(){
13617 this.el.un("mouseover", this.handleMouseReturn);
13618 if(this.pressClass){
13619 this.el.addClass(this.pressClass);
13625 handleMouseUp : function(){
13626 clearTimeout(this.timer);
13627 this.el.un("mouseover", this.handleMouseReturn);
13628 this.el.un("mouseout", this.handleMouseOut);
13629 Roo.get(document).un("mouseup", this.handleMouseUp);
13630 this.el.removeClass(this.pressClass);
13631 this.fireEvent("mouseup", this);
13635 * Ext JS Library 1.1.1
13636 * Copyright(c) 2006-2007, Ext JS, LLC.
13638 * Originally Released Under LGPL - original licence link has changed is not relivant.
13641 * <script type="text/javascript">
13646 * @class Roo.KeyNav
13647 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13648 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13649 * way to implement custom navigation schemes for any UI component.</p>
13650 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13651 * pageUp, pageDown, del, home, end. Usage:</p>
13653 var nav = new Roo.KeyNav("my-element", {
13654 "left" : function(e){
13655 this.moveLeft(e.ctrlKey);
13657 "right" : function(e){
13658 this.moveRight(e.ctrlKey);
13660 "enter" : function(e){
13667 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13668 * @param {Object} config The config
13670 Roo.KeyNav = function(el, config){
13671 this.el = Roo.get(el);
13672 Roo.apply(this, config);
13673 if(!this.disabled){
13674 this.disabled = true;
13679 Roo.KeyNav.prototype = {
13681 * @cfg {Boolean} disabled
13682 * True to disable this KeyNav instance (defaults to false)
13686 * @cfg {String} defaultEventAction
13687 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13688 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13689 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13691 defaultEventAction: "stopEvent",
13693 * @cfg {Boolean} forceKeyDown
13694 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13695 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13696 * handle keydown instead of keypress.
13698 forceKeyDown : false,
13701 prepareEvent : function(e){
13702 var k = e.getKey();
13703 var h = this.keyToHandler[k];
13704 //if(h && this[h]){
13705 // e.stopPropagation();
13707 if(Roo.isSafari && h && k >= 37 && k <= 40){
13713 relay : function(e){
13714 var k = e.getKey();
13715 var h = this.keyToHandler[k];
13717 if(this.doRelay(e, this[h], h) !== true){
13718 e[this.defaultEventAction]();
13724 doRelay : function(e, h, hname){
13725 return h.call(this.scope || this, e);
13728 // possible handlers
13742 // quick lookup hash
13759 * Enable this KeyNav
13761 enable: function(){
13763 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13764 // the EventObject will normalize Safari automatically
13765 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13766 this.el.on("keydown", this.relay, this);
13768 this.el.on("keydown", this.prepareEvent, this);
13769 this.el.on("keypress", this.relay, this);
13771 this.disabled = false;
13776 * Disable this KeyNav
13778 disable: function(){
13779 if(!this.disabled){
13780 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13781 this.el.un("keydown", this.relay);
13783 this.el.un("keydown", this.prepareEvent);
13784 this.el.un("keypress", this.relay);
13786 this.disabled = true;
13791 * Ext JS Library 1.1.1
13792 * Copyright(c) 2006-2007, Ext JS, LLC.
13794 * Originally Released Under LGPL - original licence link has changed is not relivant.
13797 * <script type="text/javascript">
13802 * @class Roo.KeyMap
13803 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13804 * The constructor accepts the same config object as defined by {@link #addBinding}.
13805 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13806 * combination it will call the function with this signature (if the match is a multi-key
13807 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13808 * A KeyMap can also handle a string representation of keys.<br />
13811 // map one key by key code
13812 var map = new Roo.KeyMap("my-element", {
13813 key: 13, // or Roo.EventObject.ENTER
13818 // map multiple keys to one action by string
13819 var map = new Roo.KeyMap("my-element", {
13825 // map multiple keys to multiple actions by strings and array of codes
13826 var map = new Roo.KeyMap("my-element", [
13829 fn: function(){ alert("Return was pressed"); }
13832 fn: function(){ alert('a, b or c was pressed'); }
13837 fn: function(){ alert('Control + shift + tab was pressed.'); }
13841 * <b>Note: A KeyMap starts enabled</b>
13843 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13844 * @param {Object} config The config (see {@link #addBinding})
13845 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13847 Roo.KeyMap = function(el, config, eventName){
13848 this.el = Roo.get(el);
13849 this.eventName = eventName || "keydown";
13850 this.bindings = [];
13852 this.addBinding(config);
13857 Roo.KeyMap.prototype = {
13859 * True to stop the event from bubbling and prevent the default browser action if the
13860 * key was handled by the KeyMap (defaults to false)
13866 * Add a new binding to this KeyMap. The following config object properties are supported:
13868 Property Type Description
13869 ---------- --------------- ----------------------------------------------------------------------
13870 key String/Array A single keycode or an array of keycodes to handle
13871 shift Boolean True to handle key only when shift is pressed (defaults to false)
13872 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13873 alt Boolean True to handle key only when alt is pressed (defaults to false)
13874 fn Function The function to call when KeyMap finds the expected key combination
13875 scope Object The scope of the callback function
13881 var map = new Roo.KeyMap(document, {
13882 key: Roo.EventObject.ENTER,
13887 //Add a new binding to the existing KeyMap later
13895 * @param {Object/Array} config A single KeyMap config or an array of configs
13897 addBinding : function(config){
13898 if(config instanceof Array){
13899 for(var i = 0, len = config.length; i < len; i++){
13900 this.addBinding(config[i]);
13904 var keyCode = config.key,
13905 shift = config.shift,
13906 ctrl = config.ctrl,
13909 scope = config.scope;
13910 if(typeof keyCode == "string"){
13912 var keyString = keyCode.toUpperCase();
13913 for(var j = 0, len = keyString.length; j < len; j++){
13914 ks.push(keyString.charCodeAt(j));
13918 var keyArray = keyCode instanceof Array;
13919 var handler = function(e){
13920 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13921 var k = e.getKey();
13923 for(var i = 0, len = keyCode.length; i < len; i++){
13924 if(keyCode[i] == k){
13925 if(this.stopEvent){
13928 fn.call(scope || window, k, e);
13934 if(this.stopEvent){
13937 fn.call(scope || window, k, e);
13942 this.bindings.push(handler);
13946 * Shorthand for adding a single key listener
13947 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13948 * following options:
13949 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13950 * @param {Function} fn The function to call
13951 * @param {Object} scope (optional) The scope of the function
13953 on : function(key, fn, scope){
13954 var keyCode, shift, ctrl, alt;
13955 if(typeof key == "object" && !(key instanceof Array)){
13974 handleKeyDown : function(e){
13975 if(this.enabled){ //just in case
13976 var b = this.bindings;
13977 for(var i = 0, len = b.length; i < len; i++){
13978 b[i].call(this, e);
13984 * Returns true if this KeyMap is enabled
13985 * @return {Boolean}
13987 isEnabled : function(){
13988 return this.enabled;
13992 * Enables this KeyMap
13994 enable: function(){
13996 this.el.on(this.eventName, this.handleKeyDown, this);
13997 this.enabled = true;
14002 * Disable this KeyMap
14004 disable: function(){
14006 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14007 this.enabled = false;
14012 * Ext JS Library 1.1.1
14013 * Copyright(c) 2006-2007, Ext JS, LLC.
14015 * Originally Released Under LGPL - original licence link has changed is not relivant.
14018 * <script type="text/javascript">
14023 * @class Roo.util.TextMetrics
14024 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14025 * wide, in pixels, a given block of text will be.
14028 Roo.util.TextMetrics = function(){
14032 * Measures the size of the specified text
14033 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14034 * that can affect the size of the rendered text
14035 * @param {String} text The text to measure
14036 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14037 * in order to accurately measure the text height
14038 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14040 measure : function(el, text, fixedWidth){
14042 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14045 shared.setFixedWidth(fixedWidth || 'auto');
14046 return shared.getSize(text);
14050 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14051 * the overhead of multiple calls to initialize the style properties on each measurement.
14052 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14053 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14054 * in order to accurately measure the text height
14055 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14057 createInstance : function(el, fixedWidth){
14058 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14065 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14066 var ml = new Roo.Element(document.createElement('div'));
14067 document.body.appendChild(ml.dom);
14068 ml.position('absolute');
14069 ml.setLeftTop(-1000, -1000);
14073 ml.setWidth(fixedWidth);
14078 * Returns the size of the specified text based on the internal element's style and width properties
14079 * @memberOf Roo.util.TextMetrics.Instance#
14080 * @param {String} text The text to measure
14081 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14083 getSize : function(text){
14085 var s = ml.getSize();
14091 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14092 * that can affect the size of the rendered text
14093 * @memberOf Roo.util.TextMetrics.Instance#
14094 * @param {String/HTMLElement} el The element, dom node or id
14096 bind : function(el){
14098 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14103 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14104 * to set a fixed width in order to accurately measure the text height.
14105 * @memberOf Roo.util.TextMetrics.Instance#
14106 * @param {Number} width The width to set on the element
14108 setFixedWidth : function(width){
14109 ml.setWidth(width);
14113 * Returns the measured width of the specified text
14114 * @memberOf Roo.util.TextMetrics.Instance#
14115 * @param {String} text The text to measure
14116 * @return {Number} width The width in pixels
14118 getWidth : function(text){
14119 ml.dom.style.width = 'auto';
14120 return this.getSize(text).width;
14124 * Returns the measured height of the specified text. For multiline text, be sure to call
14125 * {@link #setFixedWidth} if necessary.
14126 * @memberOf Roo.util.TextMetrics.Instance#
14127 * @param {String} text The text to measure
14128 * @return {Number} height The height in pixels
14130 getHeight : function(text){
14131 return this.getSize(text).height;
14135 instance.bind(bindTo);
14140 // backwards compat
14141 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14143 * Ext JS Library 1.1.1
14144 * Copyright(c) 2006-2007, Ext JS, LLC.
14146 * Originally Released Under LGPL - original licence link has changed is not relivant.
14149 * <script type="text/javascript">
14153 * @class Roo.state.Provider
14154 * Abstract base class for state provider implementations. This class provides methods
14155 * for encoding and decoding <b>typed</b> variables including dates and defines the
14156 * Provider interface.
14158 Roo.state.Provider = function(){
14160 * @event statechange
14161 * Fires when a state change occurs.
14162 * @param {Provider} this This state provider
14163 * @param {String} key The state key which was changed
14164 * @param {String} value The encoded value for the state
14167 "statechange": true
14170 Roo.state.Provider.superclass.constructor.call(this);
14172 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14174 * Returns the current value for a key
14175 * @param {String} name The key name
14176 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14177 * @return {Mixed} The state data
14179 get : function(name, defaultValue){
14180 return typeof this.state[name] == "undefined" ?
14181 defaultValue : this.state[name];
14185 * Clears a value from the state
14186 * @param {String} name The key name
14188 clear : function(name){
14189 delete this.state[name];
14190 this.fireEvent("statechange", this, name, null);
14194 * Sets the value for a key
14195 * @param {String} name The key name
14196 * @param {Mixed} value The value to set
14198 set : function(name, value){
14199 this.state[name] = value;
14200 this.fireEvent("statechange", this, name, value);
14204 * Decodes a string previously encoded with {@link #encodeValue}.
14205 * @param {String} value The value to decode
14206 * @return {Mixed} The decoded value
14208 decodeValue : function(cookie){
14209 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14210 var matches = re.exec(unescape(cookie));
14211 if(!matches || !matches[1]) return; // non state cookie
14212 var type = matches[1];
14213 var v = matches[2];
14216 return parseFloat(v);
14218 return new Date(Date.parse(v));
14223 var values = v.split("^");
14224 for(var i = 0, len = values.length; i < len; i++){
14225 all.push(this.decodeValue(values[i]));
14230 var values = v.split("^");
14231 for(var i = 0, len = values.length; i < len; i++){
14232 var kv = values[i].split("=");
14233 all[kv[0]] = this.decodeValue(kv[1]);
14242 * Encodes a value including type information. Decode with {@link #decodeValue}.
14243 * @param {Mixed} value The value to encode
14244 * @return {String} The encoded value
14246 encodeValue : function(v){
14248 if(typeof v == "number"){
14250 }else if(typeof v == "boolean"){
14251 enc = "b:" + (v ? "1" : "0");
14252 }else if(v instanceof Date){
14253 enc = "d:" + v.toGMTString();
14254 }else if(v instanceof Array){
14256 for(var i = 0, len = v.length; i < len; i++){
14257 flat += this.encodeValue(v[i]);
14258 if(i != len-1) flat += "^";
14261 }else if(typeof v == "object"){
14264 if(typeof v[key] != "function"){
14265 flat += key + "=" + this.encodeValue(v[key]) + "^";
14268 enc = "o:" + flat.substring(0, flat.length-1);
14272 return escape(enc);
14278 * Ext JS Library 1.1.1
14279 * Copyright(c) 2006-2007, Ext JS, LLC.
14281 * Originally Released Under LGPL - original licence link has changed is not relivant.
14284 * <script type="text/javascript">
14287 * @class Roo.state.Manager
14288 * This is the global state manager. By default all components that are "state aware" check this class
14289 * for state information if you don't pass them a custom state provider. In order for this class
14290 * to be useful, it must be initialized with a provider when your application initializes.
14292 // in your initialization function
14294 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14296 // supposed you have a {@link Roo.BorderLayout}
14297 var layout = new Roo.BorderLayout(...);
14298 layout.restoreState();
14299 // or a {Roo.BasicDialog}
14300 var dialog = new Roo.BasicDialog(...);
14301 dialog.restoreState();
14305 Roo.state.Manager = function(){
14306 var provider = new Roo.state.Provider();
14310 * Configures the default state provider for your application
14311 * @param {Provider} stateProvider The state provider to set
14313 setProvider : function(stateProvider){
14314 provider = stateProvider;
14318 * Returns the current value for a key
14319 * @param {String} name The key name
14320 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14321 * @return {Mixed} The state data
14323 get : function(key, defaultValue){
14324 return provider.get(key, defaultValue);
14328 * Sets the value for a key
14329 * @param {String} name The key name
14330 * @param {Mixed} value The state data
14332 set : function(key, value){
14333 provider.set(key, value);
14337 * Clears a value from the state
14338 * @param {String} name The key name
14340 clear : function(key){
14341 provider.clear(key);
14345 * Gets the currently configured state provider
14346 * @return {Provider} The state provider
14348 getProvider : function(){
14355 * Ext JS Library 1.1.1
14356 * Copyright(c) 2006-2007, Ext JS, LLC.
14358 * Originally Released Under LGPL - original licence link has changed is not relivant.
14361 * <script type="text/javascript">
14364 * @class Roo.state.CookieProvider
14365 * @extends Roo.state.Provider
14366 * The default Provider implementation which saves state via cookies.
14369 var cp = new Roo.state.CookieProvider({
14371 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14372 domain: "roojs.com"
14374 Roo.state.Manager.setProvider(cp);
14376 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14377 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14378 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14379 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14380 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14381 * domain the page is running on including the 'www' like 'www.roojs.com')
14382 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14384 * Create a new CookieProvider
14385 * @param {Object} config The configuration object
14387 Roo.state.CookieProvider = function(config){
14388 Roo.state.CookieProvider.superclass.constructor.call(this);
14390 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14391 this.domain = null;
14392 this.secure = false;
14393 Roo.apply(this, config);
14394 this.state = this.readCookies();
14397 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14399 set : function(name, value){
14400 if(typeof value == "undefined" || value === null){
14404 this.setCookie(name, value);
14405 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14409 clear : function(name){
14410 this.clearCookie(name);
14411 Roo.state.CookieProvider.superclass.clear.call(this, name);
14415 readCookies : function(){
14417 var c = document.cookie + ";";
14418 var re = /\s?(.*?)=(.*?);/g;
14420 while((matches = re.exec(c)) != null){
14421 var name = matches[1];
14422 var value = matches[2];
14423 if(name && name.substring(0,3) == "ys-"){
14424 cookies[name.substr(3)] = this.decodeValue(value);
14431 setCookie : function(name, value){
14432 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14433 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14434 ((this.path == null) ? "" : ("; path=" + this.path)) +
14435 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14436 ((this.secure == true) ? "; secure" : "");
14440 clearCookie : function(name){
14441 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14442 ((this.path == null) ? "" : ("; path=" + this.path)) +
14443 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14444 ((this.secure == true) ? "; secure" : "");
14448 * Ext JS Library 1.1.1
14449 * Copyright(c) 2006-2007, Ext JS, LLC.
14451 * Originally Released Under LGPL - original licence link has changed is not relivant.
14454 * <script type="text/javascript">
14460 * These classes are derivatives of the similarly named classes in the YUI Library.
14461 * The original license:
14462 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14463 * Code licensed under the BSD License:
14464 * http://developer.yahoo.net/yui/license.txt
14469 var Event=Roo.EventManager;
14470 var Dom=Roo.lib.Dom;
14473 * @class Roo.dd.DragDrop
14474 * @extends Roo.util.Observable
14475 * Defines the interface and base operation of items that that can be
14476 * dragged or can be drop targets. It was designed to be extended, overriding
14477 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14478 * Up to three html elements can be associated with a DragDrop instance:
14480 * <li>linked element: the element that is passed into the constructor.
14481 * This is the element which defines the boundaries for interaction with
14482 * other DragDrop objects.</li>
14483 * <li>handle element(s): The drag operation only occurs if the element that
14484 * was clicked matches a handle element. By default this is the linked
14485 * element, but there are times that you will want only a portion of the
14486 * linked element to initiate the drag operation, and the setHandleElId()
14487 * method provides a way to define this.</li>
14488 * <li>drag element: this represents the element that would be moved along
14489 * with the cursor during a drag operation. By default, this is the linked
14490 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14491 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14494 * This class should not be instantiated until the onload event to ensure that
14495 * the associated elements are available.
14496 * The following would define a DragDrop obj that would interact with any
14497 * other DragDrop obj in the "group1" group:
14499 * dd = new Roo.dd.DragDrop("div1", "group1");
14501 * Since none of the event handlers have been implemented, nothing would
14502 * actually happen if you were to run the code above. Normally you would
14503 * override this class or one of the default implementations, but you can
14504 * also override the methods you want on an instance of the class...
14506 * dd.onDragDrop = function(e, id) {
14507 * alert("dd was dropped on " + id);
14511 * @param {String} id of the element that is linked to this instance
14512 * @param {String} sGroup the group of related DragDrop objects
14513 * @param {object} config an object containing configurable attributes
14514 * Valid properties for DragDrop:
14515 * padding, isTarget, maintainOffset, primaryButtonOnly
14517 Roo.dd.DragDrop = function(id, sGroup, config) {
14519 this.init(id, sGroup, config);
14524 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
14527 * The id of the element associated with this object. This is what we
14528 * refer to as the "linked element" because the size and position of
14529 * this element is used to determine when the drag and drop objects have
14537 * Configuration attributes passed into the constructor
14544 * The id of the element that will be dragged. By default this is same
14545 * as the linked element , but could be changed to another element. Ex:
14547 * @property dragElId
14554 * the id of the element that initiates the drag operation. By default
14555 * this is the linked element, but could be changed to be a child of this
14556 * element. This lets us do things like only starting the drag when the
14557 * header element within the linked html element is clicked.
14558 * @property handleElId
14565 * An associative array of HTML tags that will be ignored if clicked.
14566 * @property invalidHandleTypes
14567 * @type {string: string}
14569 invalidHandleTypes: null,
14572 * An associative array of ids for elements that will be ignored if clicked
14573 * @property invalidHandleIds
14574 * @type {string: string}
14576 invalidHandleIds: null,
14579 * An indexted array of css class names for elements that will be ignored
14581 * @property invalidHandleClasses
14584 invalidHandleClasses: null,
14587 * The linked element's absolute X position at the time the drag was
14589 * @property startPageX
14596 * The linked element's absolute X position at the time the drag was
14598 * @property startPageY
14605 * The group defines a logical collection of DragDrop objects that are
14606 * related. Instances only get events when interacting with other
14607 * DragDrop object in the same group. This lets us define multiple
14608 * groups using a single DragDrop subclass if we want.
14610 * @type {string: string}
14615 * Individual drag/drop instances can be locked. This will prevent
14616 * onmousedown start drag.
14624 * Lock this instance
14627 lock: function() { this.locked = true; },
14630 * Unlock this instace
14633 unlock: function() { this.locked = false; },
14636 * By default, all insances can be a drop target. This can be disabled by
14637 * setting isTarget to false.
14644 * The padding configured for this drag and drop object for calculating
14645 * the drop zone intersection with this object.
14652 * Cached reference to the linked element
14653 * @property _domRef
14659 * Internal typeof flag
14660 * @property __ygDragDrop
14663 __ygDragDrop: true,
14666 * Set to true when horizontal contraints are applied
14667 * @property constrainX
14674 * Set to true when vertical contraints are applied
14675 * @property constrainY
14682 * The left constraint
14690 * The right constraint
14698 * The up constraint
14707 * The down constraint
14715 * Maintain offsets when we resetconstraints. Set to true when you want
14716 * the position of the element relative to its parent to stay the same
14717 * when the page changes
14719 * @property maintainOffset
14722 maintainOffset: false,
14725 * Array of pixel locations the element will snap to if we specified a
14726 * horizontal graduation/interval. This array is generated automatically
14727 * when you define a tick interval.
14734 * Array of pixel locations the element will snap to if we specified a
14735 * vertical graduation/interval. This array is generated automatically
14736 * when you define a tick interval.
14743 * By default the drag and drop instance will only respond to the primary
14744 * button click (left button for a right-handed mouse). Set to true to
14745 * allow drag and drop to start with any mouse click that is propogated
14747 * @property primaryButtonOnly
14750 primaryButtonOnly: true,
14753 * The availabe property is false until the linked dom element is accessible.
14754 * @property available
14760 * By default, drags can only be initiated if the mousedown occurs in the
14761 * region the linked element is. This is done in part to work around a
14762 * bug in some browsers that mis-report the mousedown if the previous
14763 * mouseup happened outside of the window. This property is set to true
14764 * if outer handles are defined.
14766 * @property hasOuterHandles
14770 hasOuterHandles: false,
14773 * Code that executes immediately before the startDrag event
14774 * @method b4StartDrag
14777 b4StartDrag: function(x, y) { },
14780 * Abstract method called after a drag/drop object is clicked
14781 * and the drag or mousedown time thresholds have beeen met.
14782 * @method startDrag
14783 * @param {int} X click location
14784 * @param {int} Y click location
14786 startDrag: function(x, y) { /* override this */ },
14789 * Code that executes immediately before the onDrag event
14793 b4Drag: function(e) { },
14796 * Abstract method called during the onMouseMove event while dragging an
14799 * @param {Event} e the mousemove event
14801 onDrag: function(e) { /* override this */ },
14804 * Abstract method called when this element fist begins hovering over
14805 * another DragDrop obj
14806 * @method onDragEnter
14807 * @param {Event} e the mousemove event
14808 * @param {String|DragDrop[]} id In POINT mode, the element
14809 * id this is hovering over. In INTERSECT mode, an array of one or more
14810 * dragdrop items being hovered over.
14812 onDragEnter: function(e, id) { /* override this */ },
14815 * Code that executes immediately before the onDragOver event
14816 * @method b4DragOver
14819 b4DragOver: function(e) { },
14822 * Abstract method called when this element is hovering over another
14824 * @method onDragOver
14825 * @param {Event} e the mousemove event
14826 * @param {String|DragDrop[]} id In POINT mode, the element
14827 * id this is hovering over. In INTERSECT mode, an array of dd items
14828 * being hovered over.
14830 onDragOver: function(e, id) { /* override this */ },
14833 * Code that executes immediately before the onDragOut event
14834 * @method b4DragOut
14837 b4DragOut: function(e) { },
14840 * Abstract method called when we are no longer hovering over an element
14841 * @method onDragOut
14842 * @param {Event} e the mousemove event
14843 * @param {String|DragDrop[]} id In POINT mode, the element
14844 * id this was hovering over. In INTERSECT mode, an array of dd items
14845 * that the mouse is no longer over.
14847 onDragOut: function(e, id) { /* override this */ },
14850 * Code that executes immediately before the onDragDrop event
14851 * @method b4DragDrop
14854 b4DragDrop: function(e) { },
14857 * Abstract method called when this item is dropped on another DragDrop
14859 * @method onDragDrop
14860 * @param {Event} e the mouseup event
14861 * @param {String|DragDrop[]} id In POINT mode, the element
14862 * id this was dropped on. In INTERSECT mode, an array of dd items this
14865 onDragDrop: function(e, id) { /* override this */ },
14868 * Abstract method called when this item is dropped on an area with no
14870 * @method onInvalidDrop
14871 * @param {Event} e the mouseup event
14873 onInvalidDrop: function(e) { /* override this */ },
14876 * Code that executes immediately before the endDrag event
14877 * @method b4EndDrag
14880 b4EndDrag: function(e) { },
14883 * Fired when we are done dragging the object
14885 * @param {Event} e the mouseup event
14887 endDrag: function(e) { /* override this */ },
14890 * Code executed immediately before the onMouseDown event
14891 * @method b4MouseDown
14892 * @param {Event} e the mousedown event
14895 b4MouseDown: function(e) { },
14898 * Event handler that fires when a drag/drop obj gets a mousedown
14899 * @method onMouseDown
14900 * @param {Event} e the mousedown event
14902 onMouseDown: function(e) { /* override this */ },
14905 * Event handler that fires when a drag/drop obj gets a mouseup
14906 * @method onMouseUp
14907 * @param {Event} e the mouseup event
14909 onMouseUp: function(e) { /* override this */ },
14912 * Override the onAvailable method to do what is needed after the initial
14913 * position was determined.
14914 * @method onAvailable
14916 onAvailable: function () {
14920 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14923 defaultPadding : {left:0, right:0, top:0, bottom:0},
14926 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14930 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14931 { dragElId: "existingProxyDiv" });
14932 dd.startDrag = function(){
14933 this.constrainTo("parent-id");
14936 * Or you can initalize it using the {@link Roo.Element} object:
14938 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14939 startDrag : function(){
14940 this.constrainTo("parent-id");
14944 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14945 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14946 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14947 * an object containing the sides to pad. For example: {right:10, bottom:10}
14948 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14950 constrainTo : function(constrainTo, pad, inContent){
14951 if(typeof pad == "number"){
14952 pad = {left: pad, right:pad, top:pad, bottom:pad};
14954 pad = pad || this.defaultPadding;
14955 var b = Roo.get(this.getEl()).getBox();
14956 var ce = Roo.get(constrainTo);
14957 var s = ce.getScroll();
14958 var c, cd = ce.dom;
14959 if(cd == document.body){
14960 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14963 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14967 var topSpace = b.y - c.y;
14968 var leftSpace = b.x - c.x;
14970 this.resetConstraints();
14971 this.setXConstraint(leftSpace - (pad.left||0), // left
14972 c.width - leftSpace - b.width - (pad.right||0) //right
14974 this.setYConstraint(topSpace - (pad.top||0), //top
14975 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14980 * Returns a reference to the linked element
14982 * @return {HTMLElement} the html element
14984 getEl: function() {
14985 if (!this._domRef) {
14986 this._domRef = Roo.getDom(this.id);
14989 return this._domRef;
14993 * Returns a reference to the actual element to drag. By default this is
14994 * the same as the html element, but it can be assigned to another
14995 * element. An example of this can be found in Roo.dd.DDProxy
14996 * @method getDragEl
14997 * @return {HTMLElement} the html element
14999 getDragEl: function() {
15000 return Roo.getDom(this.dragElId);
15004 * Sets up the DragDrop object. Must be called in the constructor of any
15005 * Roo.dd.DragDrop subclass
15007 * @param id the id of the linked element
15008 * @param {String} sGroup the group of related items
15009 * @param {object} config configuration attributes
15011 init: function(id, sGroup, config) {
15012 this.initTarget(id, sGroup, config);
15013 Event.on(this.id, "mousedown", this.handleMouseDown, this);
15014 // Event.on(this.id, "selectstart", Event.preventDefault);
15018 * Initializes Targeting functionality only... the object does not
15019 * get a mousedown handler.
15020 * @method initTarget
15021 * @param id the id of the linked element
15022 * @param {String} sGroup the group of related items
15023 * @param {object} config configuration attributes
15025 initTarget: function(id, sGroup, config) {
15027 // configuration attributes
15028 this.config = config || {};
15030 // create a local reference to the drag and drop manager
15031 this.DDM = Roo.dd.DDM;
15032 // initialize the groups array
15035 // assume that we have an element reference instead of an id if the
15036 // parameter is not a string
15037 if (typeof id !== "string") {
15044 // add to an interaction group
15045 this.addToGroup((sGroup) ? sGroup : "default");
15047 // We don't want to register this as the handle with the manager
15048 // so we just set the id rather than calling the setter.
15049 this.handleElId = id;
15051 // the linked element is the element that gets dragged by default
15052 this.setDragElId(id);
15054 // by default, clicked anchors will not start drag operations.
15055 this.invalidHandleTypes = { A: "A" };
15056 this.invalidHandleIds = {};
15057 this.invalidHandleClasses = [];
15059 this.applyConfig();
15061 this.handleOnAvailable();
15065 * Applies the configuration parameters that were passed into the constructor.
15066 * This is supposed to happen at each level through the inheritance chain. So
15067 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15068 * DragDrop in order to get all of the parameters that are available in
15070 * @method applyConfig
15072 applyConfig: function() {
15074 // configurable properties:
15075 // padding, isTarget, maintainOffset, primaryButtonOnly
15076 this.padding = this.config.padding || [0, 0, 0, 0];
15077 this.isTarget = (this.config.isTarget !== false);
15078 this.maintainOffset = (this.config.maintainOffset);
15079 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15084 * Executed when the linked element is available
15085 * @method handleOnAvailable
15088 handleOnAvailable: function() {
15089 this.available = true;
15090 this.resetConstraints();
15091 this.onAvailable();
15095 * Configures the padding for the target zone in px. Effectively expands
15096 * (or reduces) the virtual object size for targeting calculations.
15097 * Supports css-style shorthand; if only one parameter is passed, all sides
15098 * will have that padding, and if only two are passed, the top and bottom
15099 * will have the first param, the left and right the second.
15100 * @method setPadding
15101 * @param {int} iTop Top pad
15102 * @param {int} iRight Right pad
15103 * @param {int} iBot Bot pad
15104 * @param {int} iLeft Left pad
15106 setPadding: function(iTop, iRight, iBot, iLeft) {
15107 // this.padding = [iLeft, iRight, iTop, iBot];
15108 if (!iRight && 0 !== iRight) {
15109 this.padding = [iTop, iTop, iTop, iTop];
15110 } else if (!iBot && 0 !== iBot) {
15111 this.padding = [iTop, iRight, iTop, iRight];
15113 this.padding = [iTop, iRight, iBot, iLeft];
15118 * Stores the initial placement of the linked element.
15119 * @method setInitialPosition
15120 * @param {int} diffX the X offset, default 0
15121 * @param {int} diffY the Y offset, default 0
15123 setInitPosition: function(diffX, diffY) {
15124 var el = this.getEl();
15126 if (!this.DDM.verifyEl(el)) {
15130 var dx = diffX || 0;
15131 var dy = diffY || 0;
15133 var p = Dom.getXY( el );
15135 this.initPageX = p[0] - dx;
15136 this.initPageY = p[1] - dy;
15138 this.lastPageX = p[0];
15139 this.lastPageY = p[1];
15142 this.setStartPosition(p);
15146 * Sets the start position of the element. This is set when the obj
15147 * is initialized, the reset when a drag is started.
15148 * @method setStartPosition
15149 * @param pos current position (from previous lookup)
15152 setStartPosition: function(pos) {
15153 var p = pos || Dom.getXY( this.getEl() );
15154 this.deltaSetXY = null;
15156 this.startPageX = p[0];
15157 this.startPageY = p[1];
15161 * Add this instance to a group of related drag/drop objects. All
15162 * instances belong to at least one group, and can belong to as many
15163 * groups as needed.
15164 * @method addToGroup
15165 * @param sGroup {string} the name of the group
15167 addToGroup: function(sGroup) {
15168 this.groups[sGroup] = true;
15169 this.DDM.regDragDrop(this, sGroup);
15173 * Remove's this instance from the supplied interaction group
15174 * @method removeFromGroup
15175 * @param {string} sGroup The group to drop
15177 removeFromGroup: function(sGroup) {
15178 if (this.groups[sGroup]) {
15179 delete this.groups[sGroup];
15182 this.DDM.removeDDFromGroup(this, sGroup);
15186 * Allows you to specify that an element other than the linked element
15187 * will be moved with the cursor during a drag
15188 * @method setDragElId
15189 * @param id {string} the id of the element that will be used to initiate the drag
15191 setDragElId: function(id) {
15192 this.dragElId = id;
15196 * Allows you to specify a child of the linked element that should be
15197 * used to initiate the drag operation. An example of this would be if
15198 * you have a content div with text and links. Clicking anywhere in the
15199 * content area would normally start the drag operation. Use this method
15200 * to specify that an element inside of the content div is the element
15201 * that starts the drag operation.
15202 * @method setHandleElId
15203 * @param id {string} the id of the element that will be used to
15204 * initiate the drag.
15206 setHandleElId: function(id) {
15207 if (typeof id !== "string") {
15210 this.handleElId = id;
15211 this.DDM.regHandle(this.id, id);
15215 * Allows you to set an element outside of the linked element as a drag
15217 * @method setOuterHandleElId
15218 * @param id the id of the element that will be used to initiate the drag
15220 setOuterHandleElId: function(id) {
15221 if (typeof id !== "string") {
15224 Event.on(id, "mousedown",
15225 this.handleMouseDown, this);
15226 this.setHandleElId(id);
15228 this.hasOuterHandles = true;
15232 * Remove all drag and drop hooks for this element
15235 unreg: function() {
15236 Event.un(this.id, "mousedown",
15237 this.handleMouseDown);
15238 this._domRef = null;
15239 this.DDM._remove(this);
15242 destroy : function(){
15247 * Returns true if this instance is locked, or the drag drop mgr is locked
15248 * (meaning that all drag/drop is disabled on the page.)
15250 * @return {boolean} true if this obj or all drag/drop is locked, else
15253 isLocked: function() {
15254 return (this.DDM.isLocked() || this.locked);
15258 * Fired when this object is clicked
15259 * @method handleMouseDown
15261 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15264 handleMouseDown: function(e, oDD){
15265 if (this.primaryButtonOnly && e.button != 0) {
15269 if (this.isLocked()) {
15273 this.DDM.refreshCache(this.groups);
15275 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15276 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15278 if (this.clickValidator(e)) {
15280 // set the initial element position
15281 this.setStartPosition();
15284 this.b4MouseDown(e);
15285 this.onMouseDown(e);
15287 this.DDM.handleMouseDown(e, this);
15289 this.DDM.stopEvent(e);
15297 clickValidator: function(e) {
15298 var target = e.getTarget();
15299 return ( this.isValidHandleChild(target) &&
15300 (this.id == this.handleElId ||
15301 this.DDM.handleWasClicked(target, this.id)) );
15305 * Allows you to specify a tag name that should not start a drag operation
15306 * when clicked. This is designed to facilitate embedding links within a
15307 * drag handle that do something other than start the drag.
15308 * @method addInvalidHandleType
15309 * @param {string} tagName the type of element to exclude
15311 addInvalidHandleType: function(tagName) {
15312 var type = tagName.toUpperCase();
15313 this.invalidHandleTypes[type] = type;
15317 * Lets you to specify an element id for a child of a drag handle
15318 * that should not initiate a drag
15319 * @method addInvalidHandleId
15320 * @param {string} id the element id of the element you wish to ignore
15322 addInvalidHandleId: function(id) {
15323 if (typeof id !== "string") {
15326 this.invalidHandleIds[id] = id;
15330 * Lets you specify a css class of elements that will not initiate a drag
15331 * @method addInvalidHandleClass
15332 * @param {string} cssClass the class of the elements you wish to ignore
15334 addInvalidHandleClass: function(cssClass) {
15335 this.invalidHandleClasses.push(cssClass);
15339 * Unsets an excluded tag name set by addInvalidHandleType
15340 * @method removeInvalidHandleType
15341 * @param {string} tagName the type of element to unexclude
15343 removeInvalidHandleType: function(tagName) {
15344 var type = tagName.toUpperCase();
15345 // this.invalidHandleTypes[type] = null;
15346 delete this.invalidHandleTypes[type];
15350 * Unsets an invalid handle id
15351 * @method removeInvalidHandleId
15352 * @param {string} id the id of the element to re-enable
15354 removeInvalidHandleId: function(id) {
15355 if (typeof id !== "string") {
15358 delete this.invalidHandleIds[id];
15362 * Unsets an invalid css class
15363 * @method removeInvalidHandleClass
15364 * @param {string} cssClass the class of the element(s) you wish to
15367 removeInvalidHandleClass: function(cssClass) {
15368 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15369 if (this.invalidHandleClasses[i] == cssClass) {
15370 delete this.invalidHandleClasses[i];
15376 * Checks the tag exclusion list to see if this click should be ignored
15377 * @method isValidHandleChild
15378 * @param {HTMLElement} node the HTMLElement to evaluate
15379 * @return {boolean} true if this is a valid tag type, false if not
15381 isValidHandleChild: function(node) {
15384 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15387 nodeName = node.nodeName.toUpperCase();
15389 nodeName = node.nodeName;
15391 valid = valid && !this.invalidHandleTypes[nodeName];
15392 valid = valid && !this.invalidHandleIds[node.id];
15394 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15395 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15404 * Create the array of horizontal tick marks if an interval was specified
15405 * in setXConstraint().
15406 * @method setXTicks
15409 setXTicks: function(iStartX, iTickSize) {
15411 this.xTickSize = iTickSize;
15415 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15417 this.xTicks[this.xTicks.length] = i;
15422 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15424 this.xTicks[this.xTicks.length] = i;
15429 this.xTicks.sort(this.DDM.numericSort) ;
15433 * Create the array of vertical tick marks if an interval was specified in
15434 * setYConstraint().
15435 * @method setYTicks
15438 setYTicks: function(iStartY, iTickSize) {
15440 this.yTickSize = iTickSize;
15444 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15446 this.yTicks[this.yTicks.length] = i;
15451 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15453 this.yTicks[this.yTicks.length] = i;
15458 this.yTicks.sort(this.DDM.numericSort) ;
15462 * By default, the element can be dragged any place on the screen. Use
15463 * this method to limit the horizontal travel of the element. Pass in
15464 * 0,0 for the parameters if you want to lock the drag to the y axis.
15465 * @method setXConstraint
15466 * @param {int} iLeft the number of pixels the element can move to the left
15467 * @param {int} iRight the number of pixels the element can move to the
15469 * @param {int} iTickSize optional parameter for specifying that the
15471 * should move iTickSize pixels at a time.
15473 setXConstraint: function(iLeft, iRight, iTickSize) {
15474 this.leftConstraint = iLeft;
15475 this.rightConstraint = iRight;
15477 this.minX = this.initPageX - iLeft;
15478 this.maxX = this.initPageX + iRight;
15479 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15481 this.constrainX = true;
15485 * Clears any constraints applied to this instance. Also clears ticks
15486 * since they can't exist independent of a constraint at this time.
15487 * @method clearConstraints
15489 clearConstraints: function() {
15490 this.constrainX = false;
15491 this.constrainY = false;
15496 * Clears any tick interval defined for this instance
15497 * @method clearTicks
15499 clearTicks: function() {
15500 this.xTicks = null;
15501 this.yTicks = null;
15502 this.xTickSize = 0;
15503 this.yTickSize = 0;
15507 * By default, the element can be dragged any place on the screen. Set
15508 * this to limit the vertical travel of the element. Pass in 0,0 for the
15509 * parameters if you want to lock the drag to the x axis.
15510 * @method setYConstraint
15511 * @param {int} iUp the number of pixels the element can move up
15512 * @param {int} iDown the number of pixels the element can move down
15513 * @param {int} iTickSize optional parameter for specifying that the
15514 * element should move iTickSize pixels at a time.
15516 setYConstraint: function(iUp, iDown, iTickSize) {
15517 this.topConstraint = iUp;
15518 this.bottomConstraint = iDown;
15520 this.minY = this.initPageY - iUp;
15521 this.maxY = this.initPageY + iDown;
15522 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15524 this.constrainY = true;
15529 * resetConstraints must be called if you manually reposition a dd element.
15530 * @method resetConstraints
15531 * @param {boolean} maintainOffset
15533 resetConstraints: function() {
15536 // Maintain offsets if necessary
15537 if (this.initPageX || this.initPageX === 0) {
15538 // figure out how much this thing has moved
15539 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15540 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15542 this.setInitPosition(dx, dy);
15544 // This is the first time we have detected the element's position
15546 this.setInitPosition();
15549 if (this.constrainX) {
15550 this.setXConstraint( this.leftConstraint,
15551 this.rightConstraint,
15555 if (this.constrainY) {
15556 this.setYConstraint( this.topConstraint,
15557 this.bottomConstraint,
15563 * Normally the drag element is moved pixel by pixel, but we can specify
15564 * that it move a number of pixels at a time. This method resolves the
15565 * location when we have it set up like this.
15567 * @param {int} val where we want to place the object
15568 * @param {int[]} tickArray sorted array of valid points
15569 * @return {int} the closest tick
15572 getTick: function(val, tickArray) {
15575 // If tick interval is not defined, it is effectively 1 pixel,
15576 // so we return the value passed to us.
15578 } else if (tickArray[0] >= val) {
15579 // The value is lower than the first tick, so we return the first
15581 return tickArray[0];
15583 for (var i=0, len=tickArray.length; i<len; ++i) {
15585 if (tickArray[next] && tickArray[next] >= val) {
15586 var diff1 = val - tickArray[i];
15587 var diff2 = tickArray[next] - val;
15588 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15592 // The value is larger than the last tick, so we return the last
15594 return tickArray[tickArray.length - 1];
15601 * @return {string} string representation of the dd obj
15603 toString: function() {
15604 return ("DragDrop " + this.id);
15612 * Ext JS Library 1.1.1
15613 * Copyright(c) 2006-2007, Ext JS, LLC.
15615 * Originally Released Under LGPL - original licence link has changed is not relivant.
15618 * <script type="text/javascript">
15623 * The drag and drop utility provides a framework for building drag and drop
15624 * applications. In addition to enabling drag and drop for specific elements,
15625 * the drag and drop elements are tracked by the manager class, and the
15626 * interactions between the various elements are tracked during the drag and
15627 * the implementing code is notified about these important moments.
15630 // Only load the library once. Rewriting the manager class would orphan
15631 // existing drag and drop instances.
15632 if (!Roo.dd.DragDropMgr) {
15635 * @class Roo.dd.DragDropMgr
15636 * DragDropMgr is a singleton that tracks the element interaction for
15637 * all DragDrop items in the window. Generally, you will not call
15638 * this class directly, but it does have helper methods that could
15639 * be useful in your DragDrop implementations.
15642 Roo.dd.DragDropMgr = function() {
15644 var Event = Roo.EventManager;
15649 * Two dimensional Array of registered DragDrop objects. The first
15650 * dimension is the DragDrop item group, the second the DragDrop
15653 * @type {string: string}
15660 * Array of element ids defined as drag handles. Used to determine
15661 * if the element that generated the mousedown event is actually the
15662 * handle and not the html element itself.
15663 * @property handleIds
15664 * @type {string: string}
15671 * the DragDrop object that is currently being dragged
15672 * @property dragCurrent
15680 * the DragDrop object(s) that are being hovered over
15681 * @property dragOvers
15689 * the X distance between the cursor and the object being dragged
15698 * the Y distance between the cursor and the object being dragged
15707 * Flag to determine if we should prevent the default behavior of the
15708 * events we define. By default this is true, but this can be set to
15709 * false if you need the default behavior (not recommended)
15710 * @property preventDefault
15714 preventDefault: true,
15717 * Flag to determine if we should stop the propagation of the events
15718 * we generate. This is true by default but you may want to set it to
15719 * false if the html element contains other features that require the
15721 * @property stopPropagation
15725 stopPropagation: true,
15728 * Internal flag that is set to true when drag and drop has been
15730 * @property initialized
15737 * All drag and drop can be disabled.
15745 * Called the first time an element is registered.
15751 this.initialized = true;
15755 * In point mode, drag and drop interaction is defined by the
15756 * location of the cursor during the drag/drop
15764 * In intersect mode, drag and drop interactio nis defined by the
15765 * overlap of two or more drag and drop objects.
15766 * @property INTERSECT
15773 * The current drag and drop mode. Default: POINT
15781 * Runs method on all drag and drop objects
15782 * @method _execOnAll
15786 _execOnAll: function(sMethod, args) {
15787 for (var i in this.ids) {
15788 for (var j in this.ids[i]) {
15789 var oDD = this.ids[i][j];
15790 if (! this.isTypeOfDD(oDD)) {
15793 oDD[sMethod].apply(oDD, args);
15799 * Drag and drop initialization. Sets up the global event handlers
15804 _onLoad: function() {
15809 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15810 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15811 Event.on(window, "unload", this._onUnload, this, true);
15812 Event.on(window, "resize", this._onResize, this, true);
15813 // Event.on(window, "mouseout", this._test);
15818 * Reset constraints on all drag and drop objs
15819 * @method _onResize
15823 _onResize: function(e) {
15824 this._execOnAll("resetConstraints", []);
15828 * Lock all drag and drop functionality
15832 lock: function() { this.locked = true; },
15835 * Unlock all drag and drop functionality
15839 unlock: function() { this.locked = false; },
15842 * Is drag and drop locked?
15844 * @return {boolean} True if drag and drop is locked, false otherwise.
15847 isLocked: function() { return this.locked; },
15850 * Location cache that is set for all drag drop objects when a drag is
15851 * initiated, cleared when the drag is finished.
15852 * @property locationCache
15859 * Set useCache to false if you want to force object the lookup of each
15860 * drag and drop linked element constantly during a drag.
15861 * @property useCache
15868 * The number of pixels that the mouse needs to move after the
15869 * mousedown before the drag is initiated. Default=3;
15870 * @property clickPixelThresh
15874 clickPixelThresh: 3,
15877 * The number of milliseconds after the mousedown event to initiate the
15878 * drag if we don't get a mouseup event. Default=1000
15879 * @property clickTimeThresh
15883 clickTimeThresh: 350,
15886 * Flag that indicates that either the drag pixel threshold or the
15887 * mousdown time threshold has been met
15888 * @property dragThreshMet
15893 dragThreshMet: false,
15896 * Timeout used for the click time threshold
15897 * @property clickTimeout
15902 clickTimeout: null,
15905 * The X position of the mousedown event stored for later use when a
15906 * drag threshold is met.
15915 * The Y position of the mousedown event stored for later use when a
15916 * drag threshold is met.
15925 * Each DragDrop instance must be registered with the DragDropMgr.
15926 * This is executed in DragDrop.init()
15927 * @method regDragDrop
15928 * @param {DragDrop} oDD the DragDrop object to register
15929 * @param {String} sGroup the name of the group this element belongs to
15932 regDragDrop: function(oDD, sGroup) {
15933 if (!this.initialized) { this.init(); }
15935 if (!this.ids[sGroup]) {
15936 this.ids[sGroup] = {};
15938 this.ids[sGroup][oDD.id] = oDD;
15942 * Removes the supplied dd instance from the supplied group. Executed
15943 * by DragDrop.removeFromGroup, so don't call this function directly.
15944 * @method removeDDFromGroup
15948 removeDDFromGroup: function(oDD, sGroup) {
15949 if (!this.ids[sGroup]) {
15950 this.ids[sGroup] = {};
15953 var obj = this.ids[sGroup];
15954 if (obj && obj[oDD.id]) {
15955 delete obj[oDD.id];
15960 * Unregisters a drag and drop item. This is executed in
15961 * DragDrop.unreg, use that method instead of calling this directly.
15966 _remove: function(oDD) {
15967 for (var g in oDD.groups) {
15968 if (g && this.ids[g][oDD.id]) {
15969 delete this.ids[g][oDD.id];
15972 delete this.handleIds[oDD.id];
15976 * Each DragDrop handle element must be registered. This is done
15977 * automatically when executing DragDrop.setHandleElId()
15978 * @method regHandle
15979 * @param {String} sDDId the DragDrop id this element is a handle for
15980 * @param {String} sHandleId the id of the element that is the drag
15984 regHandle: function(sDDId, sHandleId) {
15985 if (!this.handleIds[sDDId]) {
15986 this.handleIds[sDDId] = {};
15988 this.handleIds[sDDId][sHandleId] = sHandleId;
15992 * Utility function to determine if a given element has been
15993 * registered as a drag drop item.
15994 * @method isDragDrop
15995 * @param {String} id the element id to check
15996 * @return {boolean} true if this element is a DragDrop item,
16000 isDragDrop: function(id) {
16001 return ( this.getDDById(id) ) ? true : false;
16005 * Returns the drag and drop instances that are in all groups the
16006 * passed in instance belongs to.
16007 * @method getRelated
16008 * @param {DragDrop} p_oDD the obj to get related data for
16009 * @param {boolean} bTargetsOnly if true, only return targetable objs
16010 * @return {DragDrop[]} the related instances
16013 getRelated: function(p_oDD, bTargetsOnly) {
16015 for (var i in p_oDD.groups) {
16016 for (j in this.ids[i]) {
16017 var dd = this.ids[i][j];
16018 if (! this.isTypeOfDD(dd)) {
16021 if (!bTargetsOnly || dd.isTarget) {
16022 oDDs[oDDs.length] = dd;
16031 * Returns true if the specified dd target is a legal target for
16032 * the specifice drag obj
16033 * @method isLegalTarget
16034 * @param {DragDrop} the drag obj
16035 * @param {DragDrop} the target
16036 * @return {boolean} true if the target is a legal target for the
16040 isLegalTarget: function (oDD, oTargetDD) {
16041 var targets = this.getRelated(oDD, true);
16042 for (var i=0, len=targets.length;i<len;++i) {
16043 if (targets[i].id == oTargetDD.id) {
16052 * My goal is to be able to transparently determine if an object is
16053 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16054 * returns "object", oDD.constructor.toString() always returns
16055 * "DragDrop" and not the name of the subclass. So for now it just
16056 * evaluates a well-known variable in DragDrop.
16057 * @method isTypeOfDD
16058 * @param {Object} the object to evaluate
16059 * @return {boolean} true if typeof oDD = DragDrop
16062 isTypeOfDD: function (oDD) {
16063 return (oDD && oDD.__ygDragDrop);
16067 * Utility function to determine if a given element has been
16068 * registered as a drag drop handle for the given Drag Drop object.
16070 * @param {String} id the element id to check
16071 * @return {boolean} true if this element is a DragDrop handle, false
16075 isHandle: function(sDDId, sHandleId) {
16076 return ( this.handleIds[sDDId] &&
16077 this.handleIds[sDDId][sHandleId] );
16081 * Returns the DragDrop instance for a given id
16082 * @method getDDById
16083 * @param {String} id the id of the DragDrop object
16084 * @return {DragDrop} the drag drop object, null if it is not found
16087 getDDById: function(id) {
16088 for (var i in this.ids) {
16089 if (this.ids[i][id]) {
16090 return this.ids[i][id];
16097 * Fired after a registered DragDrop object gets the mousedown event.
16098 * Sets up the events required to track the object being dragged
16099 * @method handleMouseDown
16100 * @param {Event} e the event
16101 * @param oDD the DragDrop object being dragged
16105 handleMouseDown: function(e, oDD) {
16107 Roo.QuickTips.disable();
16109 this.currentTarget = e.getTarget();
16111 this.dragCurrent = oDD;
16113 var el = oDD.getEl();
16115 // track start position
16116 this.startX = e.getPageX();
16117 this.startY = e.getPageY();
16119 this.deltaX = this.startX - el.offsetLeft;
16120 this.deltaY = this.startY - el.offsetTop;
16122 this.dragThreshMet = false;
16124 this.clickTimeout = setTimeout(
16126 var DDM = Roo.dd.DDM;
16127 DDM.startDrag(DDM.startX, DDM.startY);
16129 this.clickTimeThresh );
16133 * Fired when either the drag pixel threshol or the mousedown hold
16134 * time threshold has been met.
16135 * @method startDrag
16136 * @param x {int} the X position of the original mousedown
16137 * @param y {int} the Y position of the original mousedown
16140 startDrag: function(x, y) {
16141 clearTimeout(this.clickTimeout);
16142 if (this.dragCurrent) {
16143 this.dragCurrent.b4StartDrag(x, y);
16144 this.dragCurrent.startDrag(x, y);
16146 this.dragThreshMet = true;
16150 * Internal function to handle the mouseup event. Will be invoked
16151 * from the context of the document.
16152 * @method handleMouseUp
16153 * @param {Event} e the event
16157 handleMouseUp: function(e) {
16160 Roo.QuickTips.enable();
16162 if (! this.dragCurrent) {
16166 clearTimeout(this.clickTimeout);
16168 if (this.dragThreshMet) {
16169 this.fireEvents(e, true);
16179 * Utility to stop event propagation and event default, if these
16180 * features are turned on.
16181 * @method stopEvent
16182 * @param {Event} e the event as returned by this.getEvent()
16185 stopEvent: function(e){
16186 if(this.stopPropagation) {
16187 e.stopPropagation();
16190 if (this.preventDefault) {
16191 e.preventDefault();
16196 * Internal function to clean up event handlers after the drag
16197 * operation is complete
16199 * @param {Event} e the event
16203 stopDrag: function(e) {
16204 // Fire the drag end event for the item that was dragged
16205 if (this.dragCurrent) {
16206 if (this.dragThreshMet) {
16207 this.dragCurrent.b4EndDrag(e);
16208 this.dragCurrent.endDrag(e);
16211 this.dragCurrent.onMouseUp(e);
16214 this.dragCurrent = null;
16215 this.dragOvers = {};
16219 * Internal function to handle the mousemove event. Will be invoked
16220 * from the context of the html element.
16222 * @TODO figure out what we can do about mouse events lost when the
16223 * user drags objects beyond the window boundary. Currently we can
16224 * detect this in internet explorer by verifying that the mouse is
16225 * down during the mousemove event. Firefox doesn't give us the
16226 * button state on the mousemove event.
16227 * @method handleMouseMove
16228 * @param {Event} e the event
16232 handleMouseMove: function(e) {
16233 if (! this.dragCurrent) {
16237 // var button = e.which || e.button;
16239 // check for IE mouseup outside of page boundary
16240 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16242 return this.handleMouseUp(e);
16245 if (!this.dragThreshMet) {
16246 var diffX = Math.abs(this.startX - e.getPageX());
16247 var diffY = Math.abs(this.startY - e.getPageY());
16248 if (diffX > this.clickPixelThresh ||
16249 diffY > this.clickPixelThresh) {
16250 this.startDrag(this.startX, this.startY);
16254 if (this.dragThreshMet) {
16255 this.dragCurrent.b4Drag(e);
16256 this.dragCurrent.onDrag(e);
16257 if(!this.dragCurrent.moveOnly){
16258 this.fireEvents(e, false);
16268 * Iterates over all of the DragDrop elements to find ones we are
16269 * hovering over or dropping on
16270 * @method fireEvents
16271 * @param {Event} e the event
16272 * @param {boolean} isDrop is this a drop op or a mouseover op?
16276 fireEvents: function(e, isDrop) {
16277 var dc = this.dragCurrent;
16279 // If the user did the mouse up outside of the window, we could
16280 // get here even though we have ended the drag.
16281 if (!dc || dc.isLocked()) {
16285 var pt = e.getPoint();
16287 // cache the previous dragOver array
16293 var enterEvts = [];
16295 // Check to see if the object(s) we were hovering over is no longer
16296 // being hovered over so we can fire the onDragOut event
16297 for (var i in this.dragOvers) {
16299 var ddo = this.dragOvers[i];
16301 if (! this.isTypeOfDD(ddo)) {
16305 if (! this.isOverTarget(pt, ddo, this.mode)) {
16306 outEvts.push( ddo );
16309 oldOvers[i] = true;
16310 delete this.dragOvers[i];
16313 for (var sGroup in dc.groups) {
16315 if ("string" != typeof sGroup) {
16319 for (i in this.ids[sGroup]) {
16320 var oDD = this.ids[sGroup][i];
16321 if (! this.isTypeOfDD(oDD)) {
16325 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16326 if (this.isOverTarget(pt, oDD, this.mode)) {
16327 // look for drop interactions
16329 dropEvts.push( oDD );
16330 // look for drag enter and drag over interactions
16333 // initial drag over: dragEnter fires
16334 if (!oldOvers[oDD.id]) {
16335 enterEvts.push( oDD );
16336 // subsequent drag overs: dragOver fires
16338 overEvts.push( oDD );
16341 this.dragOvers[oDD.id] = oDD;
16349 if (outEvts.length) {
16350 dc.b4DragOut(e, outEvts);
16351 dc.onDragOut(e, outEvts);
16354 if (enterEvts.length) {
16355 dc.onDragEnter(e, enterEvts);
16358 if (overEvts.length) {
16359 dc.b4DragOver(e, overEvts);
16360 dc.onDragOver(e, overEvts);
16363 if (dropEvts.length) {
16364 dc.b4DragDrop(e, dropEvts);
16365 dc.onDragDrop(e, dropEvts);
16369 // fire dragout events
16371 for (i=0, len=outEvts.length; i<len; ++i) {
16372 dc.b4DragOut(e, outEvts[i].id);
16373 dc.onDragOut(e, outEvts[i].id);
16376 // fire enter events
16377 for (i=0,len=enterEvts.length; i<len; ++i) {
16378 // dc.b4DragEnter(e, oDD.id);
16379 dc.onDragEnter(e, enterEvts[i].id);
16382 // fire over events
16383 for (i=0,len=overEvts.length; i<len; ++i) {
16384 dc.b4DragOver(e, overEvts[i].id);
16385 dc.onDragOver(e, overEvts[i].id);
16388 // fire drop events
16389 for (i=0, len=dropEvts.length; i<len; ++i) {
16390 dc.b4DragDrop(e, dropEvts[i].id);
16391 dc.onDragDrop(e, dropEvts[i].id);
16396 // notify about a drop that did not find a target
16397 if (isDrop && !dropEvts.length) {
16398 dc.onInvalidDrop(e);
16404 * Helper function for getting the best match from the list of drag
16405 * and drop objects returned by the drag and drop events when we are
16406 * in INTERSECT mode. It returns either the first object that the
16407 * cursor is over, or the object that has the greatest overlap with
16408 * the dragged element.
16409 * @method getBestMatch
16410 * @param {DragDrop[]} dds The array of drag and drop objects
16412 * @return {DragDrop} The best single match
16415 getBestMatch: function(dds) {
16417 // Return null if the input is not what we expect
16418 //if (!dds || !dds.length || dds.length == 0) {
16420 // If there is only one item, it wins
16421 //} else if (dds.length == 1) {
16423 var len = dds.length;
16428 // Loop through the targeted items
16429 for (var i=0; i<len; ++i) {
16431 // If the cursor is over the object, it wins. If the
16432 // cursor is over multiple matches, the first one we come
16434 if (dd.cursorIsOver) {
16437 // Otherwise the object with the most overlap wins
16440 winner.overlap.getArea() < dd.overlap.getArea()) {
16451 * Refreshes the cache of the top-left and bottom-right points of the
16452 * drag and drop objects in the specified group(s). This is in the
16453 * format that is stored in the drag and drop instance, so typical
16456 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16460 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16462 * @TODO this really should be an indexed array. Alternatively this
16463 * method could accept both.
16464 * @method refreshCache
16465 * @param {Object} groups an associative array of groups to refresh
16468 refreshCache: function(groups) {
16469 for (var sGroup in groups) {
16470 if ("string" != typeof sGroup) {
16473 for (var i in this.ids[sGroup]) {
16474 var oDD = this.ids[sGroup][i];
16476 if (this.isTypeOfDD(oDD)) {
16477 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16478 var loc = this.getLocation(oDD);
16480 this.locationCache[oDD.id] = loc;
16482 delete this.locationCache[oDD.id];
16483 // this will unregister the drag and drop object if
16484 // the element is not in a usable state
16493 * This checks to make sure an element exists and is in the DOM. The
16494 * main purpose is to handle cases where innerHTML is used to remove
16495 * drag and drop objects from the DOM. IE provides an 'unspecified
16496 * error' when trying to access the offsetParent of such an element
16498 * @param {HTMLElement} el the element to check
16499 * @return {boolean} true if the element looks usable
16502 verifyEl: function(el) {
16507 parent = el.offsetParent;
16510 parent = el.offsetParent;
16521 * Returns a Region object containing the drag and drop element's position
16522 * and size, including the padding configured for it
16523 * @method getLocation
16524 * @param {DragDrop} oDD the drag and drop object to get the
16526 * @return {Roo.lib.Region} a Region object representing the total area
16527 * the element occupies, including any padding
16528 * the instance is configured for.
16531 getLocation: function(oDD) {
16532 if (! this.isTypeOfDD(oDD)) {
16536 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16539 pos= Roo.lib.Dom.getXY(el);
16547 x2 = x1 + el.offsetWidth;
16549 y2 = y1 + el.offsetHeight;
16551 t = y1 - oDD.padding[0];
16552 r = x2 + oDD.padding[1];
16553 b = y2 + oDD.padding[2];
16554 l = x1 - oDD.padding[3];
16556 return new Roo.lib.Region( t, r, b, l );
16560 * Checks the cursor location to see if it over the target
16561 * @method isOverTarget
16562 * @param {Roo.lib.Point} pt The point to evaluate
16563 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16564 * @return {boolean} true if the mouse is over the target
16568 isOverTarget: function(pt, oTarget, intersect) {
16569 // use cache if available
16570 var loc = this.locationCache[oTarget.id];
16571 if (!loc || !this.useCache) {
16572 loc = this.getLocation(oTarget);
16573 this.locationCache[oTarget.id] = loc;
16581 oTarget.cursorIsOver = loc.contains( pt );
16583 // DragDrop is using this as a sanity check for the initial mousedown
16584 // in this case we are done. In POINT mode, if the drag obj has no
16585 // contraints, we are also done. Otherwise we need to evaluate the
16586 // location of the target as related to the actual location of the
16587 // dragged element.
16588 var dc = this.dragCurrent;
16589 if (!dc || !dc.getTargetCoord ||
16590 (!intersect && !dc.constrainX && !dc.constrainY)) {
16591 return oTarget.cursorIsOver;
16594 oTarget.overlap = null;
16596 // Get the current location of the drag element, this is the
16597 // location of the mouse event less the delta that represents
16598 // where the original mousedown happened on the element. We
16599 // need to consider constraints and ticks as well.
16600 var pos = dc.getTargetCoord(pt.x, pt.y);
16602 var el = dc.getDragEl();
16603 var curRegion = new Roo.lib.Region( pos.y,
16604 pos.x + el.offsetWidth,
16605 pos.y + el.offsetHeight,
16608 var overlap = curRegion.intersect(loc);
16611 oTarget.overlap = overlap;
16612 return (intersect) ? true : oTarget.cursorIsOver;
16619 * unload event handler
16620 * @method _onUnload
16624 _onUnload: function(e, me) {
16625 Roo.dd.DragDropMgr.unregAll();
16629 * Cleans up the drag and drop events and objects.
16634 unregAll: function() {
16636 if (this.dragCurrent) {
16638 this.dragCurrent = null;
16641 this._execOnAll("unreg", []);
16643 for (i in this.elementCache) {
16644 delete this.elementCache[i];
16647 this.elementCache = {};
16652 * A cache of DOM elements
16653 * @property elementCache
16660 * Get the wrapper for the DOM element specified
16661 * @method getElWrapper
16662 * @param {String} id the id of the element to get
16663 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16665 * @deprecated This wrapper isn't that useful
16668 getElWrapper: function(id) {
16669 var oWrapper = this.elementCache[id];
16670 if (!oWrapper || !oWrapper.el) {
16671 oWrapper = this.elementCache[id] =
16672 new this.ElementWrapper(Roo.getDom(id));
16678 * Returns the actual DOM element
16679 * @method getElement
16680 * @param {String} id the id of the elment to get
16681 * @return {Object} The element
16682 * @deprecated use Roo.getDom instead
16685 getElement: function(id) {
16686 return Roo.getDom(id);
16690 * Returns the style property for the DOM element (i.e.,
16691 * document.getElById(id).style)
16693 * @param {String} id the id of the elment to get
16694 * @return {Object} The style property of the element
16695 * @deprecated use Roo.getDom instead
16698 getCss: function(id) {
16699 var el = Roo.getDom(id);
16700 return (el) ? el.style : null;
16704 * Inner class for cached elements
16705 * @class DragDropMgr.ElementWrapper
16710 ElementWrapper: function(el) {
16715 this.el = el || null;
16720 this.id = this.el && el.id;
16722 * A reference to the style property
16725 this.css = this.el && el.style;
16729 * Returns the X position of an html element
16731 * @param el the element for which to get the position
16732 * @return {int} the X coordinate
16734 * @deprecated use Roo.lib.Dom.getX instead
16737 getPosX: function(el) {
16738 return Roo.lib.Dom.getX(el);
16742 * Returns the Y position of an html element
16744 * @param el the element for which to get the position
16745 * @return {int} the Y coordinate
16746 * @deprecated use Roo.lib.Dom.getY instead
16749 getPosY: function(el) {
16750 return Roo.lib.Dom.getY(el);
16754 * Swap two nodes. In IE, we use the native method, for others we
16755 * emulate the IE behavior
16757 * @param n1 the first node to swap
16758 * @param n2 the other node to swap
16761 swapNode: function(n1, n2) {
16765 var p = n2.parentNode;
16766 var s = n2.nextSibling;
16769 p.insertBefore(n1, n2);
16770 } else if (n2 == n1.nextSibling) {
16771 p.insertBefore(n2, n1);
16773 n1.parentNode.replaceChild(n2, n1);
16774 p.insertBefore(n1, s);
16780 * Returns the current scroll position
16781 * @method getScroll
16785 getScroll: function () {
16786 var t, l, dde=document.documentElement, db=document.body;
16787 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16789 l = dde.scrollLeft;
16796 return { top: t, left: l };
16800 * Returns the specified element style property
16802 * @param {HTMLElement} el the element
16803 * @param {string} styleProp the style property
16804 * @return {string} The value of the style property
16805 * @deprecated use Roo.lib.Dom.getStyle
16808 getStyle: function(el, styleProp) {
16809 return Roo.fly(el).getStyle(styleProp);
16813 * Gets the scrollTop
16814 * @method getScrollTop
16815 * @return {int} the document's scrollTop
16818 getScrollTop: function () { return this.getScroll().top; },
16821 * Gets the scrollLeft
16822 * @method getScrollLeft
16823 * @return {int} the document's scrollTop
16826 getScrollLeft: function () { return this.getScroll().left; },
16829 * Sets the x/y position of an element to the location of the
16832 * @param {HTMLElement} moveEl The element to move
16833 * @param {HTMLElement} targetEl The position reference element
16836 moveToEl: function (moveEl, targetEl) {
16837 var aCoord = Roo.lib.Dom.getXY(targetEl);
16838 Roo.lib.Dom.setXY(moveEl, aCoord);
16842 * Numeric array sort function
16843 * @method numericSort
16846 numericSort: function(a, b) { return (a - b); },
16850 * @property _timeoutCount
16857 * Trying to make the load order less important. Without this we get
16858 * an error if this file is loaded before the Event Utility.
16859 * @method _addListeners
16863 _addListeners: function() {
16864 var DDM = Roo.dd.DDM;
16865 if ( Roo.lib.Event && document ) {
16868 if (DDM._timeoutCount > 2000) {
16870 setTimeout(DDM._addListeners, 10);
16871 if (document && document.body) {
16872 DDM._timeoutCount += 1;
16879 * Recursively searches the immediate parent and all child nodes for
16880 * the handle element in order to determine wheter or not it was
16882 * @method handleWasClicked
16883 * @param node the html element to inspect
16886 handleWasClicked: function(node, id) {
16887 if (this.isHandle(id, node.id)) {
16890 // check to see if this is a text node child of the one we want
16891 var p = node.parentNode;
16894 if (this.isHandle(id, p.id)) {
16909 // shorter alias, save a few bytes
16910 Roo.dd.DDM = Roo.dd.DragDropMgr;
16911 Roo.dd.DDM._addListeners();
16915 * Ext JS Library 1.1.1
16916 * Copyright(c) 2006-2007, Ext JS, LLC.
16918 * Originally Released Under LGPL - original licence link has changed is not relivant.
16921 * <script type="text/javascript">
16926 * A DragDrop implementation where the linked element follows the
16927 * mouse cursor during a drag.
16928 * @extends Roo.dd.DragDrop
16930 * @param {String} id the id of the linked element
16931 * @param {String} sGroup the group of related DragDrop items
16932 * @param {object} config an object containing configurable attributes
16933 * Valid properties for DD:
16936 Roo.dd.DD = function(id, sGroup, config) {
16938 this.init(id, sGroup, config);
16942 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16945 * When set to true, the utility automatically tries to scroll the browser
16946 * window wehn a drag and drop element is dragged near the viewport boundary.
16947 * Defaults to true.
16954 * Sets the pointer offset to the distance between the linked element's top
16955 * left corner and the location the element was clicked
16956 * @method autoOffset
16957 * @param {int} iPageX the X coordinate of the click
16958 * @param {int} iPageY the Y coordinate of the click
16960 autoOffset: function(iPageX, iPageY) {
16961 var x = iPageX - this.startPageX;
16962 var y = iPageY - this.startPageY;
16963 this.setDelta(x, y);
16967 * Sets the pointer offset. You can call this directly to force the
16968 * offset to be in a particular location (e.g., pass in 0,0 to set it
16969 * to the center of the object)
16971 * @param {int} iDeltaX the distance from the left
16972 * @param {int} iDeltaY the distance from the top
16974 setDelta: function(iDeltaX, iDeltaY) {
16975 this.deltaX = iDeltaX;
16976 this.deltaY = iDeltaY;
16980 * Sets the drag element to the location of the mousedown or click event,
16981 * maintaining the cursor location relative to the location on the element
16982 * that was clicked. Override this if you want to place the element in a
16983 * location other than where the cursor is.
16984 * @method setDragElPos
16985 * @param {int} iPageX the X coordinate of the mousedown or drag event
16986 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16988 setDragElPos: function(iPageX, iPageY) {
16989 // the first time we do this, we are going to check to make sure
16990 // the element has css positioning
16992 var el = this.getDragEl();
16993 this.alignElWithMouse(el, iPageX, iPageY);
16997 * Sets the element to the location of the mousedown or click event,
16998 * maintaining the cursor location relative to the location on the element
16999 * that was clicked. Override this if you want to place the element in a
17000 * location other than where the cursor is.
17001 * @method alignElWithMouse
17002 * @param {HTMLElement} el the element to move
17003 * @param {int} iPageX the X coordinate of the mousedown or drag event
17004 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17006 alignElWithMouse: function(el, iPageX, iPageY) {
17007 var oCoord = this.getTargetCoord(iPageX, iPageY);
17008 var fly = el.dom ? el : Roo.fly(el);
17009 if (!this.deltaSetXY) {
17010 var aCoord = [oCoord.x, oCoord.y];
17012 var newLeft = fly.getLeft(true);
17013 var newTop = fly.getTop(true);
17014 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
17016 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
17019 this.cachePosition(oCoord.x, oCoord.y);
17020 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
17025 * Saves the most recent position so that we can reset the constraints and
17026 * tick marks on-demand. We need to know this so that we can calculate the
17027 * number of pixels the element is offset from its original position.
17028 * @method cachePosition
17029 * @param iPageX the current x position (optional, this just makes it so we
17030 * don't have to look it up again)
17031 * @param iPageY the current y position (optional, this just makes it so we
17032 * don't have to look it up again)
17034 cachePosition: function(iPageX, iPageY) {
17036 this.lastPageX = iPageX;
17037 this.lastPageY = iPageY;
17039 var aCoord = Roo.lib.Dom.getXY(this.getEl());
17040 this.lastPageX = aCoord[0];
17041 this.lastPageY = aCoord[1];
17046 * Auto-scroll the window if the dragged object has been moved beyond the
17047 * visible window boundary.
17048 * @method autoScroll
17049 * @param {int} x the drag element's x position
17050 * @param {int} y the drag element's y position
17051 * @param {int} h the height of the drag element
17052 * @param {int} w the width of the drag element
17055 autoScroll: function(x, y, h, w) {
17058 // The client height
17059 var clientH = Roo.lib.Dom.getViewWidth();
17061 // The client width
17062 var clientW = Roo.lib.Dom.getViewHeight();
17064 // The amt scrolled down
17065 var st = this.DDM.getScrollTop();
17067 // The amt scrolled right
17068 var sl = this.DDM.getScrollLeft();
17070 // Location of the bottom of the element
17073 // Location of the right of the element
17076 // The distance from the cursor to the bottom of the visible area,
17077 // adjusted so that we don't scroll if the cursor is beyond the
17078 // element drag constraints
17079 var toBot = (clientH + st - y - this.deltaY);
17081 // The distance from the cursor to the right of the visible area
17082 var toRight = (clientW + sl - x - this.deltaX);
17085 // How close to the edge the cursor must be before we scroll
17086 // var thresh = (document.all) ? 100 : 40;
17089 // How many pixels to scroll per autoscroll op. This helps to reduce
17090 // clunky scrolling. IE is more sensitive about this ... it needs this
17091 // value to be higher.
17092 var scrAmt = (document.all) ? 80 : 30;
17094 // Scroll down if we are near the bottom of the visible page and the
17095 // obj extends below the crease
17096 if ( bot > clientH && toBot < thresh ) {
17097 window.scrollTo(sl, st + scrAmt);
17100 // Scroll up if the window is scrolled down and the top of the object
17101 // goes above the top border
17102 if ( y < st && st > 0 && y - st < thresh ) {
17103 window.scrollTo(sl, st - scrAmt);
17106 // Scroll right if the obj is beyond the right border and the cursor is
17107 // near the border.
17108 if ( right > clientW && toRight < thresh ) {
17109 window.scrollTo(sl + scrAmt, st);
17112 // Scroll left if the window has been scrolled to the right and the obj
17113 // extends past the left border
17114 if ( x < sl && sl > 0 && x - sl < thresh ) {
17115 window.scrollTo(sl - scrAmt, st);
17121 * Finds the location the element should be placed if we want to move
17122 * it to where the mouse location less the click offset would place us.
17123 * @method getTargetCoord
17124 * @param {int} iPageX the X coordinate of the click
17125 * @param {int} iPageY the Y coordinate of the click
17126 * @return an object that contains the coordinates (Object.x and Object.y)
17129 getTargetCoord: function(iPageX, iPageY) {
17132 var x = iPageX - this.deltaX;
17133 var y = iPageY - this.deltaY;
17135 if (this.constrainX) {
17136 if (x < this.minX) { x = this.minX; }
17137 if (x > this.maxX) { x = this.maxX; }
17140 if (this.constrainY) {
17141 if (y < this.minY) { y = this.minY; }
17142 if (y > this.maxY) { y = this.maxY; }
17145 x = this.getTick(x, this.xTicks);
17146 y = this.getTick(y, this.yTicks);
17153 * Sets up config options specific to this class. Overrides
17154 * Roo.dd.DragDrop, but all versions of this method through the
17155 * inheritance chain are called
17157 applyConfig: function() {
17158 Roo.dd.DD.superclass.applyConfig.call(this);
17159 this.scroll = (this.config.scroll !== false);
17163 * Event that fires prior to the onMouseDown event. Overrides
17166 b4MouseDown: function(e) {
17167 // this.resetConstraints();
17168 this.autoOffset(e.getPageX(),
17173 * Event that fires prior to the onDrag event. Overrides
17176 b4Drag: function(e) {
17177 this.setDragElPos(e.getPageX(),
17181 toString: function() {
17182 return ("DD " + this.id);
17185 //////////////////////////////////////////////////////////////////////////
17186 // Debugging ygDragDrop events that can be overridden
17187 //////////////////////////////////////////////////////////////////////////
17189 startDrag: function(x, y) {
17192 onDrag: function(e) {
17195 onDragEnter: function(e, id) {
17198 onDragOver: function(e, id) {
17201 onDragOut: function(e, id) {
17204 onDragDrop: function(e, id) {
17207 endDrag: function(e) {
17214 * Ext JS Library 1.1.1
17215 * Copyright(c) 2006-2007, Ext JS, LLC.
17217 * Originally Released Under LGPL - original licence link has changed is not relivant.
17220 * <script type="text/javascript">
17224 * @class Roo.dd.DDProxy
17225 * A DragDrop implementation that inserts an empty, bordered div into
17226 * the document that follows the cursor during drag operations. At the time of
17227 * the click, the frame div is resized to the dimensions of the linked html
17228 * element, and moved to the exact location of the linked element.
17230 * References to the "frame" element refer to the single proxy element that
17231 * was created to be dragged in place of all DDProxy elements on the
17234 * @extends Roo.dd.DD
17236 * @param {String} id the id of the linked html element
17237 * @param {String} sGroup the group of related DragDrop objects
17238 * @param {object} config an object containing configurable attributes
17239 * Valid properties for DDProxy in addition to those in DragDrop:
17240 * resizeFrame, centerFrame, dragElId
17242 Roo.dd.DDProxy = function(id, sGroup, config) {
17244 this.init(id, sGroup, config);
17250 * The default drag frame div id
17251 * @property Roo.dd.DDProxy.dragElId
17255 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17257 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17260 * By default we resize the drag frame to be the same size as the element
17261 * we want to drag (this is to get the frame effect). We can turn it off
17262 * if we want a different behavior.
17263 * @property resizeFrame
17269 * By default the frame is positioned exactly where the drag element is, so
17270 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17271 * you do not have constraints on the obj is to have the drag frame centered
17272 * around the cursor. Set centerFrame to true for this effect.
17273 * @property centerFrame
17276 centerFrame: false,
17279 * Creates the proxy element if it does not yet exist
17280 * @method createFrame
17282 createFrame: function() {
17284 var body = document.body;
17286 if (!body || !body.firstChild) {
17287 setTimeout( function() { self.createFrame(); }, 50 );
17291 var div = this.getDragEl();
17294 div = document.createElement("div");
17295 div.id = this.dragElId;
17298 s.position = "absolute";
17299 s.visibility = "hidden";
17301 s.border = "2px solid #aaa";
17304 // appendChild can blow up IE if invoked prior to the window load event
17305 // while rendering a table. It is possible there are other scenarios
17306 // that would cause this to happen as well.
17307 body.insertBefore(div, body.firstChild);
17312 * Initialization for the drag frame element. Must be called in the
17313 * constructor of all subclasses
17314 * @method initFrame
17316 initFrame: function() {
17317 this.createFrame();
17320 applyConfig: function() {
17321 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17323 this.resizeFrame = (this.config.resizeFrame !== false);
17324 this.centerFrame = (this.config.centerFrame);
17325 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17329 * Resizes the drag frame to the dimensions of the clicked object, positions
17330 * it over the object, and finally displays it
17331 * @method showFrame
17332 * @param {int} iPageX X click position
17333 * @param {int} iPageY Y click position
17336 showFrame: function(iPageX, iPageY) {
17337 var el = this.getEl();
17338 var dragEl = this.getDragEl();
17339 var s = dragEl.style;
17341 this._resizeProxy();
17343 if (this.centerFrame) {
17344 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17345 Math.round(parseInt(s.height, 10)/2) );
17348 this.setDragElPos(iPageX, iPageY);
17350 Roo.fly(dragEl).show();
17354 * The proxy is automatically resized to the dimensions of the linked
17355 * element when a drag is initiated, unless resizeFrame is set to false
17356 * @method _resizeProxy
17359 _resizeProxy: function() {
17360 if (this.resizeFrame) {
17361 var el = this.getEl();
17362 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17366 // overrides Roo.dd.DragDrop
17367 b4MouseDown: function(e) {
17368 var x = e.getPageX();
17369 var y = e.getPageY();
17370 this.autoOffset(x, y);
17371 this.setDragElPos(x, y);
17374 // overrides Roo.dd.DragDrop
17375 b4StartDrag: function(x, y) {
17376 // show the drag frame
17377 this.showFrame(x, y);
17380 // overrides Roo.dd.DragDrop
17381 b4EndDrag: function(e) {
17382 Roo.fly(this.getDragEl()).hide();
17385 // overrides Roo.dd.DragDrop
17386 // By default we try to move the element to the last location of the frame.
17387 // This is so that the default behavior mirrors that of Roo.dd.DD.
17388 endDrag: function(e) {
17390 var lel = this.getEl();
17391 var del = this.getDragEl();
17393 // Show the drag frame briefly so we can get its position
17394 del.style.visibility = "";
17397 // Hide the linked element before the move to get around a Safari
17399 lel.style.visibility = "hidden";
17400 Roo.dd.DDM.moveToEl(lel, del);
17401 del.style.visibility = "hidden";
17402 lel.style.visibility = "";
17407 beforeMove : function(){
17411 afterDrag : function(){
17415 toString: function() {
17416 return ("DDProxy " + this.id);
17422 * Ext JS Library 1.1.1
17423 * Copyright(c) 2006-2007, Ext JS, LLC.
17425 * Originally Released Under LGPL - original licence link has changed is not relivant.
17428 * <script type="text/javascript">
17432 * @class Roo.dd.DDTarget
17433 * A DragDrop implementation that does not move, but can be a drop
17434 * target. You would get the same result by simply omitting implementation
17435 * for the event callbacks, but this way we reduce the processing cost of the
17436 * event listener and the callbacks.
17437 * @extends Roo.dd.DragDrop
17439 * @param {String} id the id of the element that is a drop target
17440 * @param {String} sGroup the group of related DragDrop objects
17441 * @param {object} config an object containing configurable attributes
17442 * Valid properties for DDTarget in addition to those in
17446 Roo.dd.DDTarget = function(id, sGroup, config) {
17448 this.initTarget(id, sGroup, config);
17450 if (config.listeners || config.events) {
17451 Roo.dd.DragDrop.superclass.constructor.call(this, {
17452 listeners : config.listeners || {},
17453 events : config.events || {}
17458 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17459 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17460 toString: function() {
17461 return ("DDTarget " + this.id);
17466 * Ext JS Library 1.1.1
17467 * Copyright(c) 2006-2007, Ext JS, LLC.
17469 * Originally Released Under LGPL - original licence link has changed is not relivant.
17472 * <script type="text/javascript">
17477 * @class Roo.dd.ScrollManager
17478 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17479 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17482 Roo.dd.ScrollManager = function(){
17483 var ddm = Roo.dd.DragDropMgr;
17488 var onStop = function(e){
17493 var triggerRefresh = function(){
17494 if(ddm.dragCurrent){
17495 ddm.refreshCache(ddm.dragCurrent.groups);
17499 var doScroll = function(){
17500 if(ddm.dragCurrent){
17501 var dds = Roo.dd.ScrollManager;
17503 if(proc.el.scroll(proc.dir, dds.increment)){
17507 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17512 var clearProc = function(){
17514 clearInterval(proc.id);
17521 var startProc = function(el, dir){
17525 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17528 var onFire = function(e, isDrop){
17529 if(isDrop || !ddm.dragCurrent){ return; }
17530 var dds = Roo.dd.ScrollManager;
17531 if(!dragEl || dragEl != ddm.dragCurrent){
17532 dragEl = ddm.dragCurrent;
17533 // refresh regions on drag start
17534 dds.refreshCache();
17537 var xy = Roo.lib.Event.getXY(e);
17538 var pt = new Roo.lib.Point(xy[0], xy[1]);
17539 for(var id in els){
17540 var el = els[id], r = el._region;
17541 if(r && r.contains(pt) && el.isScrollable()){
17542 if(r.bottom - pt.y <= dds.thresh){
17544 startProc(el, "down");
17547 }else if(r.right - pt.x <= dds.thresh){
17549 startProc(el, "left");
17552 }else if(pt.y - r.top <= dds.thresh){
17554 startProc(el, "up");
17557 }else if(pt.x - r.left <= dds.thresh){
17559 startProc(el, "right");
17568 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17569 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17573 * Registers new overflow element(s) to auto scroll
17574 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17576 register : function(el){
17577 if(el instanceof Array){
17578 for(var i = 0, len = el.length; i < len; i++) {
17579 this.register(el[i]);
17588 * Unregisters overflow element(s) so they are no longer scrolled
17589 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17591 unregister : function(el){
17592 if(el instanceof Array){
17593 for(var i = 0, len = el.length; i < len; i++) {
17594 this.unregister(el[i]);
17603 * The number of pixels from the edge of a container the pointer needs to be to
17604 * trigger scrolling (defaults to 25)
17610 * The number of pixels to scroll in each scroll increment (defaults to 50)
17616 * The frequency of scrolls in milliseconds (defaults to 500)
17622 * True to animate the scroll (defaults to true)
17628 * The animation duration in seconds -
17629 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17635 * Manually trigger a cache refresh.
17637 refreshCache : function(){
17638 for(var id in els){
17639 if(typeof els[id] == 'object'){ // for people extending the object prototype
17640 els[id]._region = els[id].getRegion();
17647 * Ext JS Library 1.1.1
17648 * Copyright(c) 2006-2007, Ext JS, LLC.
17650 * Originally Released Under LGPL - original licence link has changed is not relivant.
17653 * <script type="text/javascript">
17658 * @class Roo.dd.Registry
17659 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17660 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17663 Roo.dd.Registry = function(){
17666 var autoIdSeed = 0;
17668 var getId = function(el, autogen){
17669 if(typeof el == "string"){
17673 if(!id && autogen !== false){
17674 id = "roodd-" + (++autoIdSeed);
17682 * Register a drag drop element
17683 * @param {String|HTMLElement} element The id or DOM node to register
17684 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17685 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17686 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17687 * populated in the data object (if applicable):
17689 Value Description<br />
17690 --------- ------------------------------------------<br />
17691 handles Array of DOM nodes that trigger dragging<br />
17692 for the element being registered<br />
17693 isHandle True if the element passed in triggers<br />
17694 dragging itself, else false
17697 register : function(el, data){
17699 if(typeof el == "string"){
17700 el = document.getElementById(el);
17703 elements[getId(el)] = data;
17704 if(data.isHandle !== false){
17705 handles[data.ddel.id] = data;
17708 var hs = data.handles;
17709 for(var i = 0, len = hs.length; i < len; i++){
17710 handles[getId(hs[i])] = data;
17716 * Unregister a drag drop element
17717 * @param {String|HTMLElement} element The id or DOM node to unregister
17719 unregister : function(el){
17720 var id = getId(el, false);
17721 var data = elements[id];
17723 delete elements[id];
17725 var hs = data.handles;
17726 for(var i = 0, len = hs.length; i < len; i++){
17727 delete handles[getId(hs[i], false)];
17734 * Returns the handle registered for a DOM Node by id
17735 * @param {String|HTMLElement} id The DOM node or id to look up
17736 * @return {Object} handle The custom handle data
17738 getHandle : function(id){
17739 if(typeof id != "string"){ // must be element?
17742 return handles[id];
17746 * Returns the handle that is registered for the DOM node that is the target of the event
17747 * @param {Event} e The event
17748 * @return {Object} handle The custom handle data
17750 getHandleFromEvent : function(e){
17751 var t = Roo.lib.Event.getTarget(e);
17752 return t ? handles[t.id] : null;
17756 * Returns a custom data object that is registered for a DOM node by id
17757 * @param {String|HTMLElement} id The DOM node or id to look up
17758 * @return {Object} data The custom data
17760 getTarget : function(id){
17761 if(typeof id != "string"){ // must be element?
17764 return elements[id];
17768 * Returns a custom data object that is registered for the DOM node that is the target of the event
17769 * @param {Event} e The event
17770 * @return {Object} data The custom data
17772 getTargetFromEvent : function(e){
17773 var t = Roo.lib.Event.getTarget(e);
17774 return t ? elements[t.id] || handles[t.id] : null;
17779 * Ext JS Library 1.1.1
17780 * Copyright(c) 2006-2007, Ext JS, LLC.
17782 * Originally Released Under LGPL - original licence link has changed is not relivant.
17785 * <script type="text/javascript">
17790 * @class Roo.dd.StatusProxy
17791 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17792 * default drag proxy used by all Roo.dd components.
17794 * @param {Object} config
17796 Roo.dd.StatusProxy = function(config){
17797 Roo.apply(this, config);
17798 this.id = this.id || Roo.id();
17799 this.el = new Roo.Layer({
17801 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17802 {tag: "div", cls: "x-dd-drop-icon"},
17803 {tag: "div", cls: "x-dd-drag-ghost"}
17806 shadow: !config || config.shadow !== false
17808 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17809 this.dropStatus = this.dropNotAllowed;
17812 Roo.dd.StatusProxy.prototype = {
17814 * @cfg {String} dropAllowed
17815 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17817 dropAllowed : "x-dd-drop-ok",
17819 * @cfg {String} dropNotAllowed
17820 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17822 dropNotAllowed : "x-dd-drop-nodrop",
17825 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17826 * over the current target element.
17827 * @param {String} cssClass The css class for the new drop status indicator image
17829 setStatus : function(cssClass){
17830 cssClass = cssClass || this.dropNotAllowed;
17831 if(this.dropStatus != cssClass){
17832 this.el.replaceClass(this.dropStatus, cssClass);
17833 this.dropStatus = cssClass;
17838 * Resets the status indicator to the default dropNotAllowed value
17839 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17841 reset : function(clearGhost){
17842 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17843 this.dropStatus = this.dropNotAllowed;
17845 this.ghost.update("");
17850 * Updates the contents of the ghost element
17851 * @param {String} html The html that will replace the current innerHTML of the ghost element
17853 update : function(html){
17854 if(typeof html == "string"){
17855 this.ghost.update(html);
17857 this.ghost.update("");
17858 html.style.margin = "0";
17859 this.ghost.dom.appendChild(html);
17861 // ensure float = none set?? cant remember why though.
17862 var el = this.ghost.dom.firstChild;
17864 Roo.fly(el).setStyle('float', 'none');
17869 * Returns the underlying proxy {@link Roo.Layer}
17870 * @return {Roo.Layer} el
17872 getEl : function(){
17877 * Returns the ghost element
17878 * @return {Roo.Element} el
17880 getGhost : function(){
17886 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17888 hide : function(clear){
17896 * Stops the repair animation if it's currently running
17899 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17905 * Displays this proxy
17912 * Force the Layer to sync its shadow and shim positions to the element
17919 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17920 * invalid drop operation by the item being dragged.
17921 * @param {Array} xy The XY position of the element ([x, y])
17922 * @param {Function} callback The function to call after the repair is complete
17923 * @param {Object} scope The scope in which to execute the callback
17925 repair : function(xy, callback, scope){
17926 this.callback = callback;
17927 this.scope = scope;
17928 if(xy && this.animRepair !== false){
17929 this.el.addClass("x-dd-drag-repair");
17930 this.el.hideUnders(true);
17931 this.anim = this.el.shift({
17932 duration: this.repairDuration || .5,
17936 callback: this.afterRepair,
17940 this.afterRepair();
17945 afterRepair : function(){
17947 if(typeof this.callback == "function"){
17948 this.callback.call(this.scope || this);
17950 this.callback = null;
17955 * Ext JS Library 1.1.1
17956 * Copyright(c) 2006-2007, Ext JS, LLC.
17958 * Originally Released Under LGPL - original licence link has changed is not relivant.
17961 * <script type="text/javascript">
17965 * @class Roo.dd.DragSource
17966 * @extends Roo.dd.DDProxy
17967 * A simple class that provides the basic implementation needed to make any element draggable.
17969 * @param {String/HTMLElement/Element} el The container element
17970 * @param {Object} config
17972 Roo.dd.DragSource = function(el, config){
17973 this.el = Roo.get(el);
17974 this.dragData = {};
17976 Roo.apply(this, config);
17979 this.proxy = new Roo.dd.StatusProxy();
17982 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
17983 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
17985 this.dragging = false;
17988 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
17990 * @cfg {String} dropAllowed
17991 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
17993 dropAllowed : "x-dd-drop-ok",
17995 * @cfg {String} dropNotAllowed
17996 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
17998 dropNotAllowed : "x-dd-drop-nodrop",
18001 * Returns the data object associated with this drag source
18002 * @return {Object} data An object containing arbitrary data
18004 getDragData : function(e){
18005 return this.dragData;
18009 onDragEnter : function(e, id){
18010 var target = Roo.dd.DragDropMgr.getDDById(id);
18011 this.cachedTarget = target;
18012 if(this.beforeDragEnter(target, e, id) !== false){
18013 if(target.isNotifyTarget){
18014 var status = target.notifyEnter(this, e, this.dragData);
18015 this.proxy.setStatus(status);
18017 this.proxy.setStatus(this.dropAllowed);
18020 if(this.afterDragEnter){
18022 * An empty function by default, but provided so that you can perform a custom action
18023 * when the dragged item enters the drop target by providing an implementation.
18024 * @param {Roo.dd.DragDrop} target The drop target
18025 * @param {Event} e The event object
18026 * @param {String} id The id of the dragged element
18027 * @method afterDragEnter
18029 this.afterDragEnter(target, e, id);
18035 * An empty function by default, but provided so that you can perform a custom action
18036 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
18037 * @param {Roo.dd.DragDrop} target The drop target
18038 * @param {Event} e The event object
18039 * @param {String} id The id of the dragged element
18040 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18042 beforeDragEnter : function(target, e, id){
18047 alignElWithMouse: function() {
18048 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18053 onDragOver : function(e, id){
18054 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18055 if(this.beforeDragOver(target, e, id) !== false){
18056 if(target.isNotifyTarget){
18057 var status = target.notifyOver(this, e, this.dragData);
18058 this.proxy.setStatus(status);
18061 if(this.afterDragOver){
18063 * An empty function by default, but provided so that you can perform a custom action
18064 * while the dragged item is over the drop target by providing an implementation.
18065 * @param {Roo.dd.DragDrop} target The drop target
18066 * @param {Event} e The event object
18067 * @param {String} id The id of the dragged element
18068 * @method afterDragOver
18070 this.afterDragOver(target, e, id);
18076 * An empty function by default, but provided so that you can perform a custom action
18077 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18078 * @param {Roo.dd.DragDrop} target The drop target
18079 * @param {Event} e The event object
18080 * @param {String} id The id of the dragged element
18081 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18083 beforeDragOver : function(target, e, id){
18088 onDragOut : function(e, id){
18089 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18090 if(this.beforeDragOut(target, e, id) !== false){
18091 if(target.isNotifyTarget){
18092 target.notifyOut(this, e, this.dragData);
18094 this.proxy.reset();
18095 if(this.afterDragOut){
18097 * An empty function by default, but provided so that you can perform a custom action
18098 * after the dragged item is dragged out of the target without dropping.
18099 * @param {Roo.dd.DragDrop} target The drop target
18100 * @param {Event} e The event object
18101 * @param {String} id The id of the dragged element
18102 * @method afterDragOut
18104 this.afterDragOut(target, e, id);
18107 this.cachedTarget = null;
18111 * An empty function by default, but provided so that you can perform a custom action before the dragged
18112 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18113 * @param {Roo.dd.DragDrop} target The drop target
18114 * @param {Event} e The event object
18115 * @param {String} id The id of the dragged element
18116 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18118 beforeDragOut : function(target, e, id){
18123 onDragDrop : function(e, id){
18124 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18125 if(this.beforeDragDrop(target, e, id) !== false){
18126 if(target.isNotifyTarget){
18127 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18128 this.onValidDrop(target, e, id);
18130 this.onInvalidDrop(target, e, id);
18133 this.onValidDrop(target, e, id);
18136 if(this.afterDragDrop){
18138 * An empty function by default, but provided so that you can perform a custom action
18139 * after a valid drag drop has occurred by providing an implementation.
18140 * @param {Roo.dd.DragDrop} target The drop target
18141 * @param {Event} e The event object
18142 * @param {String} id The id of the dropped element
18143 * @method afterDragDrop
18145 this.afterDragDrop(target, e, id);
18148 delete this.cachedTarget;
18152 * An empty function by default, but provided so that you can perform a custom action before the dragged
18153 * item is dropped onto the target and optionally cancel the onDragDrop.
18154 * @param {Roo.dd.DragDrop} target The drop target
18155 * @param {Event} e The event object
18156 * @param {String} id The id of the dragged element
18157 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18159 beforeDragDrop : function(target, e, id){
18164 onValidDrop : function(target, e, id){
18166 if(this.afterValidDrop){
18168 * An empty function by default, but provided so that you can perform a custom action
18169 * after a valid drop has occurred by providing an implementation.
18170 * @param {Object} target The target DD
18171 * @param {Event} e The event object
18172 * @param {String} id The id of the dropped element
18173 * @method afterInvalidDrop
18175 this.afterValidDrop(target, e, id);
18180 getRepairXY : function(e, data){
18181 return this.el.getXY();
18185 onInvalidDrop : function(target, e, id){
18186 this.beforeInvalidDrop(target, e, id);
18187 if(this.cachedTarget){
18188 if(this.cachedTarget.isNotifyTarget){
18189 this.cachedTarget.notifyOut(this, e, this.dragData);
18191 this.cacheTarget = null;
18193 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18195 if(this.afterInvalidDrop){
18197 * An empty function by default, but provided so that you can perform a custom action
18198 * after an invalid drop has occurred by providing an implementation.
18199 * @param {Event} e The event object
18200 * @param {String} id The id of the dropped element
18201 * @method afterInvalidDrop
18203 this.afterInvalidDrop(e, id);
18208 afterRepair : function(){
18210 this.el.highlight(this.hlColor || "c3daf9");
18212 this.dragging = false;
18216 * An empty function by default, but provided so that you can perform a custom action after an invalid
18217 * drop has occurred.
18218 * @param {Roo.dd.DragDrop} target The drop target
18219 * @param {Event} e The event object
18220 * @param {String} id The id of the dragged element
18221 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18223 beforeInvalidDrop : function(target, e, id){
18228 handleMouseDown : function(e){
18229 if(this.dragging) {
18232 var data = this.getDragData(e);
18233 if(data && this.onBeforeDrag(data, e) !== false){
18234 this.dragData = data;
18236 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18241 * An empty function by default, but provided so that you can perform a custom action before the initial
18242 * drag event begins and optionally cancel it.
18243 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18244 * @param {Event} e The event object
18245 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18247 onBeforeDrag : function(data, e){
18252 * An empty function by default, but provided so that you can perform a custom action once the initial
18253 * drag event has begun. The drag cannot be canceled from this function.
18254 * @param {Number} x The x position of the click on the dragged object
18255 * @param {Number} y The y position of the click on the dragged object
18257 onStartDrag : Roo.emptyFn,
18259 // private - YUI override
18260 startDrag : function(x, y){
18261 this.proxy.reset();
18262 this.dragging = true;
18263 this.proxy.update("");
18264 this.onInitDrag(x, y);
18269 onInitDrag : function(x, y){
18270 var clone = this.el.dom.cloneNode(true);
18271 clone.id = Roo.id(); // prevent duplicate ids
18272 this.proxy.update(clone);
18273 this.onStartDrag(x, y);
18278 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18279 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18281 getProxy : function(){
18286 * Hides the drag source's {@link Roo.dd.StatusProxy}
18288 hideProxy : function(){
18290 this.proxy.reset(true);
18291 this.dragging = false;
18295 triggerCacheRefresh : function(){
18296 Roo.dd.DDM.refreshCache(this.groups);
18299 // private - override to prevent hiding
18300 b4EndDrag: function(e) {
18303 // private - override to prevent moving
18304 endDrag : function(e){
18305 this.onEndDrag(this.dragData, e);
18309 onEndDrag : function(data, e){
18312 // private - pin to cursor
18313 autoOffset : function(x, y) {
18314 this.setDelta(-12, -20);
18318 * Ext JS Library 1.1.1
18319 * Copyright(c) 2006-2007, Ext JS, LLC.
18321 * Originally Released Under LGPL - original licence link has changed is not relivant.
18324 * <script type="text/javascript">
18329 * @class Roo.dd.DropTarget
18330 * @extends Roo.dd.DDTarget
18331 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18332 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18334 * @param {String/HTMLElement/Element} el The container element
18335 * @param {Object} config
18337 Roo.dd.DropTarget = function(el, config){
18338 this.el = Roo.get(el);
18340 var listeners = false; ;
18341 if (config && config.listeners) {
18342 listeners= config.listeners;
18343 delete config.listeners;
18345 Roo.apply(this, config);
18347 if(this.containerScroll){
18348 Roo.dd.ScrollManager.register(this.el);
18352 * @scope Roo.dd.DropTarget
18357 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18358 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18359 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18361 * IMPORTANT : it should set this.overClass and this.dropAllowed
18363 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18364 * @param {Event} e The event
18365 * @param {Object} data An object containing arbitrary data supplied by the drag source
18371 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18372 * This method will be called on every mouse movement while the drag source is over the drop target.
18373 * This default implementation simply returns the dropAllowed config value.
18375 * IMPORTANT : it should set this.dropAllowed
18377 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18378 * @param {Event} e The event
18379 * @param {Object} data An object containing arbitrary data supplied by the drag source
18385 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18386 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18387 * overClass (if any) from the drop element.
18388 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18389 * @param {Event} e The event
18390 * @param {Object} data An object containing arbitrary data supplied by the drag source
18396 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18397 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18398 * implementation that does something to process the drop event and returns true so that the drag source's
18399 * repair action does not run.
18401 * IMPORTANT : it should set this.success
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 Roo.dd.DropTarget.superclass.constructor.call( this,
18413 this.ddGroup || this.group,
18416 listeners : listeners || {}
18424 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18426 * @cfg {String} overClass
18427 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18430 * @cfg {String} ddGroup
18431 * The drag drop group to handle drop events for
18435 * @cfg {String} dropAllowed
18436 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18438 dropAllowed : "x-dd-drop-ok",
18440 * @cfg {String} dropNotAllowed
18441 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18443 dropNotAllowed : "x-dd-drop-nodrop",
18445 * @cfg {boolean} success
18446 * set this after drop listener..
18450 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
18451 * if the drop point is valid for over/enter..
18458 isNotifyTarget : true,
18463 notifyEnter : function(dd, e, data)
18466 this.fireEvent('enter', dd, e, data);
18467 if(this.overClass){
18468 this.el.addClass(this.overClass);
18470 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18471 this.valid ? this.dropAllowed : this.dropNotAllowed
18478 notifyOver : function(dd, e, data)
18481 this.fireEvent('over', dd, e, data);
18482 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18483 this.valid ? this.dropAllowed : this.dropNotAllowed
18490 notifyOut : function(dd, e, data)
18492 this.fireEvent('out', dd, e, data);
18493 if(this.overClass){
18494 this.el.removeClass(this.overClass);
18501 notifyDrop : function(dd, e, data)
18503 this.success = false;
18504 this.fireEvent('drop', dd, e, data);
18505 return this.success;
18509 * Ext JS Library 1.1.1
18510 * Copyright(c) 2006-2007, Ext JS, LLC.
18512 * Originally Released Under LGPL - original licence link has changed is not relivant.
18515 * <script type="text/javascript">
18520 * @class Roo.dd.DragZone
18521 * @extends Roo.dd.DragSource
18522 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18523 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18525 * @param {String/HTMLElement/Element} el The container element
18526 * @param {Object} config
18528 Roo.dd.DragZone = function(el, config){
18529 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18530 if(this.containerScroll){
18531 Roo.dd.ScrollManager.register(this.el);
18535 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18537 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18538 * for auto scrolling during drag operations.
18541 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18542 * method after a failed drop (defaults to "c3daf9" - light blue)
18546 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18547 * for a valid target to drag based on the mouse down. Override this method
18548 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18549 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18550 * @param {EventObject} e The mouse down event
18551 * @return {Object} The dragData
18553 getDragData : function(e){
18554 return Roo.dd.Registry.getHandleFromEvent(e);
18558 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18559 * this.dragData.ddel
18560 * @param {Number} x The x position of the click on the dragged object
18561 * @param {Number} y The y position of the click on the dragged object
18562 * @return {Boolean} true to continue the drag, false to cancel
18564 onInitDrag : function(x, y){
18565 this.proxy.update(this.dragData.ddel.cloneNode(true));
18566 this.onStartDrag(x, y);
18571 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18573 afterRepair : function(){
18575 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18577 this.dragging = false;
18581 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18582 * the XY of this.dragData.ddel
18583 * @param {EventObject} e The mouse up event
18584 * @return {Array} The xy location (e.g. [100, 200])
18586 getRepairXY : function(e){
18587 return Roo.Element.fly(this.dragData.ddel).getXY();
18591 * Ext JS Library 1.1.1
18592 * Copyright(c) 2006-2007, Ext JS, LLC.
18594 * Originally Released Under LGPL - original licence link has changed is not relivant.
18597 * <script type="text/javascript">
18600 * @class Roo.dd.DropZone
18601 * @extends Roo.dd.DropTarget
18602 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18603 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18605 * @param {String/HTMLElement/Element} el The container element
18606 * @param {Object} config
18608 Roo.dd.DropZone = function(el, config){
18609 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18612 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18614 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18615 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18616 * provide your own custom lookup.
18617 * @param {Event} e The event
18618 * @return {Object} data The custom data
18620 getTargetFromEvent : function(e){
18621 return Roo.dd.Registry.getTargetFromEvent(e);
18625 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18626 * that it has registered. This method has no default implementation and should be overridden to provide
18627 * node-specific processing if necessary.
18628 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18629 * {@link #getTargetFromEvent} for this node)
18630 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18631 * @param {Event} e The event
18632 * @param {Object} data An object containing arbitrary data supplied by the drag source
18634 onNodeEnter : function(n, dd, e, data){
18639 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18640 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18641 * overridden to provide the proper feedback.
18642 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18643 * {@link #getTargetFromEvent} for this node)
18644 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18645 * @param {Event} e The event
18646 * @param {Object} data An object containing arbitrary data supplied by the drag source
18647 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18648 * underlying {@link Roo.dd.StatusProxy} can be updated
18650 onNodeOver : function(n, dd, e, data){
18651 return this.dropAllowed;
18655 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18656 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18657 * node-specific processing if necessary.
18658 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18659 * {@link #getTargetFromEvent} for this node)
18660 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18661 * @param {Event} e The event
18662 * @param {Object} data An object containing arbitrary data supplied by the drag source
18664 onNodeOut : function(n, dd, e, data){
18669 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18670 * the drop node. The default implementation returns false, so it should be overridden to provide the
18671 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18672 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18673 * {@link #getTargetFromEvent} for this node)
18674 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18675 * @param {Event} e The event
18676 * @param {Object} data An object containing arbitrary data supplied by the drag source
18677 * @return {Boolean} True if the drop was valid, else false
18679 onNodeDrop : function(n, dd, e, data){
18684 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18685 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18686 * it should be overridden to provide the proper feedback if necessary.
18687 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18688 * @param {Event} e The event
18689 * @param {Object} data An object containing arbitrary data supplied by the drag source
18690 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18691 * underlying {@link Roo.dd.StatusProxy} can be updated
18693 onContainerOver : function(dd, e, data){
18694 return this.dropNotAllowed;
18698 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18699 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18700 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18701 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
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 {Boolean} True if the drop was valid, else false
18707 onContainerDrop : function(dd, e, data){
18712 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18713 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18714 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18715 * you should override this method and provide a custom implementation.
18716 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18717 * @param {Event} e The event
18718 * @param {Object} data An object containing arbitrary data supplied by the drag source
18719 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18720 * underlying {@link Roo.dd.StatusProxy} can be updated
18722 notifyEnter : function(dd, e, data){
18723 return this.dropNotAllowed;
18727 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18728 * This method will be called on every mouse movement while the drag source is over the drop zone.
18729 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18730 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18731 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18732 * registered node, it will call {@link #onContainerOver}.
18733 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18734 * @param {Event} e The event
18735 * @param {Object} data An object containing arbitrary data supplied by the drag source
18736 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18737 * underlying {@link Roo.dd.StatusProxy} can be updated
18739 notifyOver : function(dd, e, data){
18740 var n = this.getTargetFromEvent(e);
18741 if(!n){ // not over valid drop target
18742 if(this.lastOverNode){
18743 this.onNodeOut(this.lastOverNode, dd, e, data);
18744 this.lastOverNode = null;
18746 return this.onContainerOver(dd, e, data);
18748 if(this.lastOverNode != n){
18749 if(this.lastOverNode){
18750 this.onNodeOut(this.lastOverNode, dd, e, data);
18752 this.onNodeEnter(n, dd, e, data);
18753 this.lastOverNode = n;
18755 return this.onNodeOver(n, dd, e, data);
18759 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18760 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18761 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18762 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18763 * @param {Event} e The event
18764 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18766 notifyOut : function(dd, e, data){
18767 if(this.lastOverNode){
18768 this.onNodeOut(this.lastOverNode, dd, e, data);
18769 this.lastOverNode = null;
18774 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18775 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18776 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18777 * otherwise it will call {@link #onContainerDrop}.
18778 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18779 * @param {Event} e The event
18780 * @param {Object} data An object containing arbitrary data supplied by the drag source
18781 * @return {Boolean} True if the drop was valid, else false
18783 notifyDrop : function(dd, e, data){
18784 if(this.lastOverNode){
18785 this.onNodeOut(this.lastOverNode, dd, e, data);
18786 this.lastOverNode = null;
18788 var n = this.getTargetFromEvent(e);
18790 this.onNodeDrop(n, dd, e, data) :
18791 this.onContainerDrop(dd, e, data);
18795 triggerCacheRefresh : function(){
18796 Roo.dd.DDM.refreshCache(this.groups);
18800 * Ext JS Library 1.1.1
18801 * Copyright(c) 2006-2007, Ext JS, LLC.
18803 * Originally Released Under LGPL - original licence link has changed is not relivant.
18806 * <script type="text/javascript">
18811 * @class Roo.data.SortTypes
18813 * Defines the default sorting (casting?) comparison functions used when sorting data.
18815 Roo.data.SortTypes = {
18817 * Default sort that does nothing
18818 * @param {Mixed} s The value being converted
18819 * @return {Mixed} The comparison value
18821 none : function(s){
18826 * The regular expression used to strip tags
18830 stripTagsRE : /<\/?[^>]+>/gi,
18833 * Strips all HTML tags to sort on text only
18834 * @param {Mixed} s The value being converted
18835 * @return {String} The comparison value
18837 asText : function(s){
18838 return String(s).replace(this.stripTagsRE, "");
18842 * Strips all HTML tags to sort on text only - Case insensitive
18843 * @param {Mixed} s The value being converted
18844 * @return {String} The comparison value
18846 asUCText : function(s){
18847 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18851 * Case insensitive string
18852 * @param {Mixed} s The value being converted
18853 * @return {String} The comparison value
18855 asUCString : function(s) {
18856 return String(s).toUpperCase();
18861 * @param {Mixed} s The value being converted
18862 * @return {Number} The comparison value
18864 asDate : function(s) {
18868 if(s instanceof Date){
18869 return s.getTime();
18871 return Date.parse(String(s));
18876 * @param {Mixed} s The value being converted
18877 * @return {Float} The comparison value
18879 asFloat : function(s) {
18880 var val = parseFloat(String(s).replace(/,/g, ""));
18881 if(isNaN(val)) val = 0;
18887 * @param {Mixed} s The value being converted
18888 * @return {Number} The comparison value
18890 asInt : function(s) {
18891 var val = parseInt(String(s).replace(/,/g, ""));
18892 if(isNaN(val)) val = 0;
18897 * Ext JS Library 1.1.1
18898 * Copyright(c) 2006-2007, Ext JS, LLC.
18900 * Originally Released Under LGPL - original licence link has changed is not relivant.
18903 * <script type="text/javascript">
18907 * @class Roo.data.Record
18908 * Instances of this class encapsulate both record <em>definition</em> information, and record
18909 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18910 * to access Records cached in an {@link Roo.data.Store} object.<br>
18912 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18913 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18916 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18918 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18919 * {@link #create}. The parameters are the same.
18920 * @param {Array} data An associative Array of data values keyed by the field name.
18921 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18922 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18923 * not specified an integer id is generated.
18925 Roo.data.Record = function(data, id){
18926 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18931 * Generate a constructor for a specific record layout.
18932 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18933 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18934 * Each field definition object may contain the following properties: <ul>
18935 * <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,
18936 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18937 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18938 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18939 * is being used, then this is a string containing the javascript expression to reference the data relative to
18940 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18941 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18942 * this may be omitted.</p></li>
18943 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18944 * <ul><li>auto (Default, implies no conversion)</li>
18949 * <li>date</li></ul></p></li>
18950 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18951 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18952 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18953 * by the Reader into an object that will be stored in the Record. It is passed the
18954 * following parameters:<ul>
18955 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18957 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18959 * <br>usage:<br><pre><code>
18960 var TopicRecord = Roo.data.Record.create(
18961 {name: 'title', mapping: 'topic_title'},
18962 {name: 'author', mapping: 'username'},
18963 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18964 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18965 {name: 'lastPoster', mapping: 'user2'},
18966 {name: 'excerpt', mapping: 'post_text'}
18969 var myNewRecord = new TopicRecord({
18970 title: 'Do my job please',
18973 lastPost: new Date(),
18974 lastPoster: 'Animal',
18975 excerpt: 'No way dude!'
18977 myStore.add(myNewRecord);
18982 Roo.data.Record.create = function(o){
18983 var f = function(){
18984 f.superclass.constructor.apply(this, arguments);
18986 Roo.extend(f, Roo.data.Record);
18987 var p = f.prototype;
18988 p.fields = new Roo.util.MixedCollection(false, function(field){
18991 for(var i = 0, len = o.length; i < len; i++){
18992 p.fields.add(new Roo.data.Field(o[i]));
18994 f.getField = function(name){
18995 return p.fields.get(name);
19000 Roo.data.Record.AUTO_ID = 1000;
19001 Roo.data.Record.EDIT = 'edit';
19002 Roo.data.Record.REJECT = 'reject';
19003 Roo.data.Record.COMMIT = 'commit';
19005 Roo.data.Record.prototype = {
19007 * Readonly flag - true if this record has been modified.
19016 join : function(store){
19017 this.store = store;
19021 * Set the named field to the specified value.
19022 * @param {String} name The name of the field to set.
19023 * @param {Object} value The value to set the field to.
19025 set : function(name, value){
19026 if(this.data[name] == value){
19030 if(!this.modified){
19031 this.modified = {};
19033 if(typeof this.modified[name] == 'undefined'){
19034 this.modified[name] = this.data[name];
19036 this.data[name] = value;
19038 this.store.afterEdit(this);
19043 * Get the value of the named field.
19044 * @param {String} name The name of the field to get the value of.
19045 * @return {Object} The value of the field.
19047 get : function(name){
19048 return this.data[name];
19052 beginEdit : function(){
19053 this.editing = true;
19054 this.modified = {};
19058 cancelEdit : function(){
19059 this.editing = false;
19060 delete this.modified;
19064 endEdit : function(){
19065 this.editing = false;
19066 if(this.dirty && this.store){
19067 this.store.afterEdit(this);
19072 * Usually called by the {@link Roo.data.Store} which owns the Record.
19073 * Rejects all changes made to the Record since either creation, or the last commit operation.
19074 * Modified fields are reverted to their original values.
19076 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19077 * of reject operations.
19079 reject : function(){
19080 var m = this.modified;
19082 if(typeof m[n] != "function"){
19083 this.data[n] = m[n];
19086 this.dirty = false;
19087 delete this.modified;
19088 this.editing = false;
19090 this.store.afterReject(this);
19095 * Usually called by the {@link Roo.data.Store} which owns the Record.
19096 * Commits all changes made to the Record since either creation, or the last commit operation.
19098 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19099 * of commit operations.
19101 commit : function(){
19102 this.dirty = false;
19103 delete this.modified;
19104 this.editing = false;
19106 this.store.afterCommit(this);
19111 hasError : function(){
19112 return this.error != null;
19116 clearError : function(){
19121 * Creates a copy of this record.
19122 * @param {String} id (optional) A new record id if you don't want to use this record's id
19125 copy : function(newId) {
19126 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19130 * Ext JS Library 1.1.1
19131 * Copyright(c) 2006-2007, Ext JS, LLC.
19133 * Originally Released Under LGPL - original licence link has changed is not relivant.
19136 * <script type="text/javascript">
19142 * @class Roo.data.Store
19143 * @extends Roo.util.Observable
19144 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19145 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19147 * 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
19148 * has no knowledge of the format of the data returned by the Proxy.<br>
19150 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19151 * instances from the data object. These records are cached and made available through accessor functions.
19153 * Creates a new Store.
19154 * @param {Object} config A config object containing the objects needed for the Store to access data,
19155 * and read the data into Records.
19157 Roo.data.Store = function(config){
19158 this.data = new Roo.util.MixedCollection(false);
19159 this.data.getKey = function(o){
19162 this.baseParams = {};
19164 this.paramNames = {
19169 "multisort" : "_multisort"
19172 if(config && config.data){
19173 this.inlineData = config.data;
19174 delete config.data;
19177 Roo.apply(this, config);
19179 if(this.reader){ // reader passed
19180 this.reader = Roo.factory(this.reader, Roo.data);
19181 this.reader.xmodule = this.xmodule || false;
19182 if(!this.recordType){
19183 this.recordType = this.reader.recordType;
19185 if(this.reader.onMetaChange){
19186 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19190 if(this.recordType){
19191 this.fields = this.recordType.prototype.fields;
19193 this.modified = [];
19197 * @event datachanged
19198 * Fires when the data cache has changed, and a widget which is using this Store
19199 * as a Record cache should refresh its view.
19200 * @param {Store} this
19202 datachanged : true,
19204 * @event metachange
19205 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19206 * @param {Store} this
19207 * @param {Object} meta The JSON metadata
19212 * Fires when Records have been added to the Store
19213 * @param {Store} this
19214 * @param {Roo.data.Record[]} records The array of Records added
19215 * @param {Number} index The index at which the record(s) were added
19220 * Fires when a Record has been removed from the Store
19221 * @param {Store} this
19222 * @param {Roo.data.Record} record The Record that was removed
19223 * @param {Number} index The index at which the record was removed
19228 * Fires when a Record has been updated
19229 * @param {Store} this
19230 * @param {Roo.data.Record} record The Record that was updated
19231 * @param {String} operation The update operation being performed. Value may be one of:
19233 Roo.data.Record.EDIT
19234 Roo.data.Record.REJECT
19235 Roo.data.Record.COMMIT
19241 * Fires when the data cache has been cleared.
19242 * @param {Store} this
19246 * @event beforeload
19247 * Fires before a request is made for a new data object. If the beforeload handler returns false
19248 * the load action will be canceled.
19249 * @param {Store} this
19250 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19255 * Fires after a new set of Records has been loaded.
19256 * @param {Store} this
19257 * @param {Roo.data.Record[]} records The Records that were loaded
19258 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19262 * @event loadexception
19263 * Fires if an exception occurs in the Proxy during loading.
19264 * Called with the signature of the Proxy's "loadexception" event.
19265 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19268 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19269 * @param {Object} load options
19270 * @param {Object} jsonData from your request (normally this contains the Exception)
19272 loadexception : true
19276 this.proxy = Roo.factory(this.proxy, Roo.data);
19277 this.proxy.xmodule = this.xmodule || false;
19278 this.relayEvents(this.proxy, ["loadexception"]);
19280 this.sortToggle = {};
19282 Roo.data.Store.superclass.constructor.call(this);
19284 if(this.inlineData){
19285 this.loadData(this.inlineData);
19286 delete this.inlineData;
19289 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19291 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19292 * without a remote query - used by combo/forms at present.
19296 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19299 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19302 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19303 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19306 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19307 * on any HTTP request
19310 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19313 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns)
19317 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19318 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19320 remoteSort : false,
19323 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19324 * loaded or when a record is removed. (defaults to false).
19326 pruneModifiedRecords : false,
19329 lastOptions : null,
19332 * Add Records to the Store and fires the add event.
19333 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19335 add : function(records){
19336 records = [].concat(records);
19337 for(var i = 0, len = records.length; i < len; i++){
19338 records[i].join(this);
19340 var index = this.data.length;
19341 this.data.addAll(records);
19342 this.fireEvent("add", this, records, index);
19346 * Remove a Record from the Store and fires the remove event.
19347 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19349 remove : function(record){
19350 var index = this.data.indexOf(record);
19351 this.data.removeAt(index);
19352 if(this.pruneModifiedRecords){
19353 this.modified.remove(record);
19355 this.fireEvent("remove", this, record, index);
19359 * Remove all Records from the Store and fires the clear event.
19361 removeAll : function(){
19363 if(this.pruneModifiedRecords){
19364 this.modified = [];
19366 this.fireEvent("clear", this);
19370 * Inserts Records to the Store at the given index and fires the add event.
19371 * @param {Number} index The start index at which to insert the passed Records.
19372 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19374 insert : function(index, records){
19375 records = [].concat(records);
19376 for(var i = 0, len = records.length; i < len; i++){
19377 this.data.insert(index, records[i]);
19378 records[i].join(this);
19380 this.fireEvent("add", this, records, index);
19384 * Get the index within the cache of the passed Record.
19385 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19386 * @return {Number} The index of the passed Record. Returns -1 if not found.
19388 indexOf : function(record){
19389 return this.data.indexOf(record);
19393 * Get the index within the cache of the Record with the passed id.
19394 * @param {String} id The id of the Record to find.
19395 * @return {Number} The index of the Record. Returns -1 if not found.
19397 indexOfId : function(id){
19398 return this.data.indexOfKey(id);
19402 * Get the Record with the specified id.
19403 * @param {String} id The id of the Record to find.
19404 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19406 getById : function(id){
19407 return this.data.key(id);
19411 * Get the Record at the specified index.
19412 * @param {Number} index The index of the Record to find.
19413 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19415 getAt : function(index){
19416 return this.data.itemAt(index);
19420 * Returns a range of Records between specified indices.
19421 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19422 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19423 * @return {Roo.data.Record[]} An array of Records
19425 getRange : function(start, end){
19426 return this.data.getRange(start, end);
19430 storeOptions : function(o){
19431 o = Roo.apply({}, o);
19434 this.lastOptions = o;
19438 * Loads the Record cache from the configured Proxy using the configured Reader.
19440 * If using remote paging, then the first load call must specify the <em>start</em>
19441 * and <em>limit</em> properties in the options.params property to establish the initial
19442 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19444 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19445 * and this call will return before the new data has been loaded. Perform any post-processing
19446 * in a callback function, or in a "load" event handler.</strong>
19448 * @param {Object} options An object containing properties which control loading options:<ul>
19449 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19450 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19451 * passed the following arguments:<ul>
19452 * <li>r : Roo.data.Record[]</li>
19453 * <li>options: Options object from the load call</li>
19454 * <li>success: Boolean success indicator</li></ul></li>
19455 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19456 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19459 load : function(options){
19460 options = options || {};
19461 if(this.fireEvent("beforeload", this, options) !== false){
19462 this.storeOptions(options);
19463 var p = Roo.apply(options.params || {}, this.baseParams);
19464 // if meta was not loaded from remote source.. try requesting it.
19465 if (!this.reader.metaFromRemote) {
19466 p._requestMeta = 1;
19468 if(this.sortInfo && this.remoteSort){
19469 var pn = this.paramNames;
19470 p[pn["sort"]] = this.sortInfo.field;
19471 p[pn["dir"]] = this.sortInfo.direction;
19473 if (this.multiSort) {
19474 var pn = this.paramNames;
19475 p[pn["multisort"]] = Roo.encode(this.sortToggle);
19478 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19483 * Reloads the Record cache from the configured Proxy using the configured Reader and
19484 * the options from the last load operation performed.
19485 * @param {Object} options (optional) An object containing properties which may override the options
19486 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19487 * the most recently used options are reused).
19489 reload : function(options){
19490 this.load(Roo.applyIf(options||{}, this.lastOptions));
19494 // Called as a callback by the Reader during a load operation.
19495 loadRecords : function(o, options, success){
19496 if(!o || success === false){
19497 if(success !== false){
19498 this.fireEvent("load", this, [], options);
19500 if(options.callback){
19501 options.callback.call(options.scope || this, [], options, false);
19505 // if data returned failure - throw an exception.
19506 if (o.success === false) {
19507 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19510 var r = o.records, t = o.totalRecords || r.length;
19511 if(!options || options.add !== true){
19512 if(this.pruneModifiedRecords){
19513 this.modified = [];
19515 for(var i = 0, len = r.length; i < len; i++){
19519 this.data = this.snapshot;
19520 delete this.snapshot;
19523 this.data.addAll(r);
19524 this.totalLength = t;
19526 this.fireEvent("datachanged", this);
19528 this.totalLength = Math.max(t, this.data.length+r.length);
19531 this.fireEvent("load", this, r, options);
19532 if(options.callback){
19533 options.callback.call(options.scope || this, r, options, true);
19538 * Loads data from a passed data block. A Reader which understands the format of the data
19539 * must have been configured in the constructor.
19540 * @param {Object} data The data block from which to read the Records. The format of the data expected
19541 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19542 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19544 loadData : function(o, append){
19545 var r = this.reader.readRecords(o);
19546 this.loadRecords(r, {add: append}, true);
19550 * Gets the number of cached records.
19552 * <em>If using paging, this may not be the total size of the dataset. If the data object
19553 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19554 * the data set size</em>
19556 getCount : function(){
19557 return this.data.length || 0;
19561 * Gets the total number of records in the dataset as returned by the server.
19563 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19564 * the dataset size</em>
19566 getTotalCount : function(){
19567 return this.totalLength || 0;
19571 * Returns the sort state of the Store as an object with two properties:
19573 field {String} The name of the field by which the Records are sorted
19574 direction {String} The sort order, "ASC" or "DESC"
19577 getSortState : function(){
19578 return this.sortInfo;
19582 applySort : function(){
19583 if(this.sortInfo && !this.remoteSort){
19584 var s = this.sortInfo, f = s.field;
19585 var st = this.fields.get(f).sortType;
19586 var fn = function(r1, r2){
19587 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19588 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19590 this.data.sort(s.direction, fn);
19591 if(this.snapshot && this.snapshot != this.data){
19592 this.snapshot.sort(s.direction, fn);
19598 * Sets the default sort column and order to be used by the next load operation.
19599 * @param {String} fieldName The name of the field to sort by.
19600 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19602 setDefaultSort : function(field, dir){
19603 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19607 * Sort the Records.
19608 * If remote sorting is used, the sort is performed on the server, and the cache is
19609 * reloaded. If local sorting is used, the cache is sorted internally.
19610 * @param {String} fieldName The name of the field to sort by.
19611 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19613 sort : function(fieldName, dir){
19614 var f = this.fields.get(fieldName);
19616 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
19618 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
19619 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19624 this.sortToggle[f.name] = dir;
19625 this.sortInfo = {field: f.name, direction: dir};
19626 if(!this.remoteSort){
19628 this.fireEvent("datachanged", this);
19630 this.load(this.lastOptions);
19635 * Calls the specified function for each of the Records in the cache.
19636 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19637 * Returning <em>false</em> aborts and exits the iteration.
19638 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19640 each : function(fn, scope){
19641 this.data.each(fn, scope);
19645 * Gets all records modified since the last commit. Modified records are persisted across load operations
19646 * (e.g., during paging).
19647 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19649 getModifiedRecords : function(){
19650 return this.modified;
19654 createFilterFn : function(property, value, anyMatch){
19655 if(!value.exec){ // not a regex
19656 value = String(value);
19657 if(value.length == 0){
19660 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19662 return function(r){
19663 return value.test(r.data[property]);
19668 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19669 * @param {String} property A field on your records
19670 * @param {Number} start The record index to start at (defaults to 0)
19671 * @param {Number} end The last record index to include (defaults to length - 1)
19672 * @return {Number} The sum
19674 sum : function(property, start, end){
19675 var rs = this.data.items, v = 0;
19676 start = start || 0;
19677 end = (end || end === 0) ? end : rs.length-1;
19679 for(var i = start; i <= end; i++){
19680 v += (rs[i].data[property] || 0);
19686 * Filter the records by a specified property.
19687 * @param {String} field A field on your records
19688 * @param {String/RegExp} value Either a string that the field
19689 * should start with or a RegExp to test against the field
19690 * @param {Boolean} anyMatch True to match any part not just the beginning
19692 filter : function(property, value, anyMatch){
19693 var fn = this.createFilterFn(property, value, anyMatch);
19694 return fn ? this.filterBy(fn) : this.clearFilter();
19698 * Filter by a function. The specified function will be called with each
19699 * record in this data source. If the function returns true the record is included,
19700 * otherwise it is filtered.
19701 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19702 * @param {Object} scope (optional) The scope of the function (defaults to this)
19704 filterBy : function(fn, scope){
19705 this.snapshot = this.snapshot || this.data;
19706 this.data = this.queryBy(fn, scope||this);
19707 this.fireEvent("datachanged", this);
19711 * Query the records by a specified property.
19712 * @param {String} field A field on your records
19713 * @param {String/RegExp} value Either a string that the field
19714 * should start with or a RegExp to test against the field
19715 * @param {Boolean} anyMatch True to match any part not just the beginning
19716 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19718 query : function(property, value, anyMatch){
19719 var fn = this.createFilterFn(property, value, anyMatch);
19720 return fn ? this.queryBy(fn) : this.data.clone();
19724 * Query by a function. The specified function will be called with each
19725 * record in this data source. If the function returns true the record is included
19727 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19728 * @param {Object} scope (optional) The scope of the function (defaults to this)
19729 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19731 queryBy : function(fn, scope){
19732 var data = this.snapshot || this.data;
19733 return data.filterBy(fn, scope||this);
19737 * Collects unique values for a particular dataIndex from this store.
19738 * @param {String} dataIndex The property to collect
19739 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19740 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19741 * @return {Array} An array of the unique values
19743 collect : function(dataIndex, allowNull, bypassFilter){
19744 var d = (bypassFilter === true && this.snapshot) ?
19745 this.snapshot.items : this.data.items;
19746 var v, sv, r = [], l = {};
19747 for(var i = 0, len = d.length; i < len; i++){
19748 v = d[i].data[dataIndex];
19750 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19759 * Revert to a view of the Record cache with no filtering applied.
19760 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19762 clearFilter : function(suppressEvent){
19763 if(this.snapshot && this.snapshot != this.data){
19764 this.data = this.snapshot;
19765 delete this.snapshot;
19766 if(suppressEvent !== true){
19767 this.fireEvent("datachanged", this);
19773 afterEdit : function(record){
19774 if(this.modified.indexOf(record) == -1){
19775 this.modified.push(record);
19777 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19781 afterReject : function(record){
19782 this.modified.remove(record);
19783 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19787 afterCommit : function(record){
19788 this.modified.remove(record);
19789 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19793 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19794 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19796 commitChanges : function(){
19797 var m = this.modified.slice(0);
19798 this.modified = [];
19799 for(var i = 0, len = m.length; i < len; i++){
19805 * Cancel outstanding changes on all changed records.
19807 rejectChanges : function(){
19808 var m = this.modified.slice(0);
19809 this.modified = [];
19810 for(var i = 0, len = m.length; i < len; i++){
19815 onMetaChange : function(meta, rtype, o){
19816 this.recordType = rtype;
19817 this.fields = rtype.prototype.fields;
19818 delete this.snapshot;
19819 this.sortInfo = meta.sortInfo || this.sortInfo;
19820 this.modified = [];
19821 this.fireEvent('metachange', this, this.reader.meta);
19825 * Ext JS Library 1.1.1
19826 * Copyright(c) 2006-2007, Ext JS, LLC.
19828 * Originally Released Under LGPL - original licence link has changed is not relivant.
19831 * <script type="text/javascript">
19835 * @class Roo.data.SimpleStore
19836 * @extends Roo.data.Store
19837 * Small helper class to make creating Stores from Array data easier.
19838 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19839 * @cfg {Array} fields An array of field definition objects, or field name strings.
19840 * @cfg {Array} data The multi-dimensional array of data
19842 * @param {Object} config
19844 Roo.data.SimpleStore = function(config){
19845 Roo.data.SimpleStore.superclass.constructor.call(this, {
19847 reader: new Roo.data.ArrayReader({
19850 Roo.data.Record.create(config.fields)
19852 proxy : new Roo.data.MemoryProxy(config.data)
19856 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19858 * Ext JS Library 1.1.1
19859 * Copyright(c) 2006-2007, Ext JS, LLC.
19861 * Originally Released Under LGPL - original licence link has changed is not relivant.
19864 * <script type="text/javascript">
19869 * @extends Roo.data.Store
19870 * @class Roo.data.JsonStore
19871 * Small helper class to make creating Stores for JSON data easier. <br/>
19873 var store = new Roo.data.JsonStore({
19874 url: 'get-images.php',
19876 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19879 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19880 * JsonReader and HttpProxy (unless inline data is provided).</b>
19881 * @cfg {Array} fields An array of field definition objects, or field name strings.
19883 * @param {Object} config
19885 Roo.data.JsonStore = function(c){
19886 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19887 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19888 reader: new Roo.data.JsonReader(c, c.fields)
19891 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19893 * Ext JS Library 1.1.1
19894 * Copyright(c) 2006-2007, Ext JS, LLC.
19896 * Originally Released Under LGPL - original licence link has changed is not relivant.
19899 * <script type="text/javascript">
19903 Roo.data.Field = function(config){
19904 if(typeof config == "string"){
19905 config = {name: config};
19907 Roo.apply(this, config);
19910 this.type = "auto";
19913 var st = Roo.data.SortTypes;
19914 // named sortTypes are supported, here we look them up
19915 if(typeof this.sortType == "string"){
19916 this.sortType = st[this.sortType];
19919 // set default sortType for strings and dates
19920 if(!this.sortType){
19923 this.sortType = st.asUCString;
19926 this.sortType = st.asDate;
19929 this.sortType = st.none;
19934 var stripRe = /[\$,%]/g;
19936 // prebuilt conversion function for this field, instead of
19937 // switching every time we're reading a value
19939 var cv, dateFormat = this.dateFormat;
19944 cv = function(v){ return v; };
19947 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19951 return v !== undefined && v !== null && v !== '' ?
19952 parseInt(String(v).replace(stripRe, ""), 10) : '';
19957 return v !== undefined && v !== null && v !== '' ?
19958 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19963 cv = function(v){ return v === true || v === "true" || v == 1; };
19970 if(v instanceof Date){
19974 if(dateFormat == "timestamp"){
19975 return new Date(v*1000);
19977 return Date.parseDate(v, dateFormat);
19979 var parsed = Date.parse(v);
19980 return parsed ? new Date(parsed) : null;
19989 Roo.data.Field.prototype = {
19997 * Ext JS Library 1.1.1
19998 * Copyright(c) 2006-2007, Ext JS, LLC.
20000 * Originally Released Under LGPL - original licence link has changed is not relivant.
20003 * <script type="text/javascript">
20006 // Base class for reading structured data from a data source. This class is intended to be
20007 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20010 * @class Roo.data.DataReader
20011 * Base class for reading structured data from a data source. This class is intended to be
20012 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20015 Roo.data.DataReader = function(meta, recordType){
20019 this.recordType = recordType instanceof Array ?
20020 Roo.data.Record.create(recordType) : recordType;
20023 Roo.data.DataReader.prototype = {
20025 * Create an empty record
20026 * @param {Object} data (optional) - overlay some values
20027 * @return {Roo.data.Record} record created.
20029 newRow : function(d) {
20031 this.recordType.prototype.fields.each(function(c) {
20033 case 'int' : da[c.name] = 0; break;
20034 case 'date' : da[c.name] = new Date(); break;
20035 case 'float' : da[c.name] = 0.0; break;
20036 case 'boolean' : da[c.name] = false; break;
20037 default : da[c.name] = ""; break;
20041 return new this.recordType(Roo.apply(da, d));
20046 * Ext JS Library 1.1.1
20047 * Copyright(c) 2006-2007, Ext JS, LLC.
20049 * Originally Released Under LGPL - original licence link has changed is not relivant.
20052 * <script type="text/javascript">
20056 * @class Roo.data.DataProxy
20057 * @extends Roo.data.Observable
20058 * This class is an abstract base class for implementations which provide retrieval of
20059 * unformatted data objects.<br>
20061 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20062 * (of the appropriate type which knows how to parse the data object) to provide a block of
20063 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20065 * Custom implementations must implement the load method as described in
20066 * {@link Roo.data.HttpProxy#load}.
20068 Roo.data.DataProxy = function(){
20071 * @event beforeload
20072 * Fires before a network request is made to retrieve a data object.
20073 * @param {Object} This DataProxy object.
20074 * @param {Object} params The params parameter to the load function.
20079 * Fires before the load method's callback is called.
20080 * @param {Object} This DataProxy object.
20081 * @param {Object} o The data object.
20082 * @param {Object} arg The callback argument object passed to the load function.
20086 * @event loadexception
20087 * Fires if an Exception occurs during data retrieval.
20088 * @param {Object} This DataProxy object.
20089 * @param {Object} o The data object.
20090 * @param {Object} arg The callback argument object passed to the load function.
20091 * @param {Object} e The Exception.
20093 loadexception : true
20095 Roo.data.DataProxy.superclass.constructor.call(this);
20098 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20101 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20105 * Ext JS Library 1.1.1
20106 * Copyright(c) 2006-2007, Ext JS, LLC.
20108 * Originally Released Under LGPL - original licence link has changed is not relivant.
20111 * <script type="text/javascript">
20114 * @class Roo.data.MemoryProxy
20115 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20116 * to the Reader when its load method is called.
20118 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20120 Roo.data.MemoryProxy = function(data){
20124 Roo.data.MemoryProxy.superclass.constructor.call(this);
20128 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20130 * Load data from the requested source (in this case an in-memory
20131 * data object passed to the constructor), read the data object into
20132 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20133 * process that block using the passed callback.
20134 * @param {Object} params This parameter is not used by the MemoryProxy class.
20135 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20136 * object into a block of Roo.data.Records.
20137 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20138 * The function must be passed <ul>
20139 * <li>The Record block object</li>
20140 * <li>The "arg" argument from the load function</li>
20141 * <li>A boolean success indicator</li>
20143 * @param {Object} scope The scope in which to call the callback
20144 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20146 load : function(params, reader, callback, scope, arg){
20147 params = params || {};
20150 result = reader.readRecords(this.data);
20152 this.fireEvent("loadexception", this, arg, null, e);
20153 callback.call(scope, null, arg, false);
20156 callback.call(scope, result, arg, true);
20160 update : function(params, records){
20165 * Ext JS Library 1.1.1
20166 * Copyright(c) 2006-2007, Ext JS, LLC.
20168 * Originally Released Under LGPL - original licence link has changed is not relivant.
20171 * <script type="text/javascript">
20174 * @class Roo.data.HttpProxy
20175 * @extends Roo.data.DataProxy
20176 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20177 * configured to reference a certain URL.<br><br>
20179 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20180 * from which the running page was served.<br><br>
20182 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20184 * Be aware that to enable the browser to parse an XML document, the server must set
20185 * the Content-Type header in the HTTP response to "text/xml".
20187 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20188 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20189 * will be used to make the request.
20191 Roo.data.HttpProxy = function(conn){
20192 Roo.data.HttpProxy.superclass.constructor.call(this);
20193 // is conn a conn config or a real conn?
20195 this.useAjax = !conn || !conn.events;
20199 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20200 // thse are take from connection...
20203 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20206 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20207 * extra parameters to each request made by this object. (defaults to undefined)
20210 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20211 * to each request made by this object. (defaults to undefined)
20214 * @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)
20217 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20220 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20226 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20230 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20231 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20232 * a finer-grained basis than the DataProxy events.
20234 getConnection : function(){
20235 return this.useAjax ? Roo.Ajax : this.conn;
20239 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20240 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20241 * process that block using the passed callback.
20242 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20243 * for the request to the remote server.
20244 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20245 * object into a block of Roo.data.Records.
20246 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20247 * The function must be passed <ul>
20248 * <li>The Record block object</li>
20249 * <li>The "arg" argument from the load function</li>
20250 * <li>A boolean success indicator</li>
20252 * @param {Object} scope The scope in which to call the callback
20253 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20255 load : function(params, reader, callback, scope, arg){
20256 if(this.fireEvent("beforeload", this, params) !== false){
20258 params : params || {},
20260 callback : callback,
20265 callback : this.loadResponse,
20269 Roo.applyIf(o, this.conn);
20270 if(this.activeRequest){
20271 Roo.Ajax.abort(this.activeRequest);
20273 this.activeRequest = Roo.Ajax.request(o);
20275 this.conn.request(o);
20278 callback.call(scope||this, null, arg, false);
20283 loadResponse : function(o, success, response){
20284 delete this.activeRequest;
20286 this.fireEvent("loadexception", this, o, response);
20287 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20292 result = o.reader.read(response);
20294 this.fireEvent("loadexception", this, o, response, e);
20295 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20299 this.fireEvent("load", this, o, o.request.arg);
20300 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20304 update : function(dataSet){
20309 updateResponse : function(dataSet){
20314 * Ext JS Library 1.1.1
20315 * Copyright(c) 2006-2007, Ext JS, LLC.
20317 * Originally Released Under LGPL - original licence link has changed is not relivant.
20320 * <script type="text/javascript">
20324 * @class Roo.data.ScriptTagProxy
20325 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20326 * other than the originating domain of the running page.<br><br>
20328 * <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
20329 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20331 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20332 * source code that is used as the source inside a <script> tag.<br><br>
20334 * In order for the browser to process the returned data, the server must wrap the data object
20335 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20336 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20337 * depending on whether the callback name was passed:
20340 boolean scriptTag = false;
20341 String cb = request.getParameter("callback");
20344 response.setContentType("text/javascript");
20346 response.setContentType("application/x-json");
20348 Writer out = response.getWriter();
20350 out.write(cb + "(");
20352 out.print(dataBlock.toJsonString());
20359 * @param {Object} config A configuration object.
20361 Roo.data.ScriptTagProxy = function(config){
20362 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20363 Roo.apply(this, config);
20364 this.head = document.getElementsByTagName("head")[0];
20367 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20369 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20371 * @cfg {String} url The URL from which to request the data object.
20374 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20378 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20379 * the server the name of the callback function set up by the load call to process the returned data object.
20380 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20381 * javascript output which calls this named function passing the data object as its only parameter.
20383 callbackParam : "callback",
20385 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20386 * name to the request.
20391 * Load data from the configured URL, read the data object into
20392 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20393 * process that block using the passed callback.
20394 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20395 * for the request to the remote server.
20396 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20397 * object into a block of Roo.data.Records.
20398 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20399 * The function must be passed <ul>
20400 * <li>The Record block object</li>
20401 * <li>The "arg" argument from the load function</li>
20402 * <li>A boolean success indicator</li>
20404 * @param {Object} scope The scope in which to call the callback
20405 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20407 load : function(params, reader, callback, scope, arg){
20408 if(this.fireEvent("beforeload", this, params) !== false){
20410 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20412 var url = this.url;
20413 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20415 url += "&_dc=" + (new Date().getTime());
20417 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20420 cb : "stcCallback"+transId,
20421 scriptId : "stcScript"+transId,
20425 callback : callback,
20431 window[trans.cb] = function(o){
20432 conn.handleResponse(o, trans);
20435 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20437 if(this.autoAbort !== false){
20441 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20443 var script = document.createElement("script");
20444 script.setAttribute("src", url);
20445 script.setAttribute("type", "text/javascript");
20446 script.setAttribute("id", trans.scriptId);
20447 this.head.appendChild(script);
20449 this.trans = trans;
20451 callback.call(scope||this, null, arg, false);
20456 isLoading : function(){
20457 return this.trans ? true : false;
20461 * Abort the current server request.
20463 abort : function(){
20464 if(this.isLoading()){
20465 this.destroyTrans(this.trans);
20470 destroyTrans : function(trans, isLoaded){
20471 this.head.removeChild(document.getElementById(trans.scriptId));
20472 clearTimeout(trans.timeoutId);
20474 window[trans.cb] = undefined;
20476 delete window[trans.cb];
20479 // if hasn't been loaded, wait for load to remove it to prevent script error
20480 window[trans.cb] = function(){
20481 window[trans.cb] = undefined;
20483 delete window[trans.cb];
20490 handleResponse : function(o, trans){
20491 this.trans = false;
20492 this.destroyTrans(trans, true);
20495 result = trans.reader.readRecords(o);
20497 this.fireEvent("loadexception", this, o, trans.arg, e);
20498 trans.callback.call(trans.scope||window, null, trans.arg, false);
20501 this.fireEvent("load", this, o, trans.arg);
20502 trans.callback.call(trans.scope||window, result, trans.arg, true);
20506 handleFailure : function(trans){
20507 this.trans = false;
20508 this.destroyTrans(trans, false);
20509 this.fireEvent("loadexception", this, null, trans.arg);
20510 trans.callback.call(trans.scope||window, null, trans.arg, false);
20514 * Ext JS Library 1.1.1
20515 * Copyright(c) 2006-2007, Ext JS, LLC.
20517 * Originally Released Under LGPL - original licence link has changed is not relivant.
20520 * <script type="text/javascript">
20524 * @class Roo.data.JsonReader
20525 * @extends Roo.data.DataReader
20526 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20527 * based on mappings in a provided Roo.data.Record constructor.
20529 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
20530 * in the reply previously.
20535 var RecordDef = Roo.data.Record.create([
20536 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20537 {name: 'occupation'} // This field will use "occupation" as the mapping.
20539 var myReader = new Roo.data.JsonReader({
20540 totalProperty: "results", // The property which contains the total dataset size (optional)
20541 root: "rows", // The property which contains an Array of row objects
20542 id: "id" // The property within each row object that provides an ID for the record (optional)
20546 * This would consume a JSON file like this:
20548 { 'results': 2, 'rows': [
20549 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20550 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20553 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20554 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20555 * paged from the remote server.
20556 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20557 * @cfg {String} root name of the property which contains the Array of row objects.
20558 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20560 * Create a new JsonReader
20561 * @param {Object} meta Metadata configuration options
20562 * @param {Object} recordType Either an Array of field definition objects,
20563 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20565 Roo.data.JsonReader = function(meta, recordType){
20568 // set some defaults:
20569 Roo.applyIf(meta, {
20570 totalProperty: 'total',
20571 successProperty : 'success',
20576 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20578 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20581 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
20582 * Used by Store query builder to append _requestMeta to params.
20585 metaFromRemote : false,
20587 * This method is only used by a DataProxy which has retrieved data from a remote server.
20588 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20589 * @return {Object} data A data block which is used by an Roo.data.Store object as
20590 * a cache of Roo.data.Records.
20592 read : function(response){
20593 var json = response.responseText;
20595 var o = /* eval:var:o */ eval("("+json+")");
20597 throw {message: "JsonReader.read: Json object not found"};
20603 this.metaFromRemote = true;
20604 this.meta = o.metaData;
20605 this.recordType = Roo.data.Record.create(o.metaData.fields);
20606 this.onMetaChange(this.meta, this.recordType, o);
20608 return this.readRecords(o);
20611 // private function a store will implement
20612 onMetaChange : function(meta, recordType, o){
20619 simpleAccess: function(obj, subsc) {
20626 getJsonAccessor: function(){
20628 return function(expr) {
20630 return(re.test(expr))
20631 ? new Function("obj", "return obj." + expr)
20636 return Roo.emptyFn;
20641 * Create a data block containing Roo.data.Records from an XML document.
20642 * @param {Object} o An object which contains an Array of row objects in the property specified
20643 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20644 * which contains the total size of the dataset.
20645 * @return {Object} data A data block which is used by an Roo.data.Store object as
20646 * a cache of Roo.data.Records.
20648 readRecords : function(o){
20650 * After any data loads, the raw JSON data is available for further custom processing.
20654 var s = this.meta, Record = this.recordType,
20655 f = Record.prototype.fields, fi = f.items, fl = f.length;
20657 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20659 if(s.totalProperty) {
20660 this.getTotal = this.getJsonAccessor(s.totalProperty);
20662 if(s.successProperty) {
20663 this.getSuccess = this.getJsonAccessor(s.successProperty);
20665 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20667 var g = this.getJsonAccessor(s.id);
20668 this.getId = function(rec) {
20670 return (r === undefined || r === "") ? null : r;
20673 this.getId = function(){return null;};
20676 for(var jj = 0; jj < fl; jj++){
20678 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20679 this.ef[jj] = this.getJsonAccessor(map);
20683 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20684 if(s.totalProperty){
20685 var vt = parseInt(this.getTotal(o), 10);
20690 if(s.successProperty){
20691 var vs = this.getSuccess(o);
20692 if(vs === false || vs === 'false'){
20697 for(var i = 0; i < c; i++){
20700 var id = this.getId(n);
20701 for(var j = 0; j < fl; j++){
20703 var v = this.ef[j](n);
20705 Roo.log('missing convert for ' + f.name);
20709 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20711 var record = new Record(values, id);
20713 records[i] = record;
20718 totalRecords : totalRecords
20723 * Ext JS Library 1.1.1
20724 * Copyright(c) 2006-2007, Ext JS, LLC.
20726 * Originally Released Under LGPL - original licence link has changed is not relivant.
20729 * <script type="text/javascript">
20733 * @class Roo.data.XmlReader
20734 * @extends Roo.data.DataReader
20735 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20736 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20738 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20739 * header in the HTTP response must be set to "text/xml".</em>
20743 var RecordDef = Roo.data.Record.create([
20744 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20745 {name: 'occupation'} // This field will use "occupation" as the mapping.
20747 var myReader = new Roo.data.XmlReader({
20748 totalRecords: "results", // The element which contains the total dataset size (optional)
20749 record: "row", // The repeated element which contains row information
20750 id: "id" // The element within the row that provides an ID for the record (optional)
20754 * This would consume an XML file like this:
20758 <results>2</results>
20761 <name>Bill</name>
20762 <occupation>Gardener</occupation>
20766 <name>Ben</name>
20767 <occupation>Horticulturalist</occupation>
20771 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20772 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20773 * paged from the remote server.
20774 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20775 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20776 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20777 * a record identifier value.
20779 * Create a new XmlReader
20780 * @param {Object} meta Metadata configuration options
20781 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20782 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20783 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20785 Roo.data.XmlReader = function(meta, recordType){
20787 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20789 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20791 * This method is only used by a DataProxy which has retrieved data from a remote server.
20792 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20793 * to contain a method called 'responseXML' that returns an XML document object.
20794 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20795 * a cache of Roo.data.Records.
20797 read : function(response){
20798 var doc = response.responseXML;
20800 throw {message: "XmlReader.read: XML Document not available"};
20802 return this.readRecords(doc);
20806 * Create a data block containing Roo.data.Records from an XML document.
20807 * @param {Object} doc A parsed XML document.
20808 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20809 * a cache of Roo.data.Records.
20811 readRecords : function(doc){
20813 * After any data loads/reads, the raw XML Document is available for further custom processing.
20814 * @type XMLDocument
20816 this.xmlData = doc;
20817 var root = doc.documentElement || doc;
20818 var q = Roo.DomQuery;
20819 var recordType = this.recordType, fields = recordType.prototype.fields;
20820 var sid = this.meta.id;
20821 var totalRecords = 0, success = true;
20822 if(this.meta.totalRecords){
20823 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20826 if(this.meta.success){
20827 var sv = q.selectValue(this.meta.success, root, true);
20828 success = sv !== false && sv !== 'false';
20831 var ns = q.select(this.meta.record, root);
20832 for(var i = 0, len = ns.length; i < len; i++) {
20835 var id = sid ? q.selectValue(sid, n) : undefined;
20836 for(var j = 0, jlen = fields.length; j < jlen; j++){
20837 var f = fields.items[j];
20838 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20840 values[f.name] = v;
20842 var record = new recordType(values, id);
20844 records[records.length] = record;
20850 totalRecords : totalRecords || records.length
20855 * Ext JS Library 1.1.1
20856 * Copyright(c) 2006-2007, Ext JS, LLC.
20858 * Originally Released Under LGPL - original licence link has changed is not relivant.
20861 * <script type="text/javascript">
20865 * @class Roo.data.ArrayReader
20866 * @extends Roo.data.DataReader
20867 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20868 * Each element of that Array represents a row of data fields. The
20869 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20870 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20874 var RecordDef = Roo.data.Record.create([
20875 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20876 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20878 var myReader = new Roo.data.ArrayReader({
20879 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20883 * This would consume an Array like this:
20885 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20887 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20889 * Create a new JsonReader
20890 * @param {Object} meta Metadata configuration options.
20891 * @param {Object} recordType Either an Array of field definition objects
20892 * as specified to {@link Roo.data.Record#create},
20893 * or an {@link Roo.data.Record} object
20894 * created using {@link Roo.data.Record#create}.
20896 Roo.data.ArrayReader = function(meta, recordType){
20897 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20900 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20902 * Create a data block containing Roo.data.Records from an XML document.
20903 * @param {Object} o An Array of row objects which represents the dataset.
20904 * @return {Object} data A data block which is used by an Roo.data.Store object as
20905 * a cache of Roo.data.Records.
20907 readRecords : function(o){
20908 var sid = this.meta ? this.meta.id : null;
20909 var recordType = this.recordType, fields = recordType.prototype.fields;
20912 for(var i = 0; i < root.length; i++){
20915 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20916 for(var j = 0, jlen = fields.length; j < jlen; j++){
20917 var f = fields.items[j];
20918 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20919 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20921 values[f.name] = v;
20923 var record = new recordType(values, id);
20925 records[records.length] = record;
20929 totalRecords : records.length
20934 * Ext JS Library 1.1.1
20935 * Copyright(c) 2006-2007, Ext JS, LLC.
20937 * Originally Released Under LGPL - original licence link has changed is not relivant.
20940 * <script type="text/javascript">
20945 * @class Roo.data.Tree
20946 * @extends Roo.util.Observable
20947 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20948 * in the tree have most standard DOM functionality.
20950 * @param {Node} root (optional) The root node
20952 Roo.data.Tree = function(root){
20953 this.nodeHash = {};
20955 * The root node for this tree
20960 this.setRootNode(root);
20965 * Fires when a new child node is appended to a node in this tree.
20966 * @param {Tree} tree The owner tree
20967 * @param {Node} parent The parent node
20968 * @param {Node} node The newly appended node
20969 * @param {Number} index The index of the newly appended node
20974 * Fires when a child node is removed from a node in this tree.
20975 * @param {Tree} tree The owner tree
20976 * @param {Node} parent The parent node
20977 * @param {Node} node The child node removed
20982 * Fires when a node is moved to a new location in the tree
20983 * @param {Tree} tree The owner tree
20984 * @param {Node} node The node moved
20985 * @param {Node} oldParent The old parent of this node
20986 * @param {Node} newParent The new parent of this node
20987 * @param {Number} index The index it was moved to
20992 * Fires when a new child node is inserted in a node in this tree.
20993 * @param {Tree} tree The owner tree
20994 * @param {Node} parent The parent node
20995 * @param {Node} node The child node inserted
20996 * @param {Node} refNode The child node the node was inserted before
21000 * @event beforeappend
21001 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21002 * @param {Tree} tree The owner tree
21003 * @param {Node} parent The parent node
21004 * @param {Node} node The child node to be appended
21006 "beforeappend" : true,
21008 * @event beforeremove
21009 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21010 * @param {Tree} tree The owner tree
21011 * @param {Node} parent The parent node
21012 * @param {Node} node The child node to be removed
21014 "beforeremove" : true,
21016 * @event beforemove
21017 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21018 * @param {Tree} tree The owner tree
21019 * @param {Node} node The node being moved
21020 * @param {Node} oldParent The parent of the node
21021 * @param {Node} newParent The new parent the node is moving to
21022 * @param {Number} index The index it is being moved to
21024 "beforemove" : true,
21026 * @event beforeinsert
21027 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21028 * @param {Tree} tree The owner tree
21029 * @param {Node} parent The parent node
21030 * @param {Node} node The child node to be inserted
21031 * @param {Node} refNode The child node the node is being inserted before
21033 "beforeinsert" : true
21036 Roo.data.Tree.superclass.constructor.call(this);
21039 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21040 pathSeparator: "/",
21042 proxyNodeEvent : function(){
21043 return this.fireEvent.apply(this, arguments);
21047 * Returns the root node for this tree.
21050 getRootNode : function(){
21055 * Sets the root node for this tree.
21056 * @param {Node} node
21059 setRootNode : function(node){
21061 node.ownerTree = this;
21062 node.isRoot = true;
21063 this.registerNode(node);
21068 * Gets a node in this tree by its id.
21069 * @param {String} id
21072 getNodeById : function(id){
21073 return this.nodeHash[id];
21076 registerNode : function(node){
21077 this.nodeHash[node.id] = node;
21080 unregisterNode : function(node){
21081 delete this.nodeHash[node.id];
21084 toString : function(){
21085 return "[Tree"+(this.id?" "+this.id:"")+"]";
21090 * @class Roo.data.Node
21091 * @extends Roo.util.Observable
21092 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21093 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21095 * @param {Object} attributes The attributes/config for the node
21097 Roo.data.Node = function(attributes){
21099 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21102 this.attributes = attributes || {};
21103 this.leaf = this.attributes.leaf;
21105 * The node id. @type String
21107 this.id = this.attributes.id;
21109 this.id = Roo.id(null, "ynode-");
21110 this.attributes.id = this.id;
21113 * All child nodes of this node. @type Array
21115 this.childNodes = [];
21116 if(!this.childNodes.indexOf){ // indexOf is a must
21117 this.childNodes.indexOf = function(o){
21118 for(var i = 0, len = this.length; i < len; i++){
21127 * The parent node for this node. @type Node
21129 this.parentNode = null;
21131 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21133 this.firstChild = null;
21135 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21137 this.lastChild = null;
21139 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21141 this.previousSibling = null;
21143 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21145 this.nextSibling = null;
21150 * Fires when a new child node is appended
21151 * @param {Tree} tree The owner tree
21152 * @param {Node} this This node
21153 * @param {Node} node The newly appended node
21154 * @param {Number} index The index of the newly appended node
21159 * Fires when a child node is removed
21160 * @param {Tree} tree The owner tree
21161 * @param {Node} this This node
21162 * @param {Node} node The removed node
21167 * Fires when this node is moved to a new location in the tree
21168 * @param {Tree} tree The owner tree
21169 * @param {Node} this This node
21170 * @param {Node} oldParent The old parent of this node
21171 * @param {Node} newParent The new parent of this node
21172 * @param {Number} index The index it was moved to
21177 * Fires when a new child node is inserted.
21178 * @param {Tree} tree The owner tree
21179 * @param {Node} this This node
21180 * @param {Node} node The child node inserted
21181 * @param {Node} refNode The child node the node was inserted before
21185 * @event beforeappend
21186 * Fires before a new child is appended, return false to cancel the append.
21187 * @param {Tree} tree The owner tree
21188 * @param {Node} this This node
21189 * @param {Node} node The child node to be appended
21191 "beforeappend" : true,
21193 * @event beforeremove
21194 * Fires before a child is removed, return false to cancel the remove.
21195 * @param {Tree} tree The owner tree
21196 * @param {Node} this This node
21197 * @param {Node} node The child node to be removed
21199 "beforeremove" : true,
21201 * @event beforemove
21202 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21203 * @param {Tree} tree The owner tree
21204 * @param {Node} this This node
21205 * @param {Node} oldParent The parent of this node
21206 * @param {Node} newParent The new parent this node is moving to
21207 * @param {Number} index The index it is being moved to
21209 "beforemove" : true,
21211 * @event beforeinsert
21212 * Fires before a new child is inserted, return false to cancel the insert.
21213 * @param {Tree} tree The owner tree
21214 * @param {Node} this This node
21215 * @param {Node} node The child node to be inserted
21216 * @param {Node} refNode The child node the node is being inserted before
21218 "beforeinsert" : true
21220 this.listeners = this.attributes.listeners;
21221 Roo.data.Node.superclass.constructor.call(this);
21224 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21225 fireEvent : function(evtName){
21226 // first do standard event for this node
21227 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21230 // then bubble it up to the tree if the event wasn't cancelled
21231 var ot = this.getOwnerTree();
21233 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21241 * Returns true if this node is a leaf
21242 * @return {Boolean}
21244 isLeaf : function(){
21245 return this.leaf === true;
21249 setFirstChild : function(node){
21250 this.firstChild = node;
21254 setLastChild : function(node){
21255 this.lastChild = node;
21260 * Returns true if this node is the last child of its parent
21261 * @return {Boolean}
21263 isLast : function(){
21264 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21268 * Returns true if this node is the first child of its parent
21269 * @return {Boolean}
21271 isFirst : function(){
21272 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21275 hasChildNodes : function(){
21276 return !this.isLeaf() && this.childNodes.length > 0;
21280 * Insert node(s) as the last child node of this node.
21281 * @param {Node/Array} node The node or Array of nodes to append
21282 * @return {Node} The appended node if single append, or null if an array was passed
21284 appendChild : function(node){
21286 if(node instanceof Array){
21288 }else if(arguments.length > 1){
21291 // if passed an array or multiple args do them one by one
21293 for(var i = 0, len = multi.length; i < len; i++) {
21294 this.appendChild(multi[i]);
21297 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21300 var index = this.childNodes.length;
21301 var oldParent = node.parentNode;
21302 // it's a move, make sure we move it cleanly
21304 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21307 oldParent.removeChild(node);
21309 index = this.childNodes.length;
21311 this.setFirstChild(node);
21313 this.childNodes.push(node);
21314 node.parentNode = this;
21315 var ps = this.childNodes[index-1];
21317 node.previousSibling = ps;
21318 ps.nextSibling = node;
21320 node.previousSibling = null;
21322 node.nextSibling = null;
21323 this.setLastChild(node);
21324 node.setOwnerTree(this.getOwnerTree());
21325 this.fireEvent("append", this.ownerTree, this, node, index);
21327 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21334 * Removes a child node from this node.
21335 * @param {Node} node The node to remove
21336 * @return {Node} The removed node
21338 removeChild : function(node){
21339 var index = this.childNodes.indexOf(node);
21343 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21347 // remove it from childNodes collection
21348 this.childNodes.splice(index, 1);
21351 if(node.previousSibling){
21352 node.previousSibling.nextSibling = node.nextSibling;
21354 if(node.nextSibling){
21355 node.nextSibling.previousSibling = node.previousSibling;
21358 // update child refs
21359 if(this.firstChild == node){
21360 this.setFirstChild(node.nextSibling);
21362 if(this.lastChild == node){
21363 this.setLastChild(node.previousSibling);
21366 node.setOwnerTree(null);
21367 // clear any references from the node
21368 node.parentNode = null;
21369 node.previousSibling = null;
21370 node.nextSibling = null;
21371 this.fireEvent("remove", this.ownerTree, this, node);
21376 * Inserts the first node before the second node in this nodes childNodes collection.
21377 * @param {Node} node The node to insert
21378 * @param {Node} refNode The node to insert before (if null the node is appended)
21379 * @return {Node} The inserted node
21381 insertBefore : function(node, refNode){
21382 if(!refNode){ // like standard Dom, refNode can be null for append
21383 return this.appendChild(node);
21386 if(node == refNode){
21390 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21393 var index = this.childNodes.indexOf(refNode);
21394 var oldParent = node.parentNode;
21395 var refIndex = index;
21397 // when moving internally, indexes will change after remove
21398 if(oldParent == this && this.childNodes.indexOf(node) < index){
21402 // it's a move, make sure we move it cleanly
21404 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21407 oldParent.removeChild(node);
21410 this.setFirstChild(node);
21412 this.childNodes.splice(refIndex, 0, node);
21413 node.parentNode = this;
21414 var ps = this.childNodes[refIndex-1];
21416 node.previousSibling = ps;
21417 ps.nextSibling = node;
21419 node.previousSibling = null;
21421 node.nextSibling = refNode;
21422 refNode.previousSibling = node;
21423 node.setOwnerTree(this.getOwnerTree());
21424 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21426 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21432 * Returns the child node at the specified index.
21433 * @param {Number} index
21436 item : function(index){
21437 return this.childNodes[index];
21441 * Replaces one child node in this node with another.
21442 * @param {Node} newChild The replacement node
21443 * @param {Node} oldChild The node to replace
21444 * @return {Node} The replaced node
21446 replaceChild : function(newChild, oldChild){
21447 this.insertBefore(newChild, oldChild);
21448 this.removeChild(oldChild);
21453 * Returns the index of a child node
21454 * @param {Node} node
21455 * @return {Number} The index of the node or -1 if it was not found
21457 indexOf : function(child){
21458 return this.childNodes.indexOf(child);
21462 * Returns the tree this node is in.
21465 getOwnerTree : function(){
21466 // if it doesn't have one, look for one
21467 if(!this.ownerTree){
21471 this.ownerTree = p.ownerTree;
21477 return this.ownerTree;
21481 * Returns depth of this node (the root node has a depth of 0)
21484 getDepth : function(){
21487 while(p.parentNode){
21495 setOwnerTree : function(tree){
21496 // if it's move, we need to update everyone
21497 if(tree != this.ownerTree){
21498 if(this.ownerTree){
21499 this.ownerTree.unregisterNode(this);
21501 this.ownerTree = tree;
21502 var cs = this.childNodes;
21503 for(var i = 0, len = cs.length; i < len; i++) {
21504 cs[i].setOwnerTree(tree);
21507 tree.registerNode(this);
21513 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21514 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21515 * @return {String} The path
21517 getPath : function(attr){
21518 attr = attr || "id";
21519 var p = this.parentNode;
21520 var b = [this.attributes[attr]];
21522 b.unshift(p.attributes[attr]);
21525 var sep = this.getOwnerTree().pathSeparator;
21526 return sep + b.join(sep);
21530 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21531 * function call will be the scope provided or the current node. The arguments to the function
21532 * will be the args provided or the current node. If the function returns false at any point,
21533 * the bubble is stopped.
21534 * @param {Function} fn The function to call
21535 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21536 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21538 bubble : function(fn, scope, args){
21541 if(fn.call(scope || p, args || p) === false){
21549 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21550 * function call will be the scope provided or the current node. The arguments to the function
21551 * will be the args provided or the current node. If the function returns false at any point,
21552 * the cascade is stopped on that branch.
21553 * @param {Function} fn The function to call
21554 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21555 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21557 cascade : function(fn, scope, args){
21558 if(fn.call(scope || this, args || this) !== false){
21559 var cs = this.childNodes;
21560 for(var i = 0, len = cs.length; i < len; i++) {
21561 cs[i].cascade(fn, scope, args);
21567 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21568 * function call will be the scope provided or the current node. The arguments to the function
21569 * will be the args provided or the current node. If the function returns false at any point,
21570 * the iteration stops.
21571 * @param {Function} fn The function to call
21572 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21573 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21575 eachChild : function(fn, scope, args){
21576 var cs = this.childNodes;
21577 for(var i = 0, len = cs.length; i < len; i++) {
21578 if(fn.call(scope || this, args || cs[i]) === false){
21585 * Finds the first child that has the attribute with the specified value.
21586 * @param {String} attribute The attribute name
21587 * @param {Mixed} value The value to search for
21588 * @return {Node} The found child or null if none was found
21590 findChild : function(attribute, value){
21591 var cs = this.childNodes;
21592 for(var i = 0, len = cs.length; i < len; i++) {
21593 if(cs[i].attributes[attribute] == value){
21601 * Finds the first child by a custom function. The child matches if the function passed
21603 * @param {Function} fn
21604 * @param {Object} scope (optional)
21605 * @return {Node} The found child or null if none was found
21607 findChildBy : function(fn, scope){
21608 var cs = this.childNodes;
21609 for(var i = 0, len = cs.length; i < len; i++) {
21610 if(fn.call(scope||cs[i], cs[i]) === true){
21618 * Sorts this nodes children using the supplied sort function
21619 * @param {Function} fn
21620 * @param {Object} scope (optional)
21622 sort : function(fn, scope){
21623 var cs = this.childNodes;
21624 var len = cs.length;
21626 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21628 for(var i = 0; i < len; i++){
21630 n.previousSibling = cs[i-1];
21631 n.nextSibling = cs[i+1];
21633 this.setFirstChild(n);
21636 this.setLastChild(n);
21643 * Returns true if this node is an ancestor (at any point) of the passed node.
21644 * @param {Node} node
21645 * @return {Boolean}
21647 contains : function(node){
21648 return node.isAncestor(this);
21652 * Returns true if the passed node is an ancestor (at any point) of this node.
21653 * @param {Node} node
21654 * @return {Boolean}
21656 isAncestor : function(node){
21657 var p = this.parentNode;
21667 toString : function(){
21668 return "[Node"+(this.id?" "+this.id:"")+"]";
21672 * Ext JS Library 1.1.1
21673 * Copyright(c) 2006-2007, Ext JS, LLC.
21675 * Originally Released Under LGPL - original licence link has changed is not relivant.
21678 * <script type="text/javascript">
21683 * @class Roo.ComponentMgr
21684 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21687 Roo.ComponentMgr = function(){
21688 var all = new Roo.util.MixedCollection();
21692 * Registers a component.
21693 * @param {Roo.Component} c The component
21695 register : function(c){
21700 * Unregisters a component.
21701 * @param {Roo.Component} c The component
21703 unregister : function(c){
21708 * Returns a component by id
21709 * @param {String} id The component id
21711 get : function(id){
21712 return all.get(id);
21716 * Registers a function that will be called when a specified component is added to ComponentMgr
21717 * @param {String} id The component id
21718 * @param {Funtction} fn The callback function
21719 * @param {Object} scope The scope of the callback
21721 onAvailable : function(id, fn, scope){
21722 all.on("add", function(index, o){
21724 fn.call(scope || o, o);
21725 all.un("add", fn, scope);
21732 * Ext JS Library 1.1.1
21733 * Copyright(c) 2006-2007, Ext JS, LLC.
21735 * Originally Released Under LGPL - original licence link has changed is not relivant.
21738 * <script type="text/javascript">
21742 * @class Roo.Component
21743 * @extends Roo.util.Observable
21744 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21745 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21746 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21747 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21748 * All visual components (widgets) that require rendering into a layout should subclass Component.
21750 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21751 * 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
21752 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21754 Roo.Component = function(config){
21755 config = config || {};
21756 if(config.tagName || config.dom || typeof config == "string"){ // element object
21757 config = {el: config, id: config.id || config};
21759 this.initialConfig = config;
21761 Roo.apply(this, config);
21765 * Fires after the component is disabled.
21766 * @param {Roo.Component} this
21771 * Fires after the component is enabled.
21772 * @param {Roo.Component} this
21776 * @event beforeshow
21777 * Fires before the component is shown. Return false to stop the show.
21778 * @param {Roo.Component} this
21783 * Fires after the component is shown.
21784 * @param {Roo.Component} this
21788 * @event beforehide
21789 * Fires before the component is hidden. Return false to stop the hide.
21790 * @param {Roo.Component} this
21795 * Fires after the component is hidden.
21796 * @param {Roo.Component} this
21800 * @event beforerender
21801 * Fires before the component is rendered. Return false to stop the render.
21802 * @param {Roo.Component} this
21804 beforerender : true,
21807 * Fires after the component is rendered.
21808 * @param {Roo.Component} this
21812 * @event beforedestroy
21813 * Fires before the component is destroyed. Return false to stop the destroy.
21814 * @param {Roo.Component} this
21816 beforedestroy : true,
21819 * Fires after the component is destroyed.
21820 * @param {Roo.Component} this
21825 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21827 Roo.ComponentMgr.register(this);
21828 Roo.Component.superclass.constructor.call(this);
21829 this.initComponent();
21830 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21831 this.render(this.renderTo);
21832 delete this.renderTo;
21837 Roo.Component.AUTO_ID = 1000;
21839 Roo.extend(Roo.Component, Roo.util.Observable, {
21841 * @property {Boolean} hidden
21842 * true if this component is hidden. Read-only.
21846 * true if this component is disabled. Read-only.
21850 * true if this component has been rendered. Read-only.
21854 /** @cfg {String} disableClass
21855 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21857 disabledClass : "x-item-disabled",
21858 /** @cfg {Boolean} allowDomMove
21859 * Whether the component can move the Dom node when rendering (defaults to true).
21861 allowDomMove : true,
21862 /** @cfg {String} hideMode
21863 * How this component should hidden. Supported values are
21864 * "visibility" (css visibility), "offsets" (negative offset position) and
21865 * "display" (css display) - defaults to "display".
21867 hideMode: 'display',
21870 ctype : "Roo.Component",
21872 /** @cfg {String} actionMode
21873 * which property holds the element that used for hide() / show() / disable() / enable()
21879 getActionEl : function(){
21880 return this[this.actionMode];
21883 initComponent : Roo.emptyFn,
21885 * If this is a lazy rendering component, render it to its container element.
21886 * @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.
21888 render : function(container, position){
21889 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21890 if(!container && this.el){
21891 this.el = Roo.get(this.el);
21892 container = this.el.dom.parentNode;
21893 this.allowDomMove = false;
21895 this.container = Roo.get(container);
21896 this.rendered = true;
21897 if(position !== undefined){
21898 if(typeof position == 'number'){
21899 position = this.container.dom.childNodes[position];
21901 position = Roo.getDom(position);
21904 this.onRender(this.container, position || null);
21906 this.el.addClass(this.cls);
21910 this.el.applyStyles(this.style);
21913 this.fireEvent("render", this);
21914 this.afterRender(this.container);
21926 // default function is not really useful
21927 onRender : function(ct, position){
21929 this.el = Roo.get(this.el);
21930 if(this.allowDomMove !== false){
21931 ct.dom.insertBefore(this.el.dom, position);
21937 getAutoCreate : function(){
21938 var cfg = typeof this.autoCreate == "object" ?
21939 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21940 if(this.id && !cfg.id){
21947 afterRender : Roo.emptyFn,
21950 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21951 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21953 destroy : function(){
21954 if(this.fireEvent("beforedestroy", this) !== false){
21955 this.purgeListeners();
21956 this.beforeDestroy();
21958 this.el.removeAllListeners();
21960 if(this.actionMode == "container"){
21961 this.container.remove();
21965 Roo.ComponentMgr.unregister(this);
21966 this.fireEvent("destroy", this);
21971 beforeDestroy : function(){
21976 onDestroy : function(){
21981 * Returns the underlying {@link Roo.Element}.
21982 * @return {Roo.Element} The element
21984 getEl : function(){
21989 * Returns the id of this component.
21992 getId : function(){
21997 * Try to focus this component.
21998 * @param {Boolean} selectText True to also select the text in this component (if applicable)
21999 * @return {Roo.Component} this
22001 focus : function(selectText){
22004 if(selectText === true){
22005 this.el.dom.select();
22020 * Disable this component.
22021 * @return {Roo.Component} this
22023 disable : function(){
22027 this.disabled = true;
22028 this.fireEvent("disable", this);
22033 onDisable : function(){
22034 this.getActionEl().addClass(this.disabledClass);
22035 this.el.dom.disabled = true;
22039 * Enable this component.
22040 * @return {Roo.Component} this
22042 enable : function(){
22046 this.disabled = false;
22047 this.fireEvent("enable", this);
22052 onEnable : function(){
22053 this.getActionEl().removeClass(this.disabledClass);
22054 this.el.dom.disabled = false;
22058 * Convenience function for setting disabled/enabled by boolean.
22059 * @param {Boolean} disabled
22061 setDisabled : function(disabled){
22062 this[disabled ? "disable" : "enable"]();
22066 * Show this component.
22067 * @return {Roo.Component} this
22070 if(this.fireEvent("beforeshow", this) !== false){
22071 this.hidden = false;
22075 this.fireEvent("show", this);
22081 onShow : function(){
22082 var ae = this.getActionEl();
22083 if(this.hideMode == 'visibility'){
22084 ae.dom.style.visibility = "visible";
22085 }else if(this.hideMode == 'offsets'){
22086 ae.removeClass('x-hidden');
22088 ae.dom.style.display = "";
22093 * Hide this component.
22094 * @return {Roo.Component} this
22097 if(this.fireEvent("beforehide", this) !== false){
22098 this.hidden = true;
22102 this.fireEvent("hide", this);
22108 onHide : function(){
22109 var ae = this.getActionEl();
22110 if(this.hideMode == 'visibility'){
22111 ae.dom.style.visibility = "hidden";
22112 }else if(this.hideMode == 'offsets'){
22113 ae.addClass('x-hidden');
22115 ae.dom.style.display = "none";
22120 * Convenience function to hide or show this component by boolean.
22121 * @param {Boolean} visible True to show, false to hide
22122 * @return {Roo.Component} this
22124 setVisible: function(visible){
22134 * Returns true if this component is visible.
22136 isVisible : function(){
22137 return this.getActionEl().isVisible();
22140 cloneConfig : function(overrides){
22141 overrides = overrides || {};
22142 var id = overrides.id || Roo.id();
22143 var cfg = Roo.applyIf(overrides, this.initialConfig);
22144 cfg.id = id; // prevent dup id
22145 return new this.constructor(cfg);
22149 * Ext JS Library 1.1.1
22150 * Copyright(c) 2006-2007, Ext JS, LLC.
22152 * Originally Released Under LGPL - original licence link has changed is not relivant.
22155 * <script type="text/javascript">
22160 * @extends Roo.Element
22161 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22162 * automatic maintaining of shadow/shim positions.
22163 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22164 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22165 * you can pass a string with a CSS class name. False turns off the shadow.
22166 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22167 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22168 * @cfg {String} cls CSS class to add to the element
22169 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22170 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22172 * @param {Object} config An object with config options.
22173 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22176 Roo.Layer = function(config, existingEl){
22177 config = config || {};
22178 var dh = Roo.DomHelper;
22179 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22181 this.dom = Roo.getDom(existingEl);
22184 var o = config.dh || {tag: "div", cls: "x-layer"};
22185 this.dom = dh.append(pel, o);
22188 this.addClass(config.cls);
22190 this.constrain = config.constrain !== false;
22191 this.visibilityMode = Roo.Element.VISIBILITY;
22193 this.id = this.dom.id = config.id;
22195 this.id = Roo.id(this.dom);
22197 this.zindex = config.zindex || this.getZIndex();
22198 this.position("absolute", this.zindex);
22200 this.shadowOffset = config.shadowOffset || 4;
22201 this.shadow = new Roo.Shadow({
22202 offset : this.shadowOffset,
22203 mode : config.shadow
22206 this.shadowOffset = 0;
22208 this.useShim = config.shim !== false && Roo.useShims;
22209 this.useDisplay = config.useDisplay;
22213 var supr = Roo.Element.prototype;
22215 // shims are shared among layer to keep from having 100 iframes
22218 Roo.extend(Roo.Layer, Roo.Element, {
22220 getZIndex : function(){
22221 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22224 getShim : function(){
22231 var shim = shims.shift();
22233 shim = this.createShim();
22234 shim.enableDisplayMode('block');
22235 shim.dom.style.display = 'none';
22236 shim.dom.style.visibility = 'visible';
22238 var pn = this.dom.parentNode;
22239 if(shim.dom.parentNode != pn){
22240 pn.insertBefore(shim.dom, this.dom);
22242 shim.setStyle('z-index', this.getZIndex()-2);
22247 hideShim : function(){
22249 this.shim.setDisplayed(false);
22250 shims.push(this.shim);
22255 disableShadow : function(){
22257 this.shadowDisabled = true;
22258 this.shadow.hide();
22259 this.lastShadowOffset = this.shadowOffset;
22260 this.shadowOffset = 0;
22264 enableShadow : function(show){
22266 this.shadowDisabled = false;
22267 this.shadowOffset = this.lastShadowOffset;
22268 delete this.lastShadowOffset;
22276 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22277 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22278 sync : function(doShow){
22279 var sw = this.shadow;
22280 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22281 var sh = this.getShim();
22283 var w = this.getWidth(),
22284 h = this.getHeight();
22286 var l = this.getLeft(true),
22287 t = this.getTop(true);
22289 if(sw && !this.shadowDisabled){
22290 if(doShow && !sw.isVisible()){
22293 sw.realign(l, t, w, h);
22299 // fit the shim behind the shadow, so it is shimmed too
22300 var a = sw.adjusts, s = sh.dom.style;
22301 s.left = (Math.min(l, l+a.l))+"px";
22302 s.top = (Math.min(t, t+a.t))+"px";
22303 s.width = (w+a.w)+"px";
22304 s.height = (h+a.h)+"px";
22311 sh.setLeftTop(l, t);
22318 destroy : function(){
22321 this.shadow.hide();
22323 this.removeAllListeners();
22324 var pn = this.dom.parentNode;
22326 pn.removeChild(this.dom);
22328 Roo.Element.uncache(this.id);
22331 remove : function(){
22336 beginUpdate : function(){
22337 this.updating = true;
22341 endUpdate : function(){
22342 this.updating = false;
22347 hideUnders : function(negOffset){
22349 this.shadow.hide();
22355 constrainXY : function(){
22356 if(this.constrain){
22357 var vw = Roo.lib.Dom.getViewWidth(),
22358 vh = Roo.lib.Dom.getViewHeight();
22359 var s = Roo.get(document).getScroll();
22361 var xy = this.getXY();
22362 var x = xy[0], y = xy[1];
22363 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22364 // only move it if it needs it
22366 // first validate right/bottom
22367 if((x + w) > vw+s.left){
22368 x = vw - w - this.shadowOffset;
22371 if((y + h) > vh+s.top){
22372 y = vh - h - this.shadowOffset;
22375 // then make sure top/left isn't negative
22386 var ay = this.avoidY;
22387 if(y <= ay && (y+h) >= ay){
22393 supr.setXY.call(this, xy);
22399 isVisible : function(){
22400 return this.visible;
22404 showAction : function(){
22405 this.visible = true; // track visibility to prevent getStyle calls
22406 if(this.useDisplay === true){
22407 this.setDisplayed("");
22408 }else if(this.lastXY){
22409 supr.setXY.call(this, this.lastXY);
22410 }else if(this.lastLT){
22411 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22416 hideAction : function(){
22417 this.visible = false;
22418 if(this.useDisplay === true){
22419 this.setDisplayed(false);
22421 this.setLeftTop(-10000,-10000);
22425 // overridden Element method
22426 setVisible : function(v, a, d, c, e){
22431 var cb = function(){
22436 }.createDelegate(this);
22437 supr.setVisible.call(this, true, true, d, cb, e);
22440 this.hideUnders(true);
22449 }.createDelegate(this);
22451 supr.setVisible.call(this, v, a, d, cb, e);
22460 storeXY : function(xy){
22461 delete this.lastLT;
22465 storeLeftTop : function(left, top){
22466 delete this.lastXY;
22467 this.lastLT = [left, top];
22471 beforeFx : function(){
22472 this.beforeAction();
22473 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22477 afterFx : function(){
22478 Roo.Layer.superclass.afterFx.apply(this, arguments);
22479 this.sync(this.isVisible());
22483 beforeAction : function(){
22484 if(!this.updating && this.shadow){
22485 this.shadow.hide();
22489 // overridden Element method
22490 setLeft : function(left){
22491 this.storeLeftTop(left, this.getTop(true));
22492 supr.setLeft.apply(this, arguments);
22496 setTop : function(top){
22497 this.storeLeftTop(this.getLeft(true), top);
22498 supr.setTop.apply(this, arguments);
22502 setLeftTop : function(left, top){
22503 this.storeLeftTop(left, top);
22504 supr.setLeftTop.apply(this, arguments);
22508 setXY : function(xy, a, d, c, e){
22510 this.beforeAction();
22512 var cb = this.createCB(c);
22513 supr.setXY.call(this, xy, a, d, cb, e);
22520 createCB : function(c){
22531 // overridden Element method
22532 setX : function(x, a, d, c, e){
22533 this.setXY([x, this.getY()], a, d, c, e);
22536 // overridden Element method
22537 setY : function(y, a, d, c, e){
22538 this.setXY([this.getX(), y], a, d, c, e);
22541 // overridden Element method
22542 setSize : function(w, h, a, d, c, e){
22543 this.beforeAction();
22544 var cb = this.createCB(c);
22545 supr.setSize.call(this, w, h, a, d, cb, e);
22551 // overridden Element method
22552 setWidth : function(w, a, d, c, e){
22553 this.beforeAction();
22554 var cb = this.createCB(c);
22555 supr.setWidth.call(this, w, a, d, cb, e);
22561 // overridden Element method
22562 setHeight : function(h, a, d, c, e){
22563 this.beforeAction();
22564 var cb = this.createCB(c);
22565 supr.setHeight.call(this, h, a, d, cb, e);
22571 // overridden Element method
22572 setBounds : function(x, y, w, h, a, d, c, e){
22573 this.beforeAction();
22574 var cb = this.createCB(c);
22576 this.storeXY([x, y]);
22577 supr.setXY.call(this, [x, y]);
22578 supr.setSize.call(this, w, h, a, d, cb, e);
22581 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22587 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22588 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22589 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22590 * @param {Number} zindex The new z-index to set
22591 * @return {this} The Layer
22593 setZIndex : function(zindex){
22594 this.zindex = zindex;
22595 this.setStyle("z-index", zindex + 2);
22597 this.shadow.setZIndex(zindex + 1);
22600 this.shim.setStyle("z-index", zindex);
22606 * Ext JS Library 1.1.1
22607 * Copyright(c) 2006-2007, Ext JS, LLC.
22609 * Originally Released Under LGPL - original licence link has changed is not relivant.
22612 * <script type="text/javascript">
22617 * @class Roo.Shadow
22618 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22619 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22620 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22622 * Create a new Shadow
22623 * @param {Object} config The config object
22625 Roo.Shadow = function(config){
22626 Roo.apply(this, config);
22627 if(typeof this.mode != "string"){
22628 this.mode = this.defaultMode;
22630 var o = this.offset, a = {h: 0};
22631 var rad = Math.floor(this.offset/2);
22632 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22638 a.l -= this.offset + rad;
22639 a.t -= this.offset + rad;
22650 a.l -= (this.offset - rad);
22651 a.t -= this.offset + rad;
22653 a.w -= (this.offset - rad)*2;
22664 a.l -= (this.offset - rad);
22665 a.t -= (this.offset - rad);
22667 a.w -= (this.offset + rad + 1);
22668 a.h -= (this.offset + rad);
22677 Roo.Shadow.prototype = {
22679 * @cfg {String} mode
22680 * The shadow display mode. Supports the following options:<br />
22681 * sides: Shadow displays on both sides and bottom only<br />
22682 * frame: Shadow displays equally on all four sides<br />
22683 * drop: Traditional bottom-right drop shadow (default)
22686 * @cfg {String} offset
22687 * The number of pixels to offset the shadow from the element (defaults to 4)
22692 defaultMode: "drop",
22695 * Displays the shadow under the target element
22696 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22698 show : function(target){
22699 target = Roo.get(target);
22701 this.el = Roo.Shadow.Pool.pull();
22702 if(this.el.dom.nextSibling != target.dom){
22703 this.el.insertBefore(target);
22706 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22708 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22711 target.getLeft(true),
22712 target.getTop(true),
22716 this.el.dom.style.display = "block";
22720 * Returns true if the shadow is visible, else false
22722 isVisible : function(){
22723 return this.el ? true : false;
22727 * Direct alignment when values are already available. Show must be called at least once before
22728 * calling this method to ensure it is initialized.
22729 * @param {Number} left The target element left position
22730 * @param {Number} top The target element top position
22731 * @param {Number} width The target element width
22732 * @param {Number} height The target element height
22734 realign : function(l, t, w, h){
22738 var a = this.adjusts, d = this.el.dom, s = d.style;
22740 s.left = (l+a.l)+"px";
22741 s.top = (t+a.t)+"px";
22742 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22744 if(s.width != sws || s.height != shs){
22748 var cn = d.childNodes;
22749 var sww = Math.max(0, (sw-12))+"px";
22750 cn[0].childNodes[1].style.width = sww;
22751 cn[1].childNodes[1].style.width = sww;
22752 cn[2].childNodes[1].style.width = sww;
22753 cn[1].style.height = Math.max(0, (sh-12))+"px";
22759 * Hides this shadow
22763 this.el.dom.style.display = "none";
22764 Roo.Shadow.Pool.push(this.el);
22770 * Adjust the z-index of this shadow
22771 * @param {Number} zindex The new z-index
22773 setZIndex : function(z){
22776 this.el.setStyle("z-index", z);
22781 // Private utility class that manages the internal Shadow cache
22782 Roo.Shadow.Pool = function(){
22784 var markup = Roo.isIE ?
22785 '<div class="x-ie-shadow"></div>' :
22786 '<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>';
22789 var sh = p.shift();
22791 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22792 sh.autoBoxAdjust = false;
22797 push : function(sh){
22803 * Ext JS Library 1.1.1
22804 * Copyright(c) 2006-2007, Ext JS, LLC.
22806 * Originally Released Under LGPL - original licence link has changed is not relivant.
22809 * <script type="text/javascript">
22813 * @class Roo.BoxComponent
22814 * @extends Roo.Component
22815 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22816 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22817 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22818 * layout containers.
22820 * @param {Roo.Element/String/Object} config The configuration options.
22822 Roo.BoxComponent = function(config){
22823 Roo.Component.call(this, config);
22827 * Fires after the component is resized.
22828 * @param {Roo.Component} this
22829 * @param {Number} adjWidth The box-adjusted width that was set
22830 * @param {Number} adjHeight The box-adjusted height that was set
22831 * @param {Number} rawWidth The width that was originally specified
22832 * @param {Number} rawHeight The height that was originally specified
22837 * Fires after the component is moved.
22838 * @param {Roo.Component} this
22839 * @param {Number} x The new x position
22840 * @param {Number} y The new y position
22846 Roo.extend(Roo.BoxComponent, Roo.Component, {
22847 // private, set in afterRender to signify that the component has been rendered
22849 // private, used to defer height settings to subclasses
22850 deferHeight: false,
22851 /** @cfg {Number} width
22852 * width (optional) size of component
22854 /** @cfg {Number} height
22855 * height (optional) size of component
22859 * Sets the width and height of the component. This method fires the resize event. This method can accept
22860 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22861 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22862 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22863 * @return {Roo.BoxComponent} this
22865 setSize : function(w, h){
22866 // support for standard size objects
22867 if(typeof w == 'object'){
22872 if(!this.boxReady){
22878 // prevent recalcs when not needed
22879 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22882 this.lastSize = {width: w, height: h};
22884 var adj = this.adjustSize(w, h);
22885 var aw = adj.width, ah = adj.height;
22886 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22887 var rz = this.getResizeEl();
22888 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22889 rz.setSize(aw, ah);
22890 }else if(!this.deferHeight && ah !== undefined){
22892 }else if(aw !== undefined){
22895 this.onResize(aw, ah, w, h);
22896 this.fireEvent('resize', this, aw, ah, w, h);
22902 * Gets the current size of the component's underlying element.
22903 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22905 getSize : function(){
22906 return this.el.getSize();
22910 * Gets the current XY position of the component's underlying element.
22911 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22912 * @return {Array} The XY position of the element (e.g., [100, 200])
22914 getPosition : function(local){
22915 if(local === true){
22916 return [this.el.getLeft(true), this.el.getTop(true)];
22918 return this.xy || this.el.getXY();
22922 * Gets the current box measurements of the component's underlying element.
22923 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22924 * @returns {Object} box An object in the format {x, y, width, height}
22926 getBox : function(local){
22927 var s = this.el.getSize();
22929 s.x = this.el.getLeft(true);
22930 s.y = this.el.getTop(true);
22932 var xy = this.xy || this.el.getXY();
22940 * Sets the current box measurements of the component's underlying element.
22941 * @param {Object} box An object in the format {x, y, width, height}
22942 * @returns {Roo.BoxComponent} this
22944 updateBox : function(box){
22945 this.setSize(box.width, box.height);
22946 this.setPagePosition(box.x, box.y);
22951 getResizeEl : function(){
22952 return this.resizeEl || this.el;
22956 getPositionEl : function(){
22957 return this.positionEl || this.el;
22961 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22962 * This method fires the move event.
22963 * @param {Number} left The new left
22964 * @param {Number} top The new top
22965 * @returns {Roo.BoxComponent} this
22967 setPosition : function(x, y){
22970 if(!this.boxReady){
22973 var adj = this.adjustPosition(x, y);
22974 var ax = adj.x, ay = adj.y;
22976 var el = this.getPositionEl();
22977 if(ax !== undefined || ay !== undefined){
22978 if(ax !== undefined && ay !== undefined){
22979 el.setLeftTop(ax, ay);
22980 }else if(ax !== undefined){
22982 }else if(ay !== undefined){
22985 this.onPosition(ax, ay);
22986 this.fireEvent('move', this, ax, ay);
22992 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22993 * This method fires the move event.
22994 * @param {Number} x The new x position
22995 * @param {Number} y The new y position
22996 * @returns {Roo.BoxComponent} this
22998 setPagePosition : function(x, y){
23001 if(!this.boxReady){
23004 if(x === undefined || y === undefined){ // cannot translate undefined points
23007 var p = this.el.translatePoints(x, y);
23008 this.setPosition(p.left, p.top);
23013 onRender : function(ct, position){
23014 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23016 this.resizeEl = Roo.get(this.resizeEl);
23018 if(this.positionEl){
23019 this.positionEl = Roo.get(this.positionEl);
23024 afterRender : function(){
23025 Roo.BoxComponent.superclass.afterRender.call(this);
23026 this.boxReady = true;
23027 this.setSize(this.width, this.height);
23028 if(this.x || this.y){
23029 this.setPosition(this.x, this.y);
23031 if(this.pageX || this.pageY){
23032 this.setPagePosition(this.pageX, this.pageY);
23037 * Force the component's size to recalculate based on the underlying element's current height and width.
23038 * @returns {Roo.BoxComponent} this
23040 syncSize : function(){
23041 delete this.lastSize;
23042 this.setSize(this.el.getWidth(), this.el.getHeight());
23047 * Called after the component is resized, this method is empty by default but can be implemented by any
23048 * subclass that needs to perform custom logic after a resize occurs.
23049 * @param {Number} adjWidth The box-adjusted width that was set
23050 * @param {Number} adjHeight The box-adjusted height that was set
23051 * @param {Number} rawWidth The width that was originally specified
23052 * @param {Number} rawHeight The height that was originally specified
23054 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23059 * Called after the component is moved, this method is empty by default but can be implemented by any
23060 * subclass that needs to perform custom logic after a move occurs.
23061 * @param {Number} x The new x position
23062 * @param {Number} y The new y position
23064 onPosition : function(x, y){
23069 adjustSize : function(w, h){
23070 if(this.autoWidth){
23073 if(this.autoHeight){
23076 return {width : w, height: h};
23080 adjustPosition : function(x, y){
23081 return {x : x, y: y};
23085 * Ext JS Library 1.1.1
23086 * Copyright(c) 2006-2007, Ext JS, LLC.
23088 * Originally Released Under LGPL - original licence link has changed is not relivant.
23091 * <script type="text/javascript">
23096 * @class Roo.SplitBar
23097 * @extends Roo.util.Observable
23098 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23102 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23103 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23104 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23105 split.minSize = 100;
23106 split.maxSize = 600;
23107 split.animate = true;
23108 split.on('moved', splitterMoved);
23111 * Create a new SplitBar
23112 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23113 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23114 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23115 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23116 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23117 position of the SplitBar).
23119 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23122 this.el = Roo.get(dragElement, true);
23123 this.el.dom.unselectable = "on";
23125 this.resizingEl = Roo.get(resizingElement, true);
23129 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23130 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23133 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23136 * The minimum size of the resizing element. (Defaults to 0)
23142 * The maximum size of the resizing element. (Defaults to 2000)
23145 this.maxSize = 2000;
23148 * Whether to animate the transition to the new size
23151 this.animate = false;
23154 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23157 this.useShim = false;
23162 if(!existingProxy){
23164 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23166 this.proxy = Roo.get(existingProxy).dom;
23169 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23172 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23175 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23178 this.dragSpecs = {};
23181 * @private The adapter to use to positon and resize elements
23183 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23184 this.adapter.init(this);
23186 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23188 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23189 this.el.addClass("x-splitbar-h");
23192 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23193 this.el.addClass("x-splitbar-v");
23199 * Fires when the splitter is moved (alias for {@link #event-moved})
23200 * @param {Roo.SplitBar} this
23201 * @param {Number} newSize the new width or height
23206 * Fires when the splitter is moved
23207 * @param {Roo.SplitBar} this
23208 * @param {Number} newSize the new width or height
23212 * @event beforeresize
23213 * Fires before the splitter is dragged
23214 * @param {Roo.SplitBar} this
23216 "beforeresize" : true,
23218 "beforeapply" : true
23221 Roo.util.Observable.call(this);
23224 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23225 onStartProxyDrag : function(x, y){
23226 this.fireEvent("beforeresize", this);
23228 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23230 o.enableDisplayMode("block");
23231 // all splitbars share the same overlay
23232 Roo.SplitBar.prototype.overlay = o;
23234 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23235 this.overlay.show();
23236 Roo.get(this.proxy).setDisplayed("block");
23237 var size = this.adapter.getElementSize(this);
23238 this.activeMinSize = this.getMinimumSize();;
23239 this.activeMaxSize = this.getMaximumSize();;
23240 var c1 = size - this.activeMinSize;
23241 var c2 = Math.max(this.activeMaxSize - size, 0);
23242 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23243 this.dd.resetConstraints();
23244 this.dd.setXConstraint(
23245 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23246 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23248 this.dd.setYConstraint(0, 0);
23250 this.dd.resetConstraints();
23251 this.dd.setXConstraint(0, 0);
23252 this.dd.setYConstraint(
23253 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23254 this.placement == Roo.SplitBar.TOP ? c2 : c1
23257 this.dragSpecs.startSize = size;
23258 this.dragSpecs.startPoint = [x, y];
23259 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23263 * @private Called after the drag operation by the DDProxy
23265 onEndProxyDrag : function(e){
23266 Roo.get(this.proxy).setDisplayed(false);
23267 var endPoint = Roo.lib.Event.getXY(e);
23269 this.overlay.hide();
23272 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23273 newSize = this.dragSpecs.startSize +
23274 (this.placement == Roo.SplitBar.LEFT ?
23275 endPoint[0] - this.dragSpecs.startPoint[0] :
23276 this.dragSpecs.startPoint[0] - endPoint[0]
23279 newSize = this.dragSpecs.startSize +
23280 (this.placement == Roo.SplitBar.TOP ?
23281 endPoint[1] - this.dragSpecs.startPoint[1] :
23282 this.dragSpecs.startPoint[1] - endPoint[1]
23285 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23286 if(newSize != this.dragSpecs.startSize){
23287 if(this.fireEvent('beforeapply', this, newSize) !== false){
23288 this.adapter.setElementSize(this, newSize);
23289 this.fireEvent("moved", this, newSize);
23290 this.fireEvent("resize", this, newSize);
23296 * Get the adapter this SplitBar uses
23297 * @return The adapter object
23299 getAdapter : function(){
23300 return this.adapter;
23304 * Set the adapter this SplitBar uses
23305 * @param {Object} adapter A SplitBar adapter object
23307 setAdapter : function(adapter){
23308 this.adapter = adapter;
23309 this.adapter.init(this);
23313 * Gets the minimum size for the resizing element
23314 * @return {Number} The minimum size
23316 getMinimumSize : function(){
23317 return this.minSize;
23321 * Sets the minimum size for the resizing element
23322 * @param {Number} minSize The minimum size
23324 setMinimumSize : function(minSize){
23325 this.minSize = minSize;
23329 * Gets the maximum size for the resizing element
23330 * @return {Number} The maximum size
23332 getMaximumSize : function(){
23333 return this.maxSize;
23337 * Sets the maximum size for the resizing element
23338 * @param {Number} maxSize The maximum size
23340 setMaximumSize : function(maxSize){
23341 this.maxSize = maxSize;
23345 * Sets the initialize size for the resizing element
23346 * @param {Number} size The initial size
23348 setCurrentSize : function(size){
23349 var oldAnimate = this.animate;
23350 this.animate = false;
23351 this.adapter.setElementSize(this, size);
23352 this.animate = oldAnimate;
23356 * Destroy this splitbar.
23357 * @param {Boolean} removeEl True to remove the element
23359 destroy : function(removeEl){
23361 this.shim.remove();
23364 this.proxy.parentNode.removeChild(this.proxy);
23372 * @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.
23374 Roo.SplitBar.createProxy = function(dir){
23375 var proxy = new Roo.Element(document.createElement("div"));
23376 proxy.unselectable();
23377 var cls = 'x-splitbar-proxy';
23378 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23379 document.body.appendChild(proxy.dom);
23384 * @class Roo.SplitBar.BasicLayoutAdapter
23385 * Default Adapter. It assumes the splitter and resizing element are not positioned
23386 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23388 Roo.SplitBar.BasicLayoutAdapter = function(){
23391 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23392 // do nothing for now
23393 init : function(s){
23397 * Called before drag operations to get the current size of the resizing element.
23398 * @param {Roo.SplitBar} s The SplitBar using this adapter
23400 getElementSize : function(s){
23401 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23402 return s.resizingEl.getWidth();
23404 return s.resizingEl.getHeight();
23409 * Called after drag operations to set the size of the resizing element.
23410 * @param {Roo.SplitBar} s The SplitBar using this adapter
23411 * @param {Number} newSize The new size to set
23412 * @param {Function} onComplete A function to be invoked when resizing is complete
23414 setElementSize : function(s, newSize, onComplete){
23415 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23417 s.resizingEl.setWidth(newSize);
23419 onComplete(s, newSize);
23422 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23427 s.resizingEl.setHeight(newSize);
23429 onComplete(s, newSize);
23432 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23439 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23440 * @extends Roo.SplitBar.BasicLayoutAdapter
23441 * Adapter that moves the splitter element to align with the resized sizing element.
23442 * Used with an absolute positioned SplitBar.
23443 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23444 * document.body, make sure you assign an id to the body element.
23446 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23447 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23448 this.container = Roo.get(container);
23451 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23452 init : function(s){
23453 this.basic.init(s);
23456 getElementSize : function(s){
23457 return this.basic.getElementSize(s);
23460 setElementSize : function(s, newSize, onComplete){
23461 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23464 moveSplitter : function(s){
23465 var yes = Roo.SplitBar;
23466 switch(s.placement){
23468 s.el.setX(s.resizingEl.getRight());
23471 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23474 s.el.setY(s.resizingEl.getBottom());
23477 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23484 * Orientation constant - Create a vertical SplitBar
23488 Roo.SplitBar.VERTICAL = 1;
23491 * Orientation constant - Create a horizontal SplitBar
23495 Roo.SplitBar.HORIZONTAL = 2;
23498 * Placement constant - The resizing element is to the left of the splitter element
23502 Roo.SplitBar.LEFT = 1;
23505 * Placement constant - The resizing element is to the right of the splitter element
23509 Roo.SplitBar.RIGHT = 2;
23512 * Placement constant - The resizing element is positioned above the splitter element
23516 Roo.SplitBar.TOP = 3;
23519 * Placement constant - The resizing element is positioned under splitter element
23523 Roo.SplitBar.BOTTOM = 4;
23526 * Ext JS Library 1.1.1
23527 * Copyright(c) 2006-2007, Ext JS, LLC.
23529 * Originally Released Under LGPL - original licence link has changed is not relivant.
23532 * <script type="text/javascript">
23537 * @extends Roo.util.Observable
23538 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23539 * This class also supports single and multi selection modes. <br>
23540 * Create a data model bound view:
23542 var store = new Roo.data.Store(...);
23544 var view = new Roo.View({
23546 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
23548 singleSelect: true,
23549 selectedClass: "ydataview-selected",
23553 // listen for node click?
23554 view.on("click", function(vw, index, node, e){
23555 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23559 dataModel.load("foobar.xml");
23561 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23563 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23564 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23566 * Note: old style constructor is still suported (container, template, config)
23569 * Create a new View
23570 * @param {Object} config The config object
23573 Roo.View = function(config, depreciated_tpl, depreciated_config){
23575 if (typeof(depreciated_tpl) == 'undefined') {
23576 // new way.. - universal constructor.
23577 Roo.apply(this, config);
23578 this.el = Roo.get(this.el);
23581 this.el = Roo.get(config);
23582 this.tpl = depreciated_tpl;
23583 Roo.apply(this, depreciated_config);
23587 if(typeof(this.tpl) == "string"){
23588 this.tpl = new Roo.Template(this.tpl);
23590 // support xtype ctors..
23591 this.tpl = new Roo.factory(this.tpl, Roo);
23595 this.tpl.compile();
23602 * @event beforeclick
23603 * Fires before a click is processed. Returns false to cancel the default action.
23604 * @param {Roo.View} this
23605 * @param {Number} index The index of the target node
23606 * @param {HTMLElement} node The target node
23607 * @param {Roo.EventObject} e The raw event object
23609 "beforeclick" : true,
23612 * Fires when a template node is clicked.
23613 * @param {Roo.View} this
23614 * @param {Number} index The index of the target node
23615 * @param {HTMLElement} node The target node
23616 * @param {Roo.EventObject} e The raw event object
23621 * Fires when a template node is double clicked.
23622 * @param {Roo.View} this
23623 * @param {Number} index The index of the target node
23624 * @param {HTMLElement} node The target node
23625 * @param {Roo.EventObject} e The raw event object
23629 * @event contextmenu
23630 * Fires when a template node is right clicked.
23631 * @param {Roo.View} this
23632 * @param {Number} index The index of the target node
23633 * @param {HTMLElement} node The target node
23634 * @param {Roo.EventObject} e The raw event object
23636 "contextmenu" : true,
23638 * @event selectionchange
23639 * Fires when the selected nodes change.
23640 * @param {Roo.View} this
23641 * @param {Array} selections Array of the selected nodes
23643 "selectionchange" : true,
23646 * @event beforeselect
23647 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23648 * @param {Roo.View} this
23649 * @param {HTMLElement} node The node to be selected
23650 * @param {Array} selections Array of currently selected nodes
23652 "beforeselect" : true
23656 "click": this.onClick,
23657 "dblclick": this.onDblClick,
23658 "contextmenu": this.onContextMenu,
23662 this.selections = [];
23664 this.cmp = new Roo.CompositeElementLite([]);
23666 this.store = Roo.factory(this.store, Roo.data);
23667 this.setStore(this.store, true);
23669 Roo.View.superclass.constructor.call(this);
23672 Roo.extend(Roo.View, Roo.util.Observable, {
23675 * @cfg {Roo.data.Store} store Data store to load data from.
23680 * @cfg {String|Roo.Element} el The container element.
23685 * @cfg {String|Roo.Template} tpl The template used by this View
23690 * @cfg {String} selectedClass The css class to add to selected nodes
23692 selectedClass : "x-view-selected",
23694 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23698 * @cfg {Boolean} multiSelect Allow multiple selection
23701 multiSelect : false,
23703 * @cfg {Boolean} singleSelect Allow single selection
23705 singleSelect: false,
23708 * Returns the element this view is bound to.
23709 * @return {Roo.Element}
23711 getEl : function(){
23716 * Refreshes the view.
23718 refresh : function(){
23720 this.clearSelections();
23721 this.el.update("");
23723 var records = this.store.getRange();
23724 if(records.length < 1){
23725 this.el.update(this.emptyText);
23728 for(var i = 0, len = records.length; i < len; i++){
23729 var data = this.prepareData(records[i].data, i, records[i]);
23730 html[html.length] = t.apply(data);
23732 this.el.update(html.join(""));
23733 this.nodes = this.el.dom.childNodes;
23734 this.updateIndexes(0);
23738 * Function to override to reformat the data that is sent to
23739 * the template for each node.
23740 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23741 * a JSON object for an UpdateManager bound view).
23743 prepareData : function(data){
23747 onUpdate : function(ds, record){
23748 this.clearSelections();
23749 var index = this.store.indexOf(record);
23750 var n = this.nodes[index];
23751 this.tpl.insertBefore(n, this.prepareData(record.data));
23752 n.parentNode.removeChild(n);
23753 this.updateIndexes(index, index);
23756 onAdd : function(ds, records, index){
23757 this.clearSelections();
23758 if(this.nodes.length == 0){
23762 var n = this.nodes[index];
23763 for(var i = 0, len = records.length; i < len; i++){
23764 var d = this.prepareData(records[i].data);
23766 this.tpl.insertBefore(n, d);
23768 this.tpl.append(this.el, d);
23771 this.updateIndexes(index);
23774 onRemove : function(ds, record, index){
23775 this.clearSelections();
23776 this.el.dom.removeChild(this.nodes[index]);
23777 this.updateIndexes(index);
23781 * Refresh an individual node.
23782 * @param {Number} index
23784 refreshNode : function(index){
23785 this.onUpdate(this.store, this.store.getAt(index));
23788 updateIndexes : function(startIndex, endIndex){
23789 var ns = this.nodes;
23790 startIndex = startIndex || 0;
23791 endIndex = endIndex || ns.length - 1;
23792 for(var i = startIndex; i <= endIndex; i++){
23793 ns[i].nodeIndex = i;
23798 * Changes the data store this view uses and refresh the view.
23799 * @param {Store} store
23801 setStore : function(store, initial){
23802 if(!initial && this.store){
23803 this.store.un("datachanged", this.refresh);
23804 this.store.un("add", this.onAdd);
23805 this.store.un("remove", this.onRemove);
23806 this.store.un("update", this.onUpdate);
23807 this.store.un("clear", this.refresh);
23811 store.on("datachanged", this.refresh, this);
23812 store.on("add", this.onAdd, this);
23813 store.on("remove", this.onRemove, this);
23814 store.on("update", this.onUpdate, this);
23815 store.on("clear", this.refresh, this);
23824 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23825 * @param {HTMLElement} node
23826 * @return {HTMLElement} The template node
23828 findItemFromChild : function(node){
23829 var el = this.el.dom;
23830 if(!node || node.parentNode == el){
23833 var p = node.parentNode;
23834 while(p && p != el){
23835 if(p.parentNode == el){
23844 onClick : function(e){
23845 var item = this.findItemFromChild(e.getTarget());
23847 var index = this.indexOf(item);
23848 if(this.onItemClick(item, index, e) !== false){
23849 this.fireEvent("click", this, index, item, e);
23852 this.clearSelections();
23857 onContextMenu : function(e){
23858 var item = this.findItemFromChild(e.getTarget());
23860 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23865 onDblClick : function(e){
23866 var item = this.findItemFromChild(e.getTarget());
23868 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23872 onItemClick : function(item, index, e){
23873 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23876 if(this.multiSelect || this.singleSelect){
23877 if(this.multiSelect && e.shiftKey && this.lastSelection){
23878 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23880 this.select(item, this.multiSelect && e.ctrlKey);
23881 this.lastSelection = item;
23883 e.preventDefault();
23889 * Get the number of selected nodes.
23892 getSelectionCount : function(){
23893 return this.selections.length;
23897 * Get the currently selected nodes.
23898 * @return {Array} An array of HTMLElements
23900 getSelectedNodes : function(){
23901 return this.selections;
23905 * Get the indexes of the selected nodes.
23908 getSelectedIndexes : function(){
23909 var indexes = [], s = this.selections;
23910 for(var i = 0, len = s.length; i < len; i++){
23911 indexes.push(s[i].nodeIndex);
23917 * Clear all selections
23918 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23920 clearSelections : function(suppressEvent){
23921 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23922 this.cmp.elements = this.selections;
23923 this.cmp.removeClass(this.selectedClass);
23924 this.selections = [];
23925 if(!suppressEvent){
23926 this.fireEvent("selectionchange", this, this.selections);
23932 * Returns true if the passed node is selected
23933 * @param {HTMLElement/Number} node The node or node index
23934 * @return {Boolean}
23936 isSelected : function(node){
23937 var s = this.selections;
23941 node = this.getNode(node);
23942 return s.indexOf(node) !== -1;
23947 * @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
23948 * @param {Boolean} keepExisting (optional) true to keep existing selections
23949 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23951 select : function(nodeInfo, keepExisting, suppressEvent){
23952 if(nodeInfo instanceof Array){
23954 this.clearSelections(true);
23956 for(var i = 0, len = nodeInfo.length; i < len; i++){
23957 this.select(nodeInfo[i], true, true);
23960 var node = this.getNode(nodeInfo);
23961 if(node && !this.isSelected(node)){
23963 this.clearSelections(true);
23965 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23966 Roo.fly(node).addClass(this.selectedClass);
23967 this.selections.push(node);
23968 if(!suppressEvent){
23969 this.fireEvent("selectionchange", this, this.selections);
23977 * Gets a template node.
23978 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23979 * @return {HTMLElement} The node or null if it wasn't found
23981 getNode : function(nodeInfo){
23982 if(typeof nodeInfo == "string"){
23983 return document.getElementById(nodeInfo);
23984 }else if(typeof nodeInfo == "number"){
23985 return this.nodes[nodeInfo];
23991 * Gets a range template nodes.
23992 * @param {Number} startIndex
23993 * @param {Number} endIndex
23994 * @return {Array} An array of nodes
23996 getNodes : function(start, end){
23997 var ns = this.nodes;
23998 start = start || 0;
23999 end = typeof end == "undefined" ? ns.length - 1 : end;
24002 for(var i = start; i <= end; i++){
24006 for(var i = start; i >= end; i--){
24014 * Finds the index of the passed node
24015 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24016 * @return {Number} The index of the node or -1
24018 indexOf : function(node){
24019 node = this.getNode(node);
24020 if(typeof node.nodeIndex == "number"){
24021 return node.nodeIndex;
24023 var ns = this.nodes;
24024 for(var i = 0, len = ns.length; i < len; i++){
24034 * Ext JS Library 1.1.1
24035 * Copyright(c) 2006-2007, Ext JS, LLC.
24037 * Originally Released Under LGPL - original licence link has changed is not relivant.
24040 * <script type="text/javascript">
24044 * @class Roo.JsonView
24045 * @extends Roo.View
24046 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24048 var view = new Roo.JsonView({
24049 container: "my-element",
24050 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24055 // listen for node click?
24056 view.on("click", function(vw, index, node, e){
24057 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24060 // direct load of JSON data
24061 view.load("foobar.php");
24063 // Example from my blog list
24064 var tpl = new Roo.Template(
24065 '<div class="entry">' +
24066 '<a class="entry-title" href="{link}">{title}</a>' +
24067 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24068 "</div><hr />"
24071 var moreView = new Roo.JsonView({
24072 container : "entry-list",
24076 moreView.on("beforerender", this.sortEntries, this);
24078 url: "/blog/get-posts.php",
24079 params: "allposts=true",
24080 text: "Loading Blog Entries..."
24084 * Note: old code is supported with arguments : (container, template, config)
24088 * Create a new JsonView
24090 * @param {Object} config The config object
24093 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24096 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24098 var um = this.el.getUpdateManager();
24099 um.setRenderer(this);
24100 um.on("update", this.onLoad, this);
24101 um.on("failure", this.onLoadException, this);
24104 * @event beforerender
24105 * Fires before rendering of the downloaded JSON data.
24106 * @param {Roo.JsonView} this
24107 * @param {Object} data The JSON data loaded
24111 * Fires when data is loaded.
24112 * @param {Roo.JsonView} this
24113 * @param {Object} data The JSON data loaded
24114 * @param {Object} response The raw Connect response object
24117 * @event loadexception
24118 * Fires when loading fails.
24119 * @param {Roo.JsonView} this
24120 * @param {Object} response The raw Connect response object
24123 'beforerender' : true,
24125 'loadexception' : true
24128 Roo.extend(Roo.JsonView, Roo.View, {
24130 * @type {String} The root property in the loaded JSON object that contains the data
24135 * Refreshes the view.
24137 refresh : function(){
24138 this.clearSelections();
24139 this.el.update("");
24141 var o = this.jsonData;
24142 if(o && o.length > 0){
24143 for(var i = 0, len = o.length; i < len; i++){
24144 var data = this.prepareData(o[i], i, o);
24145 html[html.length] = this.tpl.apply(data);
24148 html.push(this.emptyText);
24150 this.el.update(html.join(""));
24151 this.nodes = this.el.dom.childNodes;
24152 this.updateIndexes(0);
24156 * 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.
24157 * @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:
24160 url: "your-url.php",
24161 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24162 callback: yourFunction,
24163 scope: yourObject, //(optional scope)
24166 text: "Loading...",
24171 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24172 * 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.
24173 * @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}
24174 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24175 * @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.
24178 var um = this.el.getUpdateManager();
24179 um.update.apply(um, arguments);
24182 render : function(el, response){
24183 this.clearSelections();
24184 this.el.update("");
24187 o = Roo.util.JSON.decode(response.responseText);
24190 o = o[this.jsonRoot];
24195 * The current JSON data or null
24198 this.beforeRender();
24203 * Get the number of records in the current JSON dataset
24206 getCount : function(){
24207 return this.jsonData ? this.jsonData.length : 0;
24211 * Returns the JSON object for the specified node(s)
24212 * @param {HTMLElement/Array} node The node or an array of nodes
24213 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24214 * you get the JSON object for the node
24216 getNodeData : function(node){
24217 if(node instanceof Array){
24219 for(var i = 0, len = node.length; i < len; i++){
24220 data.push(this.getNodeData(node[i]));
24224 return this.jsonData[this.indexOf(node)] || null;
24227 beforeRender : function(){
24228 this.snapshot = this.jsonData;
24230 this.sort.apply(this, this.sortInfo);
24232 this.fireEvent("beforerender", this, this.jsonData);
24235 onLoad : function(el, o){
24236 this.fireEvent("load", this, this.jsonData, o);
24239 onLoadException : function(el, o){
24240 this.fireEvent("loadexception", this, o);
24244 * Filter the data by a specific property.
24245 * @param {String} property A property on your JSON objects
24246 * @param {String/RegExp} value Either string that the property values
24247 * should start with, or a RegExp to test against the property
24249 filter : function(property, value){
24252 var ss = this.snapshot;
24253 if(typeof value == "string"){
24254 var vlen = value.length;
24256 this.clearFilter();
24259 value = value.toLowerCase();
24260 for(var i = 0, len = ss.length; i < len; i++){
24262 if(o[property].substr(0, vlen).toLowerCase() == value){
24266 } else if(value.exec){ // regex?
24267 for(var i = 0, len = ss.length; i < len; i++){
24269 if(value.test(o[property])){
24276 this.jsonData = data;
24282 * Filter by a function. The passed function will be called with each
24283 * object in the current dataset. If the function returns true the value is kept,
24284 * otherwise it is filtered.
24285 * @param {Function} fn
24286 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24288 filterBy : function(fn, scope){
24291 var ss = this.snapshot;
24292 for(var i = 0, len = ss.length; i < len; i++){
24294 if(fn.call(scope || this, o)){
24298 this.jsonData = data;
24304 * Clears the current filter.
24306 clearFilter : function(){
24307 if(this.snapshot && this.jsonData != this.snapshot){
24308 this.jsonData = this.snapshot;
24315 * Sorts the data for this view and refreshes it.
24316 * @param {String} property A property on your JSON objects to sort on
24317 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24318 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24320 sort : function(property, dir, sortType){
24321 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24324 var dsc = dir && dir.toLowerCase() == "desc";
24325 var f = function(o1, o2){
24326 var v1 = sortType ? sortType(o1[p]) : o1[p];
24327 var v2 = sortType ? sortType(o2[p]) : o2[p];
24330 return dsc ? +1 : -1;
24331 } else if(v1 > v2){
24332 return dsc ? -1 : +1;
24337 this.jsonData.sort(f);
24339 if(this.jsonData != this.snapshot){
24340 this.snapshot.sort(f);
24346 * Ext JS Library 1.1.1
24347 * Copyright(c) 2006-2007, Ext JS, LLC.
24349 * Originally Released Under LGPL - original licence link has changed is not relivant.
24352 * <script type="text/javascript">
24357 * @class Roo.ColorPalette
24358 * @extends Roo.Component
24359 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24360 * Here's an example of typical usage:
24362 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24363 cp.render('my-div');
24365 cp.on('select', function(palette, selColor){
24366 // do something with selColor
24370 * Create a new ColorPalette
24371 * @param {Object} config The config object
24373 Roo.ColorPalette = function(config){
24374 Roo.ColorPalette.superclass.constructor.call(this, config);
24378 * Fires when a color is selected
24379 * @param {ColorPalette} this
24380 * @param {String} color The 6-digit color hex code (without the # symbol)
24386 this.on("select", this.handler, this.scope, true);
24389 Roo.extend(Roo.ColorPalette, Roo.Component, {
24391 * @cfg {String} itemCls
24392 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24394 itemCls : "x-color-palette",
24396 * @cfg {String} value
24397 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24398 * the hex codes are case-sensitive.
24401 clickEvent:'click',
24403 ctype: "Roo.ColorPalette",
24406 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24408 allowReselect : false,
24411 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24412 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24413 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24414 * of colors with the width setting until the box is symmetrical.</p>
24415 * <p>You can override individual colors if needed:</p>
24417 var cp = new Roo.ColorPalette();
24418 cp.colors[0] = "FF0000"; // change the first box to red
24421 Or you can provide a custom array of your own for complete control:
24423 var cp = new Roo.ColorPalette();
24424 cp.colors = ["000000", "993300", "333300"];
24429 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24430 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24431 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24432 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24433 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24437 onRender : function(container, position){
24438 var t = new Roo.MasterTemplate(
24439 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24441 var c = this.colors;
24442 for(var i = 0, len = c.length; i < len; i++){
24445 var el = document.createElement("div");
24446 el.className = this.itemCls;
24448 container.dom.insertBefore(el, position);
24449 this.el = Roo.get(el);
24450 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24451 if(this.clickEvent != 'click'){
24452 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24457 afterRender : function(){
24458 Roo.ColorPalette.superclass.afterRender.call(this);
24460 var s = this.value;
24467 handleClick : function(e, t){
24468 e.preventDefault();
24469 if(!this.disabled){
24470 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24471 this.select(c.toUpperCase());
24476 * Selects the specified color in the palette (fires the select event)
24477 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24479 select : function(color){
24480 color = color.replace("#", "");
24481 if(color != this.value || this.allowReselect){
24484 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24486 el.child("a.color-"+color).addClass("x-color-palette-sel");
24487 this.value = color;
24488 this.fireEvent("select", this, color);
24493 * Ext JS Library 1.1.1
24494 * Copyright(c) 2006-2007, Ext JS, LLC.
24496 * Originally Released Under LGPL - original licence link has changed is not relivant.
24499 * <script type="text/javascript">
24503 * @class Roo.DatePicker
24504 * @extends Roo.Component
24505 * Simple date picker class.
24507 * Create a new DatePicker
24508 * @param {Object} config The config object
24510 Roo.DatePicker = function(config){
24511 Roo.DatePicker.superclass.constructor.call(this, config);
24513 this.value = config && config.value ?
24514 config.value.clearTime() : new Date().clearTime();
24519 * Fires when a date is selected
24520 * @param {DatePicker} this
24521 * @param {Date} date The selected date
24527 this.on("select", this.handler, this.scope || this);
24529 // build the disabledDatesRE
24530 if(!this.disabledDatesRE && this.disabledDates){
24531 var dd = this.disabledDates;
24533 for(var i = 0; i < dd.length; i++){
24535 if(i != dd.length-1) re += "|";
24537 this.disabledDatesRE = new RegExp(re + ")");
24541 Roo.extend(Roo.DatePicker, Roo.Component, {
24543 * @cfg {String} todayText
24544 * The text to display on the button that selects the current date (defaults to "Today")
24546 todayText : "Today",
24548 * @cfg {String} okText
24549 * The text to display on the ok button
24551 okText : " OK ", //   to give the user extra clicking room
24553 * @cfg {String} cancelText
24554 * The text to display on the cancel button
24556 cancelText : "Cancel",
24558 * @cfg {String} todayTip
24559 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24561 todayTip : "{0} (Spacebar)",
24563 * @cfg {Date} minDate
24564 * Minimum allowable date (JavaScript date object, defaults to null)
24568 * @cfg {Date} maxDate
24569 * Maximum allowable date (JavaScript date object, defaults to null)
24573 * @cfg {String} minText
24574 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24576 minText : "This date is before the minimum date",
24578 * @cfg {String} maxText
24579 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24581 maxText : "This date is after the maximum date",
24583 * @cfg {String} format
24584 * The default date format string which can be overriden for localization support. The format must be
24585 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24589 * @cfg {Array} disabledDays
24590 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24592 disabledDays : null,
24594 * @cfg {String} disabledDaysText
24595 * The tooltip to display when the date falls on a disabled day (defaults to "")
24597 disabledDaysText : "",
24599 * @cfg {RegExp} disabledDatesRE
24600 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24602 disabledDatesRE : null,
24604 * @cfg {String} disabledDatesText
24605 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24607 disabledDatesText : "",
24609 * @cfg {Boolean} constrainToViewport
24610 * True to constrain the date picker to the viewport (defaults to true)
24612 constrainToViewport : true,
24614 * @cfg {Array} monthNames
24615 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24617 monthNames : Date.monthNames,
24619 * @cfg {Array} dayNames
24620 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24622 dayNames : Date.dayNames,
24624 * @cfg {String} nextText
24625 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24627 nextText: 'Next Month (Control+Right)',
24629 * @cfg {String} prevText
24630 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24632 prevText: 'Previous Month (Control+Left)',
24634 * @cfg {String} monthYearText
24635 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24637 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24639 * @cfg {Number} startDay
24640 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24644 * @cfg {Bool} showClear
24645 * Show a clear button (usefull for date form elements that can be blank.)
24651 * Sets the value of the date field
24652 * @param {Date} value The date to set
24654 setValue : function(value){
24655 var old = this.value;
24656 this.value = value.clearTime(true);
24658 this.update(this.value);
24663 * Gets the current selected value of the date field
24664 * @return {Date} The selected date
24666 getValue : function(){
24671 focus : function(){
24673 this.update(this.activeDate);
24678 onRender : function(container, position){
24680 '<table cellspacing="0">',
24681 '<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>',
24682 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24683 var dn = this.dayNames;
24684 for(var i = 0; i < 7; i++){
24685 var d = this.startDay+i;
24689 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24691 m[m.length] = "</tr></thead><tbody><tr>";
24692 for(var i = 0; i < 42; i++) {
24693 if(i % 7 == 0 && i != 0){
24694 m[m.length] = "</tr><tr>";
24696 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24698 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24699 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24701 var el = document.createElement("div");
24702 el.className = "x-date-picker";
24703 el.innerHTML = m.join("");
24705 container.dom.insertBefore(el, position);
24707 this.el = Roo.get(el);
24708 this.eventEl = Roo.get(el.firstChild);
24710 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24711 handler: this.showPrevMonth,
24713 preventDefault:true,
24717 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24718 handler: this.showNextMonth,
24720 preventDefault:true,
24724 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24726 this.monthPicker = this.el.down('div.x-date-mp');
24727 this.monthPicker.enableDisplayMode('block');
24729 var kn = new Roo.KeyNav(this.eventEl, {
24730 "left" : function(e){
24732 this.showPrevMonth() :
24733 this.update(this.activeDate.add("d", -1));
24736 "right" : function(e){
24738 this.showNextMonth() :
24739 this.update(this.activeDate.add("d", 1));
24742 "up" : function(e){
24744 this.showNextYear() :
24745 this.update(this.activeDate.add("d", -7));
24748 "down" : function(e){
24750 this.showPrevYear() :
24751 this.update(this.activeDate.add("d", 7));
24754 "pageUp" : function(e){
24755 this.showNextMonth();
24758 "pageDown" : function(e){
24759 this.showPrevMonth();
24762 "enter" : function(e){
24763 e.stopPropagation();
24770 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24772 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24774 this.el.unselectable();
24776 this.cells = this.el.select("table.x-date-inner tbody td");
24777 this.textNodes = this.el.query("table.x-date-inner tbody span");
24779 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24781 tooltip: this.monthYearText
24784 this.mbtn.on('click', this.showMonthPicker, this);
24785 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24788 var today = (new Date()).dateFormat(this.format);
24790 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24791 if (this.showClear) {
24792 baseTb.add( new Roo.Toolbar.Fill());
24795 text: String.format(this.todayText, today),
24796 tooltip: String.format(this.todayTip, today),
24797 handler: this.selectToday,
24801 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24804 if (this.showClear) {
24806 baseTb.add( new Roo.Toolbar.Fill());
24809 cls: 'x-btn-icon x-btn-clear',
24810 handler: function() {
24812 this.fireEvent("select", this, '');
24822 this.update(this.value);
24825 createMonthPicker : function(){
24826 if(!this.monthPicker.dom.firstChild){
24827 var buf = ['<table border="0" cellspacing="0">'];
24828 for(var i = 0; i < 6; i++){
24830 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24831 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24833 '<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>' :
24834 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24838 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24840 '</button><button type="button" class="x-date-mp-cancel">',
24842 '</button></td></tr>',
24845 this.monthPicker.update(buf.join(''));
24846 this.monthPicker.on('click', this.onMonthClick, this);
24847 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24849 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24850 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24852 this.mpMonths.each(function(m, a, i){
24855 m.dom.xmonth = 5 + Math.round(i * .5);
24857 m.dom.xmonth = Math.round((i-1) * .5);
24863 showMonthPicker : function(){
24864 this.createMonthPicker();
24865 var size = this.el.getSize();
24866 this.monthPicker.setSize(size);
24867 this.monthPicker.child('table').setSize(size);
24869 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24870 this.updateMPMonth(this.mpSelMonth);
24871 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24872 this.updateMPYear(this.mpSelYear);
24874 this.monthPicker.slideIn('t', {duration:.2});
24877 updateMPYear : function(y){
24879 var ys = this.mpYears.elements;
24880 for(var i = 1; i <= 10; i++){
24881 var td = ys[i-1], y2;
24883 y2 = y + Math.round(i * .5);
24884 td.firstChild.innerHTML = y2;
24887 y2 = y - (5-Math.round(i * .5));
24888 td.firstChild.innerHTML = y2;
24891 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24895 updateMPMonth : function(sm){
24896 this.mpMonths.each(function(m, a, i){
24897 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24901 selectMPMonth: function(m){
24905 onMonthClick : function(e, t){
24907 var el = new Roo.Element(t), pn;
24908 if(el.is('button.x-date-mp-cancel')){
24909 this.hideMonthPicker();
24911 else if(el.is('button.x-date-mp-ok')){
24912 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24913 this.hideMonthPicker();
24915 else if(pn = el.up('td.x-date-mp-month', 2)){
24916 this.mpMonths.removeClass('x-date-mp-sel');
24917 pn.addClass('x-date-mp-sel');
24918 this.mpSelMonth = pn.dom.xmonth;
24920 else if(pn = el.up('td.x-date-mp-year', 2)){
24921 this.mpYears.removeClass('x-date-mp-sel');
24922 pn.addClass('x-date-mp-sel');
24923 this.mpSelYear = pn.dom.xyear;
24925 else if(el.is('a.x-date-mp-prev')){
24926 this.updateMPYear(this.mpyear-10);
24928 else if(el.is('a.x-date-mp-next')){
24929 this.updateMPYear(this.mpyear+10);
24933 onMonthDblClick : function(e, t){
24935 var el = new Roo.Element(t), pn;
24936 if(pn = el.up('td.x-date-mp-month', 2)){
24937 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24938 this.hideMonthPicker();
24940 else if(pn = el.up('td.x-date-mp-year', 2)){
24941 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24942 this.hideMonthPicker();
24946 hideMonthPicker : function(disableAnim){
24947 if(this.monthPicker){
24948 if(disableAnim === true){
24949 this.monthPicker.hide();
24951 this.monthPicker.slideOut('t', {duration:.2});
24957 showPrevMonth : function(e){
24958 this.update(this.activeDate.add("mo", -1));
24962 showNextMonth : function(e){
24963 this.update(this.activeDate.add("mo", 1));
24967 showPrevYear : function(){
24968 this.update(this.activeDate.add("y", -1));
24972 showNextYear : function(){
24973 this.update(this.activeDate.add("y", 1));
24977 handleMouseWheel : function(e){
24978 var delta = e.getWheelDelta();
24980 this.showPrevMonth();
24982 } else if(delta < 0){
24983 this.showNextMonth();
24989 handleDateClick : function(e, t){
24991 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24992 this.setValue(new Date(t.dateValue));
24993 this.fireEvent("select", this, this.value);
24998 selectToday : function(){
24999 this.setValue(new Date().clearTime());
25000 this.fireEvent("select", this, this.value);
25004 update : function(date){
25005 var vd = this.activeDate;
25006 this.activeDate = date;
25008 var t = date.getTime();
25009 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25010 this.cells.removeClass("x-date-selected");
25011 this.cells.each(function(c){
25012 if(c.dom.firstChild.dateValue == t){
25013 c.addClass("x-date-selected");
25014 setTimeout(function(){
25015 try{c.dom.firstChild.focus();}catch(e){}
25023 var days = date.getDaysInMonth();
25024 var firstOfMonth = date.getFirstDateOfMonth();
25025 var startingPos = firstOfMonth.getDay()-this.startDay;
25027 if(startingPos <= this.startDay){
25031 var pm = date.add("mo", -1);
25032 var prevStart = pm.getDaysInMonth()-startingPos;
25034 var cells = this.cells.elements;
25035 var textEls = this.textNodes;
25036 days += startingPos;
25038 // convert everything to numbers so it's fast
25039 var day = 86400000;
25040 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25041 var today = new Date().clearTime().getTime();
25042 var sel = date.clearTime().getTime();
25043 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25044 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25045 var ddMatch = this.disabledDatesRE;
25046 var ddText = this.disabledDatesText;
25047 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25048 var ddaysText = this.disabledDaysText;
25049 var format = this.format;
25051 var setCellClass = function(cal, cell){
25053 var t = d.getTime();
25054 cell.firstChild.dateValue = t;
25056 cell.className += " x-date-today";
25057 cell.title = cal.todayText;
25060 cell.className += " x-date-selected";
25061 setTimeout(function(){
25062 try{cell.firstChild.focus();}catch(e){}
25067 cell.className = " x-date-disabled";
25068 cell.title = cal.minText;
25072 cell.className = " x-date-disabled";
25073 cell.title = cal.maxText;
25077 if(ddays.indexOf(d.getDay()) != -1){
25078 cell.title = ddaysText;
25079 cell.className = " x-date-disabled";
25082 if(ddMatch && format){
25083 var fvalue = d.dateFormat(format);
25084 if(ddMatch.test(fvalue)){
25085 cell.title = ddText.replace("%0", fvalue);
25086 cell.className = " x-date-disabled";
25092 for(; i < startingPos; i++) {
25093 textEls[i].innerHTML = (++prevStart);
25094 d.setDate(d.getDate()+1);
25095 cells[i].className = "x-date-prevday";
25096 setCellClass(this, cells[i]);
25098 for(; i < days; i++){
25099 intDay = i - startingPos + 1;
25100 textEls[i].innerHTML = (intDay);
25101 d.setDate(d.getDate()+1);
25102 cells[i].className = "x-date-active";
25103 setCellClass(this, cells[i]);
25106 for(; i < 42; i++) {
25107 textEls[i].innerHTML = (++extraDays);
25108 d.setDate(d.getDate()+1);
25109 cells[i].className = "x-date-nextday";
25110 setCellClass(this, cells[i]);
25113 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25115 if(!this.internalRender){
25116 var main = this.el.dom.firstChild;
25117 var w = main.offsetWidth;
25118 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25119 Roo.fly(main).setWidth(w);
25120 this.internalRender = true;
25121 // opera does not respect the auto grow header center column
25122 // then, after it gets a width opera refuses to recalculate
25123 // without a second pass
25124 if(Roo.isOpera && !this.secondPass){
25125 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25126 this.secondPass = true;
25127 this.update.defer(10, this, [date]);
25133 * Ext JS Library 1.1.1
25134 * Copyright(c) 2006-2007, Ext JS, LLC.
25136 * Originally Released Under LGPL - original licence link has changed is not relivant.
25139 * <script type="text/javascript">
25142 * @class Roo.TabPanel
25143 * @extends Roo.util.Observable
25144 * A lightweight tab container.
25148 // basic tabs 1, built from existing content
25149 var tabs = new Roo.TabPanel("tabs1");
25150 tabs.addTab("script", "View Script");
25151 tabs.addTab("markup", "View Markup");
25152 tabs.activate("script");
25154 // more advanced tabs, built from javascript
25155 var jtabs = new Roo.TabPanel("jtabs");
25156 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25158 // set up the UpdateManager
25159 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25160 var updater = tab2.getUpdateManager();
25161 updater.setDefaultUrl("ajax1.htm");
25162 tab2.on('activate', updater.refresh, updater, true);
25164 // Use setUrl for Ajax loading
25165 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25166 tab3.setUrl("ajax2.htm", null, true);
25169 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25172 jtabs.activate("jtabs-1");
25175 * Create a new TabPanel.
25176 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25177 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25179 Roo.TabPanel = function(container, config){
25181 * The container element for this TabPanel.
25182 * @type Roo.Element
25184 this.el = Roo.get(container, true);
25186 if(typeof config == "boolean"){
25187 this.tabPosition = config ? "bottom" : "top";
25189 Roo.apply(this, config);
25192 if(this.tabPosition == "bottom"){
25193 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25194 this.el.addClass("x-tabs-bottom");
25196 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25197 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25198 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25200 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25202 if(this.tabPosition != "bottom"){
25203 /** The body element that contains {@link Roo.TabPanelItem} bodies.
25204 * @type Roo.Element
25206 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25207 this.el.addClass("x-tabs-top");
25211 this.bodyEl.setStyle("position", "relative");
25213 this.active = null;
25214 this.activateDelegate = this.activate.createDelegate(this);
25219 * Fires when the active tab changes
25220 * @param {Roo.TabPanel} this
25221 * @param {Roo.TabPanelItem} activePanel The new active tab
25225 * @event beforetabchange
25226 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25227 * @param {Roo.TabPanel} this
25228 * @param {Object} e Set cancel to true on this object to cancel the tab change
25229 * @param {Roo.TabPanelItem} tab The tab being changed to
25231 "beforetabchange" : true
25234 Roo.EventManager.onWindowResize(this.onResize, this);
25235 this.cpad = this.el.getPadding("lr");
25236 this.hiddenCount = 0;
25238 Roo.TabPanel.superclass.constructor.call(this);
25241 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25243 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25245 tabPosition : "top",
25247 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25249 currentTabWidth : 0,
25251 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25255 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25259 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25261 preferredTabWidth : 175,
25263 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25265 resizeTabs : false,
25267 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25269 monitorResize : true,
25272 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25273 * @param {String} id The id of the div to use <b>or create</b>
25274 * @param {String} text The text for the tab
25275 * @param {String} content (optional) Content to put in the TabPanelItem body
25276 * @param {Boolean} closable (optional) True to create a close icon on the tab
25277 * @return {Roo.TabPanelItem} The created TabPanelItem
25279 addTab : function(id, text, content, closable){
25280 var item = new Roo.TabPanelItem(this, id, text, closable);
25281 this.addTabItem(item);
25283 item.setContent(content);
25289 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25290 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25291 * @return {Roo.TabPanelItem}
25293 getTab : function(id){
25294 return this.items[id];
25298 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25299 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25301 hideTab : function(id){
25302 var t = this.items[id];
25305 this.hiddenCount++;
25306 this.autoSizeTabs();
25311 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25312 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25314 unhideTab : function(id){
25315 var t = this.items[id];
25317 t.setHidden(false);
25318 this.hiddenCount--;
25319 this.autoSizeTabs();
25324 * Adds an existing {@link Roo.TabPanelItem}.
25325 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25327 addTabItem : function(item){
25328 this.items[item.id] = item;
25329 this.items.push(item);
25330 if(this.resizeTabs){
25331 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25332 this.autoSizeTabs();
25339 * Removes a {@link Roo.TabPanelItem}.
25340 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25342 removeTab : function(id){
25343 var items = this.items;
25344 var tab = items[id];
25345 if(!tab) { return; }
25346 var index = items.indexOf(tab);
25347 if(this.active == tab && items.length > 1){
25348 var newTab = this.getNextAvailable(index);
25353 this.stripEl.dom.removeChild(tab.pnode.dom);
25354 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25355 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25357 items.splice(index, 1);
25358 delete this.items[tab.id];
25359 tab.fireEvent("close", tab);
25360 tab.purgeListeners();
25361 this.autoSizeTabs();
25364 getNextAvailable : function(start){
25365 var items = this.items;
25367 // look for a next tab that will slide over to
25368 // replace the one being removed
25369 while(index < items.length){
25370 var item = items[++index];
25371 if(item && !item.isHidden()){
25375 // if one isn't found select the previous tab (on the left)
25378 var item = items[--index];
25379 if(item && !item.isHidden()){
25387 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25388 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25390 disableTab : function(id){
25391 var tab = this.items[id];
25392 if(tab && this.active != tab){
25398 * Enables a {@link Roo.TabPanelItem} that is disabled.
25399 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25401 enableTab : function(id){
25402 var tab = this.items[id];
25407 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25408 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25409 * @return {Roo.TabPanelItem} The TabPanelItem.
25411 activate : function(id){
25412 var tab = this.items[id];
25416 if(tab == this.active || tab.disabled){
25420 this.fireEvent("beforetabchange", this, e, tab);
25421 if(e.cancel !== true && !tab.disabled){
25423 this.active.hide();
25425 this.active = this.items[id];
25426 this.active.show();
25427 this.fireEvent("tabchange", this, this.active);
25433 * Gets the active {@link Roo.TabPanelItem}.
25434 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25436 getActiveTab : function(){
25437 return this.active;
25441 * Updates the tab body element to fit the height of the container element
25442 * for overflow scrolling
25443 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25445 syncHeight : function(targetHeight){
25446 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25447 var bm = this.bodyEl.getMargins();
25448 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25449 this.bodyEl.setHeight(newHeight);
25453 onResize : function(){
25454 if(this.monitorResize){
25455 this.autoSizeTabs();
25460 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25462 beginUpdate : function(){
25463 this.updating = true;
25467 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25469 endUpdate : function(){
25470 this.updating = false;
25471 this.autoSizeTabs();
25475 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25477 autoSizeTabs : function(){
25478 var count = this.items.length;
25479 var vcount = count - this.hiddenCount;
25480 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25481 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25482 var availWidth = Math.floor(w / vcount);
25483 var b = this.stripBody;
25484 if(b.getWidth() > w){
25485 var tabs = this.items;
25486 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25487 if(availWidth < this.minTabWidth){
25488 /*if(!this.sleft){ // incomplete scrolling code
25489 this.createScrollButtons();
25492 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25495 if(this.currentTabWidth < this.preferredTabWidth){
25496 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25502 * Returns the number of tabs in this TabPanel.
25505 getCount : function(){
25506 return this.items.length;
25510 * Resizes all the tabs to the passed width
25511 * @param {Number} The new width
25513 setTabWidth : function(width){
25514 this.currentTabWidth = width;
25515 for(var i = 0, len = this.items.length; i < len; i++) {
25516 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25521 * Destroys this TabPanel
25522 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25524 destroy : function(removeEl){
25525 Roo.EventManager.removeResizeListener(this.onResize, this);
25526 for(var i = 0, len = this.items.length; i < len; i++){
25527 this.items[i].purgeListeners();
25529 if(removeEl === true){
25530 this.el.update("");
25537 * @class Roo.TabPanelItem
25538 * @extends Roo.util.Observable
25539 * Represents an individual item (tab plus body) in a TabPanel.
25540 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25541 * @param {String} id The id of this TabPanelItem
25542 * @param {String} text The text for the tab of this TabPanelItem
25543 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25545 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25547 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25548 * @type Roo.TabPanel
25550 this.tabPanel = tabPanel;
25552 * The id for this TabPanelItem
25557 this.disabled = false;
25561 this.loaded = false;
25562 this.closable = closable;
25565 * The body element for this TabPanelItem.
25566 * @type Roo.Element
25568 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25569 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25570 this.bodyEl.setStyle("display", "block");
25571 this.bodyEl.setStyle("zoom", "1");
25574 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25576 this.el = Roo.get(els.el, true);
25577 this.inner = Roo.get(els.inner, true);
25578 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25579 this.pnode = Roo.get(els.el.parentNode, true);
25580 this.el.on("mousedown", this.onTabMouseDown, this);
25581 this.el.on("click", this.onTabClick, this);
25584 var c = Roo.get(els.close, true);
25585 c.dom.title = this.closeText;
25586 c.addClassOnOver("close-over");
25587 c.on("click", this.closeClick, this);
25593 * Fires when this tab becomes the active tab.
25594 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25595 * @param {Roo.TabPanelItem} this
25599 * @event beforeclose
25600 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25601 * @param {Roo.TabPanelItem} this
25602 * @param {Object} e Set cancel to true on this object to cancel the close.
25604 "beforeclose": true,
25607 * Fires when this tab is closed.
25608 * @param {Roo.TabPanelItem} this
25612 * @event deactivate
25613 * Fires when this tab is no longer the active tab.
25614 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25615 * @param {Roo.TabPanelItem} this
25617 "deactivate" : true
25619 this.hidden = false;
25621 Roo.TabPanelItem.superclass.constructor.call(this);
25624 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25625 purgeListeners : function(){
25626 Roo.util.Observable.prototype.purgeListeners.call(this);
25627 this.el.removeAllListeners();
25630 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25633 this.pnode.addClass("on");
25636 this.tabPanel.stripWrap.repaint();
25638 this.fireEvent("activate", this.tabPanel, this);
25642 * Returns true if this tab is the active tab.
25643 * @return {Boolean}
25645 isActive : function(){
25646 return this.tabPanel.getActiveTab() == this;
25650 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25653 this.pnode.removeClass("on");
25655 this.fireEvent("deactivate", this.tabPanel, this);
25658 hideAction : function(){
25659 this.bodyEl.hide();
25660 this.bodyEl.setStyle("position", "absolute");
25661 this.bodyEl.setLeft("-20000px");
25662 this.bodyEl.setTop("-20000px");
25665 showAction : function(){
25666 this.bodyEl.setStyle("position", "relative");
25667 this.bodyEl.setTop("");
25668 this.bodyEl.setLeft("");
25669 this.bodyEl.show();
25673 * Set the tooltip for the tab.
25674 * @param {String} tooltip The tab's tooltip
25676 setTooltip : function(text){
25677 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25678 this.textEl.dom.qtip = text;
25679 this.textEl.dom.removeAttribute('title');
25681 this.textEl.dom.title = text;
25685 onTabClick : function(e){
25686 e.preventDefault();
25687 this.tabPanel.activate(this.id);
25690 onTabMouseDown : function(e){
25691 e.preventDefault();
25692 this.tabPanel.activate(this.id);
25695 getWidth : function(){
25696 return this.inner.getWidth();
25699 setWidth : function(width){
25700 var iwidth = width - this.pnode.getPadding("lr");
25701 this.inner.setWidth(iwidth);
25702 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25703 this.pnode.setWidth(width);
25707 * Show or hide the tab
25708 * @param {Boolean} hidden True to hide or false to show.
25710 setHidden : function(hidden){
25711 this.hidden = hidden;
25712 this.pnode.setStyle("display", hidden ? "none" : "");
25716 * Returns true if this tab is "hidden"
25717 * @return {Boolean}
25719 isHidden : function(){
25720 return this.hidden;
25724 * Returns the text for this tab
25727 getText : function(){
25731 autoSize : function(){
25732 //this.el.beginMeasure();
25733 this.textEl.setWidth(1);
25734 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25735 //this.el.endMeasure();
25739 * Sets the text for the tab (Note: this also sets the tooltip text)
25740 * @param {String} text The tab's text and tooltip
25742 setText : function(text){
25744 this.textEl.update(text);
25745 this.setTooltip(text);
25746 if(!this.tabPanel.resizeTabs){
25751 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25753 activate : function(){
25754 this.tabPanel.activate(this.id);
25758 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25760 disable : function(){
25761 if(this.tabPanel.active != this){
25762 this.disabled = true;
25763 this.pnode.addClass("disabled");
25768 * Enables this TabPanelItem if it was previously disabled.
25770 enable : function(){
25771 this.disabled = false;
25772 this.pnode.removeClass("disabled");
25776 * Sets the content for this TabPanelItem.
25777 * @param {String} content The content
25778 * @param {Boolean} loadScripts true to look for and load scripts
25780 setContent : function(content, loadScripts){
25781 this.bodyEl.update(content, loadScripts);
25785 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25786 * @return {Roo.UpdateManager} The UpdateManager
25788 getUpdateManager : function(){
25789 return this.bodyEl.getUpdateManager();
25793 * Set a URL to be used to load the content for this TabPanelItem.
25794 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25795 * @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)
25796 * @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)
25797 * @return {Roo.UpdateManager} The UpdateManager
25799 setUrl : function(url, params, loadOnce){
25800 if(this.refreshDelegate){
25801 this.un('activate', this.refreshDelegate);
25803 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25804 this.on("activate", this.refreshDelegate);
25805 return this.bodyEl.getUpdateManager();
25809 _handleRefresh : function(url, params, loadOnce){
25810 if(!loadOnce || !this.loaded){
25811 var updater = this.bodyEl.getUpdateManager();
25812 updater.update(url, params, this._setLoaded.createDelegate(this));
25817 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25818 * Will fail silently if the setUrl method has not been called.
25819 * This does not activate the panel, just updates its content.
25821 refresh : function(){
25822 if(this.refreshDelegate){
25823 this.loaded = false;
25824 this.refreshDelegate();
25829 _setLoaded : function(){
25830 this.loaded = true;
25834 closeClick : function(e){
25837 this.fireEvent("beforeclose", this, o);
25838 if(o.cancel !== true){
25839 this.tabPanel.removeTab(this.id);
25843 * The text displayed in the tooltip for the close icon.
25846 closeText : "Close this tab"
25850 Roo.TabPanel.prototype.createStrip = function(container){
25851 var strip = document.createElement("div");
25852 strip.className = "x-tabs-wrap";
25853 container.appendChild(strip);
25857 Roo.TabPanel.prototype.createStripList = function(strip){
25858 // div wrapper for retard IE
25859 strip.innerHTML = '<div class="x-tabs-strip-wrap"><table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
25860 return strip.firstChild.firstChild.firstChild.firstChild;
25863 Roo.TabPanel.prototype.createBody = function(container){
25864 var body = document.createElement("div");
25865 Roo.id(body, "tab-body");
25866 Roo.fly(body).addClass("x-tabs-body");
25867 container.appendChild(body);
25871 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25872 var body = Roo.getDom(id);
25874 body = document.createElement("div");
25877 Roo.fly(body).addClass("x-tabs-item-body");
25878 bodyEl.insertBefore(body, bodyEl.firstChild);
25882 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25883 var td = document.createElement("td");
25884 stripEl.appendChild(td);
25886 td.className = "x-tabs-closable";
25887 if(!this.closeTpl){
25888 this.closeTpl = new Roo.Template(
25889 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25890 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25891 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25894 var el = this.closeTpl.overwrite(td, {"text": text});
25895 var close = el.getElementsByTagName("div")[0];
25896 var inner = el.getElementsByTagName("em")[0];
25897 return {"el": el, "close": close, "inner": inner};
25900 this.tabTpl = new Roo.Template(
25901 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25902 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25905 var el = this.tabTpl.overwrite(td, {"text": text});
25906 var inner = el.getElementsByTagName("em")[0];
25907 return {"el": el, "inner": inner};
25911 * Ext JS Library 1.1.1
25912 * Copyright(c) 2006-2007, Ext JS, LLC.
25914 * Originally Released Under LGPL - original licence link has changed is not relivant.
25917 * <script type="text/javascript">
25921 * @class Roo.Button
25922 * @extends Roo.util.Observable
25923 * Simple Button class
25924 * @cfg {String} text The button text
25925 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25926 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25927 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25928 * @cfg {Object} scope The scope of the handler
25929 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25930 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25931 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25932 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25933 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25934 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25935 applies if enableToggle = true)
25936 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25937 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25938 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25940 * Create a new button
25941 * @param {Object} config The config object
25943 Roo.Button = function(renderTo, config)
25947 renderTo = config.renderTo || false;
25950 Roo.apply(this, config);
25954 * Fires when this button is clicked
25955 * @param {Button} this
25956 * @param {EventObject} e The click event
25961 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25962 * @param {Button} this
25963 * @param {Boolean} pressed
25968 * Fires when the mouse hovers over the button
25969 * @param {Button} this
25970 * @param {Event} e The event object
25972 'mouseover' : true,
25975 * Fires when the mouse exits the button
25976 * @param {Button} this
25977 * @param {Event} e The event object
25982 * Fires when the button is rendered
25983 * @param {Button} this
25988 this.menu = Roo.menu.MenuMgr.get(this.menu);
25990 // register listeners first!! - so render can be captured..
25991 Roo.util.Observable.call(this);
25993 this.render(renderTo);
25999 Roo.extend(Roo.Button, Roo.util.Observable, {
26005 * Read-only. True if this button is hidden
26010 * Read-only. True if this button is disabled
26015 * Read-only. True if this button is pressed (only if enableToggle = true)
26021 * @cfg {Number} tabIndex
26022 * The DOM tabIndex for this button (defaults to undefined)
26024 tabIndex : undefined,
26027 * @cfg {Boolean} enableToggle
26028 * True to enable pressed/not pressed toggling (defaults to false)
26030 enableToggle: false,
26032 * @cfg {Mixed} menu
26033 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26037 * @cfg {String} menuAlign
26038 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26040 menuAlign : "tl-bl?",
26043 * @cfg {String} iconCls
26044 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26046 iconCls : undefined,
26048 * @cfg {String} type
26049 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26054 menuClassTarget: 'tr',
26057 * @cfg {String} clickEvent
26058 * The type of event to map to the button's event handler (defaults to 'click')
26060 clickEvent : 'click',
26063 * @cfg {Boolean} handleMouseEvents
26064 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26066 handleMouseEvents : true,
26069 * @cfg {String} tooltipType
26070 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26072 tooltipType : 'qtip',
26075 * @cfg {String} cls
26076 * A CSS class to apply to the button's main element.
26080 * @cfg {Roo.Template} template (Optional)
26081 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26082 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26083 * require code modifications if required elements (e.g. a button) aren't present.
26087 render : function(renderTo){
26089 if(this.hideParent){
26090 this.parentEl = Roo.get(renderTo);
26092 if(!this.dhconfig){
26093 if(!this.template){
26094 if(!Roo.Button.buttonTemplate){
26095 // hideous table template
26096 Roo.Button.buttonTemplate = new Roo.Template(
26097 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26098 '<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>',
26099 "</tr></tbody></table>");
26101 this.template = Roo.Button.buttonTemplate;
26103 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26104 var btnEl = btn.child("button:first");
26105 btnEl.on('focus', this.onFocus, this);
26106 btnEl.on('blur', this.onBlur, this);
26108 btn.addClass(this.cls);
26111 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26114 btnEl.addClass(this.iconCls);
26116 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26119 if(this.tabIndex !== undefined){
26120 btnEl.dom.tabIndex = this.tabIndex;
26123 if(typeof this.tooltip == 'object'){
26124 Roo.QuickTips.tips(Roo.apply({
26128 btnEl.dom[this.tooltipType] = this.tooltip;
26132 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26136 this.el.dom.id = this.el.id = this.id;
26139 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26140 this.menu.on("show", this.onMenuShow, this);
26141 this.menu.on("hide", this.onMenuHide, this);
26143 btn.addClass("x-btn");
26144 if(Roo.isIE && !Roo.isIE7){
26145 this.autoWidth.defer(1, this);
26149 if(this.handleMouseEvents){
26150 btn.on("mouseover", this.onMouseOver, this);
26151 btn.on("mouseout", this.onMouseOut, this);
26152 btn.on("mousedown", this.onMouseDown, this);
26154 btn.on(this.clickEvent, this.onClick, this);
26155 //btn.on("mouseup", this.onMouseUp, this);
26162 Roo.ButtonToggleMgr.register(this);
26164 this.el.addClass("x-btn-pressed");
26167 var repeater = new Roo.util.ClickRepeater(btn,
26168 typeof this.repeat == "object" ? this.repeat : {}
26170 repeater.on("click", this.onClick, this);
26173 this.fireEvent('render', this);
26177 * Returns the button's underlying element
26178 * @return {Roo.Element} The element
26180 getEl : function(){
26185 * Destroys this Button and removes any listeners.
26187 destroy : function(){
26188 Roo.ButtonToggleMgr.unregister(this);
26189 this.el.removeAllListeners();
26190 this.purgeListeners();
26195 autoWidth : function(){
26197 this.el.setWidth("auto");
26198 if(Roo.isIE7 && Roo.isStrict){
26199 var ib = this.el.child('button');
26200 if(ib && ib.getWidth() > 20){
26202 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26207 this.el.beginMeasure();
26209 if(this.el.getWidth() < this.minWidth){
26210 this.el.setWidth(this.minWidth);
26213 this.el.endMeasure();
26220 * Assigns this button's click handler
26221 * @param {Function} handler The function to call when the button is clicked
26222 * @param {Object} scope (optional) Scope for the function passed in
26224 setHandler : function(handler, scope){
26225 this.handler = handler;
26226 this.scope = scope;
26230 * Sets this button's text
26231 * @param {String} text The button text
26233 setText : function(text){
26236 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26242 * Gets the text for this button
26243 * @return {String} The button text
26245 getText : function(){
26253 this.hidden = false;
26255 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26263 this.hidden = true;
26265 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26270 * Convenience function for boolean show/hide
26271 * @param {Boolean} visible True to show, false to hide
26273 setVisible: function(visible){
26282 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26283 * @param {Boolean} state (optional) Force a particular state
26285 toggle : function(state){
26286 state = state === undefined ? !this.pressed : state;
26287 if(state != this.pressed){
26289 this.el.addClass("x-btn-pressed");
26290 this.pressed = true;
26291 this.fireEvent("toggle", this, true);
26293 this.el.removeClass("x-btn-pressed");
26294 this.pressed = false;
26295 this.fireEvent("toggle", this, false);
26297 if(this.toggleHandler){
26298 this.toggleHandler.call(this.scope || this, this, state);
26306 focus : function(){
26307 this.el.child('button:first').focus();
26311 * Disable this button
26313 disable : function(){
26315 this.el.addClass("x-btn-disabled");
26317 this.disabled = true;
26321 * Enable this button
26323 enable : function(){
26325 this.el.removeClass("x-btn-disabled");
26327 this.disabled = false;
26331 * Convenience function for boolean enable/disable
26332 * @param {Boolean} enabled True to enable, false to disable
26334 setDisabled : function(v){
26335 this[v !== true ? "enable" : "disable"]();
26339 onClick : function(e){
26341 e.preventDefault();
26346 if(!this.disabled){
26347 if(this.enableToggle){
26350 if(this.menu && !this.menu.isVisible()){
26351 this.menu.show(this.el, this.menuAlign);
26353 this.fireEvent("click", this, e);
26355 this.el.removeClass("x-btn-over");
26356 this.handler.call(this.scope || this, this, e);
26361 onMouseOver : function(e){
26362 if(!this.disabled){
26363 this.el.addClass("x-btn-over");
26364 this.fireEvent('mouseover', this, e);
26368 onMouseOut : function(e){
26369 if(!e.within(this.el, true)){
26370 this.el.removeClass("x-btn-over");
26371 this.fireEvent('mouseout', this, e);
26375 onFocus : function(e){
26376 if(!this.disabled){
26377 this.el.addClass("x-btn-focus");
26381 onBlur : function(e){
26382 this.el.removeClass("x-btn-focus");
26385 onMouseDown : function(e){
26386 if(!this.disabled && e.button == 0){
26387 this.el.addClass("x-btn-click");
26388 Roo.get(document).on('mouseup', this.onMouseUp, this);
26392 onMouseUp : function(e){
26394 this.el.removeClass("x-btn-click");
26395 Roo.get(document).un('mouseup', this.onMouseUp, this);
26399 onMenuShow : function(e){
26400 this.el.addClass("x-btn-menu-active");
26403 onMenuHide : function(e){
26404 this.el.removeClass("x-btn-menu-active");
26408 // Private utility class used by Button
26409 Roo.ButtonToggleMgr = function(){
26412 function toggleGroup(btn, state){
26414 var g = groups[btn.toggleGroup];
26415 for(var i = 0, l = g.length; i < l; i++){
26417 g[i].toggle(false);
26424 register : function(btn){
26425 if(!btn.toggleGroup){
26428 var g = groups[btn.toggleGroup];
26430 g = groups[btn.toggleGroup] = [];
26433 btn.on("toggle", toggleGroup);
26436 unregister : function(btn){
26437 if(!btn.toggleGroup){
26440 var g = groups[btn.toggleGroup];
26443 btn.un("toggle", toggleGroup);
26449 * Ext JS Library 1.1.1
26450 * Copyright(c) 2006-2007, Ext JS, LLC.
26452 * Originally Released Under LGPL - original licence link has changed is not relivant.
26455 * <script type="text/javascript">
26459 * @class Roo.SplitButton
26460 * @extends Roo.Button
26461 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26462 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26463 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26464 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26465 * @cfg {String} arrowTooltip The title attribute of the arrow
26467 * Create a new menu button
26468 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26469 * @param {Object} config The config object
26471 Roo.SplitButton = function(renderTo, config){
26472 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26474 * @event arrowclick
26475 * Fires when this button's arrow is clicked
26476 * @param {SplitButton} this
26477 * @param {EventObject} e The click event
26479 this.addEvents({"arrowclick":true});
26482 Roo.extend(Roo.SplitButton, Roo.Button, {
26483 render : function(renderTo){
26484 // this is one sweet looking template!
26485 var tpl = new Roo.Template(
26486 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26487 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26488 '<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>',
26489 "</tbody></table></td><td>",
26490 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26491 '<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>',
26492 "</tbody></table></td></tr></table>"
26494 var btn = tpl.append(renderTo, [this.text, this.type], true);
26495 var btnEl = btn.child("button");
26497 btn.addClass(this.cls);
26500 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26503 btnEl.addClass(this.iconCls);
26505 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26509 if(this.handleMouseEvents){
26510 btn.on("mouseover", this.onMouseOver, this);
26511 btn.on("mouseout", this.onMouseOut, this);
26512 btn.on("mousedown", this.onMouseDown, this);
26513 btn.on("mouseup", this.onMouseUp, this);
26515 btn.on(this.clickEvent, this.onClick, this);
26517 if(typeof this.tooltip == 'object'){
26518 Roo.QuickTips.tips(Roo.apply({
26522 btnEl.dom[this.tooltipType] = this.tooltip;
26525 if(this.arrowTooltip){
26526 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26535 this.el.addClass("x-btn-pressed");
26537 if(Roo.isIE && !Roo.isIE7){
26538 this.autoWidth.defer(1, this);
26543 this.menu.on("show", this.onMenuShow, this);
26544 this.menu.on("hide", this.onMenuHide, this);
26546 this.fireEvent('render', this);
26550 autoWidth : function(){
26552 var tbl = this.el.child("table:first");
26553 var tbl2 = this.el.child("table:last");
26554 this.el.setWidth("auto");
26555 tbl.setWidth("auto");
26556 if(Roo.isIE7 && Roo.isStrict){
26557 var ib = this.el.child('button:first');
26558 if(ib && ib.getWidth() > 20){
26560 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26565 this.el.beginMeasure();
26567 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26568 tbl.setWidth(this.minWidth-tbl2.getWidth());
26571 this.el.endMeasure();
26574 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26578 * Sets this button's click handler
26579 * @param {Function} handler The function to call when the button is clicked
26580 * @param {Object} scope (optional) Scope for the function passed above
26582 setHandler : function(handler, scope){
26583 this.handler = handler;
26584 this.scope = scope;
26588 * Sets this button's arrow click handler
26589 * @param {Function} handler The function to call when the arrow is clicked
26590 * @param {Object} scope (optional) Scope for the function passed above
26592 setArrowHandler : function(handler, scope){
26593 this.arrowHandler = handler;
26594 this.scope = scope;
26600 focus : function(){
26602 this.el.child("button:first").focus();
26607 onClick : function(e){
26608 e.preventDefault();
26609 if(!this.disabled){
26610 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26611 if(this.menu && !this.menu.isVisible()){
26612 this.menu.show(this.el, this.menuAlign);
26614 this.fireEvent("arrowclick", this, e);
26615 if(this.arrowHandler){
26616 this.arrowHandler.call(this.scope || this, this, e);
26619 this.fireEvent("click", this, e);
26621 this.handler.call(this.scope || this, this, e);
26627 onMouseDown : function(e){
26628 if(!this.disabled){
26629 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26633 onMouseUp : function(e){
26634 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26639 // backwards compat
26640 Roo.MenuButton = Roo.SplitButton;/*
26642 * Ext JS Library 1.1.1
26643 * Copyright(c) 2006-2007, Ext JS, LLC.
26645 * Originally Released Under LGPL - original licence link has changed is not relivant.
26648 * <script type="text/javascript">
26652 * @class Roo.Toolbar
26653 * Basic Toolbar class.
26655 * Creates a new Toolbar
26656 * @param {Object} config The config object
26658 Roo.Toolbar = function(container, buttons, config)
26660 /// old consturctor format still supported..
26661 if(container instanceof Array){ // omit the container for later rendering
26662 buttons = container;
26666 if (typeof(container) == 'object' && container.xtype) {
26667 config = container;
26668 container = config.container;
26669 buttons = config.buttons; // not really - use items!!
26672 if (config && config.items) {
26673 xitems = config.items;
26674 delete config.items;
26676 Roo.apply(this, config);
26677 this.buttons = buttons;
26680 this.render(container);
26682 Roo.each(xitems, function(b) {
26688 Roo.Toolbar.prototype = {
26690 * @cfg {Roo.data.Store} items
26691 * array of button configs or elements to add
26695 * @cfg {String/HTMLElement/Element} container
26696 * The id or element that will contain the toolbar
26699 render : function(ct){
26700 this.el = Roo.get(ct);
26702 this.el.addClass(this.cls);
26704 // using a table allows for vertical alignment
26705 // 100% width is needed by Safari...
26706 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26707 this.tr = this.el.child("tr", true);
26709 this.items = new Roo.util.MixedCollection(false, function(o){
26710 return o.id || ("item" + (++autoId));
26713 this.add.apply(this, this.buttons);
26714 delete this.buttons;
26719 * Adds element(s) to the toolbar -- this function takes a variable number of
26720 * arguments of mixed type and adds them to the toolbar.
26721 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26723 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26724 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26725 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26726 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26727 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26728 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26729 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26730 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26731 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26733 * @param {Mixed} arg2
26734 * @param {Mixed} etc.
26737 var a = arguments, l = a.length;
26738 for(var i = 0; i < l; i++){
26743 _add : function(el) {
26746 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26749 if (el.applyTo){ // some kind of form field
26750 return this.addField(el);
26752 if (el.render){ // some kind of Toolbar.Item
26753 return this.addItem(el);
26755 if (typeof el == "string"){ // string
26756 if(el == "separator" || el == "-"){
26757 return this.addSeparator();
26760 return this.addSpacer();
26763 return this.addFill();
26765 return this.addText(el);
26768 if(el.tagName){ // element
26769 return this.addElement(el);
26771 if(typeof el == "object"){ // must be button config?
26772 return this.addButton(el);
26774 // and now what?!?!
26780 * Add an Xtype element
26781 * @param {Object} xtype Xtype Object
26782 * @return {Object} created Object
26784 addxtype : function(e){
26785 return this.add(e);
26789 * Returns the Element for this toolbar.
26790 * @return {Roo.Element}
26792 getEl : function(){
26798 * @return {Roo.Toolbar.Item} The separator item
26800 addSeparator : function(){
26801 return this.addItem(new Roo.Toolbar.Separator());
26805 * Adds a spacer element
26806 * @return {Roo.Toolbar.Spacer} The spacer item
26808 addSpacer : function(){
26809 return this.addItem(new Roo.Toolbar.Spacer());
26813 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26814 * @return {Roo.Toolbar.Fill} The fill item
26816 addFill : function(){
26817 return this.addItem(new Roo.Toolbar.Fill());
26821 * Adds any standard HTML element to the toolbar
26822 * @param {String/HTMLElement/Element} el The element or id of the element to add
26823 * @return {Roo.Toolbar.Item} The element's item
26825 addElement : function(el){
26826 return this.addItem(new Roo.Toolbar.Item(el));
26829 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26830 * @type Roo.util.MixedCollection
26835 * Adds any Toolbar.Item or subclass
26836 * @param {Roo.Toolbar.Item} item
26837 * @return {Roo.Toolbar.Item} The item
26839 addItem : function(item){
26840 var td = this.nextBlock();
26842 this.items.add(item);
26847 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26848 * @param {Object/Array} config A button config or array of configs
26849 * @return {Roo.Toolbar.Button/Array}
26851 addButton : function(config){
26852 if(config instanceof Array){
26854 for(var i = 0, len = config.length; i < len; i++) {
26855 buttons.push(this.addButton(config[i]));
26860 if(!(config instanceof Roo.Toolbar.Button)){
26862 new Roo.Toolbar.SplitButton(config) :
26863 new Roo.Toolbar.Button(config);
26865 var td = this.nextBlock();
26872 * Adds text to the toolbar
26873 * @param {String} text The text to add
26874 * @return {Roo.Toolbar.Item} The element's item
26876 addText : function(text){
26877 return this.addItem(new Roo.Toolbar.TextItem(text));
26881 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26882 * @param {Number} index The index where the item is to be inserted
26883 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26884 * @return {Roo.Toolbar.Button/Item}
26886 insertButton : function(index, item){
26887 if(item instanceof Array){
26889 for(var i = 0, len = item.length; i < len; i++) {
26890 buttons.push(this.insertButton(index + i, item[i]));
26894 if (!(item instanceof Roo.Toolbar.Button)){
26895 item = new Roo.Toolbar.Button(item);
26897 var td = document.createElement("td");
26898 this.tr.insertBefore(td, this.tr.childNodes[index]);
26900 this.items.insert(index, item);
26905 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26906 * @param {Object} config
26907 * @return {Roo.Toolbar.Item} The element's item
26909 addDom : function(config, returnEl){
26910 var td = this.nextBlock();
26911 Roo.DomHelper.overwrite(td, config);
26912 var ti = new Roo.Toolbar.Item(td.firstChild);
26914 this.items.add(ti);
26919 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26920 * @type Roo.util.MixedCollection
26925 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26926 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26927 * @param {Roo.form.Field} field
26928 * @return {Roo.ToolbarItem}
26932 addField : function(field) {
26933 if (!this.fields) {
26935 this.fields = new Roo.util.MixedCollection(false, function(o){
26936 return o.id || ("item" + (++autoId));
26941 var td = this.nextBlock();
26943 var ti = new Roo.Toolbar.Item(td.firstChild);
26945 this.items.add(ti);
26946 this.fields.add(field);
26957 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26958 this.el.child('div').hide();
26966 this.el.child('div').show();
26970 nextBlock : function(){
26971 var td = document.createElement("td");
26972 this.tr.appendChild(td);
26977 destroy : function(){
26978 if(this.items){ // rendered?
26979 Roo.destroy.apply(Roo, this.items.items);
26981 if(this.fields){ // rendered?
26982 Roo.destroy.apply(Roo, this.fields.items);
26984 Roo.Element.uncache(this.el, this.tr);
26989 * @class Roo.Toolbar.Item
26990 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26992 * Creates a new Item
26993 * @param {HTMLElement} el
26995 Roo.Toolbar.Item = function(el){
26996 this.el = Roo.getDom(el);
26997 this.id = Roo.id(this.el);
26998 this.hidden = false;
27001 Roo.Toolbar.Item.prototype = {
27004 * Get this item's HTML Element
27005 * @return {HTMLElement}
27007 getEl : function(){
27012 render : function(td){
27014 td.appendChild(this.el);
27018 * Removes and destroys this item.
27020 destroy : function(){
27021 this.td.parentNode.removeChild(this.td);
27028 this.hidden = false;
27029 this.td.style.display = "";
27036 this.hidden = true;
27037 this.td.style.display = "none";
27041 * Convenience function for boolean show/hide.
27042 * @param {Boolean} visible true to show/false to hide
27044 setVisible: function(visible){
27053 * Try to focus this item.
27055 focus : function(){
27056 Roo.fly(this.el).focus();
27060 * Disables this item.
27062 disable : function(){
27063 Roo.fly(this.td).addClass("x-item-disabled");
27064 this.disabled = true;
27065 this.el.disabled = true;
27069 * Enables this item.
27071 enable : function(){
27072 Roo.fly(this.td).removeClass("x-item-disabled");
27073 this.disabled = false;
27074 this.el.disabled = false;
27080 * @class Roo.Toolbar.Separator
27081 * @extends Roo.Toolbar.Item
27082 * A simple toolbar separator class
27084 * Creates a new Separator
27086 Roo.Toolbar.Separator = function(){
27087 var s = document.createElement("span");
27088 s.className = "ytb-sep";
27089 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27091 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27092 enable:Roo.emptyFn,
27093 disable:Roo.emptyFn,
27098 * @class Roo.Toolbar.Spacer
27099 * @extends Roo.Toolbar.Item
27100 * A simple element that adds extra horizontal space to a toolbar.
27102 * Creates a new Spacer
27104 Roo.Toolbar.Spacer = function(){
27105 var s = document.createElement("div");
27106 s.className = "ytb-spacer";
27107 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27109 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27110 enable:Roo.emptyFn,
27111 disable:Roo.emptyFn,
27116 * @class Roo.Toolbar.Fill
27117 * @extends Roo.Toolbar.Spacer
27118 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27120 * Creates a new Spacer
27122 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27124 render : function(td){
27125 td.style.width = '100%';
27126 Roo.Toolbar.Fill.superclass.render.call(this, td);
27131 * @class Roo.Toolbar.TextItem
27132 * @extends Roo.Toolbar.Item
27133 * A simple class that renders text directly into a toolbar.
27135 * Creates a new TextItem
27136 * @param {String} text
27138 Roo.Toolbar.TextItem = function(text){
27139 if (typeof(text) == 'object') {
27142 var s = document.createElement("span");
27143 s.className = "ytb-text";
27144 s.innerHTML = text;
27145 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27147 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27148 enable:Roo.emptyFn,
27149 disable:Roo.emptyFn,
27154 * @class Roo.Toolbar.Button
27155 * @extends Roo.Button
27156 * A button that renders into a toolbar.
27158 * Creates a new Button
27159 * @param {Object} config A standard {@link Roo.Button} config object
27161 Roo.Toolbar.Button = function(config){
27162 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27164 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27165 render : function(td){
27167 Roo.Toolbar.Button.superclass.render.call(this, td);
27171 * Removes and destroys this button
27173 destroy : function(){
27174 Roo.Toolbar.Button.superclass.destroy.call(this);
27175 this.td.parentNode.removeChild(this.td);
27179 * Shows this button
27182 this.hidden = false;
27183 this.td.style.display = "";
27187 * Hides this button
27190 this.hidden = true;
27191 this.td.style.display = "none";
27195 * Disables this item
27197 disable : function(){
27198 Roo.fly(this.td).addClass("x-item-disabled");
27199 this.disabled = true;
27203 * Enables this item
27205 enable : function(){
27206 Roo.fly(this.td).removeClass("x-item-disabled");
27207 this.disabled = false;
27210 // backwards compat
27211 Roo.ToolbarButton = Roo.Toolbar.Button;
27214 * @class Roo.Toolbar.SplitButton
27215 * @extends Roo.SplitButton
27216 * A menu button that renders into a toolbar.
27218 * Creates a new SplitButton
27219 * @param {Object} config A standard {@link Roo.SplitButton} config object
27221 Roo.Toolbar.SplitButton = function(config){
27222 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27224 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27225 render : function(td){
27227 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27231 * Removes and destroys this button
27233 destroy : function(){
27234 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27235 this.td.parentNode.removeChild(this.td);
27239 * Shows this button
27242 this.hidden = false;
27243 this.td.style.display = "";
27247 * Hides this button
27250 this.hidden = true;
27251 this.td.style.display = "none";
27255 // backwards compat
27256 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27258 * Ext JS Library 1.1.1
27259 * Copyright(c) 2006-2007, Ext JS, LLC.
27261 * Originally Released Under LGPL - original licence link has changed is not relivant.
27264 * <script type="text/javascript">
27268 * @class Roo.PagingToolbar
27269 * @extends Roo.Toolbar
27270 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27272 * Create a new PagingToolbar
27273 * @param {Object} config The config object
27275 Roo.PagingToolbar = function(el, ds, config)
27277 // old args format still supported... - xtype is prefered..
27278 if (typeof(el) == 'object' && el.xtype) {
27279 // created from xtype...
27281 ds = el.dataSource;
27282 el = config.container;
27285 if (config.items) {
27286 items = config.items;
27290 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27293 this.renderButtons(this.el);
27296 // supprot items array.
27298 Roo.each(items, function(e) {
27299 this.add(Roo.factory(e));
27304 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27306 * @cfg {Roo.data.Store} dataSource
27307 * The underlying data store providing the paged data
27310 * @cfg {String/HTMLElement/Element} container
27311 * container The id or element that will contain the toolbar
27314 * @cfg {Boolean} displayInfo
27315 * True to display the displayMsg (defaults to false)
27318 * @cfg {Number} pageSize
27319 * The number of records to display per page (defaults to 20)
27323 * @cfg {String} displayMsg
27324 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27326 displayMsg : 'Displaying {0} - {1} of {2}',
27328 * @cfg {String} emptyMsg
27329 * The message to display when no records are found (defaults to "No data to display")
27331 emptyMsg : 'No data to display',
27333 * Customizable piece of the default paging text (defaults to "Page")
27336 beforePageText : "Page",
27338 * Customizable piece of the default paging text (defaults to "of %0")
27341 afterPageText : "of {0}",
27343 * Customizable piece of the default paging text (defaults to "First Page")
27346 firstText : "First Page",
27348 * Customizable piece of the default paging text (defaults to "Previous Page")
27351 prevText : "Previous Page",
27353 * Customizable piece of the default paging text (defaults to "Next Page")
27356 nextText : "Next Page",
27358 * Customizable piece of the default paging text (defaults to "Last Page")
27361 lastText : "Last Page",
27363 * Customizable piece of the default paging text (defaults to "Refresh")
27366 refreshText : "Refresh",
27369 renderButtons : function(el){
27370 Roo.PagingToolbar.superclass.render.call(this, el);
27371 this.first = this.addButton({
27372 tooltip: this.firstText,
27373 cls: "x-btn-icon x-grid-page-first",
27375 handler: this.onClick.createDelegate(this, ["first"])
27377 this.prev = this.addButton({
27378 tooltip: this.prevText,
27379 cls: "x-btn-icon x-grid-page-prev",
27381 handler: this.onClick.createDelegate(this, ["prev"])
27383 //this.addSeparator();
27384 this.add(this.beforePageText);
27385 this.field = Roo.get(this.addDom({
27390 cls: "x-grid-page-number"
27392 this.field.on("keydown", this.onPagingKeydown, this);
27393 this.field.on("focus", function(){this.dom.select();});
27394 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27395 this.field.setHeight(18);
27396 //this.addSeparator();
27397 this.next = this.addButton({
27398 tooltip: this.nextText,
27399 cls: "x-btn-icon x-grid-page-next",
27401 handler: this.onClick.createDelegate(this, ["next"])
27403 this.last = this.addButton({
27404 tooltip: this.lastText,
27405 cls: "x-btn-icon x-grid-page-last",
27407 handler: this.onClick.createDelegate(this, ["last"])
27409 //this.addSeparator();
27410 this.loading = this.addButton({
27411 tooltip: this.refreshText,
27412 cls: "x-btn-icon x-grid-loading",
27413 handler: this.onClick.createDelegate(this, ["refresh"])
27416 if(this.displayInfo){
27417 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27422 updateInfo : function(){
27423 if(this.displayEl){
27424 var count = this.ds.getCount();
27425 var msg = count == 0 ?
27429 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27431 this.displayEl.update(msg);
27436 onLoad : function(ds, r, o){
27437 this.cursor = o.params ? o.params.start : 0;
27438 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27440 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27441 this.field.dom.value = ap;
27442 this.first.setDisabled(ap == 1);
27443 this.prev.setDisabled(ap == 1);
27444 this.next.setDisabled(ap == ps);
27445 this.last.setDisabled(ap == ps);
27446 this.loading.enable();
27451 getPageData : function(){
27452 var total = this.ds.getTotalCount();
27455 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27456 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27461 onLoadError : function(){
27462 this.loading.enable();
27466 onPagingKeydown : function(e){
27467 var k = e.getKey();
27468 var d = this.getPageData();
27470 var v = this.field.dom.value, pageNum;
27471 if(!v || isNaN(pageNum = parseInt(v, 10))){
27472 this.field.dom.value = d.activePage;
27475 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27476 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27479 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))
27481 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27482 this.field.dom.value = pageNum;
27483 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27486 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27488 var v = this.field.dom.value, pageNum;
27489 var increment = (e.shiftKey) ? 10 : 1;
27490 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27492 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27493 this.field.dom.value = d.activePage;
27496 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27498 this.field.dom.value = parseInt(v, 10) + increment;
27499 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27500 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27507 beforeLoad : function(){
27509 this.loading.disable();
27514 onClick : function(which){
27518 ds.load({params:{start: 0, limit: this.pageSize}});
27521 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27524 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27527 var total = ds.getTotalCount();
27528 var extra = total % this.pageSize;
27529 var lastStart = extra ? (total - extra) : total-this.pageSize;
27530 ds.load({params:{start: lastStart, limit: this.pageSize}});
27533 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27539 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27540 * @param {Roo.data.Store} store The data store to unbind
27542 unbind : function(ds){
27543 ds.un("beforeload", this.beforeLoad, this);
27544 ds.un("load", this.onLoad, this);
27545 ds.un("loadexception", this.onLoadError, this);
27546 ds.un("remove", this.updateInfo, this);
27547 ds.un("add", this.updateInfo, this);
27548 this.ds = undefined;
27552 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27553 * @param {Roo.data.Store} store The data store to bind
27555 bind : function(ds){
27556 ds.on("beforeload", this.beforeLoad, this);
27557 ds.on("load", this.onLoad, this);
27558 ds.on("loadexception", this.onLoadError, this);
27559 ds.on("remove", this.updateInfo, this);
27560 ds.on("add", this.updateInfo, this);
27565 * Ext JS Library 1.1.1
27566 * Copyright(c) 2006-2007, Ext JS, LLC.
27568 * Originally Released Under LGPL - original licence link has changed is not relivant.
27571 * <script type="text/javascript">
27575 * @class Roo.Resizable
27576 * @extends Roo.util.Observable
27577 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27578 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27579 * 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
27580 * the element will be wrapped for you automatically.</p>
27581 * <p>Here is the list of valid resize handles:</p>
27584 ------ -------------------
27593 'hd' horizontal drag
27596 * <p>Here's an example showing the creation of a typical Resizable:</p>
27598 var resizer = new Roo.Resizable("element-id", {
27606 resizer.on("resize", myHandler);
27608 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27609 * resizer.east.setDisplayed(false);</p>
27610 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27611 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27612 * resize operation's new size (defaults to [0, 0])
27613 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27614 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27615 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27616 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27617 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27618 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27619 * @cfg {Number} width The width of the element in pixels (defaults to null)
27620 * @cfg {Number} height The height of the element in pixels (defaults to null)
27621 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27622 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27623 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27624 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27625 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27626 * in favor of the handles config option (defaults to false)
27627 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27628 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27629 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27630 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27631 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27632 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27633 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27634 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27635 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27636 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27637 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27639 * Create a new resizable component
27640 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27641 * @param {Object} config configuration options
27643 Roo.Resizable = function(el, config)
27645 this.el = Roo.get(el);
27647 if(config && config.wrap){
27648 config.resizeChild = this.el;
27649 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27650 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27651 this.el.setStyle("overflow", "hidden");
27652 this.el.setPositioning(config.resizeChild.getPositioning());
27653 config.resizeChild.clearPositioning();
27654 if(!config.width || !config.height){
27655 var csize = config.resizeChild.getSize();
27656 this.el.setSize(csize.width, csize.height);
27658 if(config.pinned && !config.adjustments){
27659 config.adjustments = "auto";
27663 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27664 this.proxy.unselectable();
27665 this.proxy.enableDisplayMode('block');
27667 Roo.apply(this, config);
27670 this.disableTrackOver = true;
27671 this.el.addClass("x-resizable-pinned");
27673 // if the element isn't positioned, make it relative
27674 var position = this.el.getStyle("position");
27675 if(position != "absolute" && position != "fixed"){
27676 this.el.setStyle("position", "relative");
27678 if(!this.handles){ // no handles passed, must be legacy style
27679 this.handles = 's,e,se';
27680 if(this.multiDirectional){
27681 this.handles += ',n,w';
27684 if(this.handles == "all"){
27685 this.handles = "n s e w ne nw se sw";
27687 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27688 var ps = Roo.Resizable.positions;
27689 for(var i = 0, len = hs.length; i < len; i++){
27690 if(hs[i] && ps[hs[i]]){
27691 var pos = ps[hs[i]];
27692 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27696 this.corner = this.southeast;
27698 // updateBox = the box can move..
27699 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27700 this.updateBox = true;
27703 this.activeHandle = null;
27705 if(this.resizeChild){
27706 if(typeof this.resizeChild == "boolean"){
27707 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27709 this.resizeChild = Roo.get(this.resizeChild, true);
27713 if(this.adjustments == "auto"){
27714 var rc = this.resizeChild;
27715 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27716 if(rc && (hw || hn)){
27717 rc.position("relative");
27718 rc.setLeft(hw ? hw.el.getWidth() : 0);
27719 rc.setTop(hn ? hn.el.getHeight() : 0);
27721 this.adjustments = [
27722 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27723 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27727 if(this.draggable){
27728 this.dd = this.dynamic ?
27729 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27730 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27736 * @event beforeresize
27737 * Fired before resize is allowed. Set enabled to false to cancel resize.
27738 * @param {Roo.Resizable} this
27739 * @param {Roo.EventObject} e The mousedown event
27741 "beforeresize" : true,
27744 * Fired after a resize.
27745 * @param {Roo.Resizable} this
27746 * @param {Number} width The new width
27747 * @param {Number} height The new height
27748 * @param {Roo.EventObject} e The mouseup event
27753 if(this.width !== null && this.height !== null){
27754 this.resizeTo(this.width, this.height);
27756 this.updateChildSize();
27759 this.el.dom.style.zoom = 1;
27761 Roo.Resizable.superclass.constructor.call(this);
27764 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27765 resizeChild : false,
27766 adjustments : [0, 0],
27776 multiDirectional : false,
27777 disableTrackOver : false,
27778 easing : 'easeOutStrong',
27779 widthIncrement : 0,
27780 heightIncrement : 0,
27784 preserveRatio : false,
27785 transparent: false,
27791 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27793 constrainTo: undefined,
27795 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27797 resizeRegion: undefined,
27801 * Perform a manual resize
27802 * @param {Number} width
27803 * @param {Number} height
27805 resizeTo : function(width, height){
27806 this.el.setSize(width, height);
27807 this.updateChildSize();
27808 this.fireEvent("resize", this, width, height, null);
27812 startSizing : function(e, handle){
27813 this.fireEvent("beforeresize", this, e);
27814 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27817 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27818 this.overlay.unselectable();
27819 this.overlay.enableDisplayMode("block");
27820 this.overlay.on("mousemove", this.onMouseMove, this);
27821 this.overlay.on("mouseup", this.onMouseUp, this);
27823 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27825 this.resizing = true;
27826 this.startBox = this.el.getBox();
27827 this.startPoint = e.getXY();
27828 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27829 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27831 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27832 this.overlay.show();
27834 if(this.constrainTo) {
27835 var ct = Roo.get(this.constrainTo);
27836 this.resizeRegion = ct.getRegion().adjust(
27837 ct.getFrameWidth('t'),
27838 ct.getFrameWidth('l'),
27839 -ct.getFrameWidth('b'),
27840 -ct.getFrameWidth('r')
27844 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27846 this.proxy.setBox(this.startBox);
27848 this.proxy.setStyle('visibility', 'visible');
27854 onMouseDown : function(handle, e){
27857 this.activeHandle = handle;
27858 this.startSizing(e, handle);
27863 onMouseUp : function(e){
27864 var size = this.resizeElement();
27865 this.resizing = false;
27867 this.overlay.hide();
27869 this.fireEvent("resize", this, size.width, size.height, e);
27873 updateChildSize : function(){
27874 if(this.resizeChild){
27876 var child = this.resizeChild;
27877 var adj = this.adjustments;
27878 if(el.dom.offsetWidth){
27879 var b = el.getSize(true);
27880 child.setSize(b.width+adj[0], b.height+adj[1]);
27882 // Second call here for IE
27883 // The first call enables instant resizing and
27884 // the second call corrects scroll bars if they
27887 setTimeout(function(){
27888 if(el.dom.offsetWidth){
27889 var b = el.getSize(true);
27890 child.setSize(b.width+adj[0], b.height+adj[1]);
27898 snap : function(value, inc, min){
27899 if(!inc || !value) return value;
27900 var newValue = value;
27901 var m = value % inc;
27904 newValue = value + (inc-m);
27906 newValue = value - m;
27909 return Math.max(min, newValue);
27913 resizeElement : function(){
27914 var box = this.proxy.getBox();
27915 if(this.updateBox){
27916 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27918 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27920 this.updateChildSize();
27928 constrain : function(v, diff, m, mx){
27931 }else if(v - diff > mx){
27938 onMouseMove : function(e){
27940 try{// try catch so if something goes wrong the user doesn't get hung
27942 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27946 //var curXY = this.startPoint;
27947 var curSize = this.curSize || this.startBox;
27948 var x = this.startBox.x, y = this.startBox.y;
27949 var ox = x, oy = y;
27950 var w = curSize.width, h = curSize.height;
27951 var ow = w, oh = h;
27952 var mw = this.minWidth, mh = this.minHeight;
27953 var mxw = this.maxWidth, mxh = this.maxHeight;
27954 var wi = this.widthIncrement;
27955 var hi = this.heightIncrement;
27957 var eventXY = e.getXY();
27958 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27959 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27961 var pos = this.activeHandle.position;
27966 w = Math.min(Math.max(mw, w), mxw);
27971 h = Math.min(Math.max(mh, h), mxh);
27976 w = Math.min(Math.max(mw, w), mxw);
27977 h = Math.min(Math.max(mh, h), mxh);
27980 diffY = this.constrain(h, diffY, mh, mxh);
27987 var adiffX = Math.abs(diffX);
27988 var sub = (adiffX % wi); // how much
27989 if (sub > (wi/2)) { // far enough to snap
27990 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
27992 // remove difference..
27993 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
27997 x = Math.max(this.minX, x);
28000 diffX = this.constrain(w, diffX, mw, mxw);
28006 w = Math.min(Math.max(mw, w), mxw);
28007 diffY = this.constrain(h, diffY, mh, mxh);
28012 diffX = this.constrain(w, diffX, mw, mxw);
28013 diffY = this.constrain(h, diffY, mh, mxh);
28020 diffX = this.constrain(w, diffX, mw, mxw);
28022 h = Math.min(Math.max(mh, h), mxh);
28028 var sw = this.snap(w, wi, mw);
28029 var sh = this.snap(h, hi, mh);
28030 if(sw != w || sh != h){
28053 if(this.preserveRatio){
28058 h = Math.min(Math.max(mh, h), mxh);
28063 w = Math.min(Math.max(mw, w), mxw);
28068 w = Math.min(Math.max(mw, w), mxw);
28074 w = Math.min(Math.max(mw, w), mxw);
28080 h = Math.min(Math.max(mh, h), mxh);
28088 h = Math.min(Math.max(mh, h), mxh);
28098 h = Math.min(Math.max(mh, h), mxh);
28106 if (pos == 'hdrag') {
28109 this.proxy.setBounds(x, y, w, h);
28111 this.resizeElement();
28118 handleOver : function(){
28120 this.el.addClass("x-resizable-over");
28125 handleOut : function(){
28126 if(!this.resizing){
28127 this.el.removeClass("x-resizable-over");
28132 * Returns the element this component is bound to.
28133 * @return {Roo.Element}
28135 getEl : function(){
28140 * Returns the resizeChild element (or null).
28141 * @return {Roo.Element}
28143 getResizeChild : function(){
28144 return this.resizeChild;
28148 * Destroys this resizable. If the element was wrapped and
28149 * removeEl is not true then the element remains.
28150 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28152 destroy : function(removeEl){
28153 this.proxy.remove();
28155 this.overlay.removeAllListeners();
28156 this.overlay.remove();
28158 var ps = Roo.Resizable.positions;
28160 if(typeof ps[k] != "function" && this[ps[k]]){
28161 var h = this[ps[k]];
28162 h.el.removeAllListeners();
28167 this.el.update("");
28174 // hash to map config positions to true positions
28175 Roo.Resizable.positions = {
28176 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28181 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28183 // only initialize the template if resizable is used
28184 var tpl = Roo.DomHelper.createTemplate(
28185 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28188 Roo.Resizable.Handle.prototype.tpl = tpl;
28190 this.position = pos;
28192 // show north drag fro topdra
28193 var handlepos = pos == 'hdrag' ? 'north' : pos;
28195 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28196 if (pos == 'hdrag') {
28197 this.el.setStyle('cursor', 'pointer');
28199 this.el.unselectable();
28201 this.el.setOpacity(0);
28203 this.el.on("mousedown", this.onMouseDown, this);
28204 if(!disableTrackOver){
28205 this.el.on("mouseover", this.onMouseOver, this);
28206 this.el.on("mouseout", this.onMouseOut, this);
28211 Roo.Resizable.Handle.prototype = {
28212 afterResize : function(rz){
28216 onMouseDown : function(e){
28217 this.rz.onMouseDown(this, e);
28220 onMouseOver : function(e){
28221 this.rz.handleOver(this, e);
28224 onMouseOut : function(e){
28225 this.rz.handleOut(this, e);
28229 * Ext JS Library 1.1.1
28230 * Copyright(c) 2006-2007, Ext JS, LLC.
28232 * Originally Released Under LGPL - original licence link has changed is not relivant.
28235 * <script type="text/javascript">
28239 * @class Roo.Editor
28240 * @extends Roo.Component
28241 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28243 * Create a new Editor
28244 * @param {Roo.form.Field} field The Field object (or descendant)
28245 * @param {Object} config The config object
28247 Roo.Editor = function(field, config){
28248 Roo.Editor.superclass.constructor.call(this, config);
28249 this.field = field;
28252 * @event beforestartedit
28253 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28254 * false from the handler of this event.
28255 * @param {Editor} this
28256 * @param {Roo.Element} boundEl The underlying element bound to this editor
28257 * @param {Mixed} value The field value being set
28259 "beforestartedit" : true,
28262 * Fires when this editor is displayed
28263 * @param {Roo.Element} boundEl The underlying element bound to this editor
28264 * @param {Mixed} value The starting field value
28266 "startedit" : true,
28268 * @event beforecomplete
28269 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28270 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28271 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28272 * event will not fire since no edit actually occurred.
28273 * @param {Editor} this
28274 * @param {Mixed} value The current field value
28275 * @param {Mixed} startValue The original field value
28277 "beforecomplete" : true,
28280 * Fires after editing is complete and any changed value has been written to the underlying field.
28281 * @param {Editor} this
28282 * @param {Mixed} value The current field value
28283 * @param {Mixed} startValue The original field value
28287 * @event specialkey
28288 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28289 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28290 * @param {Roo.form.Field} this
28291 * @param {Roo.EventObject} e The event object
28293 "specialkey" : true
28297 Roo.extend(Roo.Editor, Roo.Component, {
28299 * @cfg {Boolean/String} autosize
28300 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28301 * or "height" to adopt the height only (defaults to false)
28304 * @cfg {Boolean} revertInvalid
28305 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28306 * validation fails (defaults to true)
28309 * @cfg {Boolean} ignoreNoChange
28310 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28311 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28312 * will never be ignored.
28315 * @cfg {Boolean} hideEl
28316 * False to keep the bound element visible while the editor is displayed (defaults to true)
28319 * @cfg {Mixed} value
28320 * The data value of the underlying field (defaults to "")
28324 * @cfg {String} alignment
28325 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28329 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28330 * for bottom-right shadow (defaults to "frame")
28334 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28338 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28340 completeOnEnter : false,
28342 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28344 cancelOnEsc : false,
28346 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28351 onRender : function(ct, position){
28352 this.el = new Roo.Layer({
28353 shadow: this.shadow,
28359 constrain: this.constrain
28361 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28362 if(this.field.msgTarget != 'title'){
28363 this.field.msgTarget = 'qtip';
28365 this.field.render(this.el);
28367 this.field.el.dom.setAttribute('autocomplete', 'off');
28369 this.field.on("specialkey", this.onSpecialKey, this);
28370 if(this.swallowKeys){
28371 this.field.el.swallowEvent(['keydown','keypress']);
28374 this.field.on("blur", this.onBlur, this);
28375 if(this.field.grow){
28376 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28380 onSpecialKey : function(field, e)
28382 //Roo.log('editor onSpecialKey');
28383 if(this.completeOnEnter && e.getKey() == e.ENTER){
28385 this.completeEdit();
28388 // do not fire special key otherwise it might hide close the editor...
28389 if(e.getKey() == e.ENTER){
28392 if(this.cancelOnEsc && e.getKey() == e.ESC){
28396 this.fireEvent('specialkey', field, e);
28401 * Starts the editing process and shows the editor.
28402 * @param {String/HTMLElement/Element} el The element to edit
28403 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28404 * to the innerHTML of el.
28406 startEdit : function(el, value){
28408 this.completeEdit();
28410 this.boundEl = Roo.get(el);
28411 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28412 if(!this.rendered){
28413 this.render(this.parentEl || document.body);
28415 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28418 this.startValue = v;
28419 this.field.setValue(v);
28421 var sz = this.boundEl.getSize();
28422 switch(this.autoSize){
28424 this.setSize(sz.width, "");
28427 this.setSize("", sz.height);
28430 this.setSize(sz.width, sz.height);
28433 this.el.alignTo(this.boundEl, this.alignment);
28434 this.editing = true;
28436 Roo.QuickTips.disable();
28442 * Sets the height and width of this editor.
28443 * @param {Number} width The new width
28444 * @param {Number} height The new height
28446 setSize : function(w, h){
28447 this.field.setSize(w, h);
28454 * Realigns the editor to the bound field based on the current alignment config value.
28456 realign : function(){
28457 this.el.alignTo(this.boundEl, this.alignment);
28461 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28462 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28464 completeEdit : function(remainVisible){
28468 var v = this.getValue();
28469 if(this.revertInvalid !== false && !this.field.isValid()){
28470 v = this.startValue;
28471 this.cancelEdit(true);
28473 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28474 this.editing = false;
28478 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28479 this.editing = false;
28480 if(this.updateEl && this.boundEl){
28481 this.boundEl.update(v);
28483 if(remainVisible !== true){
28486 this.fireEvent("complete", this, v, this.startValue);
28491 onShow : function(){
28493 if(this.hideEl !== false){
28494 this.boundEl.hide();
28497 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28498 this.fixIEFocus = true;
28499 this.deferredFocus.defer(50, this);
28501 this.field.focus();
28503 this.fireEvent("startedit", this.boundEl, this.startValue);
28506 deferredFocus : function(){
28508 this.field.focus();
28513 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28514 * reverted to the original starting value.
28515 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28516 * cancel (defaults to false)
28518 cancelEdit : function(remainVisible){
28520 this.setValue(this.startValue);
28521 if(remainVisible !== true){
28528 onBlur : function(){
28529 if(this.allowBlur !== true && this.editing){
28530 this.completeEdit();
28535 onHide : function(){
28537 this.completeEdit();
28541 if(this.field.collapse){
28542 this.field.collapse();
28545 if(this.hideEl !== false){
28546 this.boundEl.show();
28549 Roo.QuickTips.enable();
28554 * Sets the data value of the editor
28555 * @param {Mixed} value Any valid value supported by the underlying field
28557 setValue : function(v){
28558 this.field.setValue(v);
28562 * Gets the data value of the editor
28563 * @return {Mixed} The data value
28565 getValue : function(){
28566 return this.field.getValue();
28570 * Ext JS Library 1.1.1
28571 * Copyright(c) 2006-2007, Ext JS, LLC.
28573 * Originally Released Under LGPL - original licence link has changed is not relivant.
28576 * <script type="text/javascript">
28580 * @class Roo.BasicDialog
28581 * @extends Roo.util.Observable
28582 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28584 var dlg = new Roo.BasicDialog("my-dlg", {
28593 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28594 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28595 dlg.addButton('Cancel', dlg.hide, dlg);
28598 <b>A Dialog should always be a direct child of the body element.</b>
28599 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28600 * @cfg {String} title Default text to display in the title bar (defaults to null)
28601 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28602 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28603 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28604 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28605 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28606 * (defaults to null with no animation)
28607 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28608 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28609 * property for valid values (defaults to 'all')
28610 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28611 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28612 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28613 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28614 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28615 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28616 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28617 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28618 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28619 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28620 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28621 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28622 * draggable = true (defaults to false)
28623 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28624 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28625 * shadow (defaults to false)
28626 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28627 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28628 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28629 * @cfg {Array} buttons Array of buttons
28630 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28632 * Create a new BasicDialog.
28633 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28634 * @param {Object} config Configuration options
28636 Roo.BasicDialog = function(el, config){
28637 this.el = Roo.get(el);
28638 var dh = Roo.DomHelper;
28639 if(!this.el && config && config.autoCreate){
28640 if(typeof config.autoCreate == "object"){
28641 if(!config.autoCreate.id){
28642 config.autoCreate.id = el;
28644 this.el = dh.append(document.body,
28645 config.autoCreate, true);
28647 this.el = dh.append(document.body,
28648 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28652 el.setDisplayed(true);
28653 el.hide = this.hideAction;
28655 el.addClass("x-dlg");
28657 Roo.apply(this, config);
28659 this.proxy = el.createProxy("x-dlg-proxy");
28660 this.proxy.hide = this.hideAction;
28661 this.proxy.setOpacity(.5);
28665 el.setWidth(config.width);
28668 el.setHeight(config.height);
28670 this.size = el.getSize();
28671 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28672 this.xy = [config.x,config.y];
28674 this.xy = el.getCenterXY(true);
28676 /** The header element @type Roo.Element */
28677 this.header = el.child("> .x-dlg-hd");
28678 /** The body element @type Roo.Element */
28679 this.body = el.child("> .x-dlg-bd");
28680 /** The footer element @type Roo.Element */
28681 this.footer = el.child("> .x-dlg-ft");
28684 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28687 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28690 this.header.unselectable();
28692 this.header.update(this.title);
28694 // this element allows the dialog to be focused for keyboard event
28695 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28696 this.focusEl.swallowEvent("click", true);
28698 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28700 // wrap the body and footer for special rendering
28701 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28703 this.bwrap.dom.appendChild(this.footer.dom);
28706 this.bg = this.el.createChild({
28707 tag: "div", cls:"x-dlg-bg",
28708 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28710 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28713 if(this.autoScroll !== false && !this.autoTabs){
28714 this.body.setStyle("overflow", "auto");
28717 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28719 if(this.closable !== false){
28720 this.el.addClass("x-dlg-closable");
28721 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28722 this.close.on("click", this.closeClick, this);
28723 this.close.addClassOnOver("x-dlg-close-over");
28725 if(this.collapsible !== false){
28726 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28727 this.collapseBtn.on("click", this.collapseClick, this);
28728 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28729 this.header.on("dblclick", this.collapseClick, this);
28731 if(this.resizable !== false){
28732 this.el.addClass("x-dlg-resizable");
28733 this.resizer = new Roo.Resizable(el, {
28734 minWidth: this.minWidth || 80,
28735 minHeight:this.minHeight || 80,
28736 handles: this.resizeHandles || "all",
28739 this.resizer.on("beforeresize", this.beforeResize, this);
28740 this.resizer.on("resize", this.onResize, this);
28742 if(this.draggable !== false){
28743 el.addClass("x-dlg-draggable");
28744 if (!this.proxyDrag) {
28745 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28748 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28750 dd.setHandleElId(this.header.id);
28751 dd.endDrag = this.endMove.createDelegate(this);
28752 dd.startDrag = this.startMove.createDelegate(this);
28753 dd.onDrag = this.onDrag.createDelegate(this);
28758 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28759 this.mask.enableDisplayMode("block");
28761 this.el.addClass("x-dlg-modal");
28764 this.shadow = new Roo.Shadow({
28765 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28766 offset : this.shadowOffset
28769 this.shadowOffset = 0;
28771 if(Roo.useShims && this.shim !== false){
28772 this.shim = this.el.createShim();
28773 this.shim.hide = this.hideAction;
28781 if (this.buttons) {
28782 var bts= this.buttons;
28784 Roo.each(bts, function(b) {
28793 * Fires when a key is pressed
28794 * @param {Roo.BasicDialog} this
28795 * @param {Roo.EventObject} e
28800 * Fires when this dialog is moved by the user.
28801 * @param {Roo.BasicDialog} this
28802 * @param {Number} x The new page X
28803 * @param {Number} y The new page Y
28808 * Fires when this dialog is resized by the user.
28809 * @param {Roo.BasicDialog} this
28810 * @param {Number} width The new width
28811 * @param {Number} height The new height
28815 * @event beforehide
28816 * Fires before this dialog is hidden.
28817 * @param {Roo.BasicDialog} this
28819 "beforehide" : true,
28822 * Fires when this dialog is hidden.
28823 * @param {Roo.BasicDialog} this
28827 * @event beforeshow
28828 * Fires before this dialog is shown.
28829 * @param {Roo.BasicDialog} this
28831 "beforeshow" : true,
28834 * Fires when this dialog is shown.
28835 * @param {Roo.BasicDialog} this
28839 el.on("keydown", this.onKeyDown, this);
28840 el.on("mousedown", this.toFront, this);
28841 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28843 Roo.DialogManager.register(this);
28844 Roo.BasicDialog.superclass.constructor.call(this);
28847 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28848 shadowOffset: Roo.isIE ? 6 : 5,
28851 minButtonWidth: 75,
28852 defaultButton: null,
28853 buttonAlign: "right",
28858 * Sets the dialog title text
28859 * @param {String} text The title text to display
28860 * @return {Roo.BasicDialog} this
28862 setTitle : function(text){
28863 this.header.update(text);
28868 closeClick : function(){
28873 collapseClick : function(){
28874 this[this.collapsed ? "expand" : "collapse"]();
28878 * Collapses the dialog to its minimized state (only the title bar is visible).
28879 * Equivalent to the user clicking the collapse dialog button.
28881 collapse : function(){
28882 if(!this.collapsed){
28883 this.collapsed = true;
28884 this.el.addClass("x-dlg-collapsed");
28885 this.restoreHeight = this.el.getHeight();
28886 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28891 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28892 * clicking the expand dialog button.
28894 expand : function(){
28895 if(this.collapsed){
28896 this.collapsed = false;
28897 this.el.removeClass("x-dlg-collapsed");
28898 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28903 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28904 * @return {Roo.TabPanel} The tabs component
28906 initTabs : function(){
28907 var tabs = this.getTabs();
28908 while(tabs.getTab(0)){
28911 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28913 tabs.addTab(Roo.id(dom), dom.title);
28921 beforeResize : function(){
28922 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28926 onResize : function(){
28927 this.refreshSize();
28928 this.syncBodyHeight();
28929 this.adjustAssets();
28931 this.fireEvent("resize", this, this.size.width, this.size.height);
28935 onKeyDown : function(e){
28936 if(this.isVisible()){
28937 this.fireEvent("keydown", this, e);
28942 * Resizes the dialog.
28943 * @param {Number} width
28944 * @param {Number} height
28945 * @return {Roo.BasicDialog} this
28947 resizeTo : function(width, height){
28948 this.el.setSize(width, height);
28949 this.size = {width: width, height: height};
28950 this.syncBodyHeight();
28951 if(this.fixedcenter){
28954 if(this.isVisible()){
28955 this.constrainXY();
28956 this.adjustAssets();
28958 this.fireEvent("resize", this, width, height);
28964 * Resizes the dialog to fit the specified content size.
28965 * @param {Number} width
28966 * @param {Number} height
28967 * @return {Roo.BasicDialog} this
28969 setContentSize : function(w, h){
28970 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28971 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28972 //if(!this.el.isBorderBox()){
28973 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28974 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28977 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28978 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
28980 this.resizeTo(w, h);
28985 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
28986 * executed in response to a particular key being pressed while the dialog is active.
28987 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
28988 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
28989 * @param {Function} fn The function to call
28990 * @param {Object} scope (optional) The scope of the function
28991 * @return {Roo.BasicDialog} this
28993 addKeyListener : function(key, fn, scope){
28994 var keyCode, shift, ctrl, alt;
28995 if(typeof key == "object" && !(key instanceof Array)){
28996 keyCode = key["key"];
28997 shift = key["shift"];
28998 ctrl = key["ctrl"];
29003 var handler = function(dlg, e){
29004 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29005 var k = e.getKey();
29006 if(keyCode instanceof Array){
29007 for(var i = 0, len = keyCode.length; i < len; i++){
29008 if(keyCode[i] == k){
29009 fn.call(scope || window, dlg, k, e);
29015 fn.call(scope || window, dlg, k, e);
29020 this.on("keydown", handler);
29025 * Returns the TabPanel component (creates it if it doesn't exist).
29026 * Note: If you wish to simply check for the existence of tabs without creating them,
29027 * check for a null 'tabs' property.
29028 * @return {Roo.TabPanel} The tabs component
29030 getTabs : function(){
29032 this.el.addClass("x-dlg-auto-tabs");
29033 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29034 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29040 * Adds a button to the footer section of the dialog.
29041 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29042 * object or a valid Roo.DomHelper element config
29043 * @param {Function} handler The function called when the button is clicked
29044 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29045 * @return {Roo.Button} The new button
29047 addButton : function(config, handler, scope){
29048 var dh = Roo.DomHelper;
29050 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29052 if(!this.btnContainer){
29053 var tb = this.footer.createChild({
29055 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29056 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29058 this.btnContainer = tb.firstChild.firstChild.firstChild;
29063 minWidth: this.minButtonWidth,
29066 if(typeof config == "string"){
29067 bconfig.text = config;
29070 bconfig.dhconfig = config;
29072 Roo.apply(bconfig, config);
29076 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29077 bconfig.position = Math.max(0, bconfig.position);
29078 fc = this.btnContainer.childNodes[bconfig.position];
29081 var btn = new Roo.Button(
29083 this.btnContainer.insertBefore(document.createElement("td"),fc)
29084 : this.btnContainer.appendChild(document.createElement("td")),
29085 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29088 this.syncBodyHeight();
29091 * Array of all the buttons that have been added to this dialog via addButton
29096 this.buttons.push(btn);
29101 * Sets the default button to be focused when the dialog is displayed.
29102 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29103 * @return {Roo.BasicDialog} this
29105 setDefaultButton : function(btn){
29106 this.defaultButton = btn;
29111 getHeaderFooterHeight : function(safe){
29114 height += this.header.getHeight();
29117 var fm = this.footer.getMargins();
29118 height += (this.footer.getHeight()+fm.top+fm.bottom);
29120 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29121 height += this.centerBg.getPadding("tb");
29126 syncBodyHeight : function(){
29127 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29128 var height = this.size.height - this.getHeaderFooterHeight(false);
29129 bd.setHeight(height-bd.getMargins("tb"));
29130 var hh = this.header.getHeight();
29131 var h = this.size.height-hh;
29133 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29134 bw.setHeight(h-cb.getPadding("tb"));
29135 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29136 bd.setWidth(bw.getWidth(true));
29138 this.tabs.syncHeight();
29140 this.tabs.el.repaint();
29146 * Restores the previous state of the dialog if Roo.state is configured.
29147 * @return {Roo.BasicDialog} this
29149 restoreState : function(){
29150 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29151 if(box && box.width){
29152 this.xy = [box.x, box.y];
29153 this.resizeTo(box.width, box.height);
29159 beforeShow : function(){
29161 if(this.fixedcenter){
29162 this.xy = this.el.getCenterXY(true);
29165 Roo.get(document.body).addClass("x-body-masked");
29166 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29169 this.constrainXY();
29173 animShow : function(){
29174 var b = Roo.get(this.animateTarget).getBox();
29175 this.proxy.setSize(b.width, b.height);
29176 this.proxy.setLocation(b.x, b.y);
29178 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29179 true, .35, this.showEl.createDelegate(this));
29183 * Shows the dialog.
29184 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29185 * @return {Roo.BasicDialog} this
29187 show : function(animateTarget){
29188 if (this.fireEvent("beforeshow", this) === false){
29191 if(this.syncHeightBeforeShow){
29192 this.syncBodyHeight();
29193 }else if(this.firstShow){
29194 this.firstShow = false;
29195 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29197 this.animateTarget = animateTarget || this.animateTarget;
29198 if(!this.el.isVisible()){
29200 if(this.animateTarget && Roo.get(this.animateTarget)){
29210 showEl : function(){
29212 this.el.setXY(this.xy);
29214 this.adjustAssets(true);
29217 // IE peekaboo bug - fix found by Dave Fenwick
29221 this.fireEvent("show", this);
29225 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29226 * dialog itself will receive focus.
29228 focus : function(){
29229 if(this.defaultButton){
29230 this.defaultButton.focus();
29232 this.focusEl.focus();
29237 constrainXY : function(){
29238 if(this.constraintoviewport !== false){
29239 if(!this.viewSize){
29240 if(this.container){
29241 var s = this.container.getSize();
29242 this.viewSize = [s.width, s.height];
29244 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29247 var s = Roo.get(this.container||document).getScroll();
29249 var x = this.xy[0], y = this.xy[1];
29250 var w = this.size.width, h = this.size.height;
29251 var vw = this.viewSize[0], vh = this.viewSize[1];
29252 // only move it if it needs it
29254 // first validate right/bottom
29255 if(x + w > vw+s.left){
29259 if(y + h > vh+s.top){
29263 // then make sure top/left isn't negative
29275 if(this.isVisible()){
29276 this.el.setLocation(x, y);
29277 this.adjustAssets();
29284 onDrag : function(){
29285 if(!this.proxyDrag){
29286 this.xy = this.el.getXY();
29287 this.adjustAssets();
29292 adjustAssets : function(doShow){
29293 var x = this.xy[0], y = this.xy[1];
29294 var w = this.size.width, h = this.size.height;
29295 if(doShow === true){
29297 this.shadow.show(this.el);
29303 if(this.shadow && this.shadow.isVisible()){
29304 this.shadow.show(this.el);
29306 if(this.shim && this.shim.isVisible()){
29307 this.shim.setBounds(x, y, w, h);
29312 adjustViewport : function(w, h){
29314 w = Roo.lib.Dom.getViewWidth();
29315 h = Roo.lib.Dom.getViewHeight();
29318 this.viewSize = [w, h];
29319 if(this.modal && this.mask.isVisible()){
29320 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29321 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29323 if(this.isVisible()){
29324 this.constrainXY();
29329 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29330 * shadow, proxy, mask, etc.) Also removes all event listeners.
29331 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29333 destroy : function(removeEl){
29334 if(this.isVisible()){
29335 this.animateTarget = null;
29338 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29340 this.tabs.destroy(removeEl);
29353 for(var i = 0, len = this.buttons.length; i < len; i++){
29354 this.buttons[i].destroy();
29357 this.el.removeAllListeners();
29358 if(removeEl === true){
29359 this.el.update("");
29362 Roo.DialogManager.unregister(this);
29366 startMove : function(){
29367 if(this.proxyDrag){
29370 if(this.constraintoviewport !== false){
29371 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29376 endMove : function(){
29377 if(!this.proxyDrag){
29378 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29380 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29383 this.refreshSize();
29384 this.adjustAssets();
29386 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29390 * Brings this dialog to the front of any other visible dialogs
29391 * @return {Roo.BasicDialog} this
29393 toFront : function(){
29394 Roo.DialogManager.bringToFront(this);
29399 * Sends this dialog to the back (under) of any other visible dialogs
29400 * @return {Roo.BasicDialog} this
29402 toBack : function(){
29403 Roo.DialogManager.sendToBack(this);
29408 * Centers this dialog in the viewport
29409 * @return {Roo.BasicDialog} this
29411 center : function(){
29412 var xy = this.el.getCenterXY(true);
29413 this.moveTo(xy[0], xy[1]);
29418 * Moves the dialog's top-left corner to the specified point
29419 * @param {Number} x
29420 * @param {Number} y
29421 * @return {Roo.BasicDialog} this
29423 moveTo : function(x, y){
29425 if(this.isVisible()){
29426 this.el.setXY(this.xy);
29427 this.adjustAssets();
29433 * Aligns the dialog to the specified element
29434 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29435 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29436 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29437 * @return {Roo.BasicDialog} this
29439 alignTo : function(element, position, offsets){
29440 this.xy = this.el.getAlignToXY(element, position, offsets);
29441 if(this.isVisible()){
29442 this.el.setXY(this.xy);
29443 this.adjustAssets();
29449 * Anchors an element to another element and realigns it when the window is resized.
29450 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29451 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29452 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29453 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29454 * is a number, it is used as the buffer delay (defaults to 50ms).
29455 * @return {Roo.BasicDialog} this
29457 anchorTo : function(el, alignment, offsets, monitorScroll){
29458 var action = function(){
29459 this.alignTo(el, alignment, offsets);
29461 Roo.EventManager.onWindowResize(action, this);
29462 var tm = typeof monitorScroll;
29463 if(tm != 'undefined'){
29464 Roo.EventManager.on(window, 'scroll', action, this,
29465 {buffer: tm == 'number' ? monitorScroll : 50});
29472 * Returns true if the dialog is visible
29473 * @return {Boolean}
29475 isVisible : function(){
29476 return this.el.isVisible();
29480 animHide : function(callback){
29481 var b = Roo.get(this.animateTarget).getBox();
29483 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29485 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29486 this.hideEl.createDelegate(this, [callback]));
29490 * Hides the dialog.
29491 * @param {Function} callback (optional) Function to call when the dialog is hidden
29492 * @return {Roo.BasicDialog} this
29494 hide : function(callback){
29495 if (this.fireEvent("beforehide", this) === false){
29499 this.shadow.hide();
29504 // sometimes animateTarget seems to get set.. causing problems...
29505 // this just double checks..
29506 if(this.animateTarget && Roo.get(this.animateTarget)) {
29507 this.animHide(callback);
29510 this.hideEl(callback);
29516 hideEl : function(callback){
29520 Roo.get(document.body).removeClass("x-body-masked");
29522 this.fireEvent("hide", this);
29523 if(typeof callback == "function"){
29529 hideAction : function(){
29530 this.setLeft("-10000px");
29531 this.setTop("-10000px");
29532 this.setStyle("visibility", "hidden");
29536 refreshSize : function(){
29537 this.size = this.el.getSize();
29538 this.xy = this.el.getXY();
29539 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29543 // z-index is managed by the DialogManager and may be overwritten at any time
29544 setZIndex : function(index){
29546 this.mask.setStyle("z-index", index);
29549 this.shim.setStyle("z-index", ++index);
29552 this.shadow.setZIndex(++index);
29554 this.el.setStyle("z-index", ++index);
29556 this.proxy.setStyle("z-index", ++index);
29559 this.resizer.proxy.setStyle("z-index", ++index);
29562 this.lastZIndex = index;
29566 * Returns the element for this dialog
29567 * @return {Roo.Element} The underlying dialog Element
29569 getEl : function(){
29575 * @class Roo.DialogManager
29576 * Provides global access to BasicDialogs that have been created and
29577 * support for z-indexing (layering) multiple open dialogs.
29579 Roo.DialogManager = function(){
29581 var accessList = [];
29585 var sortDialogs = function(d1, d2){
29586 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29590 var orderDialogs = function(){
29591 accessList.sort(sortDialogs);
29592 var seed = Roo.DialogManager.zseed;
29593 for(var i = 0, len = accessList.length; i < len; i++){
29594 var dlg = accessList[i];
29596 dlg.setZIndex(seed + (i*10));
29603 * The starting z-index for BasicDialogs (defaults to 9000)
29604 * @type Number The z-index value
29609 register : function(dlg){
29610 list[dlg.id] = dlg;
29611 accessList.push(dlg);
29615 unregister : function(dlg){
29616 delete list[dlg.id];
29619 if(!accessList.indexOf){
29620 for( i = 0, len = accessList.length; i < len; i++){
29621 if(accessList[i] == dlg){
29622 accessList.splice(i, 1);
29627 i = accessList.indexOf(dlg);
29629 accessList.splice(i, 1);
29635 * Gets a registered dialog by id
29636 * @param {String/Object} id The id of the dialog or a dialog
29637 * @return {Roo.BasicDialog} this
29639 get : function(id){
29640 return typeof id == "object" ? id : list[id];
29644 * Brings the specified dialog to the front
29645 * @param {String/Object} dlg The id of the dialog or a dialog
29646 * @return {Roo.BasicDialog} this
29648 bringToFront : function(dlg){
29649 dlg = this.get(dlg);
29652 dlg._lastAccess = new Date().getTime();
29659 * Sends the specified dialog to the back
29660 * @param {String/Object} dlg The id of the dialog or a dialog
29661 * @return {Roo.BasicDialog} this
29663 sendToBack : function(dlg){
29664 dlg = this.get(dlg);
29665 dlg._lastAccess = -(new Date().getTime());
29671 * Hides all dialogs
29673 hideAll : function(){
29674 for(var id in list){
29675 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29684 * @class Roo.LayoutDialog
29685 * @extends Roo.BasicDialog
29686 * Dialog which provides adjustments for working with a layout in a Dialog.
29687 * Add your necessary layout config options to the dialog's config.<br>
29688 * Example usage (including a nested layout):
29691 dialog = new Roo.LayoutDialog("download-dlg", {
29700 // layout config merges with the dialog config
29702 tabPosition: "top",
29703 alwaysShowTabs: true
29706 dialog.addKeyListener(27, dialog.hide, dialog);
29707 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29708 dialog.addButton("Build It!", this.getDownload, this);
29710 // we can even add nested layouts
29711 var innerLayout = new Roo.BorderLayout("dl-inner", {
29721 innerLayout.beginUpdate();
29722 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29723 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29724 innerLayout.endUpdate(true);
29726 var layout = dialog.getLayout();
29727 layout.beginUpdate();
29728 layout.add("center", new Roo.ContentPanel("standard-panel",
29729 {title: "Download the Source", fitToFrame:true}));
29730 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29731 {title: "Build your own roo.js"}));
29732 layout.getRegion("center").showPanel(sp);
29733 layout.endUpdate();
29737 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29738 * @param {Object} config configuration options
29740 Roo.LayoutDialog = function(el, cfg){
29743 if (typeof(cfg) == 'undefined') {
29744 config = Roo.apply({}, el);
29745 // not sure why we use documentElement here.. - it should always be body.
29746 // IE7 borks horribly if we use documentElement.
29747 // webkit also does not like documentElement - it creates a body element...
29748 el = Roo.get( document.body || document.documentElement ).createChild();
29749 //config.autoCreate = true;
29753 config.autoTabs = false;
29754 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29755 this.body.setStyle({overflow:"hidden", position:"relative"});
29756 this.layout = new Roo.BorderLayout(this.body.dom, config);
29757 this.layout.monitorWindowResize = false;
29758 this.el.addClass("x-dlg-auto-layout");
29759 // fix case when center region overwrites center function
29760 this.center = Roo.BasicDialog.prototype.center;
29761 this.on("show", this.layout.layout, this.layout, true);
29762 if (config.items) {
29763 var xitems = config.items;
29764 delete config.items;
29765 Roo.each(xitems, this.addxtype, this);
29770 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29772 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29775 endUpdate : function(){
29776 this.layout.endUpdate();
29780 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29783 beginUpdate : function(){
29784 this.layout.beginUpdate();
29788 * Get the BorderLayout for this dialog
29789 * @return {Roo.BorderLayout}
29791 getLayout : function(){
29792 return this.layout;
29795 showEl : function(){
29796 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29798 this.layout.layout();
29803 // Use the syncHeightBeforeShow config option to control this automatically
29804 syncBodyHeight : function(){
29805 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29806 if(this.layout){this.layout.layout();}
29810 * Add an xtype element (actually adds to the layout.)
29811 * @return {Object} xdata xtype object data.
29814 addxtype : function(c) {
29815 return this.layout.addxtype(c);
29819 * Ext JS Library 1.1.1
29820 * Copyright(c) 2006-2007, Ext JS, LLC.
29822 * Originally Released Under LGPL - original licence link has changed is not relivant.
29825 * <script type="text/javascript">
29829 * @class Roo.MessageBox
29830 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29834 Roo.Msg.alert('Status', 'Changes saved successfully.');
29836 // Prompt for user data:
29837 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29839 // process text value...
29843 // Show a dialog using config options:
29845 title:'Save Changes?',
29846 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29847 buttons: Roo.Msg.YESNOCANCEL,
29854 Roo.MessageBox = function(){
29855 var dlg, opt, mask, waitTimer;
29856 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29857 var buttons, activeTextEl, bwidth;
29860 var handleButton = function(button){
29862 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29866 var handleHide = function(){
29867 if(opt && opt.cls){
29868 dlg.el.removeClass(opt.cls);
29871 Roo.TaskMgr.stop(waitTimer);
29877 var updateButtons = function(b){
29880 buttons["ok"].hide();
29881 buttons["cancel"].hide();
29882 buttons["yes"].hide();
29883 buttons["no"].hide();
29884 dlg.footer.dom.style.display = 'none';
29887 dlg.footer.dom.style.display = '';
29888 for(var k in buttons){
29889 if(typeof buttons[k] != "function"){
29892 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29893 width += buttons[k].el.getWidth()+15;
29903 var handleEsc = function(d, k, e){
29904 if(opt && opt.closable !== false){
29914 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29915 * @return {Roo.BasicDialog} The BasicDialog element
29917 getDialog : function(){
29919 dlg = new Roo.BasicDialog("x-msg-box", {
29924 constraintoviewport:false,
29926 collapsible : false,
29929 width:400, height:100,
29930 buttonAlign:"center",
29931 closeClick : function(){
29932 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29933 handleButton("no");
29935 handleButton("cancel");
29939 dlg.on("hide", handleHide);
29941 dlg.addKeyListener(27, handleEsc);
29943 var bt = this.buttonText;
29944 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29945 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29946 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29947 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29948 bodyEl = dlg.body.createChild({
29950 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>'
29952 msgEl = bodyEl.dom.firstChild;
29953 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29954 textboxEl.enableDisplayMode();
29955 textboxEl.addKeyListener([10,13], function(){
29956 if(dlg.isVisible() && opt && opt.buttons){
29957 if(opt.buttons.ok){
29958 handleButton("ok");
29959 }else if(opt.buttons.yes){
29960 handleButton("yes");
29964 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29965 textareaEl.enableDisplayMode();
29966 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29967 progressEl.enableDisplayMode();
29968 var pf = progressEl.dom.firstChild;
29970 pp = Roo.get(pf.firstChild);
29971 pp.setHeight(pf.offsetHeight);
29979 * Updates the message box body text
29980 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29981 * the XHTML-compliant non-breaking space character '&#160;')
29982 * @return {Roo.MessageBox} This message box
29984 updateText : function(text){
29985 if(!dlg.isVisible() && !opt.width){
29986 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29988 msgEl.innerHTML = text || ' ';
29989 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29990 Math.max(opt.minWidth || this.minWidth, bwidth));
29992 activeTextEl.setWidth(w);
29994 if(dlg.isVisible()){
29995 dlg.fixedcenter = false;
29997 dlg.setContentSize(w, bodyEl.getHeight());
29998 if(dlg.isVisible()){
29999 dlg.fixedcenter = true;
30005 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30006 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30007 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30008 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30009 * @return {Roo.MessageBox} This message box
30011 updateProgress : function(value, text){
30013 this.updateText(text);
30015 if (pp) { // weird bug on my firefox - for some reason this is not defined
30016 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30022 * Returns true if the message box is currently displayed
30023 * @return {Boolean} True if the message box is visible, else false
30025 isVisible : function(){
30026 return dlg && dlg.isVisible();
30030 * Hides the message box if it is displayed
30033 if(this.isVisible()){
30039 * Displays a new message box, or reinitializes an existing message box, based on the config options
30040 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30041 * The following config object properties are supported:
30043 Property Type Description
30044 ---------- --------------- ------------------------------------------------------------------------------------
30045 animEl String/Element An id or Element from which the message box should animate as it opens and
30046 closes (defaults to undefined)
30047 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30048 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30049 closable Boolean False to hide the top-right close button (defaults to true). Note that
30050 progress and wait dialogs will ignore this property and always hide the
30051 close button as they can only be closed programmatically.
30052 cls String A custom CSS class to apply to the message box element
30053 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30054 displayed (defaults to 75)
30055 fn Function A callback function to execute after closing the dialog. The arguments to the
30056 function will be btn (the name of the button that was clicked, if applicable,
30057 e.g. "ok"), and text (the value of the active text field, if applicable).
30058 Progress and wait dialogs will ignore this option since they do not respond to
30059 user actions and can only be closed programmatically, so any required function
30060 should be called by the same code after it closes the dialog.
30061 icon String A CSS class that provides a background image to be used as an icon for
30062 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30063 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30064 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30065 modal Boolean False to allow user interaction with the page while the message box is
30066 displayed (defaults to true)
30067 msg String A string that will replace the existing message box body text (defaults
30068 to the XHTML-compliant non-breaking space character ' ')
30069 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30070 progress Boolean True to display a progress bar (defaults to false)
30071 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30072 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30073 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30074 title String The title text
30075 value String The string value to set into the active textbox element if displayed
30076 wait Boolean True to display a progress bar (defaults to false)
30077 width Number The width of the dialog in pixels
30084 msg: 'Please enter your address:',
30086 buttons: Roo.MessageBox.OKCANCEL,
30089 animEl: 'addAddressBtn'
30092 * @param {Object} config Configuration options
30093 * @return {Roo.MessageBox} This message box
30095 show : function(options){
30096 if(this.isVisible()){
30099 var d = this.getDialog();
30101 d.setTitle(opt.title || " ");
30102 d.close.setDisplayed(opt.closable !== false);
30103 activeTextEl = textboxEl;
30104 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30109 textareaEl.setHeight(typeof opt.multiline == "number" ?
30110 opt.multiline : this.defaultTextHeight);
30111 activeTextEl = textareaEl;
30120 progressEl.setDisplayed(opt.progress === true);
30121 this.updateProgress(0);
30122 activeTextEl.dom.value = opt.value || "";
30124 dlg.setDefaultButton(activeTextEl);
30126 var bs = opt.buttons;
30129 db = buttons["ok"];
30130 }else if(bs && bs.yes){
30131 db = buttons["yes"];
30133 dlg.setDefaultButton(db);
30135 bwidth = updateButtons(opt.buttons);
30136 this.updateText(opt.msg);
30138 d.el.addClass(opt.cls);
30140 d.proxyDrag = opt.proxyDrag === true;
30141 d.modal = opt.modal !== false;
30142 d.mask = opt.modal !== false ? mask : false;
30143 if(!d.isVisible()){
30144 // force it to the end of the z-index stack so it gets a cursor in FF
30145 document.body.appendChild(dlg.el.dom);
30146 d.animateTarget = null;
30147 d.show(options.animEl);
30153 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30154 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30155 * and closing the message box when the process is complete.
30156 * @param {String} title The title bar text
30157 * @param {String} msg The message box body text
30158 * @return {Roo.MessageBox} This message box
30160 progress : function(title, msg){
30167 minWidth: this.minProgressWidth,
30174 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30175 * If a callback function is passed it will be called after the user clicks the button, and the
30176 * id of the button that was clicked will be passed as the only parameter to the callback
30177 * (could also be the top-right close button).
30178 * @param {String} title The title bar text
30179 * @param {String} msg The message box body text
30180 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30181 * @param {Object} scope (optional) The scope of the callback function
30182 * @return {Roo.MessageBox} This message box
30184 alert : function(title, msg, fn, scope){
30197 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30198 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30199 * You are responsible for closing the message box when the process is complete.
30200 * @param {String} msg The message box body text
30201 * @param {String} title (optional) The title bar text
30202 * @return {Roo.MessageBox} This message box
30204 wait : function(msg, title){
30215 waitTimer = Roo.TaskMgr.start({
30217 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30225 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30226 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30227 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30228 * @param {String} title The title bar text
30229 * @param {String} msg The message box body text
30230 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30231 * @param {Object} scope (optional) The scope of the callback function
30232 * @return {Roo.MessageBox} This message box
30234 confirm : function(title, msg, fn, scope){
30238 buttons: this.YESNO,
30247 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30248 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30249 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30250 * (could also be the top-right close button) and the text that was entered will be passed as the two
30251 * parameters to the callback.
30252 * @param {String} title The title bar text
30253 * @param {String} msg The message box body text
30254 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30255 * @param {Object} scope (optional) The scope of the callback function
30256 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30257 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30258 * @return {Roo.MessageBox} This message box
30260 prompt : function(title, msg, fn, scope, multiline){
30264 buttons: this.OKCANCEL,
30269 multiline: multiline,
30276 * Button config that displays a single OK button
30281 * Button config that displays Yes and No buttons
30284 YESNO : {yes:true, no:true},
30286 * Button config that displays OK and Cancel buttons
30289 OKCANCEL : {ok:true, cancel:true},
30291 * Button config that displays Yes, No and Cancel buttons
30294 YESNOCANCEL : {yes:true, no:true, cancel:true},
30297 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30300 defaultTextHeight : 75,
30302 * The maximum width in pixels of the message box (defaults to 600)
30307 * The minimum width in pixels of the message box (defaults to 100)
30312 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30313 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30316 minProgressWidth : 250,
30318 * An object containing the default button text strings that can be overriden for localized language support.
30319 * Supported properties are: ok, cancel, yes and no.
30320 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30333 * Shorthand for {@link Roo.MessageBox}
30335 Roo.Msg = Roo.MessageBox;/*
30337 * Ext JS Library 1.1.1
30338 * Copyright(c) 2006-2007, Ext JS, LLC.
30340 * Originally Released Under LGPL - original licence link has changed is not relivant.
30343 * <script type="text/javascript">
30346 * @class Roo.QuickTips
30347 * Provides attractive and customizable tooltips for any element.
30350 Roo.QuickTips = function(){
30351 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30352 var ce, bd, xy, dd;
30353 var visible = false, disabled = true, inited = false;
30354 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30356 var onOver = function(e){
30360 var t = e.getTarget();
30361 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30364 if(ce && t == ce.el){
30365 clearTimeout(hideProc);
30368 if(t && tagEls[t.id]){
30369 tagEls[t.id].el = t;
30370 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30373 var ttp, et = Roo.fly(t);
30374 var ns = cfg.namespace;
30375 if(tm.interceptTitles && t.title){
30378 t.removeAttribute("title");
30379 e.preventDefault();
30381 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30384 showProc = show.defer(tm.showDelay, tm, [{
30387 width: et.getAttributeNS(ns, cfg.width),
30388 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30389 title: et.getAttributeNS(ns, cfg.title),
30390 cls: et.getAttributeNS(ns, cfg.cls)
30395 var onOut = function(e){
30396 clearTimeout(showProc);
30397 var t = e.getTarget();
30398 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30399 hideProc = setTimeout(hide, tm.hideDelay);
30403 var onMove = function(e){
30409 if(tm.trackMouse && ce){
30414 var onDown = function(e){
30415 clearTimeout(showProc);
30416 clearTimeout(hideProc);
30418 if(tm.hideOnClick){
30421 tm.enable.defer(100, tm);
30426 var getPad = function(){
30427 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30430 var show = function(o){
30434 clearTimeout(dismissProc);
30436 if(removeCls){ // in case manually hidden
30437 el.removeClass(removeCls);
30441 el.addClass(ce.cls);
30442 removeCls = ce.cls;
30445 tipTitle.update(ce.title);
30448 tipTitle.update('');
30451 el.dom.style.width = tm.maxWidth+'px';
30452 //tipBody.dom.style.width = '';
30453 tipBodyText.update(o.text);
30454 var p = getPad(), w = ce.width;
30456 var td = tipBodyText.dom;
30457 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30458 if(aw > tm.maxWidth){
30460 }else if(aw < tm.minWidth){
30466 //tipBody.setWidth(w);
30467 el.setWidth(parseInt(w, 10) + p);
30468 if(ce.autoHide === false){
30469 close.setDisplayed(true);
30474 close.setDisplayed(false);
30480 el.avoidY = xy[1]-18;
30485 el.setStyle("visibility", "visible");
30486 el.fadeIn({callback: afterShow});
30492 var afterShow = function(){
30496 if(tm.autoDismiss && ce.autoHide !== false){
30497 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30502 var hide = function(noanim){
30503 clearTimeout(dismissProc);
30504 clearTimeout(hideProc);
30506 if(el.isVisible()){
30508 if(noanim !== true && tm.animate){
30509 el.fadeOut({callback: afterHide});
30516 var afterHide = function(){
30519 el.removeClass(removeCls);
30526 * @cfg {Number} minWidth
30527 * The minimum width of the quick tip (defaults to 40)
30531 * @cfg {Number} maxWidth
30532 * The maximum width of the quick tip (defaults to 300)
30536 * @cfg {Boolean} interceptTitles
30537 * True to automatically use the element's DOM title value if available (defaults to false)
30539 interceptTitles : false,
30541 * @cfg {Boolean} trackMouse
30542 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30544 trackMouse : false,
30546 * @cfg {Boolean} hideOnClick
30547 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30549 hideOnClick : true,
30551 * @cfg {Number} showDelay
30552 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30556 * @cfg {Number} hideDelay
30557 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30561 * @cfg {Boolean} autoHide
30562 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30563 * Used in conjunction with hideDelay.
30568 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30569 * (defaults to true). Used in conjunction with autoDismissDelay.
30571 autoDismiss : true,
30574 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30576 autoDismissDelay : 5000,
30578 * @cfg {Boolean} animate
30579 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30584 * @cfg {String} title
30585 * Title text to display (defaults to ''). This can be any valid HTML markup.
30589 * @cfg {String} text
30590 * Body text to display (defaults to ''). This can be any valid HTML markup.
30594 * @cfg {String} cls
30595 * A CSS class to apply to the base quick tip element (defaults to '').
30599 * @cfg {Number} width
30600 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30601 * minWidth or maxWidth.
30606 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30607 * or display QuickTips in a page.
30610 tm = Roo.QuickTips;
30611 cfg = tm.tagConfig;
30613 if(!Roo.isReady){ // allow calling of init() before onReady
30614 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30617 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30618 el.fxDefaults = {stopFx: true};
30619 // maximum custom styling
30620 //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>');
30621 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>');
30622 tipTitle = el.child('h3');
30623 tipTitle.enableDisplayMode("block");
30624 tipBody = el.child('div.x-tip-bd');
30625 tipBodyText = el.child('div.x-tip-bd-inner');
30626 //bdLeft = el.child('div.x-tip-bd-left');
30627 //bdRight = el.child('div.x-tip-bd-right');
30628 close = el.child('div.x-tip-close');
30629 close.enableDisplayMode("block");
30630 close.on("click", hide);
30631 var d = Roo.get(document);
30632 d.on("mousedown", onDown);
30633 d.on("mouseover", onOver);
30634 d.on("mouseout", onOut);
30635 d.on("mousemove", onMove);
30636 esc = d.addKeyListener(27, hide);
30639 dd = el.initDD("default", null, {
30640 onDrag : function(){
30644 dd.setHandleElId(tipTitle.id);
30653 * Configures a new quick tip instance and assigns it to a target element. The following config options
30656 Property Type Description
30657 ---------- --------------------- ------------------------------------------------------------------------
30658 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30660 * @param {Object} config The config object
30662 register : function(config){
30663 var cs = config instanceof Array ? config : arguments;
30664 for(var i = 0, len = cs.length; i < len; i++) {
30666 var target = c.target;
30668 if(target instanceof Array){
30669 for(var j = 0, jlen = target.length; j < jlen; j++){
30670 tagEls[target[j]] = c;
30673 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30680 * Removes this quick tip from its element and destroys it.
30681 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30683 unregister : function(el){
30684 delete tagEls[Roo.id(el)];
30688 * Enable this quick tip.
30690 enable : function(){
30691 if(inited && disabled){
30693 if(locks.length < 1){
30700 * Disable this quick tip.
30702 disable : function(){
30704 clearTimeout(showProc);
30705 clearTimeout(hideProc);
30706 clearTimeout(dismissProc);
30714 * Returns true if the quick tip is enabled, else false.
30716 isEnabled : function(){
30723 attribute : "qtip",
30733 // backwards compat
30734 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30736 * Ext JS Library 1.1.1
30737 * Copyright(c) 2006-2007, Ext JS, LLC.
30739 * Originally Released Under LGPL - original licence link has changed is not relivant.
30742 * <script type="text/javascript">
30747 * @class Roo.tree.TreePanel
30748 * @extends Roo.data.Tree
30750 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30751 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30752 * @cfg {Boolean} enableDD true to enable drag and drop
30753 * @cfg {Boolean} enableDrag true to enable just drag
30754 * @cfg {Boolean} enableDrop true to enable just drop
30755 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30756 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30757 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30758 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30759 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30760 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30761 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30762 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30763 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30764 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30765 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30766 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30767 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30768 * @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>
30769 * @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>
30772 * @param {String/HTMLElement/Element} el The container element
30773 * @param {Object} config
30775 Roo.tree.TreePanel = function(el, config){
30777 var loader = false;
30779 root = config.root;
30780 delete config.root;
30782 if (config.loader) {
30783 loader = config.loader;
30784 delete config.loader;
30787 Roo.apply(this, config);
30788 Roo.tree.TreePanel.superclass.constructor.call(this);
30789 this.el = Roo.get(el);
30790 this.el.addClass('x-tree');
30791 //console.log(root);
30793 this.setRootNode( Roo.factory(root, Roo.tree));
30796 this.loader = Roo.factory(loader, Roo.tree);
30799 * Read-only. The id of the container element becomes this TreePanel's id.
30801 this.id = this.el.id;
30804 * @event beforeload
30805 * Fires before a node is loaded, return false to cancel
30806 * @param {Node} node The node being loaded
30808 "beforeload" : true,
30811 * Fires when a node is loaded
30812 * @param {Node} node The node that was loaded
30816 * @event textchange
30817 * Fires when the text for a node is changed
30818 * @param {Node} node The node
30819 * @param {String} text The new text
30820 * @param {String} oldText The old text
30822 "textchange" : true,
30824 * @event beforeexpand
30825 * Fires before a node is expanded, return false to cancel.
30826 * @param {Node} node The node
30827 * @param {Boolean} deep
30828 * @param {Boolean} anim
30830 "beforeexpand" : true,
30832 * @event beforecollapse
30833 * Fires before a node is collapsed, return false to cancel.
30834 * @param {Node} node The node
30835 * @param {Boolean} deep
30836 * @param {Boolean} anim
30838 "beforecollapse" : true,
30841 * Fires when a node is expanded
30842 * @param {Node} node The node
30846 * @event disabledchange
30847 * Fires when the disabled status of a node changes
30848 * @param {Node} node The node
30849 * @param {Boolean} disabled
30851 "disabledchange" : true,
30854 * Fires when a node is collapsed
30855 * @param {Node} node The node
30859 * @event beforeclick
30860 * Fires before click processing on a node. Return false to cancel the default action.
30861 * @param {Node} node The node
30862 * @param {Roo.EventObject} e The event object
30864 "beforeclick":true,
30866 * @event checkchange
30867 * Fires when a node with a checkbox's checked property changes
30868 * @param {Node} this This node
30869 * @param {Boolean} checked
30871 "checkchange":true,
30874 * Fires when a node is clicked
30875 * @param {Node} node The node
30876 * @param {Roo.EventObject} e The event object
30881 * Fires when a node is double clicked
30882 * @param {Node} node The node
30883 * @param {Roo.EventObject} e The event object
30887 * @event contextmenu
30888 * Fires when a node is right clicked
30889 * @param {Node} node The node
30890 * @param {Roo.EventObject} e The event object
30892 "contextmenu":true,
30894 * @event beforechildrenrendered
30895 * Fires right before the child nodes for a node are rendered
30896 * @param {Node} node The node
30898 "beforechildrenrendered":true,
30901 * Fires when a node starts being dragged
30902 * @param {Roo.tree.TreePanel} this
30903 * @param {Roo.tree.TreeNode} node
30904 * @param {event} e The raw browser event
30906 "startdrag" : true,
30909 * Fires when a drag operation is complete
30910 * @param {Roo.tree.TreePanel} this
30911 * @param {Roo.tree.TreeNode} node
30912 * @param {event} e The raw browser event
30917 * Fires when a dragged node is dropped on a valid DD target
30918 * @param {Roo.tree.TreePanel} this
30919 * @param {Roo.tree.TreeNode} node
30920 * @param {DD} dd The dd it was dropped on
30921 * @param {event} e The raw browser event
30925 * @event beforenodedrop
30926 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30927 * passed to handlers has the following properties:<br />
30928 * <ul style="padding:5px;padding-left:16px;">
30929 * <li>tree - The TreePanel</li>
30930 * <li>target - The node being targeted for the drop</li>
30931 * <li>data - The drag data from the drag source</li>
30932 * <li>point - The point of the drop - append, above or below</li>
30933 * <li>source - The drag source</li>
30934 * <li>rawEvent - Raw mouse event</li>
30935 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30936 * to be inserted by setting them on this object.</li>
30937 * <li>cancel - Set this to true to cancel the drop.</li>
30939 * @param {Object} dropEvent
30941 "beforenodedrop" : true,
30944 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30945 * passed to handlers has the following properties:<br />
30946 * <ul style="padding:5px;padding-left:16px;">
30947 * <li>tree - The TreePanel</li>
30948 * <li>target - The node being targeted for the drop</li>
30949 * <li>data - The drag data from the drag source</li>
30950 * <li>point - The point of the drop - append, above or below</li>
30951 * <li>source - The drag source</li>
30952 * <li>rawEvent - Raw mouse event</li>
30953 * <li>dropNode - Dropped node(s).</li>
30955 * @param {Object} dropEvent
30959 * @event nodedragover
30960 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30961 * passed to handlers has the following properties:<br />
30962 * <ul style="padding:5px;padding-left:16px;">
30963 * <li>tree - The TreePanel</li>
30964 * <li>target - The node being targeted for the drop</li>
30965 * <li>data - The drag data from the drag source</li>
30966 * <li>point - The point of the drop - append, above or below</li>
30967 * <li>source - The drag source</li>
30968 * <li>rawEvent - Raw mouse event</li>
30969 * <li>dropNode - Drop node(s) provided by the source.</li>
30970 * <li>cancel - Set this to true to signal drop not allowed.</li>
30972 * @param {Object} dragOverEvent
30974 "nodedragover" : true
30977 if(this.singleExpand){
30978 this.on("beforeexpand", this.restrictExpand, this);
30981 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30982 rootVisible : true,
30983 animate: Roo.enableFx,
30986 hlDrop : Roo.enableFx,
30990 rendererTip: false,
30992 restrictExpand : function(node){
30993 var p = node.parentNode;
30995 if(p.expandedChild && p.expandedChild.parentNode == p){
30996 p.expandedChild.collapse();
30998 p.expandedChild = node;
31002 // private override
31003 setRootNode : function(node){
31004 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31005 if(!this.rootVisible){
31006 node.ui = new Roo.tree.RootTreeNodeUI(node);
31012 * Returns the container element for this TreePanel
31014 getEl : function(){
31019 * Returns the default TreeLoader for this TreePanel
31021 getLoader : function(){
31022 return this.loader;
31028 expandAll : function(){
31029 this.root.expand(true);
31033 * Collapse all nodes
31035 collapseAll : function(){
31036 this.root.collapse(true);
31040 * Returns the selection model used by this TreePanel
31042 getSelectionModel : function(){
31043 if(!this.selModel){
31044 this.selModel = new Roo.tree.DefaultSelectionModel();
31046 return this.selModel;
31050 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31051 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31052 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31055 getChecked : function(a, startNode){
31056 startNode = startNode || this.root;
31058 var f = function(){
31059 if(this.attributes.checked){
31060 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31063 startNode.cascade(f);
31068 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31069 * @param {String} path
31070 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31071 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31072 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31074 expandPath : function(path, attr, callback){
31075 attr = attr || "id";
31076 var keys = path.split(this.pathSeparator);
31077 var curNode = this.root;
31078 if(curNode.attributes[attr] != keys[1]){ // invalid root
31080 callback(false, null);
31085 var f = function(){
31086 if(++index == keys.length){
31088 callback(true, curNode);
31092 var c = curNode.findChild(attr, keys[index]);
31095 callback(false, curNode);
31100 c.expand(false, false, f);
31102 curNode.expand(false, false, f);
31106 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31107 * @param {String} path
31108 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31109 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31110 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31112 selectPath : function(path, attr, callback){
31113 attr = attr || "id";
31114 var keys = path.split(this.pathSeparator);
31115 var v = keys.pop();
31116 if(keys.length > 0){
31117 var f = function(success, node){
31118 if(success && node){
31119 var n = node.findChild(attr, v);
31125 }else if(callback){
31126 callback(false, n);
31130 callback(false, n);
31134 this.expandPath(keys.join(this.pathSeparator), attr, f);
31136 this.root.select();
31138 callback(true, this.root);
31143 getTreeEl : function(){
31148 * Trigger rendering of this TreePanel
31150 render : function(){
31151 if (this.innerCt) {
31152 return this; // stop it rendering more than once!!
31155 this.innerCt = this.el.createChild({tag:"ul",
31156 cls:"x-tree-root-ct " +
31157 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31159 if(this.containerScroll){
31160 Roo.dd.ScrollManager.register(this.el);
31162 if((this.enableDD || this.enableDrop) && !this.dropZone){
31164 * The dropZone used by this tree if drop is enabled
31165 * @type Roo.tree.TreeDropZone
31167 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31168 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31171 if((this.enableDD || this.enableDrag) && !this.dragZone){
31173 * The dragZone used by this tree if drag is enabled
31174 * @type Roo.tree.TreeDragZone
31176 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31177 ddGroup: this.ddGroup || "TreeDD",
31178 scroll: this.ddScroll
31181 this.getSelectionModel().init(this);
31183 console.log("ROOT not set in tree");
31186 this.root.render();
31187 if(!this.rootVisible){
31188 this.root.renderChildren();
31194 * Ext JS Library 1.1.1
31195 * Copyright(c) 2006-2007, Ext JS, LLC.
31197 * Originally Released Under LGPL - original licence link has changed is not relivant.
31200 * <script type="text/javascript">
31205 * @class Roo.tree.DefaultSelectionModel
31206 * @extends Roo.util.Observable
31207 * The default single selection for a TreePanel.
31209 Roo.tree.DefaultSelectionModel = function(){
31210 this.selNode = null;
31214 * @event selectionchange
31215 * Fires when the selected node changes
31216 * @param {DefaultSelectionModel} this
31217 * @param {TreeNode} node the new selection
31219 "selectionchange" : true,
31222 * @event beforeselect
31223 * Fires before the selected node changes, return false to cancel the change
31224 * @param {DefaultSelectionModel} this
31225 * @param {TreeNode} node the new selection
31226 * @param {TreeNode} node the old selection
31228 "beforeselect" : true
31232 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31233 init : function(tree){
31235 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31236 tree.on("click", this.onNodeClick, this);
31239 onNodeClick : function(node, e){
31240 if (e.ctrlKey && this.selNode == node) {
31241 this.unselect(node);
31249 * @param {TreeNode} node The node to select
31250 * @return {TreeNode} The selected node
31252 select : function(node){
31253 var last = this.selNode;
31254 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31256 last.ui.onSelectedChange(false);
31258 this.selNode = node;
31259 node.ui.onSelectedChange(true);
31260 this.fireEvent("selectionchange", this, node, last);
31267 * @param {TreeNode} node The node to unselect
31269 unselect : function(node){
31270 if(this.selNode == node){
31271 this.clearSelections();
31276 * Clear all selections
31278 clearSelections : function(){
31279 var n = this.selNode;
31281 n.ui.onSelectedChange(false);
31282 this.selNode = null;
31283 this.fireEvent("selectionchange", this, null);
31289 * Get the selected node
31290 * @return {TreeNode} The selected node
31292 getSelectedNode : function(){
31293 return this.selNode;
31297 * Returns true if the node is selected
31298 * @param {TreeNode} node The node to check
31299 * @return {Boolean}
31301 isSelected : function(node){
31302 return this.selNode == node;
31306 * Selects the node above the selected node in the tree, intelligently walking the nodes
31307 * @return TreeNode The new selection
31309 selectPrevious : function(){
31310 var s = this.selNode || this.lastSelNode;
31314 var ps = s.previousSibling;
31316 if(!ps.isExpanded() || ps.childNodes.length < 1){
31317 return this.select(ps);
31319 var lc = ps.lastChild;
31320 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31323 return this.select(lc);
31325 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31326 return this.select(s.parentNode);
31332 * Selects the node above the selected node in the tree, intelligently walking the nodes
31333 * @return TreeNode The new selection
31335 selectNext : function(){
31336 var s = this.selNode || this.lastSelNode;
31340 if(s.firstChild && s.isExpanded()){
31341 return this.select(s.firstChild);
31342 }else if(s.nextSibling){
31343 return this.select(s.nextSibling);
31344 }else if(s.parentNode){
31346 s.parentNode.bubble(function(){
31347 if(this.nextSibling){
31348 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31357 onKeyDown : function(e){
31358 var s = this.selNode || this.lastSelNode;
31359 // undesirable, but required
31364 var k = e.getKey();
31372 this.selectPrevious();
31375 e.preventDefault();
31376 if(s.hasChildNodes()){
31377 if(!s.isExpanded()){
31379 }else if(s.firstChild){
31380 this.select(s.firstChild, e);
31385 e.preventDefault();
31386 if(s.hasChildNodes() && s.isExpanded()){
31388 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31389 this.select(s.parentNode, e);
31397 * @class Roo.tree.MultiSelectionModel
31398 * @extends Roo.util.Observable
31399 * Multi selection for a TreePanel.
31401 Roo.tree.MultiSelectionModel = function(){
31402 this.selNodes = [];
31406 * @event selectionchange
31407 * Fires when the selected nodes change
31408 * @param {MultiSelectionModel} this
31409 * @param {Array} nodes Array of the selected nodes
31411 "selectionchange" : true
31415 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31416 init : function(tree){
31418 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31419 tree.on("click", this.onNodeClick, this);
31422 onNodeClick : function(node, e){
31423 this.select(node, e, e.ctrlKey);
31428 * @param {TreeNode} node The node to select
31429 * @param {EventObject} e (optional) An event associated with the selection
31430 * @param {Boolean} keepExisting True to retain existing selections
31431 * @return {TreeNode} The selected node
31433 select : function(node, e, keepExisting){
31434 if(keepExisting !== true){
31435 this.clearSelections(true);
31437 if(this.isSelected(node)){
31438 this.lastSelNode = node;
31441 this.selNodes.push(node);
31442 this.selMap[node.id] = node;
31443 this.lastSelNode = node;
31444 node.ui.onSelectedChange(true);
31445 this.fireEvent("selectionchange", this, this.selNodes);
31451 * @param {TreeNode} node The node to unselect
31453 unselect : function(node){
31454 if(this.selMap[node.id]){
31455 node.ui.onSelectedChange(false);
31456 var sn = this.selNodes;
31459 index = sn.indexOf(node);
31461 for(var i = 0, len = sn.length; i < len; i++){
31469 this.selNodes.splice(index, 1);
31471 delete this.selMap[node.id];
31472 this.fireEvent("selectionchange", this, this.selNodes);
31477 * Clear all selections
31479 clearSelections : function(suppressEvent){
31480 var sn = this.selNodes;
31482 for(var i = 0, len = sn.length; i < len; i++){
31483 sn[i].ui.onSelectedChange(false);
31485 this.selNodes = [];
31487 if(suppressEvent !== true){
31488 this.fireEvent("selectionchange", this, this.selNodes);
31494 * Returns true if the node is selected
31495 * @param {TreeNode} node The node to check
31496 * @return {Boolean}
31498 isSelected : function(node){
31499 return this.selMap[node.id] ? true : false;
31503 * Returns an array of the selected nodes
31506 getSelectedNodes : function(){
31507 return this.selNodes;
31510 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31512 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31514 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31517 * Ext JS Library 1.1.1
31518 * Copyright(c) 2006-2007, Ext JS, LLC.
31520 * Originally Released Under LGPL - original licence link has changed is not relivant.
31523 * <script type="text/javascript">
31527 * @class Roo.tree.TreeNode
31528 * @extends Roo.data.Node
31529 * @cfg {String} text The text for this node
31530 * @cfg {Boolean} expanded true to start the node expanded
31531 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31532 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31533 * @cfg {Boolean} disabled true to start the node disabled
31534 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31535 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31536 * @cfg {String} cls A css class to be added to the node
31537 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31538 * @cfg {String} href URL of the link used for the node (defaults to #)
31539 * @cfg {String} hrefTarget target frame for the link
31540 * @cfg {String} qtip An Ext QuickTip for the node
31541 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31542 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31543 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31544 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31545 * (defaults to undefined with no checkbox rendered)
31547 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31549 Roo.tree.TreeNode = function(attributes){
31550 attributes = attributes || {};
31551 if(typeof attributes == "string"){
31552 attributes = {text: attributes};
31554 this.childrenRendered = false;
31555 this.rendered = false;
31556 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31557 this.expanded = attributes.expanded === true;
31558 this.isTarget = attributes.isTarget !== false;
31559 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31560 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31563 * Read-only. The text for this node. To change it use setText().
31566 this.text = attributes.text;
31568 * True if this node is disabled.
31571 this.disabled = attributes.disabled === true;
31575 * @event textchange
31576 * Fires when the text for this node is changed
31577 * @param {Node} this This node
31578 * @param {String} text The new text
31579 * @param {String} oldText The old text
31581 "textchange" : true,
31583 * @event beforeexpand
31584 * Fires before this node is expanded, return false to cancel.
31585 * @param {Node} this This node
31586 * @param {Boolean} deep
31587 * @param {Boolean} anim
31589 "beforeexpand" : true,
31591 * @event beforecollapse
31592 * Fires before this node is collapsed, return false to cancel.
31593 * @param {Node} this This node
31594 * @param {Boolean} deep
31595 * @param {Boolean} anim
31597 "beforecollapse" : true,
31600 * Fires when this node is expanded
31601 * @param {Node} this This node
31605 * @event disabledchange
31606 * Fires when the disabled status of this node changes
31607 * @param {Node} this This node
31608 * @param {Boolean} disabled
31610 "disabledchange" : true,
31613 * Fires when this node is collapsed
31614 * @param {Node} this This node
31618 * @event beforeclick
31619 * Fires before click processing. Return false to cancel the default action.
31620 * @param {Node} this This node
31621 * @param {Roo.EventObject} e The event object
31623 "beforeclick":true,
31625 * @event checkchange
31626 * Fires when a node with a checkbox's checked property changes
31627 * @param {Node} this This node
31628 * @param {Boolean} checked
31630 "checkchange":true,
31633 * Fires when this node is clicked
31634 * @param {Node} this This node
31635 * @param {Roo.EventObject} e The event object
31640 * Fires when this node is double clicked
31641 * @param {Node} this This node
31642 * @param {Roo.EventObject} e The event object
31646 * @event contextmenu
31647 * Fires when this node is right clicked
31648 * @param {Node} this This node
31649 * @param {Roo.EventObject} e The event object
31651 "contextmenu":true,
31653 * @event beforechildrenrendered
31654 * Fires right before the child nodes for this node are rendered
31655 * @param {Node} this This node
31657 "beforechildrenrendered":true
31660 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31663 * Read-only. The UI for this node
31666 this.ui = new uiClass(this);
31668 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31669 preventHScroll: true,
31671 * Returns true if this node is expanded
31672 * @return {Boolean}
31674 isExpanded : function(){
31675 return this.expanded;
31679 * Returns the UI object for this node
31680 * @return {TreeNodeUI}
31682 getUI : function(){
31686 // private override
31687 setFirstChild : function(node){
31688 var of = this.firstChild;
31689 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31690 if(this.childrenRendered && of && node != of){
31691 of.renderIndent(true, true);
31694 this.renderIndent(true, true);
31698 // private override
31699 setLastChild : function(node){
31700 var ol = this.lastChild;
31701 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31702 if(this.childrenRendered && ol && node != ol){
31703 ol.renderIndent(true, true);
31706 this.renderIndent(true, true);
31710 // these methods are overridden to provide lazy rendering support
31711 // private override
31712 appendChild : function(){
31713 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31714 if(node && this.childrenRendered){
31717 this.ui.updateExpandIcon();
31721 // private override
31722 removeChild : function(node){
31723 this.ownerTree.getSelectionModel().unselect(node);
31724 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31725 // if it's been rendered remove dom node
31726 if(this.childrenRendered){
31729 if(this.childNodes.length < 1){
31730 this.collapse(false, false);
31732 this.ui.updateExpandIcon();
31734 if(!this.firstChild) {
31735 this.childrenRendered = false;
31740 // private override
31741 insertBefore : function(node, refNode){
31742 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31743 if(newNode && refNode && this.childrenRendered){
31746 this.ui.updateExpandIcon();
31751 * Sets the text for this node
31752 * @param {String} text
31754 setText : function(text){
31755 var oldText = this.text;
31757 this.attributes.text = text;
31758 if(this.rendered){ // event without subscribing
31759 this.ui.onTextChange(this, text, oldText);
31761 this.fireEvent("textchange", this, text, oldText);
31765 * Triggers selection of this node
31767 select : function(){
31768 this.getOwnerTree().getSelectionModel().select(this);
31772 * Triggers deselection of this node
31774 unselect : function(){
31775 this.getOwnerTree().getSelectionModel().unselect(this);
31779 * Returns true if this node is selected
31780 * @return {Boolean}
31782 isSelected : function(){
31783 return this.getOwnerTree().getSelectionModel().isSelected(this);
31787 * Expand this node.
31788 * @param {Boolean} deep (optional) True to expand all children as well
31789 * @param {Boolean} anim (optional) false to cancel the default animation
31790 * @param {Function} callback (optional) A callback to be called when
31791 * expanding this node completes (does not wait for deep expand to complete).
31792 * Called with 1 parameter, this node.
31794 expand : function(deep, anim, callback){
31795 if(!this.expanded){
31796 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31799 if(!this.childrenRendered){
31800 this.renderChildren();
31802 this.expanded = true;
31803 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31804 this.ui.animExpand(function(){
31805 this.fireEvent("expand", this);
31806 if(typeof callback == "function"){
31810 this.expandChildNodes(true);
31812 }.createDelegate(this));
31816 this.fireEvent("expand", this);
31817 if(typeof callback == "function"){
31822 if(typeof callback == "function"){
31827 this.expandChildNodes(true);
31831 isHiddenRoot : function(){
31832 return this.isRoot && !this.getOwnerTree().rootVisible;
31836 * Collapse this node.
31837 * @param {Boolean} deep (optional) True to collapse all children as well
31838 * @param {Boolean} anim (optional) false to cancel the default animation
31840 collapse : function(deep, anim){
31841 if(this.expanded && !this.isHiddenRoot()){
31842 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31845 this.expanded = false;
31846 if((this.getOwnerTree().animate && anim !== false) || anim){
31847 this.ui.animCollapse(function(){
31848 this.fireEvent("collapse", this);
31850 this.collapseChildNodes(true);
31852 }.createDelegate(this));
31855 this.ui.collapse();
31856 this.fireEvent("collapse", this);
31860 var cs = this.childNodes;
31861 for(var i = 0, len = cs.length; i < len; i++) {
31862 cs[i].collapse(true, false);
31868 delayedExpand : function(delay){
31869 if(!this.expandProcId){
31870 this.expandProcId = this.expand.defer(delay, this);
31875 cancelExpand : function(){
31876 if(this.expandProcId){
31877 clearTimeout(this.expandProcId);
31879 this.expandProcId = false;
31883 * Toggles expanded/collapsed state of the node
31885 toggle : function(){
31894 * Ensures all parent nodes are expanded
31896 ensureVisible : function(callback){
31897 var tree = this.getOwnerTree();
31898 tree.expandPath(this.parentNode.getPath(), false, function(){
31899 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31900 Roo.callback(callback);
31901 }.createDelegate(this));
31905 * Expand all child nodes
31906 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31908 expandChildNodes : function(deep){
31909 var cs = this.childNodes;
31910 for(var i = 0, len = cs.length; i < len; i++) {
31911 cs[i].expand(deep);
31916 * Collapse all child nodes
31917 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31919 collapseChildNodes : function(deep){
31920 var cs = this.childNodes;
31921 for(var i = 0, len = cs.length; i < len; i++) {
31922 cs[i].collapse(deep);
31927 * Disables this node
31929 disable : function(){
31930 this.disabled = true;
31932 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31933 this.ui.onDisableChange(this, true);
31935 this.fireEvent("disabledchange", this, true);
31939 * Enables this node
31941 enable : function(){
31942 this.disabled = false;
31943 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31944 this.ui.onDisableChange(this, false);
31946 this.fireEvent("disabledchange", this, false);
31950 renderChildren : function(suppressEvent){
31951 if(suppressEvent !== false){
31952 this.fireEvent("beforechildrenrendered", this);
31954 var cs = this.childNodes;
31955 for(var i = 0, len = cs.length; i < len; i++){
31956 cs[i].render(true);
31958 this.childrenRendered = true;
31962 sort : function(fn, scope){
31963 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31964 if(this.childrenRendered){
31965 var cs = this.childNodes;
31966 for(var i = 0, len = cs.length; i < len; i++){
31967 cs[i].render(true);
31973 render : function(bulkRender){
31974 this.ui.render(bulkRender);
31975 if(!this.rendered){
31976 this.rendered = true;
31978 this.expanded = false;
31979 this.expand(false, false);
31985 renderIndent : function(deep, refresh){
31987 this.ui.childIndent = null;
31989 this.ui.renderIndent();
31990 if(deep === true && this.childrenRendered){
31991 var cs = this.childNodes;
31992 for(var i = 0, len = cs.length; i < len; i++){
31993 cs[i].renderIndent(true, refresh);
31999 * Ext JS Library 1.1.1
32000 * Copyright(c) 2006-2007, Ext JS, LLC.
32002 * Originally Released Under LGPL - original licence link has changed is not relivant.
32005 * <script type="text/javascript">
32009 * @class Roo.tree.AsyncTreeNode
32010 * @extends Roo.tree.TreeNode
32011 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32013 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32015 Roo.tree.AsyncTreeNode = function(config){
32016 this.loaded = false;
32017 this.loading = false;
32018 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32020 * @event beforeload
32021 * Fires before this node is loaded, return false to cancel
32022 * @param {Node} this This node
32024 this.addEvents({'beforeload':true, 'load': true});
32027 * Fires when this node is loaded
32028 * @param {Node} this This node
32031 * The loader used by this node (defaults to using the tree's defined loader)
32036 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32037 expand : function(deep, anim, callback){
32038 if(this.loading){ // if an async load is already running, waiting til it's done
32040 var f = function(){
32041 if(!this.loading){ // done loading
32042 clearInterval(timer);
32043 this.expand(deep, anim, callback);
32045 }.createDelegate(this);
32046 timer = setInterval(f, 200);
32050 if(this.fireEvent("beforeload", this) === false){
32053 this.loading = true;
32054 this.ui.beforeLoad(this);
32055 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32057 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32061 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32065 * Returns true if this node is currently loading
32066 * @return {Boolean}
32068 isLoading : function(){
32069 return this.loading;
32072 loadComplete : function(deep, anim, callback){
32073 this.loading = false;
32074 this.loaded = true;
32075 this.ui.afterLoad(this);
32076 this.fireEvent("load", this);
32077 this.expand(deep, anim, callback);
32081 * Returns true if this node has been loaded
32082 * @return {Boolean}
32084 isLoaded : function(){
32085 return this.loaded;
32088 hasChildNodes : function(){
32089 if(!this.isLeaf() && !this.loaded){
32092 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32097 * Trigger a reload for this node
32098 * @param {Function} callback
32100 reload : function(callback){
32101 this.collapse(false, false);
32102 while(this.firstChild){
32103 this.removeChild(this.firstChild);
32105 this.childrenRendered = false;
32106 this.loaded = false;
32107 if(this.isHiddenRoot()){
32108 this.expanded = false;
32110 this.expand(false, false, callback);
32114 * Ext JS Library 1.1.1
32115 * Copyright(c) 2006-2007, Ext JS, LLC.
32117 * Originally Released Under LGPL - original licence link has changed is not relivant.
32120 * <script type="text/javascript">
32124 * @class Roo.tree.TreeNodeUI
32126 * @param {Object} node The node to render
32127 * The TreeNode UI implementation is separate from the
32128 * tree implementation. Unless you are customizing the tree UI,
32129 * you should never have to use this directly.
32131 Roo.tree.TreeNodeUI = function(node){
32133 this.rendered = false;
32134 this.animating = false;
32135 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32138 Roo.tree.TreeNodeUI.prototype = {
32139 removeChild : function(node){
32141 this.ctNode.removeChild(node.ui.getEl());
32145 beforeLoad : function(){
32146 this.addClass("x-tree-node-loading");
32149 afterLoad : function(){
32150 this.removeClass("x-tree-node-loading");
32153 onTextChange : function(node, text, oldText){
32155 this.textNode.innerHTML = text;
32159 onDisableChange : function(node, state){
32160 this.disabled = state;
32162 this.addClass("x-tree-node-disabled");
32164 this.removeClass("x-tree-node-disabled");
32168 onSelectedChange : function(state){
32171 this.addClass("x-tree-selected");
32174 this.removeClass("x-tree-selected");
32178 onMove : function(tree, node, oldParent, newParent, index, refNode){
32179 this.childIndent = null;
32181 var targetNode = newParent.ui.getContainer();
32182 if(!targetNode){//target not rendered
32183 this.holder = document.createElement("div");
32184 this.holder.appendChild(this.wrap);
32187 var insertBefore = refNode ? refNode.ui.getEl() : null;
32189 targetNode.insertBefore(this.wrap, insertBefore);
32191 targetNode.appendChild(this.wrap);
32193 this.node.renderIndent(true);
32197 addClass : function(cls){
32199 Roo.fly(this.elNode).addClass(cls);
32203 removeClass : function(cls){
32205 Roo.fly(this.elNode).removeClass(cls);
32209 remove : function(){
32211 this.holder = document.createElement("div");
32212 this.holder.appendChild(this.wrap);
32216 fireEvent : function(){
32217 return this.node.fireEvent.apply(this.node, arguments);
32220 initEvents : function(){
32221 this.node.on("move", this.onMove, this);
32222 var E = Roo.EventManager;
32223 var a = this.anchor;
32225 var el = Roo.fly(a, '_treeui');
32227 if(Roo.isOpera){ // opera render bug ignores the CSS
32228 el.setStyle("text-decoration", "none");
32231 el.on("click", this.onClick, this);
32232 el.on("dblclick", this.onDblClick, this);
32235 Roo.EventManager.on(this.checkbox,
32236 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32239 el.on("contextmenu", this.onContextMenu, this);
32241 var icon = Roo.fly(this.iconNode);
32242 icon.on("click", this.onClick, this);
32243 icon.on("dblclick", this.onDblClick, this);
32244 icon.on("contextmenu", this.onContextMenu, this);
32245 E.on(this.ecNode, "click", this.ecClick, this, true);
32247 if(this.node.disabled){
32248 this.addClass("x-tree-node-disabled");
32250 if(this.node.hidden){
32251 this.addClass("x-tree-node-disabled");
32253 var ot = this.node.getOwnerTree();
32254 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32255 if(dd && (!this.node.isRoot || ot.rootVisible)){
32256 Roo.dd.Registry.register(this.elNode, {
32258 handles: this.getDDHandles(),
32264 getDDHandles : function(){
32265 return [this.iconNode, this.textNode];
32270 this.wrap.style.display = "none";
32276 this.wrap.style.display = "";
32280 onContextMenu : function(e){
32281 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32282 e.preventDefault();
32284 this.fireEvent("contextmenu", this.node, e);
32288 onClick : function(e){
32293 if(this.fireEvent("beforeclick", this.node, e) !== false){
32294 if(!this.disabled && this.node.attributes.href){
32295 this.fireEvent("click", this.node, e);
32298 e.preventDefault();
32303 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32304 this.node.toggle();
32307 this.fireEvent("click", this.node, e);
32313 onDblClick : function(e){
32314 e.preventDefault();
32319 this.toggleCheck();
32321 if(!this.animating && this.node.hasChildNodes()){
32322 this.node.toggle();
32324 this.fireEvent("dblclick", this.node, e);
32327 onCheckChange : function(){
32328 var checked = this.checkbox.checked;
32329 this.node.attributes.checked = checked;
32330 this.fireEvent('checkchange', this.node, checked);
32333 ecClick : function(e){
32334 if(!this.animating && this.node.hasChildNodes()){
32335 this.node.toggle();
32339 startDrop : function(){
32340 this.dropping = true;
32343 // delayed drop so the click event doesn't get fired on a drop
32344 endDrop : function(){
32345 setTimeout(function(){
32346 this.dropping = false;
32347 }.createDelegate(this), 50);
32350 expand : function(){
32351 this.updateExpandIcon();
32352 this.ctNode.style.display = "";
32355 focus : function(){
32356 if(!this.node.preventHScroll){
32357 try{this.anchor.focus();
32359 }else if(!Roo.isIE){
32361 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32362 var l = noscroll.scrollLeft;
32363 this.anchor.focus();
32364 noscroll.scrollLeft = l;
32369 toggleCheck : function(value){
32370 var cb = this.checkbox;
32372 cb.checked = (value === undefined ? !cb.checked : value);
32378 this.anchor.blur();
32382 animExpand : function(callback){
32383 var ct = Roo.get(this.ctNode);
32385 if(!this.node.hasChildNodes()){
32386 this.updateExpandIcon();
32387 this.ctNode.style.display = "";
32388 Roo.callback(callback);
32391 this.animating = true;
32392 this.updateExpandIcon();
32395 callback : function(){
32396 this.animating = false;
32397 Roo.callback(callback);
32400 duration: this.node.ownerTree.duration || .25
32404 highlight : function(){
32405 var tree = this.node.getOwnerTree();
32406 Roo.fly(this.wrap).highlight(
32407 tree.hlColor || "C3DAF9",
32408 {endColor: tree.hlBaseColor}
32412 collapse : function(){
32413 this.updateExpandIcon();
32414 this.ctNode.style.display = "none";
32417 animCollapse : function(callback){
32418 var ct = Roo.get(this.ctNode);
32419 ct.enableDisplayMode('block');
32422 this.animating = true;
32423 this.updateExpandIcon();
32426 callback : function(){
32427 this.animating = false;
32428 Roo.callback(callback);
32431 duration: this.node.ownerTree.duration || .25
32435 getContainer : function(){
32436 return this.ctNode;
32439 getEl : function(){
32443 appendDDGhost : function(ghostNode){
32444 ghostNode.appendChild(this.elNode.cloneNode(true));
32447 getDDRepairXY : function(){
32448 return Roo.lib.Dom.getXY(this.iconNode);
32451 onRender : function(){
32455 render : function(bulkRender){
32456 var n = this.node, a = n.attributes;
32457 var targetNode = n.parentNode ?
32458 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32460 if(!this.rendered){
32461 this.rendered = true;
32463 this.renderElements(n, a, targetNode, bulkRender);
32466 if(this.textNode.setAttributeNS){
32467 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32469 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32472 this.textNode.setAttribute("ext:qtip", a.qtip);
32474 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32477 }else if(a.qtipCfg){
32478 a.qtipCfg.target = Roo.id(this.textNode);
32479 Roo.QuickTips.register(a.qtipCfg);
32482 if(!this.node.expanded){
32483 this.updateExpandIcon();
32486 if(bulkRender === true) {
32487 targetNode.appendChild(this.wrap);
32492 renderElements : function(n, a, targetNode, bulkRender){
32493 // add some indent caching, this helps performance when rendering a large tree
32494 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32495 var t = n.getOwnerTree();
32496 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32497 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32498 var cb = typeof a.checked == 'boolean';
32499 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32500 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32501 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32502 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32503 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32504 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32505 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32506 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32507 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32508 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32511 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32512 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32513 n.nextSibling.ui.getEl(), buf.join(""));
32515 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32518 this.elNode = this.wrap.childNodes[0];
32519 this.ctNode = this.wrap.childNodes[1];
32520 var cs = this.elNode.childNodes;
32521 this.indentNode = cs[0];
32522 this.ecNode = cs[1];
32523 this.iconNode = cs[2];
32526 this.checkbox = cs[3];
32529 this.anchor = cs[index];
32530 this.textNode = cs[index].firstChild;
32533 getAnchor : function(){
32534 return this.anchor;
32537 getTextEl : function(){
32538 return this.textNode;
32541 getIconEl : function(){
32542 return this.iconNode;
32545 isChecked : function(){
32546 return this.checkbox ? this.checkbox.checked : false;
32549 updateExpandIcon : function(){
32551 var n = this.node, c1, c2;
32552 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32553 var hasChild = n.hasChildNodes();
32557 c1 = "x-tree-node-collapsed";
32558 c2 = "x-tree-node-expanded";
32561 c1 = "x-tree-node-expanded";
32562 c2 = "x-tree-node-collapsed";
32565 this.removeClass("x-tree-node-leaf");
32566 this.wasLeaf = false;
32568 if(this.c1 != c1 || this.c2 != c2){
32569 Roo.fly(this.elNode).replaceClass(c1, c2);
32570 this.c1 = c1; this.c2 = c2;
32574 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32577 this.wasLeaf = true;
32580 var ecc = "x-tree-ec-icon "+cls;
32581 if(this.ecc != ecc){
32582 this.ecNode.className = ecc;
32588 getChildIndent : function(){
32589 if(!this.childIndent){
32593 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32595 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32597 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32602 this.childIndent = buf.join("");
32604 return this.childIndent;
32607 renderIndent : function(){
32610 var p = this.node.parentNode;
32612 indent = p.ui.getChildIndent();
32614 if(this.indentMarkup != indent){ // don't rerender if not required
32615 this.indentNode.innerHTML = indent;
32616 this.indentMarkup = indent;
32618 this.updateExpandIcon();
32623 Roo.tree.RootTreeNodeUI = function(){
32624 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32626 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32627 render : function(){
32628 if(!this.rendered){
32629 var targetNode = this.node.ownerTree.innerCt.dom;
32630 this.node.expanded = true;
32631 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32632 this.wrap = this.ctNode = targetNode.firstChild;
32635 collapse : function(){
32637 expand : function(){
32641 * Ext JS Library 1.1.1
32642 * Copyright(c) 2006-2007, Ext JS, LLC.
32644 * Originally Released Under LGPL - original licence link has changed is not relivant.
32647 * <script type="text/javascript">
32650 * @class Roo.tree.TreeLoader
32651 * @extends Roo.util.Observable
32652 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32653 * nodes from a specified URL. The response must be a javascript Array definition
32654 * who's elements are node definition objects. eg:
32656 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32657 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32660 * A server request is sent, and child nodes are loaded only when a node is expanded.
32661 * The loading node's id is passed to the server under the parameter name "node" to
32662 * enable the server to produce the correct child nodes.
32664 * To pass extra parameters, an event handler may be attached to the "beforeload"
32665 * event, and the parameters specified in the TreeLoader's baseParams property:
32667 myTreeLoader.on("beforeload", function(treeLoader, node) {
32668 this.baseParams.category = node.attributes.category;
32671 * This would pass an HTTP parameter called "category" to the server containing
32672 * the value of the Node's "category" attribute.
32674 * Creates a new Treeloader.
32675 * @param {Object} config A config object containing config properties.
32677 Roo.tree.TreeLoader = function(config){
32678 this.baseParams = {};
32679 this.requestMethod = "POST";
32680 Roo.apply(this, config);
32685 * @event beforeload
32686 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32687 * @param {Object} This TreeLoader object.
32688 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32689 * @param {Object} callback The callback function specified in the {@link #load} call.
32694 * Fires when the node has been successfuly loaded.
32695 * @param {Object} This TreeLoader object.
32696 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32697 * @param {Object} response The response object containing the data from the server.
32701 * @event loadexception
32702 * Fires if the network request failed.
32703 * @param {Object} This TreeLoader object.
32704 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32705 * @param {Object} response The response object containing the data from the server.
32707 loadexception : true,
32710 * Fires before a node is created, enabling you to return custom Node types
32711 * @param {Object} This TreeLoader object.
32712 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32717 Roo.tree.TreeLoader.superclass.constructor.call(this);
32720 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32722 * @cfg {String} dataUrl The URL from which to request a Json string which
32723 * specifies an array of node definition object representing the child nodes
32727 * @cfg {Object} baseParams (optional) An object containing properties which
32728 * specify HTTP parameters to be passed to each request for child nodes.
32731 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32732 * created by this loader. If the attributes sent by the server have an attribute in this object,
32733 * they take priority.
32736 * @cfg {Object} uiProviders (optional) An object containing properties which
32738 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32739 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32740 * <i>uiProvider</i> attribute of a returned child node is a string rather
32741 * than a reference to a TreeNodeUI implementation, this that string value
32742 * is used as a property name in the uiProviders object. You can define the provider named
32743 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32748 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32749 * child nodes before loading.
32751 clearOnLoad : true,
32754 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32755 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32756 * Grid query { data : [ .....] }
32761 * @cfg {String} queryParam (optional)
32762 * Name of the query as it will be passed on the querystring (defaults to 'node')
32763 * eg. the request will be ?node=[id]
32770 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32771 * This is called automatically when a node is expanded, but may be used to reload
32772 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32773 * @param {Roo.tree.TreeNode} node
32774 * @param {Function} callback
32776 load : function(node, callback){
32777 if(this.clearOnLoad){
32778 while(node.firstChild){
32779 node.removeChild(node.firstChild);
32782 if(node.attributes.children){ // preloaded json children
32783 var cs = node.attributes.children;
32784 for(var i = 0, len = cs.length; i < len; i++){
32785 node.appendChild(this.createNode(cs[i]));
32787 if(typeof callback == "function"){
32790 }else if(this.dataUrl){
32791 this.requestData(node, callback);
32795 getParams: function(node){
32796 var buf = [], bp = this.baseParams;
32797 for(var key in bp){
32798 if(typeof bp[key] != "function"){
32799 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32802 var n = this.queryParam === false ? 'node' : this.queryParam;
32803 buf.push(n + "=", encodeURIComponent(node.id));
32804 return buf.join("");
32807 requestData : function(node, callback){
32808 if(this.fireEvent("beforeload", this, node, callback) !== false){
32809 this.transId = Roo.Ajax.request({
32810 method:this.requestMethod,
32811 url: this.dataUrl||this.url,
32812 success: this.handleResponse,
32813 failure: this.handleFailure,
32815 argument: {callback: callback, node: node},
32816 params: this.getParams(node)
32819 // if the load is cancelled, make sure we notify
32820 // the node that we are done
32821 if(typeof callback == "function"){
32827 isLoading : function(){
32828 return this.transId ? true : false;
32831 abort : function(){
32832 if(this.isLoading()){
32833 Roo.Ajax.abort(this.transId);
32838 createNode : function(attr){
32839 // apply baseAttrs, nice idea Corey!
32840 if(this.baseAttrs){
32841 Roo.applyIf(attr, this.baseAttrs);
32843 if(this.applyLoader !== false){
32844 attr.loader = this;
32846 // uiProvider = depreciated..
32848 if(typeof(attr.uiProvider) == 'string'){
32849 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32850 /** eval:var:attr */ eval(attr.uiProvider);
32852 if(typeof(this.uiProviders['default']) != 'undefined') {
32853 attr.uiProvider = this.uiProviders['default'];
32856 this.fireEvent('create', this, attr);
32858 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32860 new Roo.tree.TreeNode(attr) :
32861 new Roo.tree.AsyncTreeNode(attr));
32864 processResponse : function(response, node, callback){
32865 var json = response.responseText;
32868 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32869 if (this.root !== false) {
32873 for(var i = 0, len = o.length; i < len; i++){
32874 var n = this.createNode(o[i]);
32876 node.appendChild(n);
32879 if(typeof callback == "function"){
32880 callback(this, node);
32883 this.handleFailure(response);
32887 handleResponse : function(response){
32888 this.transId = false;
32889 var a = response.argument;
32890 this.processResponse(response, a.node, a.callback);
32891 this.fireEvent("load", this, a.node, response);
32894 handleFailure : function(response){
32895 this.transId = false;
32896 var a = response.argument;
32897 this.fireEvent("loadexception", this, a.node, response);
32898 if(typeof a.callback == "function"){
32899 a.callback(this, a.node);
32904 * Ext JS Library 1.1.1
32905 * Copyright(c) 2006-2007, Ext JS, LLC.
32907 * Originally Released Under LGPL - original licence link has changed is not relivant.
32910 * <script type="text/javascript">
32914 * @class Roo.tree.TreeFilter
32915 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32916 * @param {TreePanel} tree
32917 * @param {Object} config (optional)
32919 Roo.tree.TreeFilter = function(tree, config){
32921 this.filtered = {};
32922 Roo.apply(this, config);
32925 Roo.tree.TreeFilter.prototype = {
32932 * Filter the data by a specific attribute.
32933 * @param {String/RegExp} value Either string that the attribute value
32934 * should start with or a RegExp to test against the attribute
32935 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32936 * @param {TreeNode} startNode (optional) The node to start the filter at.
32938 filter : function(value, attr, startNode){
32939 attr = attr || "text";
32941 if(typeof value == "string"){
32942 var vlen = value.length;
32943 // auto clear empty filter
32944 if(vlen == 0 && this.clearBlank){
32948 value = value.toLowerCase();
32950 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32952 }else if(value.exec){ // regex?
32954 return value.test(n.attributes[attr]);
32957 throw 'Illegal filter type, must be string or regex';
32959 this.filterBy(f, null, startNode);
32963 * Filter by a function. The passed function will be called with each
32964 * node in the tree (or from the startNode). If the function returns true, the node is kept
32965 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32966 * @param {Function} fn The filter function
32967 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32969 filterBy : function(fn, scope, startNode){
32970 startNode = startNode || this.tree.root;
32971 if(this.autoClear){
32974 var af = this.filtered, rv = this.reverse;
32975 var f = function(n){
32976 if(n == startNode){
32982 var m = fn.call(scope || n, n);
32990 startNode.cascade(f);
32993 if(typeof id != "function"){
32995 if(n && n.parentNode){
32996 n.parentNode.removeChild(n);
33004 * Clears the current filter. Note: with the "remove" option
33005 * set a filter cannot be cleared.
33007 clear : function(){
33009 var af = this.filtered;
33011 if(typeof id != "function"){
33018 this.filtered = {};
33023 * Ext JS Library 1.1.1
33024 * Copyright(c) 2006-2007, Ext JS, LLC.
33026 * Originally Released Under LGPL - original licence link has changed is not relivant.
33029 * <script type="text/javascript">
33034 * @class Roo.tree.TreeSorter
33035 * Provides sorting of nodes in a TreePanel
33037 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33038 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33039 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33040 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33041 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33042 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33044 * @param {TreePanel} tree
33045 * @param {Object} config
33047 Roo.tree.TreeSorter = function(tree, config){
33048 Roo.apply(this, config);
33049 tree.on("beforechildrenrendered", this.doSort, this);
33050 tree.on("append", this.updateSort, this);
33051 tree.on("insert", this.updateSort, this);
33053 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33054 var p = this.property || "text";
33055 var sortType = this.sortType;
33056 var fs = this.folderSort;
33057 var cs = this.caseSensitive === true;
33058 var leafAttr = this.leafAttr || 'leaf';
33060 this.sortFn = function(n1, n2){
33062 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33065 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33069 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33070 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33072 return dsc ? +1 : -1;
33074 return dsc ? -1 : +1;
33081 Roo.tree.TreeSorter.prototype = {
33082 doSort : function(node){
33083 node.sort(this.sortFn);
33086 compareNodes : function(n1, n2){
33087 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33090 updateSort : function(tree, node){
33091 if(node.childrenRendered){
33092 this.doSort.defer(1, this, [node]);
33097 * Ext JS Library 1.1.1
33098 * Copyright(c) 2006-2007, Ext JS, LLC.
33100 * Originally Released Under LGPL - original licence link has changed is not relivant.
33103 * <script type="text/javascript">
33106 if(Roo.dd.DropZone){
33108 Roo.tree.TreeDropZone = function(tree, config){
33109 this.allowParentInsert = false;
33110 this.allowContainerDrop = false;
33111 this.appendOnly = false;
33112 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33114 this.lastInsertClass = "x-tree-no-status";
33115 this.dragOverData = {};
33118 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33119 ddGroup : "TreeDD",
33121 expandDelay : 1000,
33123 expandNode : function(node){
33124 if(node.hasChildNodes() && !node.isExpanded()){
33125 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33129 queueExpand : function(node){
33130 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33133 cancelExpand : function(){
33134 if(this.expandProcId){
33135 clearTimeout(this.expandProcId);
33136 this.expandProcId = false;
33140 isValidDropPoint : function(n, pt, dd, e, data){
33141 if(!n || !data){ return false; }
33142 var targetNode = n.node;
33143 var dropNode = data.node;
33144 // default drop rules
33145 if(!(targetNode && targetNode.isTarget && pt)){
33148 if(pt == "append" && targetNode.allowChildren === false){
33151 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33154 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33157 // reuse the object
33158 var overEvent = this.dragOverData;
33159 overEvent.tree = this.tree;
33160 overEvent.target = targetNode;
33161 overEvent.data = data;
33162 overEvent.point = pt;
33163 overEvent.source = dd;
33164 overEvent.rawEvent = e;
33165 overEvent.dropNode = dropNode;
33166 overEvent.cancel = false;
33167 var result = this.tree.fireEvent("nodedragover", overEvent);
33168 return overEvent.cancel === false && result !== false;
33171 getDropPoint : function(e, n, dd){
33174 return tn.allowChildren !== false ? "append" : false; // always append for root
33176 var dragEl = n.ddel;
33177 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33178 var y = Roo.lib.Event.getPageY(e);
33179 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33181 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33182 var noAppend = tn.allowChildren === false;
33183 if(this.appendOnly || tn.parentNode.allowChildren === false){
33184 return noAppend ? false : "append";
33186 var noBelow = false;
33187 if(!this.allowParentInsert){
33188 noBelow = tn.hasChildNodes() && tn.isExpanded();
33190 var q = (b - t) / (noAppend ? 2 : 3);
33191 if(y >= t && y < (t + q)){
33193 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33200 onNodeEnter : function(n, dd, e, data){
33201 this.cancelExpand();
33204 onNodeOver : function(n, dd, e, data){
33205 var pt = this.getDropPoint(e, n, dd);
33208 // auto node expand check
33209 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33210 this.queueExpand(node);
33211 }else if(pt != "append"){
33212 this.cancelExpand();
33215 // set the insert point style on the target node
33216 var returnCls = this.dropNotAllowed;
33217 if(this.isValidDropPoint(n, pt, dd, e, data)){
33222 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33223 cls = "x-tree-drag-insert-above";
33224 }else if(pt == "below"){
33225 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33226 cls = "x-tree-drag-insert-below";
33228 returnCls = "x-tree-drop-ok-append";
33229 cls = "x-tree-drag-append";
33231 if(this.lastInsertClass != cls){
33232 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33233 this.lastInsertClass = cls;
33240 onNodeOut : function(n, dd, e, data){
33241 this.cancelExpand();
33242 this.removeDropIndicators(n);
33245 onNodeDrop : function(n, dd, e, data){
33246 var point = this.getDropPoint(e, n, dd);
33247 var targetNode = n.node;
33248 targetNode.ui.startDrop();
33249 if(!this.isValidDropPoint(n, point, dd, e, data)){
33250 targetNode.ui.endDrop();
33253 // first try to find the drop node
33254 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33257 target: targetNode,
33262 dropNode: dropNode,
33265 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33266 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33267 targetNode.ui.endDrop();
33270 // allow target changing
33271 targetNode = dropEvent.target;
33272 if(point == "append" && !targetNode.isExpanded()){
33273 targetNode.expand(false, null, function(){
33274 this.completeDrop(dropEvent);
33275 }.createDelegate(this));
33277 this.completeDrop(dropEvent);
33282 completeDrop : function(de){
33283 var ns = de.dropNode, p = de.point, t = de.target;
33284 if(!(ns instanceof Array)){
33288 for(var i = 0, len = ns.length; i < len; i++){
33291 t.parentNode.insertBefore(n, t);
33292 }else if(p == "below"){
33293 t.parentNode.insertBefore(n, t.nextSibling);
33299 if(this.tree.hlDrop){
33303 this.tree.fireEvent("nodedrop", de);
33306 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33307 if(this.tree.hlDrop){
33308 dropNode.ui.focus();
33309 dropNode.ui.highlight();
33311 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33314 getTree : function(){
33318 removeDropIndicators : function(n){
33321 Roo.fly(el).removeClass([
33322 "x-tree-drag-insert-above",
33323 "x-tree-drag-insert-below",
33324 "x-tree-drag-append"]);
33325 this.lastInsertClass = "_noclass";
33329 beforeDragDrop : function(target, e, id){
33330 this.cancelExpand();
33334 afterRepair : function(data){
33335 if(data && Roo.enableFx){
33336 data.node.ui.highlight();
33345 * Ext JS Library 1.1.1
33346 * Copyright(c) 2006-2007, Ext JS, LLC.
33348 * Originally Released Under LGPL - original licence link has changed is not relivant.
33351 * <script type="text/javascript">
33355 if(Roo.dd.DragZone){
33356 Roo.tree.TreeDragZone = function(tree, config){
33357 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33361 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33362 ddGroup : "TreeDD",
33364 onBeforeDrag : function(data, e){
33366 return n && n.draggable && !n.disabled;
33369 onInitDrag : function(e){
33370 var data = this.dragData;
33371 this.tree.getSelectionModel().select(data.node);
33372 this.proxy.update("");
33373 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33374 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33377 getRepairXY : function(e, data){
33378 return data.node.ui.getDDRepairXY();
33381 onEndDrag : function(data, e){
33382 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33385 onValidDrop : function(dd, e, id){
33386 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33390 beforeInvalidDrop : function(e, id){
33391 // this scrolls the original position back into view
33392 var sm = this.tree.getSelectionModel();
33393 sm.clearSelections();
33394 sm.select(this.dragData.node);
33399 * Ext JS Library 1.1.1
33400 * Copyright(c) 2006-2007, Ext JS, LLC.
33402 * Originally Released Under LGPL - original licence link has changed is not relivant.
33405 * <script type="text/javascript">
33408 * @class Roo.tree.TreeEditor
33409 * @extends Roo.Editor
33410 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33411 * as the editor field.
33413 * @param {TreePanel} tree
33414 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33416 Roo.tree.TreeEditor = function(tree, config){
33417 config = config || {};
33418 var field = config.events ? config : new Roo.form.TextField(config);
33419 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33423 tree.on('beforeclick', this.beforeNodeClick, this);
33424 tree.getTreeEl().on('mousedown', this.hide, this);
33425 this.on('complete', this.updateNode, this);
33426 this.on('beforestartedit', this.fitToTree, this);
33427 this.on('startedit', this.bindScroll, this, {delay:10});
33428 this.on('specialkey', this.onSpecialKey, this);
33431 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33433 * @cfg {String} alignment
33434 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33440 * @cfg {Boolean} hideEl
33441 * True to hide the bound element while the editor is displayed (defaults to false)
33445 * @cfg {String} cls
33446 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33448 cls: "x-small-editor x-tree-editor",
33450 * @cfg {Boolean} shim
33451 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33457 * @cfg {Number} maxWidth
33458 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33459 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33460 * scroll and client offsets into account prior to each edit.
33467 fitToTree : function(ed, el){
33468 var td = this.tree.getTreeEl().dom, nd = el.dom;
33469 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33470 td.scrollLeft = nd.offsetLeft;
33474 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33475 this.setSize(w, '');
33479 triggerEdit : function(node){
33480 this.completeEdit();
33481 this.editNode = node;
33482 this.startEdit(node.ui.textNode, node.text);
33486 bindScroll : function(){
33487 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33491 beforeNodeClick : function(node, e){
33492 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33493 this.lastClick = new Date();
33494 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33496 this.triggerEdit(node);
33502 updateNode : function(ed, value){
33503 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33504 this.editNode.setText(value);
33508 onHide : function(){
33509 Roo.tree.TreeEditor.superclass.onHide.call(this);
33511 this.editNode.ui.focus();
33516 onSpecialKey : function(field, e){
33517 var k = e.getKey();
33521 }else if(k == e.ENTER && !e.hasModifier()){
33523 this.completeEdit();
33526 });//<Script type="text/javascript">
33529 * Ext JS Library 1.1.1
33530 * Copyright(c) 2006-2007, Ext JS, LLC.
33532 * Originally Released Under LGPL - original licence link has changed is not relivant.
33535 * <script type="text/javascript">
33539 * Not documented??? - probably should be...
33542 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33543 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33545 renderElements : function(n, a, targetNode, bulkRender){
33546 //consel.log("renderElements?");
33547 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33549 var t = n.getOwnerTree();
33550 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33552 var cols = t.columns;
33553 var bw = t.borderWidth;
33555 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33556 var cb = typeof a.checked == "boolean";
33557 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33558 var colcls = 'x-t-' + tid + '-c0';
33560 '<li class="x-tree-node">',
33563 '<div class="x-tree-node-el ', a.cls,'">',
33565 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33568 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33569 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33570 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33571 (a.icon ? ' x-tree-node-inline-icon' : ''),
33572 (a.iconCls ? ' '+a.iconCls : ''),
33573 '" unselectable="on" />',
33574 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33575 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33577 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33578 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33579 '<span unselectable="on" qtip="' + tx + '">',
33583 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33584 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33586 for(var i = 1, len = cols.length; i < len; i++){
33588 colcls = 'x-t-' + tid + '-c' +i;
33589 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33590 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33591 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33597 '<div class="x-clear"></div></div>',
33598 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33601 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33602 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33603 n.nextSibling.ui.getEl(), buf.join(""));
33605 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33607 var el = this.wrap.firstChild;
33609 this.elNode = el.firstChild;
33610 this.ranchor = el.childNodes[1];
33611 this.ctNode = this.wrap.childNodes[1];
33612 var cs = el.firstChild.childNodes;
33613 this.indentNode = cs[0];
33614 this.ecNode = cs[1];
33615 this.iconNode = cs[2];
33618 this.checkbox = cs[3];
33621 this.anchor = cs[index];
33623 this.textNode = cs[index].firstChild;
33625 //el.on("click", this.onClick, this);
33626 //el.on("dblclick", this.onDblClick, this);
33629 // console.log(this);
33631 initEvents : function(){
33632 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33635 var a = this.ranchor;
33637 var el = Roo.get(a);
33639 if(Roo.isOpera){ // opera render bug ignores the CSS
33640 el.setStyle("text-decoration", "none");
33643 el.on("click", this.onClick, this);
33644 el.on("dblclick", this.onDblClick, this);
33645 el.on("contextmenu", this.onContextMenu, this);
33649 /*onSelectedChange : function(state){
33652 this.addClass("x-tree-selected");
33655 this.removeClass("x-tree-selected");
33658 addClass : function(cls){
33660 Roo.fly(this.elRow).addClass(cls);
33666 removeClass : function(cls){
33668 Roo.fly(this.elRow).removeClass(cls);
33674 });//<Script type="text/javascript">
33678 * Ext JS Library 1.1.1
33679 * Copyright(c) 2006-2007, Ext JS, LLC.
33681 * Originally Released Under LGPL - original licence link has changed is not relivant.
33684 * <script type="text/javascript">
33689 * @class Roo.tree.ColumnTree
33690 * @extends Roo.data.TreePanel
33691 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33692 * @cfg {int} borderWidth compined right/left border allowance
33694 * @param {String/HTMLElement/Element} el The container element
33695 * @param {Object} config
33697 Roo.tree.ColumnTree = function(el, config)
33699 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33703 * Fire this event on a container when it resizes
33704 * @param {int} w Width
33705 * @param {int} h Height
33709 this.on('resize', this.onResize, this);
33712 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33716 borderWidth: Roo.isBorderBox ? 0 : 2,
33719 render : function(){
33720 // add the header.....
33722 Roo.tree.ColumnTree.superclass.render.apply(this);
33724 this.el.addClass('x-column-tree');
33726 this.headers = this.el.createChild(
33727 {cls:'x-tree-headers'},this.innerCt.dom);
33729 var cols = this.columns, c;
33730 var totalWidth = 0;
33732 var len = cols.length;
33733 for(var i = 0; i < len; i++){
33735 totalWidth += c.width;
33736 this.headEls.push(this.headers.createChild({
33737 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33739 cls:'x-tree-hd-text',
33742 style:'width:'+(c.width-this.borderWidth)+'px;'
33745 this.headers.createChild({cls:'x-clear'});
33746 // prevent floats from wrapping when clipped
33747 this.headers.setWidth(totalWidth);
33748 //this.innerCt.setWidth(totalWidth);
33749 this.innerCt.setStyle({ overflow: 'auto' });
33750 this.onResize(this.width, this.height);
33754 onResize : function(w,h)
33759 this.innerCt.setWidth(this.width);
33760 this.innerCt.setHeight(this.height-20);
33763 var cols = this.columns, c;
33764 var totalWidth = 0;
33766 var len = cols.length;
33767 for(var i = 0; i < len; i++){
33769 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33770 // it's the expander..
33771 expEl = this.headEls[i];
33774 totalWidth += c.width;
33778 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33780 this.headers.setWidth(w-20);
33789 * Ext JS Library 1.1.1
33790 * Copyright(c) 2006-2007, Ext JS, LLC.
33792 * Originally Released Under LGPL - original licence link has changed is not relivant.
33795 * <script type="text/javascript">
33799 * @class Roo.menu.Menu
33800 * @extends Roo.util.Observable
33801 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33802 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33804 * Creates a new Menu
33805 * @param {Object} config Configuration options
33807 Roo.menu.Menu = function(config){
33808 Roo.apply(this, config);
33809 this.id = this.id || Roo.id();
33812 * @event beforeshow
33813 * Fires before this menu is displayed
33814 * @param {Roo.menu.Menu} this
33818 * @event beforehide
33819 * Fires before this menu is hidden
33820 * @param {Roo.menu.Menu} this
33825 * Fires after this menu is displayed
33826 * @param {Roo.menu.Menu} this
33831 * Fires after this menu is hidden
33832 * @param {Roo.menu.Menu} this
33837 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33838 * @param {Roo.menu.Menu} this
33839 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33840 * @param {Roo.EventObject} e
33845 * Fires when the mouse is hovering over this menu
33846 * @param {Roo.menu.Menu} this
33847 * @param {Roo.EventObject} e
33848 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33853 * Fires when the mouse exits this menu
33854 * @param {Roo.menu.Menu} this
33855 * @param {Roo.EventObject} e
33856 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33861 * Fires when a menu item contained in this menu is clicked
33862 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33863 * @param {Roo.EventObject} e
33867 if (this.registerMenu) {
33868 Roo.menu.MenuMgr.register(this);
33871 var mis = this.items;
33872 this.items = new Roo.util.MixedCollection();
33874 this.add.apply(this, mis);
33878 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33880 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33884 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33885 * for bottom-right shadow (defaults to "sides")
33889 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33890 * this menu (defaults to "tl-tr?")
33892 subMenuAlign : "tl-tr?",
33894 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33895 * relative to its element of origin (defaults to "tl-bl?")
33897 defaultAlign : "tl-bl?",
33899 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33901 allowOtherMenus : false,
33903 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33905 registerMenu : true,
33910 render : function(){
33914 var el = this.el = new Roo.Layer({
33916 shadow:this.shadow,
33918 parentEl: this.parentEl || document.body,
33922 this.keyNav = new Roo.menu.MenuNav(this);
33925 el.addClass("x-menu-plain");
33928 el.addClass(this.cls);
33930 // generic focus element
33931 this.focusEl = el.createChild({
33932 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33934 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33935 ul.on("click", this.onClick, this);
33936 ul.on("mouseover", this.onMouseOver, this);
33937 ul.on("mouseout", this.onMouseOut, this);
33938 this.items.each(function(item){
33939 var li = document.createElement("li");
33940 li.className = "x-menu-list-item";
33941 ul.dom.appendChild(li);
33942 item.render(li, this);
33949 autoWidth : function(){
33950 var el = this.el, ul = this.ul;
33954 var w = this.width;
33957 }else if(Roo.isIE){
33958 el.setWidth(this.minWidth);
33959 var t = el.dom.offsetWidth; // force recalc
33960 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33965 delayAutoWidth : function(){
33968 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33970 this.awTask.delay(20);
33975 findTargetItem : function(e){
33976 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33977 if(t && t.menuItemId){
33978 return this.items.get(t.menuItemId);
33983 onClick : function(e){
33985 if(t = this.findTargetItem(e)){
33987 this.fireEvent("click", this, t, e);
33992 setActiveItem : function(item, autoExpand){
33993 if(item != this.activeItem){
33994 if(this.activeItem){
33995 this.activeItem.deactivate();
33997 this.activeItem = item;
33998 item.activate(autoExpand);
33999 }else if(autoExpand){
34005 tryActivate : function(start, step){
34006 var items = this.items;
34007 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34008 var item = items.get(i);
34009 if(!item.disabled && item.canActivate){
34010 this.setActiveItem(item, false);
34018 onMouseOver : function(e){
34020 if(t = this.findTargetItem(e)){
34021 if(t.canActivate && !t.disabled){
34022 this.setActiveItem(t, true);
34025 this.fireEvent("mouseover", this, e, t);
34029 onMouseOut : function(e){
34031 if(t = this.findTargetItem(e)){
34032 if(t == this.activeItem && t.shouldDeactivate(e)){
34033 this.activeItem.deactivate();
34034 delete this.activeItem;
34037 this.fireEvent("mouseout", this, e, t);
34041 * Read-only. Returns true if the menu is currently displayed, else false.
34044 isVisible : function(){
34045 return this.el && !this.hidden;
34049 * Displays this menu relative to another element
34050 * @param {String/HTMLElement/Roo.Element} element The element to align to
34051 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34052 * the element (defaults to this.defaultAlign)
34053 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34055 show : function(el, pos, parentMenu){
34056 this.parentMenu = parentMenu;
34060 this.fireEvent("beforeshow", this);
34061 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34065 * Displays this menu at a specific xy position
34066 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34067 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34069 showAt : function(xy, parentMenu, /* private: */_e){
34070 this.parentMenu = parentMenu;
34075 this.fireEvent("beforeshow", this);
34076 xy = this.el.adjustForConstraints(xy);
34080 this.hidden = false;
34082 this.fireEvent("show", this);
34085 focus : function(){
34087 this.doFocus.defer(50, this);
34091 doFocus : function(){
34093 this.focusEl.focus();
34098 * Hides this menu and optionally all parent menus
34099 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34101 hide : function(deep){
34102 if(this.el && this.isVisible()){
34103 this.fireEvent("beforehide", this);
34104 if(this.activeItem){
34105 this.activeItem.deactivate();
34106 this.activeItem = null;
34109 this.hidden = true;
34110 this.fireEvent("hide", this);
34112 if(deep === true && this.parentMenu){
34113 this.parentMenu.hide(true);
34118 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34119 * Any of the following are valid:
34121 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34122 * <li>An HTMLElement object which will be converted to a menu item</li>
34123 * <li>A menu item config object that will be created as a new menu item</li>
34124 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34125 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34130 var menu = new Roo.menu.Menu();
34132 // Create a menu item to add by reference
34133 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34135 // Add a bunch of items at once using different methods.
34136 // Only the last item added will be returned.
34137 var item = menu.add(
34138 menuItem, // add existing item by ref
34139 'Dynamic Item', // new TextItem
34140 '-', // new separator
34141 { text: 'Config Item' } // new item by config
34144 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34145 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34148 var a = arguments, l = a.length, item;
34149 for(var i = 0; i < l; i++){
34151 if ((typeof(el) == "object") && el.xtype && el.xns) {
34152 el = Roo.factory(el, Roo.menu);
34155 if(el.render){ // some kind of Item
34156 item = this.addItem(el);
34157 }else if(typeof el == "string"){ // string
34158 if(el == "separator" || el == "-"){
34159 item = this.addSeparator();
34161 item = this.addText(el);
34163 }else if(el.tagName || el.el){ // element
34164 item = this.addElement(el);
34165 }else if(typeof el == "object"){ // must be menu item config?
34166 item = this.addMenuItem(el);
34173 * Returns this menu's underlying {@link Roo.Element} object
34174 * @return {Roo.Element} The element
34176 getEl : function(){
34184 * Adds a separator bar to the menu
34185 * @return {Roo.menu.Item} The menu item that was added
34187 addSeparator : function(){
34188 return this.addItem(new Roo.menu.Separator());
34192 * Adds an {@link Roo.Element} object to the menu
34193 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34194 * @return {Roo.menu.Item} The menu item that was added
34196 addElement : function(el){
34197 return this.addItem(new Roo.menu.BaseItem(el));
34201 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34202 * @param {Roo.menu.Item} item The menu item to add
34203 * @return {Roo.menu.Item} The menu item that was added
34205 addItem : function(item){
34206 this.items.add(item);
34208 var li = document.createElement("li");
34209 li.className = "x-menu-list-item";
34210 this.ul.dom.appendChild(li);
34211 item.render(li, this);
34212 this.delayAutoWidth();
34218 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34219 * @param {Object} config A MenuItem config object
34220 * @return {Roo.menu.Item} The menu item that was added
34222 addMenuItem : function(config){
34223 if(!(config instanceof Roo.menu.Item)){
34224 if(typeof config.checked == "boolean"){ // must be check menu item config?
34225 config = new Roo.menu.CheckItem(config);
34227 config = new Roo.menu.Item(config);
34230 return this.addItem(config);
34234 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34235 * @param {String} text The text to display in the menu item
34236 * @return {Roo.menu.Item} The menu item that was added
34238 addText : function(text){
34239 return this.addItem(new Roo.menu.TextItem({ text : text }));
34243 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34244 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34245 * @param {Roo.menu.Item} item The menu item to add
34246 * @return {Roo.menu.Item} The menu item that was added
34248 insert : function(index, item){
34249 this.items.insert(index, item);
34251 var li = document.createElement("li");
34252 li.className = "x-menu-list-item";
34253 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34254 item.render(li, this);
34255 this.delayAutoWidth();
34261 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34262 * @param {Roo.menu.Item} item The menu item to remove
34264 remove : function(item){
34265 this.items.removeKey(item.id);
34270 * Removes and destroys all items in the menu
34272 removeAll : function(){
34274 while(f = this.items.first()){
34280 // MenuNav is a private utility class used internally by the Menu
34281 Roo.menu.MenuNav = function(menu){
34282 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34283 this.scope = this.menu = menu;
34286 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34287 doRelay : function(e, h){
34288 var k = e.getKey();
34289 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34290 this.menu.tryActivate(0, 1);
34293 return h.call(this.scope || this, e, this.menu);
34296 up : function(e, m){
34297 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34298 m.tryActivate(m.items.length-1, -1);
34302 down : function(e, m){
34303 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34304 m.tryActivate(0, 1);
34308 right : function(e, m){
34310 m.activeItem.expandMenu(true);
34314 left : function(e, m){
34316 if(m.parentMenu && m.parentMenu.activeItem){
34317 m.parentMenu.activeItem.activate();
34321 enter : function(e, m){
34323 e.stopPropagation();
34324 m.activeItem.onClick(e);
34325 m.fireEvent("click", this, m.activeItem);
34331 * Ext JS Library 1.1.1
34332 * Copyright(c) 2006-2007, Ext JS, LLC.
34334 * Originally Released Under LGPL - original licence link has changed is not relivant.
34337 * <script type="text/javascript">
34341 * @class Roo.menu.MenuMgr
34342 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34345 Roo.menu.MenuMgr = function(){
34346 var menus, active, groups = {}, attached = false, lastShow = new Date();
34348 // private - called when first menu is created
34351 active = new Roo.util.MixedCollection();
34352 Roo.get(document).addKeyListener(27, function(){
34353 if(active.length > 0){
34360 function hideAll(){
34361 if(active && active.length > 0){
34362 var c = active.clone();
34363 c.each(function(m){
34370 function onHide(m){
34372 if(active.length < 1){
34373 Roo.get(document).un("mousedown", onMouseDown);
34379 function onShow(m){
34380 var last = active.last();
34381 lastShow = new Date();
34384 Roo.get(document).on("mousedown", onMouseDown);
34388 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34389 m.parentMenu.activeChild = m;
34390 }else if(last && last.isVisible()){
34391 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34396 function onBeforeHide(m){
34398 m.activeChild.hide();
34400 if(m.autoHideTimer){
34401 clearTimeout(m.autoHideTimer);
34402 delete m.autoHideTimer;
34407 function onBeforeShow(m){
34408 var pm = m.parentMenu;
34409 if(!pm && !m.allowOtherMenus){
34411 }else if(pm && pm.activeChild && active != m){
34412 pm.activeChild.hide();
34417 function onMouseDown(e){
34418 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34424 function onBeforeCheck(mi, state){
34426 var g = groups[mi.group];
34427 for(var i = 0, l = g.length; i < l; i++){
34429 g[i].setChecked(false);
34438 * Hides all menus that are currently visible
34440 hideAll : function(){
34445 register : function(menu){
34449 menus[menu.id] = menu;
34450 menu.on("beforehide", onBeforeHide);
34451 menu.on("hide", onHide);
34452 menu.on("beforeshow", onBeforeShow);
34453 menu.on("show", onShow);
34454 var g = menu.group;
34455 if(g && menu.events["checkchange"]){
34459 groups[g].push(menu);
34460 menu.on("checkchange", onCheck);
34465 * Returns a {@link Roo.menu.Menu} object
34466 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34467 * be used to generate and return a new Menu instance.
34469 get : function(menu){
34470 if(typeof menu == "string"){ // menu id
34471 return menus[menu];
34472 }else if(menu.events){ // menu instance
34474 }else if(typeof menu.length == 'number'){ // array of menu items?
34475 return new Roo.menu.Menu({items:menu});
34476 }else{ // otherwise, must be a config
34477 return new Roo.menu.Menu(menu);
34482 unregister : function(menu){
34483 delete menus[menu.id];
34484 menu.un("beforehide", onBeforeHide);
34485 menu.un("hide", onHide);
34486 menu.un("beforeshow", onBeforeShow);
34487 menu.un("show", onShow);
34488 var g = menu.group;
34489 if(g && menu.events["checkchange"]){
34490 groups[g].remove(menu);
34491 menu.un("checkchange", onCheck);
34496 registerCheckable : function(menuItem){
34497 var g = menuItem.group;
34502 groups[g].push(menuItem);
34503 menuItem.on("beforecheckchange", onBeforeCheck);
34508 unregisterCheckable : function(menuItem){
34509 var g = menuItem.group;
34511 groups[g].remove(menuItem);
34512 menuItem.un("beforecheckchange", onBeforeCheck);
34518 * Ext JS Library 1.1.1
34519 * Copyright(c) 2006-2007, Ext JS, LLC.
34521 * Originally Released Under LGPL - original licence link has changed is not relivant.
34524 * <script type="text/javascript">
34529 * @class Roo.menu.BaseItem
34530 * @extends Roo.Component
34531 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34532 * management and base configuration options shared by all menu components.
34534 * Creates a new BaseItem
34535 * @param {Object} config Configuration options
34537 Roo.menu.BaseItem = function(config){
34538 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34543 * Fires when this item is clicked
34544 * @param {Roo.menu.BaseItem} this
34545 * @param {Roo.EventObject} e
34550 * Fires when this item is activated
34551 * @param {Roo.menu.BaseItem} this
34555 * @event deactivate
34556 * Fires when this item is deactivated
34557 * @param {Roo.menu.BaseItem} this
34563 this.on("click", this.handler, this.scope, true);
34567 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34569 * @cfg {Function} handler
34570 * A function that will handle the click event of this menu item (defaults to undefined)
34573 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34575 canActivate : false,
34577 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34579 activeClass : "x-menu-item-active",
34581 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34583 hideOnClick : true,
34585 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34590 ctype: "Roo.menu.BaseItem",
34593 actionMode : "container",
34596 render : function(container, parentMenu){
34597 this.parentMenu = parentMenu;
34598 Roo.menu.BaseItem.superclass.render.call(this, container);
34599 this.container.menuItemId = this.id;
34603 onRender : function(container, position){
34604 this.el = Roo.get(this.el);
34605 container.dom.appendChild(this.el.dom);
34609 onClick : function(e){
34610 if(!this.disabled && this.fireEvent("click", this, e) !== false
34611 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34612 this.handleClick(e);
34619 activate : function(){
34623 var li = this.container;
34624 li.addClass(this.activeClass);
34625 this.region = li.getRegion().adjust(2, 2, -2, -2);
34626 this.fireEvent("activate", this);
34631 deactivate : function(){
34632 this.container.removeClass(this.activeClass);
34633 this.fireEvent("deactivate", this);
34637 shouldDeactivate : function(e){
34638 return !this.region || !this.region.contains(e.getPoint());
34642 handleClick : function(e){
34643 if(this.hideOnClick){
34644 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34649 expandMenu : function(autoActivate){
34654 hideMenu : function(){
34659 * Ext JS Library 1.1.1
34660 * Copyright(c) 2006-2007, Ext JS, LLC.
34662 * Originally Released Under LGPL - original licence link has changed is not relivant.
34665 * <script type="text/javascript">
34669 * @class Roo.menu.Adapter
34670 * @extends Roo.menu.BaseItem
34671 * 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.
34672 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34674 * Creates a new Adapter
34675 * @param {Object} config Configuration options
34677 Roo.menu.Adapter = function(component, config){
34678 Roo.menu.Adapter.superclass.constructor.call(this, config);
34679 this.component = component;
34681 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34683 canActivate : true,
34686 onRender : function(container, position){
34687 this.component.render(container);
34688 this.el = this.component.getEl();
34692 activate : function(){
34696 this.component.focus();
34697 this.fireEvent("activate", this);
34702 deactivate : function(){
34703 this.fireEvent("deactivate", this);
34707 disable : function(){
34708 this.component.disable();
34709 Roo.menu.Adapter.superclass.disable.call(this);
34713 enable : function(){
34714 this.component.enable();
34715 Roo.menu.Adapter.superclass.enable.call(this);
34719 * Ext JS Library 1.1.1
34720 * Copyright(c) 2006-2007, Ext JS, LLC.
34722 * Originally Released Under LGPL - original licence link has changed is not relivant.
34725 * <script type="text/javascript">
34729 * @class Roo.menu.TextItem
34730 * @extends Roo.menu.BaseItem
34731 * Adds a static text string to a menu, usually used as either a heading or group separator.
34732 * Note: old style constructor with text is still supported.
34735 * Creates a new TextItem
34736 * @param {Object} cfg Configuration
34738 Roo.menu.TextItem = function(cfg){
34739 if (typeof(cfg) == 'string') {
34742 Roo.apply(this,cfg);
34745 Roo.menu.TextItem.superclass.constructor.call(this);
34748 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34750 * @cfg {Boolean} text Text to show on item.
34755 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34757 hideOnClick : false,
34759 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34761 itemCls : "x-menu-text",
34764 onRender : function(){
34765 var s = document.createElement("span");
34766 s.className = this.itemCls;
34767 s.innerHTML = this.text;
34769 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34773 * Ext JS Library 1.1.1
34774 * Copyright(c) 2006-2007, Ext JS, LLC.
34776 * Originally Released Under LGPL - original licence link has changed is not relivant.
34779 * <script type="text/javascript">
34783 * @class Roo.menu.Separator
34784 * @extends Roo.menu.BaseItem
34785 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34786 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34788 * @param {Object} config Configuration options
34790 Roo.menu.Separator = function(config){
34791 Roo.menu.Separator.superclass.constructor.call(this, config);
34794 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34796 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34798 itemCls : "x-menu-sep",
34800 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34802 hideOnClick : false,
34805 onRender : function(li){
34806 var s = document.createElement("span");
34807 s.className = this.itemCls;
34808 s.innerHTML = " ";
34810 li.addClass("x-menu-sep-li");
34811 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34815 * Ext JS Library 1.1.1
34816 * Copyright(c) 2006-2007, Ext JS, LLC.
34818 * Originally Released Under LGPL - original licence link has changed is not relivant.
34821 * <script type="text/javascript">
34824 * @class Roo.menu.Item
34825 * @extends Roo.menu.BaseItem
34826 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34827 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34828 * activation and click handling.
34830 * Creates a new Item
34831 * @param {Object} config Configuration options
34833 Roo.menu.Item = function(config){
34834 Roo.menu.Item.superclass.constructor.call(this, config);
34836 this.menu = Roo.menu.MenuMgr.get(this.menu);
34839 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34842 * @cfg {String} text
34843 * The text to show on the menu item.
34847 * @cfg {String} HTML to render in menu
34848 * The text to show on the menu item (HTML version).
34852 * @cfg {String} icon
34853 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34857 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34859 itemCls : "x-menu-item",
34861 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34863 canActivate : true,
34865 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34868 // doc'd in BaseItem
34872 ctype: "Roo.menu.Item",
34875 onRender : function(container, position){
34876 var el = document.createElement("a");
34877 el.hideFocus = true;
34878 el.unselectable = "on";
34879 el.href = this.href || "#";
34880 if(this.hrefTarget){
34881 el.target = this.hrefTarget;
34883 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34885 var html = this.html.length ? this.html : String.format('{0}',this.text);
34887 el.innerHTML = String.format(
34888 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
34889 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
34891 Roo.menu.Item.superclass.onRender.call(this, container, position);
34895 * Sets the text to display in this menu item
34896 * @param {String} text The text to display
34897 * @param {Boolean} isHTML true to indicate text is pure html.
34899 setText : function(text, isHTML){
34907 var html = this.html.length ? this.html : String.format('{0}',this.text);
34909 this.el.update(String.format(
34910 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
34911 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34912 this.parentMenu.autoWidth();
34917 handleClick : function(e){
34918 if(!this.href){ // if no link defined, stop the event automatically
34921 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34925 activate : function(autoExpand){
34926 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34936 shouldDeactivate : function(e){
34937 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34938 if(this.menu && this.menu.isVisible()){
34939 return !this.menu.getEl().getRegion().contains(e.getPoint());
34947 deactivate : function(){
34948 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34953 expandMenu : function(autoActivate){
34954 if(!this.disabled && this.menu){
34955 clearTimeout(this.hideTimer);
34956 delete this.hideTimer;
34957 if(!this.menu.isVisible() && !this.showTimer){
34958 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34959 }else if (this.menu.isVisible() && autoActivate){
34960 this.menu.tryActivate(0, 1);
34966 deferExpand : function(autoActivate){
34967 delete this.showTimer;
34968 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34970 this.menu.tryActivate(0, 1);
34975 hideMenu : function(){
34976 clearTimeout(this.showTimer);
34977 delete this.showTimer;
34978 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34979 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
34984 deferHide : function(){
34985 delete this.hideTimer;
34990 * Ext JS Library 1.1.1
34991 * Copyright(c) 2006-2007, Ext JS, LLC.
34993 * Originally Released Under LGPL - original licence link has changed is not relivant.
34996 * <script type="text/javascript">
35000 * @class Roo.menu.CheckItem
35001 * @extends Roo.menu.Item
35002 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35004 * Creates a new CheckItem
35005 * @param {Object} config Configuration options
35007 Roo.menu.CheckItem = function(config){
35008 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35011 * @event beforecheckchange
35012 * Fires before the checked value is set, providing an opportunity to cancel if needed
35013 * @param {Roo.menu.CheckItem} this
35014 * @param {Boolean} checked The new checked value that will be set
35016 "beforecheckchange" : true,
35018 * @event checkchange
35019 * Fires after the checked value has been set
35020 * @param {Roo.menu.CheckItem} this
35021 * @param {Boolean} checked The checked value that was set
35023 "checkchange" : true
35025 if(this.checkHandler){
35026 this.on('checkchange', this.checkHandler, this.scope);
35029 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35031 * @cfg {String} group
35032 * All check items with the same group name will automatically be grouped into a single-select
35033 * radio button group (defaults to '')
35036 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35038 itemCls : "x-menu-item x-menu-check-item",
35040 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35042 groupClass : "x-menu-group-item",
35045 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35046 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35047 * initialized with checked = true will be rendered as checked.
35052 ctype: "Roo.menu.CheckItem",
35055 onRender : function(c){
35056 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35058 this.el.addClass(this.groupClass);
35060 Roo.menu.MenuMgr.registerCheckable(this);
35062 this.checked = false;
35063 this.setChecked(true, true);
35068 destroy : function(){
35070 Roo.menu.MenuMgr.unregisterCheckable(this);
35072 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35076 * Set the checked state of this item
35077 * @param {Boolean} checked The new checked value
35078 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35080 setChecked : function(state, suppressEvent){
35081 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35082 if(this.container){
35083 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35085 this.checked = state;
35086 if(suppressEvent !== true){
35087 this.fireEvent("checkchange", this, state);
35093 handleClick : function(e){
35094 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35095 this.setChecked(!this.checked);
35097 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35101 * Ext JS Library 1.1.1
35102 * Copyright(c) 2006-2007, Ext JS, LLC.
35104 * Originally Released Under LGPL - original licence link has changed is not relivant.
35107 * <script type="text/javascript">
35111 * @class Roo.menu.DateItem
35112 * @extends Roo.menu.Adapter
35113 * A menu item that wraps the {@link Roo.DatPicker} component.
35115 * Creates a new DateItem
35116 * @param {Object} config Configuration options
35118 Roo.menu.DateItem = function(config){
35119 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35120 /** The Roo.DatePicker object @type Roo.DatePicker */
35121 this.picker = this.component;
35122 this.addEvents({select: true});
35124 this.picker.on("render", function(picker){
35125 picker.getEl().swallowEvent("click");
35126 picker.container.addClass("x-menu-date-item");
35129 this.picker.on("select", this.onSelect, this);
35132 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35134 onSelect : function(picker, date){
35135 this.fireEvent("select", this, date, picker);
35136 Roo.menu.DateItem.superclass.handleClick.call(this);
35140 * Ext JS Library 1.1.1
35141 * Copyright(c) 2006-2007, Ext JS, LLC.
35143 * Originally Released Under LGPL - original licence link has changed is not relivant.
35146 * <script type="text/javascript">
35150 * @class Roo.menu.ColorItem
35151 * @extends Roo.menu.Adapter
35152 * A menu item that wraps the {@link Roo.ColorPalette} component.
35154 * Creates a new ColorItem
35155 * @param {Object} config Configuration options
35157 Roo.menu.ColorItem = function(config){
35158 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35159 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35160 this.palette = this.component;
35161 this.relayEvents(this.palette, ["select"]);
35162 if(this.selectHandler){
35163 this.on('select', this.selectHandler, this.scope);
35166 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35168 * Ext JS Library 1.1.1
35169 * Copyright(c) 2006-2007, Ext JS, LLC.
35171 * Originally Released Under LGPL - original licence link has changed is not relivant.
35174 * <script type="text/javascript">
35179 * @class Roo.menu.DateMenu
35180 * @extends Roo.menu.Menu
35181 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35183 * Creates a new DateMenu
35184 * @param {Object} config Configuration options
35186 Roo.menu.DateMenu = function(config){
35187 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35189 var di = new Roo.menu.DateItem(config);
35192 * The {@link Roo.DatePicker} instance for this DateMenu
35195 this.picker = di.picker;
35198 * @param {DatePicker} picker
35199 * @param {Date} date
35201 this.relayEvents(di, ["select"]);
35203 this.on('beforeshow', function(){
35205 this.picker.hideMonthPicker(true);
35209 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35213 * Ext JS Library 1.1.1
35214 * Copyright(c) 2006-2007, Ext JS, LLC.
35216 * Originally Released Under LGPL - original licence link has changed is not relivant.
35219 * <script type="text/javascript">
35224 * @class Roo.menu.ColorMenu
35225 * @extends Roo.menu.Menu
35226 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35228 * Creates a new ColorMenu
35229 * @param {Object} config Configuration options
35231 Roo.menu.ColorMenu = function(config){
35232 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35234 var ci = new Roo.menu.ColorItem(config);
35237 * The {@link Roo.ColorPalette} instance for this ColorMenu
35238 * @type ColorPalette
35240 this.palette = ci.palette;
35243 * @param {ColorPalette} palette
35244 * @param {String} color
35246 this.relayEvents(ci, ["select"]);
35248 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35250 * Ext JS Library 1.1.1
35251 * Copyright(c) 2006-2007, Ext JS, LLC.
35253 * Originally Released Under LGPL - original licence link has changed is not relivant.
35256 * <script type="text/javascript">
35260 * @class Roo.form.Field
35261 * @extends Roo.BoxComponent
35262 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35264 * Creates a new Field
35265 * @param {Object} config Configuration options
35267 Roo.form.Field = function(config){
35268 Roo.form.Field.superclass.constructor.call(this, config);
35271 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35273 * @cfg {String} fieldLabel Label to use when rendering a form.
35276 * @cfg {String} qtip Mouse over tip
35280 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35282 invalidClass : "x-form-invalid",
35284 * @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")
35286 invalidText : "The value in this field is invalid",
35288 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35290 focusClass : "x-form-focus",
35292 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35293 automatic validation (defaults to "keyup").
35295 validationEvent : "keyup",
35297 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35299 validateOnBlur : true,
35301 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35303 validationDelay : 250,
35305 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35306 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35308 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35310 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35312 fieldClass : "x-form-field",
35314 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35317 ----------- ----------------------------------------------------------------------
35318 qtip Display a quick tip when the user hovers over the field
35319 title Display a default browser title attribute popup
35320 under Add a block div beneath the field containing the error text
35321 side Add an error icon to the right of the field with a popup on hover
35322 [element id] Add the error text directly to the innerHTML of the specified element
35325 msgTarget : 'qtip',
35327 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35332 * @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.
35337 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35342 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35344 inputType : undefined,
35347 * @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).
35349 tabIndex : undefined,
35352 isFormField : true,
35357 * @property {Roo.Element} fieldEl
35358 * Element Containing the rendered Field (with label etc.)
35361 * @cfg {Mixed} value A value to initialize this field with.
35366 * @cfg {String} name The field's HTML name attribute.
35369 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35373 initComponent : function(){
35374 Roo.form.Field.superclass.initComponent.call(this);
35378 * Fires when this field receives input focus.
35379 * @param {Roo.form.Field} this
35384 * Fires when this field loses input focus.
35385 * @param {Roo.form.Field} this
35389 * @event specialkey
35390 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35391 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35392 * @param {Roo.form.Field} this
35393 * @param {Roo.EventObject} e The event object
35398 * Fires just before the field blurs if the field value has changed.
35399 * @param {Roo.form.Field} this
35400 * @param {Mixed} newValue The new value
35401 * @param {Mixed} oldValue The original value
35406 * Fires after the field has been marked as invalid.
35407 * @param {Roo.form.Field} this
35408 * @param {String} msg The validation message
35413 * Fires after the field has been validated with no errors.
35414 * @param {Roo.form.Field} this
35419 * Fires after the key up
35420 * @param {Roo.form.Field} this
35421 * @param {Roo.EventObject} e The event Object
35428 * Returns the name attribute of the field if available
35429 * @return {String} name The field name
35431 getName: function(){
35432 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35436 onRender : function(ct, position){
35437 Roo.form.Field.superclass.onRender.call(this, ct, position);
35439 var cfg = this.getAutoCreate();
35441 cfg.name = this.name || this.id;
35443 if(this.inputType){
35444 cfg.type = this.inputType;
35446 this.el = ct.createChild(cfg, position);
35448 var type = this.el.dom.type;
35450 if(type == 'password'){
35453 this.el.addClass('x-form-'+type);
35456 this.el.dom.readOnly = true;
35458 if(this.tabIndex !== undefined){
35459 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35462 this.el.addClass([this.fieldClass, this.cls]);
35467 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35468 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35469 * @return {Roo.form.Field} this
35471 applyTo : function(target){
35472 this.allowDomMove = false;
35473 this.el = Roo.get(target);
35474 this.render(this.el.dom.parentNode);
35479 initValue : function(){
35480 if(this.value !== undefined){
35481 this.setValue(this.value);
35482 }else if(this.el.dom.value.length > 0){
35483 this.setValue(this.el.dom.value);
35488 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35490 isDirty : function() {
35491 if(this.disabled) {
35494 return String(this.getValue()) !== String(this.originalValue);
35498 afterRender : function(){
35499 Roo.form.Field.superclass.afterRender.call(this);
35504 fireKey : function(e){
35505 //Roo.log('field ' + e.getKey());
35506 if(e.isNavKeyPress()){
35507 this.fireEvent("specialkey", this, e);
35512 * Resets the current field value to the originally loaded value and clears any validation messages
35514 reset : function(){
35515 this.setValue(this.originalValue);
35516 this.clearInvalid();
35520 initEvents : function(){
35521 // safari killled keypress - so keydown is now used..
35522 this.el.on("keydown" , this.fireKey, this);
35523 this.el.on("focus", this.onFocus, this);
35524 this.el.on("blur", this.onBlur, this);
35525 this.el.relayEvent('keyup', this);
35527 // reference to original value for reset
35528 this.originalValue = this.getValue();
35532 onFocus : function(){
35533 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35534 this.el.addClass(this.focusClass);
35536 if(!this.hasFocus){
35537 this.hasFocus = true;
35538 this.startValue = this.getValue();
35539 this.fireEvent("focus", this);
35543 beforeBlur : Roo.emptyFn,
35546 onBlur : function(){
35548 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35549 this.el.removeClass(this.focusClass);
35551 this.hasFocus = false;
35552 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35555 var v = this.getValue();
35556 if(String(v) !== String(this.startValue)){
35557 this.fireEvent('change', this, v, this.startValue);
35559 this.fireEvent("blur", this);
35563 * Returns whether or not the field value is currently valid
35564 * @param {Boolean} preventMark True to disable marking the field invalid
35565 * @return {Boolean} True if the value is valid, else false
35567 isValid : function(preventMark){
35571 var restore = this.preventMark;
35572 this.preventMark = preventMark === true;
35573 var v = this.validateValue(this.processValue(this.getRawValue()));
35574 this.preventMark = restore;
35579 * Validates the field value
35580 * @return {Boolean} True if the value is valid, else false
35582 validate : function(){
35583 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35584 this.clearInvalid();
35590 processValue : function(value){
35595 // Subclasses should provide the validation implementation by overriding this
35596 validateValue : function(value){
35601 * Mark this field as invalid
35602 * @param {String} msg The validation message
35604 markInvalid : function(msg){
35605 if(!this.rendered || this.preventMark){ // not rendered
35608 this.el.addClass(this.invalidClass);
35609 msg = msg || this.invalidText;
35610 switch(this.msgTarget){
35612 this.el.dom.qtip = msg;
35613 this.el.dom.qclass = 'x-form-invalid-tip';
35614 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35615 Roo.QuickTips.enable();
35619 this.el.dom.title = msg;
35623 var elp = this.el.findParent('.x-form-element', 5, true);
35624 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35625 this.errorEl.setWidth(elp.getWidth(true)-20);
35627 this.errorEl.update(msg);
35628 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35631 if(!this.errorIcon){
35632 var elp = this.el.findParent('.x-form-element', 5, true);
35633 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35635 this.alignErrorIcon();
35636 this.errorIcon.dom.qtip = msg;
35637 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35638 this.errorIcon.show();
35639 this.on('resize', this.alignErrorIcon, this);
35642 var t = Roo.getDom(this.msgTarget);
35644 t.style.display = this.msgDisplay;
35647 this.fireEvent('invalid', this, msg);
35651 alignErrorIcon : function(){
35652 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35656 * Clear any invalid styles/messages for this field
35658 clearInvalid : function(){
35659 if(!this.rendered || this.preventMark){ // not rendered
35662 this.el.removeClass(this.invalidClass);
35663 switch(this.msgTarget){
35665 this.el.dom.qtip = '';
35668 this.el.dom.title = '';
35672 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35676 if(this.errorIcon){
35677 this.errorIcon.dom.qtip = '';
35678 this.errorIcon.hide();
35679 this.un('resize', this.alignErrorIcon, this);
35683 var t = Roo.getDom(this.msgTarget);
35685 t.style.display = 'none';
35688 this.fireEvent('valid', this);
35692 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35693 * @return {Mixed} value The field value
35695 getRawValue : function(){
35696 var v = this.el.getValue();
35697 if(v === this.emptyText){
35704 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35705 * @return {Mixed} value The field value
35707 getValue : function(){
35708 var v = this.el.getValue();
35709 if(v === this.emptyText || v === undefined){
35716 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35717 * @param {Mixed} value The value to set
35719 setRawValue : function(v){
35720 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35724 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35725 * @param {Mixed} value The value to set
35727 setValue : function(v){
35730 this.el.dom.value = (v === null || v === undefined ? '' : v);
35735 adjustSize : function(w, h){
35736 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35737 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35741 adjustWidth : function(tag, w){
35742 tag = tag.toLowerCase();
35743 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35744 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35745 if(tag == 'input'){
35748 if(tag = 'textarea'){
35751 }else if(Roo.isOpera){
35752 if(tag == 'input'){
35755 if(tag = 'textarea'){
35765 // anything other than normal should be considered experimental
35766 Roo.form.Field.msgFx = {
35768 show: function(msgEl, f){
35769 msgEl.setDisplayed('block');
35772 hide : function(msgEl, f){
35773 msgEl.setDisplayed(false).update('');
35778 show: function(msgEl, f){
35779 msgEl.slideIn('t', {stopFx:true});
35782 hide : function(msgEl, f){
35783 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35788 show: function(msgEl, f){
35789 msgEl.fixDisplay();
35790 msgEl.alignTo(f.el, 'tl-tr');
35791 msgEl.slideIn('l', {stopFx:true});
35794 hide : function(msgEl, f){
35795 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35800 * Ext JS Library 1.1.1
35801 * Copyright(c) 2006-2007, Ext JS, LLC.
35803 * Originally Released Under LGPL - original licence link has changed is not relivant.
35806 * <script type="text/javascript">
35811 * @class Roo.form.TextField
35812 * @extends Roo.form.Field
35813 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35814 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35816 * Creates a new TextField
35817 * @param {Object} config Configuration options
35819 Roo.form.TextField = function(config){
35820 Roo.form.TextField.superclass.constructor.call(this, config);
35824 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35825 * according to the default logic, but this event provides a hook for the developer to apply additional
35826 * logic at runtime to resize the field if needed.
35827 * @param {Roo.form.Field} this This text field
35828 * @param {Number} width The new field width
35834 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35836 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35840 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35844 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35848 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35852 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35856 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35858 disableKeyFilter : false,
35860 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35864 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35868 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35870 maxLength : Number.MAX_VALUE,
35872 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35874 minLengthText : "The minimum length for this field is {0}",
35876 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35878 maxLengthText : "The maximum length for this field is {0}",
35880 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35882 selectOnFocus : false,
35884 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35886 blankText : "This field is required",
35888 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35889 * If available, this function will be called only after the basic validators all return true, and will be passed the
35890 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35894 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35895 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35896 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35900 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35904 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35908 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35909 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35911 emptyClass : 'x-form-empty-field',
35914 initEvents : function(){
35915 Roo.form.TextField.superclass.initEvents.call(this);
35916 if(this.validationEvent == 'keyup'){
35917 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35918 this.el.on('keyup', this.filterValidation, this);
35920 else if(this.validationEvent !== false){
35921 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35923 if(this.selectOnFocus || this.emptyText){
35924 this.on("focus", this.preFocus, this);
35925 if(this.emptyText){
35926 this.on('blur', this.postBlur, this);
35927 this.applyEmptyText();
35930 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35931 this.el.on("keypress", this.filterKeys, this);
35934 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35935 this.el.on("click", this.autoSize, this);
35939 processValue : function(value){
35940 if(this.stripCharsRe){
35941 var newValue = value.replace(this.stripCharsRe, '');
35942 if(newValue !== value){
35943 this.setRawValue(newValue);
35950 filterValidation : function(e){
35951 if(!e.isNavKeyPress()){
35952 this.validationTask.delay(this.validationDelay);
35957 onKeyUp : function(e){
35958 if(!e.isNavKeyPress()){
35964 * Resets the current field value to the originally-loaded value and clears any validation messages.
35965 * Also adds emptyText and emptyClass if the original value was blank.
35967 reset : function(){
35968 Roo.form.TextField.superclass.reset.call(this);
35969 this.applyEmptyText();
35972 applyEmptyText : function(){
35973 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35974 this.setRawValue(this.emptyText);
35975 this.el.addClass(this.emptyClass);
35980 preFocus : function(){
35981 if(this.emptyText){
35982 if(this.el.dom.value == this.emptyText){
35983 this.setRawValue('');
35985 this.el.removeClass(this.emptyClass);
35987 if(this.selectOnFocus){
35988 this.el.dom.select();
35993 postBlur : function(){
35994 this.applyEmptyText();
35998 filterKeys : function(e){
35999 var k = e.getKey();
36000 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36003 var c = e.getCharCode(), cc = String.fromCharCode(c);
36004 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36007 if(!this.maskRe.test(cc)){
36012 setValue : function(v){
36013 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
36014 this.el.removeClass(this.emptyClass);
36016 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36017 this.applyEmptyText();
36022 * Validates a value according to the field's validation rules and marks the field as invalid
36023 * if the validation fails
36024 * @param {Mixed} value The value to validate
36025 * @return {Boolean} True if the value is valid, else false
36027 validateValue : function(value){
36028 if(value.length < 1 || value === this.emptyText){ // if it's blank
36029 if(this.allowBlank){
36030 this.clearInvalid();
36033 this.markInvalid(this.blankText);
36037 if(value.length < this.minLength){
36038 this.markInvalid(String.format(this.minLengthText, this.minLength));
36041 if(value.length > this.maxLength){
36042 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36046 var vt = Roo.form.VTypes;
36047 if(!vt[this.vtype](value, this)){
36048 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36052 if(typeof this.validator == "function"){
36053 var msg = this.validator(value);
36055 this.markInvalid(msg);
36059 if(this.regex && !this.regex.test(value)){
36060 this.markInvalid(this.regexText);
36067 * Selects text in this field
36068 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36069 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36071 selectText : function(start, end){
36072 var v = this.getRawValue();
36074 start = start === undefined ? 0 : start;
36075 end = end === undefined ? v.length : end;
36076 var d = this.el.dom;
36077 if(d.setSelectionRange){
36078 d.setSelectionRange(start, end);
36079 }else if(d.createTextRange){
36080 var range = d.createTextRange();
36081 range.moveStart("character", start);
36082 range.moveEnd("character", v.length-end);
36089 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36090 * This only takes effect if grow = true, and fires the autosize event.
36092 autoSize : function(){
36093 if(!this.grow || !this.rendered){
36097 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36100 var v = el.dom.value;
36101 var d = document.createElement('div');
36102 d.appendChild(document.createTextNode(v));
36106 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36107 this.el.setWidth(w);
36108 this.fireEvent("autosize", this, w);
36112 * Ext JS Library 1.1.1
36113 * Copyright(c) 2006-2007, Ext JS, LLC.
36115 * Originally Released Under LGPL - original licence link has changed is not relivant.
36118 * <script type="text/javascript">
36122 * @class Roo.form.Hidden
36123 * @extends Roo.form.TextField
36124 * Simple Hidden element used on forms
36126 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36129 * Creates a new Hidden form element.
36130 * @param {Object} config Configuration options
36135 // easy hidden field...
36136 Roo.form.Hidden = function(config){
36137 Roo.form.Hidden.superclass.constructor.call(this, config);
36140 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36142 inputType: 'hidden',
36145 labelSeparator: '',
36147 itemCls : 'x-form-item-display-none'
36155 * Ext JS Library 1.1.1
36156 * Copyright(c) 2006-2007, Ext JS, LLC.
36158 * Originally Released Under LGPL - original licence link has changed is not relivant.
36161 * <script type="text/javascript">
36165 * @class Roo.form.TriggerField
36166 * @extends Roo.form.TextField
36167 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36168 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36169 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36170 * for which you can provide a custom implementation. For example:
36172 var trigger = new Roo.form.TriggerField();
36173 trigger.onTriggerClick = myTriggerFn;
36174 trigger.applyTo('my-field');
36177 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36178 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36179 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36180 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36182 * Create a new TriggerField.
36183 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36184 * to the base TextField)
36186 Roo.form.TriggerField = function(config){
36187 this.mimicing = false;
36188 Roo.form.TriggerField.superclass.constructor.call(this, config);
36191 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36193 * @cfg {String} triggerClass A CSS class to apply to the trigger
36196 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36197 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36199 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36201 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36205 /** @cfg {Boolean} grow @hide */
36206 /** @cfg {Number} growMin @hide */
36207 /** @cfg {Number} growMax @hide */
36213 autoSize: Roo.emptyFn,
36217 deferHeight : true,
36220 actionMode : 'wrap',
36222 onResize : function(w, h){
36223 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36224 if(typeof w == 'number'){
36225 var x = w - this.trigger.getWidth();
36226 this.el.setWidth(this.adjustWidth('input', x));
36227 this.trigger.setStyle('left', x+'px');
36232 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36235 getResizeEl : function(){
36240 getPositionEl : function(){
36245 alignErrorIcon : function(){
36246 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36250 onRender : function(ct, position){
36251 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36252 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36253 this.trigger = this.wrap.createChild(this.triggerConfig ||
36254 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36255 if(this.hideTrigger){
36256 this.trigger.setDisplayed(false);
36258 this.initTrigger();
36260 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36265 initTrigger : function(){
36266 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36267 this.trigger.addClassOnOver('x-form-trigger-over');
36268 this.trigger.addClassOnClick('x-form-trigger-click');
36272 onDestroy : function(){
36274 this.trigger.removeAllListeners();
36275 this.trigger.remove();
36278 this.wrap.remove();
36280 Roo.form.TriggerField.superclass.onDestroy.call(this);
36284 onFocus : function(){
36285 Roo.form.TriggerField.superclass.onFocus.call(this);
36286 if(!this.mimicing){
36287 this.wrap.addClass('x-trigger-wrap-focus');
36288 this.mimicing = true;
36289 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36290 if(this.monitorTab){
36291 this.el.on("keydown", this.checkTab, this);
36297 checkTab : function(e){
36298 if(e.getKey() == e.TAB){
36299 this.triggerBlur();
36304 onBlur : function(){
36309 mimicBlur : function(e, t){
36310 if(!this.wrap.contains(t) && this.validateBlur()){
36311 this.triggerBlur();
36316 triggerBlur : function(){
36317 this.mimicing = false;
36318 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36319 if(this.monitorTab){
36320 this.el.un("keydown", this.checkTab, this);
36322 this.wrap.removeClass('x-trigger-wrap-focus');
36323 Roo.form.TriggerField.superclass.onBlur.call(this);
36327 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36328 validateBlur : function(e, t){
36333 onDisable : function(){
36334 Roo.form.TriggerField.superclass.onDisable.call(this);
36336 this.wrap.addClass('x-item-disabled');
36341 onEnable : function(){
36342 Roo.form.TriggerField.superclass.onEnable.call(this);
36344 this.wrap.removeClass('x-item-disabled');
36349 onShow : function(){
36350 var ae = this.getActionEl();
36353 ae.dom.style.display = '';
36354 ae.dom.style.visibility = 'visible';
36360 onHide : function(){
36361 var ae = this.getActionEl();
36362 ae.dom.style.display = 'none';
36366 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36367 * by an implementing function.
36369 * @param {EventObject} e
36371 onTriggerClick : Roo.emptyFn
36374 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36375 // to be extended by an implementing class. For an example of implementing this class, see the custom
36376 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36377 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36378 initComponent : function(){
36379 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36381 this.triggerConfig = {
36382 tag:'span', cls:'x-form-twin-triggers', cn:[
36383 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36384 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36388 getTrigger : function(index){
36389 return this.triggers[index];
36392 initTrigger : function(){
36393 var ts = this.trigger.select('.x-form-trigger', true);
36394 this.wrap.setStyle('overflow', 'hidden');
36395 var triggerField = this;
36396 ts.each(function(t, all, index){
36397 t.hide = function(){
36398 var w = triggerField.wrap.getWidth();
36399 this.dom.style.display = 'none';
36400 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36402 t.show = function(){
36403 var w = triggerField.wrap.getWidth();
36404 this.dom.style.display = '';
36405 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36407 var triggerIndex = 'Trigger'+(index+1);
36409 if(this['hide'+triggerIndex]){
36410 t.dom.style.display = 'none';
36412 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36413 t.addClassOnOver('x-form-trigger-over');
36414 t.addClassOnClick('x-form-trigger-click');
36416 this.triggers = ts.elements;
36419 onTrigger1Click : Roo.emptyFn,
36420 onTrigger2Click : Roo.emptyFn
36423 * Ext JS Library 1.1.1
36424 * Copyright(c) 2006-2007, Ext JS, LLC.
36426 * Originally Released Under LGPL - original licence link has changed is not relivant.
36429 * <script type="text/javascript">
36433 * @class Roo.form.TextArea
36434 * @extends Roo.form.TextField
36435 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36436 * support for auto-sizing.
36438 * Creates a new TextArea
36439 * @param {Object} config Configuration options
36441 Roo.form.TextArea = function(config){
36442 Roo.form.TextArea.superclass.constructor.call(this, config);
36443 // these are provided exchanges for backwards compat
36444 // minHeight/maxHeight were replaced by growMin/growMax to be
36445 // compatible with TextField growing config values
36446 if(this.minHeight !== undefined){
36447 this.growMin = this.minHeight;
36449 if(this.maxHeight !== undefined){
36450 this.growMax = this.maxHeight;
36454 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36456 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36460 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36464 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36465 * in the field (equivalent to setting overflow: hidden, defaults to false)
36467 preventScrollbars: false,
36469 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36470 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36474 onRender : function(ct, position){
36476 this.defaultAutoCreate = {
36478 style:"width:300px;height:60px;",
36479 autocomplete: "off"
36482 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36484 this.textSizeEl = Roo.DomHelper.append(document.body, {
36485 tag: "pre", cls: "x-form-grow-sizer"
36487 if(this.preventScrollbars){
36488 this.el.setStyle("overflow", "hidden");
36490 this.el.setHeight(this.growMin);
36494 onDestroy : function(){
36495 if(this.textSizeEl){
36496 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36498 Roo.form.TextArea.superclass.onDestroy.call(this);
36502 onKeyUp : function(e){
36503 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36509 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36510 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36512 autoSize : function(){
36513 if(!this.grow || !this.textSizeEl){
36517 var v = el.dom.value;
36518 var ts = this.textSizeEl;
36521 ts.appendChild(document.createTextNode(v));
36524 Roo.fly(ts).setWidth(this.el.getWidth());
36526 v = "  ";
36529 v = v.replace(/\n/g, '<p> </p>');
36531 v += " \n ";
36534 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36535 if(h != this.lastHeight){
36536 this.lastHeight = h;
36537 this.el.setHeight(h);
36538 this.fireEvent("autosize", this, h);
36543 * Ext JS Library 1.1.1
36544 * Copyright(c) 2006-2007, Ext JS, LLC.
36546 * Originally Released Under LGPL - original licence link has changed is not relivant.
36549 * <script type="text/javascript">
36554 * @class Roo.form.NumberField
36555 * @extends Roo.form.TextField
36556 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36558 * Creates a new NumberField
36559 * @param {Object} config Configuration options
36561 Roo.form.NumberField = function(config){
36562 Roo.form.NumberField.superclass.constructor.call(this, config);
36565 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36567 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36569 fieldClass: "x-form-field x-form-num-field",
36571 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36573 allowDecimals : true,
36575 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36577 decimalSeparator : ".",
36579 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36581 decimalPrecision : 2,
36583 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36585 allowNegative : true,
36587 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36589 minValue : Number.NEGATIVE_INFINITY,
36591 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36593 maxValue : Number.MAX_VALUE,
36595 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36597 minText : "The minimum value for this field is {0}",
36599 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36601 maxText : "The maximum value for this field is {0}",
36603 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36604 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36606 nanText : "{0} is not a valid number",
36609 initEvents : function(){
36610 Roo.form.NumberField.superclass.initEvents.call(this);
36611 var allowed = "0123456789";
36612 if(this.allowDecimals){
36613 allowed += this.decimalSeparator;
36615 if(this.allowNegative){
36618 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36619 var keyPress = function(e){
36620 var k = e.getKey();
36621 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36624 var c = e.getCharCode();
36625 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36629 this.el.on("keypress", keyPress, this);
36633 validateValue : function(value){
36634 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36637 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36640 var num = this.parseValue(value);
36642 this.markInvalid(String.format(this.nanText, value));
36645 if(num < this.minValue){
36646 this.markInvalid(String.format(this.minText, this.minValue));
36649 if(num > this.maxValue){
36650 this.markInvalid(String.format(this.maxText, this.maxValue));
36656 getValue : function(){
36657 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36661 parseValue : function(value){
36662 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36663 return isNaN(value) ? '' : value;
36667 fixPrecision : function(value){
36668 var nan = isNaN(value);
36669 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36670 return nan ? '' : value;
36672 return parseFloat(value).toFixed(this.decimalPrecision);
36675 setValue : function(v){
36676 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36680 decimalPrecisionFcn : function(v){
36681 return Math.floor(v);
36684 beforeBlur : function(){
36685 var v = this.parseValue(this.getRawValue());
36687 this.setValue(this.fixPrecision(v));
36692 * Ext JS Library 1.1.1
36693 * Copyright(c) 2006-2007, Ext JS, LLC.
36695 * Originally Released Under LGPL - original licence link has changed is not relivant.
36698 * <script type="text/javascript">
36702 * @class Roo.form.DateField
36703 * @extends Roo.form.TriggerField
36704 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36706 * Create a new DateField
36707 * @param {Object} config
36709 Roo.form.DateField = function(config){
36710 Roo.form.DateField.superclass.constructor.call(this, config);
36716 * Fires when a date is selected
36717 * @param {Roo.form.DateField} combo This combo box
36718 * @param {Date} date The date selected
36725 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36726 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36727 this.ddMatch = null;
36728 if(this.disabledDates){
36729 var dd = this.disabledDates;
36731 for(var i = 0; i < dd.length; i++){
36733 if(i != dd.length-1) re += "|";
36735 this.ddMatch = new RegExp(re + ")");
36739 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36741 * @cfg {String} format
36742 * The default date format string which can be overriden for localization support. The format must be
36743 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36747 * @cfg {String} altFormats
36748 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36749 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36751 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36753 * @cfg {Array} disabledDays
36754 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36756 disabledDays : null,
36758 * @cfg {String} disabledDaysText
36759 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36761 disabledDaysText : "Disabled",
36763 * @cfg {Array} disabledDates
36764 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36765 * expression so they are very powerful. Some examples:
36767 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36768 * <li>["03/08", "09/16"] would disable those days for every year</li>
36769 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36770 * <li>["03/../2006"] would disable every day in March 2006</li>
36771 * <li>["^03"] would disable every day in every March</li>
36773 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36774 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36776 disabledDates : null,
36778 * @cfg {String} disabledDatesText
36779 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36781 disabledDatesText : "Disabled",
36783 * @cfg {Date/String} minValue
36784 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36785 * valid format (defaults to null).
36789 * @cfg {Date/String} maxValue
36790 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36791 * valid format (defaults to null).
36795 * @cfg {String} minText
36796 * The error text to display when the date in the cell is before minValue (defaults to
36797 * 'The date in this field must be after {minValue}').
36799 minText : "The date in this field must be equal to or after {0}",
36801 * @cfg {String} maxText
36802 * The error text to display when the date in the cell is after maxValue (defaults to
36803 * 'The date in this field must be before {maxValue}').
36805 maxText : "The date in this field must be equal to or before {0}",
36807 * @cfg {String} invalidText
36808 * The error text to display when the date in the field is invalid (defaults to
36809 * '{value} is not a valid date - it must be in the format {format}').
36811 invalidText : "{0} is not a valid date - it must be in the format {1}",
36813 * @cfg {String} triggerClass
36814 * An additional CSS class used to style the trigger button. The trigger will always get the
36815 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36816 * which displays a calendar icon).
36818 triggerClass : 'x-form-date-trigger',
36822 * @cfg {bool} useIso
36823 * if enabled, then the date field will use a hidden field to store the
36824 * real value as iso formated date. default (false)
36828 * @cfg {String/Object} autoCreate
36829 * A DomHelper element spec, or true for a default element spec (defaults to
36830 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36833 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36836 hiddenField: false,
36838 onRender : function(ct, position)
36840 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36842 this.el.dom.removeAttribute('name');
36843 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36845 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36846 // prevent input submission
36847 this.hiddenName = this.name;
36854 validateValue : function(value)
36856 value = this.formatDate(value);
36857 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36860 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36863 var svalue = value;
36864 value = this.parseDate(value);
36866 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36869 var time = value.getTime();
36870 if(this.minValue && time < this.minValue.getTime()){
36871 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36874 if(this.maxValue && time > this.maxValue.getTime()){
36875 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36878 if(this.disabledDays){
36879 var day = value.getDay();
36880 for(var i = 0; i < this.disabledDays.length; i++) {
36881 if(day === this.disabledDays[i]){
36882 this.markInvalid(this.disabledDaysText);
36887 var fvalue = this.formatDate(value);
36888 if(this.ddMatch && this.ddMatch.test(fvalue)){
36889 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36896 // Provides logic to override the default TriggerField.validateBlur which just returns true
36897 validateBlur : function(){
36898 return !this.menu || !this.menu.isVisible();
36902 * Returns the current date value of the date field.
36903 * @return {Date} The date value
36905 getValue : function(){
36907 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36911 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36912 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36913 * (the default format used is "m/d/y").
36916 //All of these calls set the same date value (May 4, 2006)
36918 //Pass a date object:
36919 var dt = new Date('5/4/06');
36920 dateField.setValue(dt);
36922 //Pass a date string (default format):
36923 dateField.setValue('5/4/06');
36925 //Pass a date string (custom format):
36926 dateField.format = 'Y-m-d';
36927 dateField.setValue('2006-5-4');
36929 * @param {String/Date} date The date or valid date string
36931 setValue : function(date){
36932 if (this.hiddenField) {
36933 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36935 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36939 parseDate : function(value){
36940 if(!value || value instanceof Date){
36943 var v = Date.parseDate(value, this.format);
36944 if(!v && this.altFormats){
36945 if(!this.altFormatsArray){
36946 this.altFormatsArray = this.altFormats.split("|");
36948 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36949 v = Date.parseDate(value, this.altFormatsArray[i]);
36956 formatDate : function(date, fmt){
36957 return (!date || !(date instanceof Date)) ?
36958 date : date.dateFormat(fmt || this.format);
36963 select: function(m, d){
36965 this.fireEvent('select', this, d);
36967 show : function(){ // retain focus styling
36971 this.focus.defer(10, this);
36972 var ml = this.menuListeners;
36973 this.menu.un("select", ml.select, this);
36974 this.menu.un("show", ml.show, this);
36975 this.menu.un("hide", ml.hide, this);
36980 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
36981 onTriggerClick : function(){
36985 if(this.menu == null){
36986 this.menu = new Roo.menu.DateMenu();
36988 Roo.apply(this.menu.picker, {
36989 showClear: this.allowBlank,
36990 minDate : this.minValue,
36991 maxDate : this.maxValue,
36992 disabledDatesRE : this.ddMatch,
36993 disabledDatesText : this.disabledDatesText,
36994 disabledDays : this.disabledDays,
36995 disabledDaysText : this.disabledDaysText,
36996 format : this.format,
36997 minText : String.format(this.minText, this.formatDate(this.minValue)),
36998 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37000 this.menu.on(Roo.apply({}, this.menuListeners, {
37003 this.menu.picker.setValue(this.getValue() || new Date());
37004 this.menu.show(this.el, "tl-bl?");
37007 beforeBlur : function(){
37008 var v = this.parseDate(this.getRawValue());
37014 /** @cfg {Boolean} grow @hide */
37015 /** @cfg {Number} growMin @hide */
37016 /** @cfg {Number} growMax @hide */
37023 * Ext JS Library 1.1.1
37024 * Copyright(c) 2006-2007, Ext JS, LLC.
37026 * Originally Released Under LGPL - original licence link has changed is not relivant.
37029 * <script type="text/javascript">
37034 * @class Roo.form.ComboBox
37035 * @extends Roo.form.TriggerField
37036 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
37038 * Create a new ComboBox.
37039 * @param {Object} config Configuration options
37041 Roo.form.ComboBox = function(config){
37042 Roo.form.ComboBox.superclass.constructor.call(this, config);
37046 * Fires when the dropdown list is expanded
37047 * @param {Roo.form.ComboBox} combo This combo box
37052 * Fires when the dropdown list is collapsed
37053 * @param {Roo.form.ComboBox} combo This combo box
37057 * @event beforeselect
37058 * Fires before a list item is selected. Return false to cancel the selection.
37059 * @param {Roo.form.ComboBox} combo This combo box
37060 * @param {Roo.data.Record} record The data record returned from the underlying store
37061 * @param {Number} index The index of the selected item in the dropdown list
37063 'beforeselect' : true,
37066 * Fires when a list item is selected
37067 * @param {Roo.form.ComboBox} combo This combo box
37068 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37069 * @param {Number} index The index of the selected item in the dropdown list
37073 * @event beforequery
37074 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37075 * The event object passed has these properties:
37076 * @param {Roo.form.ComboBox} combo This combo box
37077 * @param {String} query The query
37078 * @param {Boolean} forceAll true to force "all" query
37079 * @param {Boolean} cancel true to cancel the query
37080 * @param {Object} e The query event object
37082 'beforequery': true,
37085 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37086 * @param {Roo.form.ComboBox} combo This combo box
37091 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37092 * @param {Roo.form.ComboBox} combo This combo box
37093 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37099 if(this.transform){
37100 this.allowDomMove = false;
37101 var s = Roo.getDom(this.transform);
37102 if(!this.hiddenName){
37103 this.hiddenName = s.name;
37106 this.mode = 'local';
37107 var d = [], opts = s.options;
37108 for(var i = 0, len = opts.length;i < len; i++){
37110 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37112 this.value = value;
37114 d.push([value, o.text]);
37116 this.store = new Roo.data.SimpleStore({
37118 fields: ['value', 'text'],
37121 this.valueField = 'value';
37122 this.displayField = 'text';
37124 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37125 if(!this.lazyRender){
37126 this.target = true;
37127 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37128 s.parentNode.removeChild(s); // remove it
37129 this.render(this.el.parentNode);
37131 s.parentNode.removeChild(s); // remove it
37136 this.store = Roo.factory(this.store, Roo.data);
37139 this.selectedIndex = -1;
37140 if(this.mode == 'local'){
37141 if(config.queryDelay === undefined){
37142 this.queryDelay = 10;
37144 if(config.minChars === undefined){
37150 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37152 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37155 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37156 * rendering into an Roo.Editor, defaults to false)
37159 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37160 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37163 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37166 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37167 * the dropdown list (defaults to undefined, with no header element)
37171 * @cfg {String/Roo.Template} tpl The template to use to render the output
37175 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37177 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37179 listWidth: undefined,
37181 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37182 * mode = 'remote' or 'text' if mode = 'local')
37184 displayField: undefined,
37186 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37187 * mode = 'remote' or 'value' if mode = 'local').
37188 * Note: use of a valueField requires the user make a selection
37189 * in order for a value to be mapped.
37191 valueField: undefined,
37193 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37194 * field's data value (defaults to the underlying DOM element's name)
37196 hiddenName: undefined,
37198 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37202 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37204 selectedClass: 'x-combo-selected',
37206 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37207 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37208 * which displays a downward arrow icon).
37210 triggerClass : 'x-form-arrow-trigger',
37212 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37216 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37217 * anchor positions (defaults to 'tl-bl')
37219 listAlign: 'tl-bl?',
37221 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37225 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37226 * query specified by the allQuery config option (defaults to 'query')
37228 triggerAction: 'query',
37230 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37231 * (defaults to 4, does not apply if editable = false)
37235 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37236 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37240 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37241 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37245 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37246 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37250 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37251 * when editable = true (defaults to false)
37253 selectOnFocus:false,
37255 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37257 queryParam: 'query',
37259 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37260 * when mode = 'remote' (defaults to 'Loading...')
37262 loadingText: 'Loading...',
37264 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37268 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37272 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37273 * traditional select (defaults to true)
37277 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37281 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37285 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37286 * listWidth has a higher value)
37290 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37291 * allow the user to set arbitrary text into the field (defaults to false)
37293 forceSelection:false,
37295 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37296 * if typeAhead = true (defaults to 250)
37298 typeAheadDelay : 250,
37300 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37301 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37303 valueNotFoundText : undefined,
37305 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37307 blockFocus : false,
37310 * @cfg {Boolean} disableClear Disable showing of clear button.
37312 disableClear : false,
37314 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37316 alwaysQuery : false,
37324 onRender : function(ct, position){
37325 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37326 if(this.hiddenName){
37327 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37329 this.hiddenField.value =
37330 this.hiddenValue !== undefined ? this.hiddenValue :
37331 this.value !== undefined ? this.value : '';
37333 // prevent input submission
37334 this.el.dom.removeAttribute('name');
37337 this.el.dom.setAttribute('autocomplete', 'off');
37340 var cls = 'x-combo-list';
37342 this.list = new Roo.Layer({
37343 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37346 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37347 this.list.setWidth(lw);
37348 this.list.swallowEvent('mousewheel');
37349 this.assetHeight = 0;
37352 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37353 this.assetHeight += this.header.getHeight();
37356 this.innerList = this.list.createChild({cls:cls+'-inner'});
37357 this.innerList.on('mouseover', this.onViewOver, this);
37358 this.innerList.on('mousemove', this.onViewMove, this);
37359 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37361 if(this.allowBlank && !this.pageSize && !this.disableClear){
37362 this.footer = this.list.createChild({cls:cls+'-ft'});
37363 this.pageTb = new Roo.Toolbar(this.footer);
37367 this.footer = this.list.createChild({cls:cls+'-ft'});
37368 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37369 {pageSize: this.pageSize});
37373 if (this.pageTb && this.allowBlank && !this.disableClear) {
37375 this.pageTb.add(new Roo.Toolbar.Fill(), {
37376 cls: 'x-btn-icon x-btn-clear',
37378 handler: function()
37381 _this.clearValue();
37382 _this.onSelect(false, -1);
37387 this.assetHeight += this.footer.getHeight();
37392 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37395 this.view = new Roo.View(this.innerList, this.tpl, {
37396 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37399 this.view.on('click', this.onViewClick, this);
37401 this.store.on('beforeload', this.onBeforeLoad, this);
37402 this.store.on('load', this.onLoad, this);
37403 this.store.on('loadexception', this.collapse, this);
37405 if(this.resizable){
37406 this.resizer = new Roo.Resizable(this.list, {
37407 pinned:true, handles:'se'
37409 this.resizer.on('resize', function(r, w, h){
37410 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37411 this.listWidth = w;
37412 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37413 this.restrictHeight();
37415 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37417 if(!this.editable){
37418 this.editable = true;
37419 this.setEditable(false);
37423 if (typeof(this.events.add.listeners) != 'undefined') {
37425 this.addicon = this.wrap.createChild(
37426 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37428 this.addicon.on('click', function(e) {
37429 this.fireEvent('add', this);
37432 if (typeof(this.events.edit.listeners) != 'undefined') {
37434 this.editicon = this.wrap.createChild(
37435 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37436 if (this.addicon) {
37437 this.editicon.setStyle('margin-left', '40px');
37439 this.editicon.on('click', function(e) {
37441 // we fire even if inothing is selected..
37442 this.fireEvent('edit', this, this.lastData );
37452 initEvents : function(){
37453 Roo.form.ComboBox.superclass.initEvents.call(this);
37455 this.keyNav = new Roo.KeyNav(this.el, {
37456 "up" : function(e){
37457 this.inKeyMode = true;
37461 "down" : function(e){
37462 if(!this.isExpanded()){
37463 this.onTriggerClick();
37465 this.inKeyMode = true;
37470 "enter" : function(e){
37471 this.onViewClick();
37475 "esc" : function(e){
37479 "tab" : function(e){
37480 this.onViewClick(false);
37486 doRelay : function(foo, bar, hname){
37487 if(hname == 'down' || this.scope.isExpanded()){
37488 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37495 this.queryDelay = Math.max(this.queryDelay || 10,
37496 this.mode == 'local' ? 10 : 250);
37497 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37498 if(this.typeAhead){
37499 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37501 if(this.editable !== false){
37502 this.el.on("keyup", this.onKeyUp, this);
37504 if(this.forceSelection){
37505 this.on('blur', this.doForce, this);
37509 onDestroy : function(){
37511 this.view.setStore(null);
37512 this.view.el.removeAllListeners();
37513 this.view.el.remove();
37514 this.view.purgeListeners();
37517 this.list.destroy();
37520 this.store.un('beforeload', this.onBeforeLoad, this);
37521 this.store.un('load', this.onLoad, this);
37522 this.store.un('loadexception', this.collapse, this);
37524 Roo.form.ComboBox.superclass.onDestroy.call(this);
37528 fireKey : function(e){
37529 if(e.isNavKeyPress() && !this.list.isVisible()){
37530 this.fireEvent("specialkey", this, e);
37535 onResize: function(w, h){
37536 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37538 if(typeof w != 'number'){
37539 // we do not handle it!?!?
37542 var tw = this.trigger.getWidth();
37543 tw += this.addicon ? this.addicon.getWidth() : 0;
37544 tw += this.editicon ? this.editicon.getWidth() : 0;
37546 this.el.setWidth( this.adjustWidth('input', x));
37548 this.trigger.setStyle('left', x+'px');
37550 if(this.list && this.listWidth === undefined){
37551 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37552 this.list.setWidth(lw);
37553 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37561 * Allow or prevent the user from directly editing the field text. If false is passed,
37562 * the user will only be able to select from the items defined in the dropdown list. This method
37563 * is the runtime equivalent of setting the 'editable' config option at config time.
37564 * @param {Boolean} value True to allow the user to directly edit the field text
37566 setEditable : function(value){
37567 if(value == this.editable){
37570 this.editable = value;
37572 this.el.dom.setAttribute('readOnly', true);
37573 this.el.on('mousedown', this.onTriggerClick, this);
37574 this.el.addClass('x-combo-noedit');
37576 this.el.dom.setAttribute('readOnly', false);
37577 this.el.un('mousedown', this.onTriggerClick, this);
37578 this.el.removeClass('x-combo-noedit');
37583 onBeforeLoad : function(){
37584 if(!this.hasFocus){
37587 this.innerList.update(this.loadingText ?
37588 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37589 this.restrictHeight();
37590 this.selectedIndex = -1;
37594 onLoad : function(){
37595 if(!this.hasFocus){
37598 if(this.store.getCount() > 0){
37600 this.restrictHeight();
37601 if(this.lastQuery == this.allQuery){
37603 this.el.dom.select();
37605 if(!this.selectByValue(this.value, true)){
37606 this.select(0, true);
37610 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37611 this.taTask.delay(this.typeAheadDelay);
37615 this.onEmptyResults();
37621 onTypeAhead : function(){
37622 if(this.store.getCount() > 0){
37623 var r = this.store.getAt(0);
37624 var newValue = r.data[this.displayField];
37625 var len = newValue.length;
37626 var selStart = this.getRawValue().length;
37627 if(selStart != len){
37628 this.setRawValue(newValue);
37629 this.selectText(selStart, newValue.length);
37635 onSelect : function(record, index){
37636 if(this.fireEvent('beforeselect', this, record, index) !== false){
37637 this.setFromData(index > -1 ? record.data : false);
37639 this.fireEvent('select', this, record, index);
37644 * Returns the currently selected field value or empty string if no value is set.
37645 * @return {String} value The selected value
37647 getValue : function(){
37648 if(this.valueField){
37649 return typeof this.value != 'undefined' ? this.value : '';
37651 return Roo.form.ComboBox.superclass.getValue.call(this);
37656 * Clears any text/value currently set in the field
37658 clearValue : function(){
37659 if(this.hiddenField){
37660 this.hiddenField.value = '';
37663 this.setRawValue('');
37664 this.lastSelectionText = '';
37665 this.applyEmptyText();
37669 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37670 * will be displayed in the field. If the value does not match the data value of an existing item,
37671 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37672 * Otherwise the field will be blank (although the value will still be set).
37673 * @param {String} value The value to match
37675 setValue : function(v){
37677 if(this.valueField){
37678 var r = this.findRecord(this.valueField, v);
37680 text = r.data[this.displayField];
37681 }else if(this.valueNotFoundText !== undefined){
37682 text = this.valueNotFoundText;
37685 this.lastSelectionText = text;
37686 if(this.hiddenField){
37687 this.hiddenField.value = v;
37689 Roo.form.ComboBox.superclass.setValue.call(this, text);
37693 * @property {Object} the last set data for the element
37698 * Sets the value of the field based on a object which is related to the record format for the store.
37699 * @param {Object} value the value to set as. or false on reset?
37701 setFromData : function(o){
37702 var dv = ''; // display value
37703 var vv = ''; // value value..
37705 if (this.displayField) {
37706 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37708 // this is an error condition!!!
37709 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
37712 if(this.valueField){
37713 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37715 if(this.hiddenField){
37716 this.hiddenField.value = vv;
37718 this.lastSelectionText = dv;
37719 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37723 // no hidden field.. - we store the value in 'value', but still display
37724 // display field!!!!
37725 this.lastSelectionText = dv;
37726 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37732 reset : function(){
37733 // overridden so that last data is reset..
37734 this.setValue(this.originalValue);
37735 this.clearInvalid();
37736 this.lastData = false;
37739 findRecord : function(prop, value){
37741 if(this.store.getCount() > 0){
37742 this.store.each(function(r){
37743 if(r.data[prop] == value){
37753 onViewMove : function(e, t){
37754 this.inKeyMode = false;
37758 onViewOver : function(e, t){
37759 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37762 var item = this.view.findItemFromChild(t);
37764 var index = this.view.indexOf(item);
37765 this.select(index, false);
37770 onViewClick : function(doFocus){
37771 var index = this.view.getSelectedIndexes()[0];
37772 var r = this.store.getAt(index);
37774 this.onSelect(r, index);
37776 if(doFocus !== false && !this.blockFocus){
37782 restrictHeight : function(){
37783 this.innerList.dom.style.height = '';
37784 var inner = this.innerList.dom;
37785 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37786 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37787 this.list.beginUpdate();
37788 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37789 this.list.alignTo(this.el, this.listAlign);
37790 this.list.endUpdate();
37794 onEmptyResults : function(){
37799 * Returns true if the dropdown list is expanded, else false.
37801 isExpanded : function(){
37802 return this.list.isVisible();
37806 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37807 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37808 * @param {String} value The data value of the item to select
37809 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37810 * selected item if it is not currently in view (defaults to true)
37811 * @return {Boolean} True if the value matched an item in the list, else false
37813 selectByValue : function(v, scrollIntoView){
37814 if(v !== undefined && v !== null){
37815 var r = this.findRecord(this.valueField || this.displayField, v);
37817 this.select(this.store.indexOf(r), scrollIntoView);
37825 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37826 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37827 * @param {Number} index The zero-based index of the list item to select
37828 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37829 * selected item if it is not currently in view (defaults to true)
37831 select : function(index, scrollIntoView){
37832 this.selectedIndex = index;
37833 this.view.select(index);
37834 if(scrollIntoView !== false){
37835 var el = this.view.getNode(index);
37837 this.innerList.scrollChildIntoView(el, false);
37843 selectNext : function(){
37844 var ct = this.store.getCount();
37846 if(this.selectedIndex == -1){
37848 }else if(this.selectedIndex < ct-1){
37849 this.select(this.selectedIndex+1);
37855 selectPrev : function(){
37856 var ct = this.store.getCount();
37858 if(this.selectedIndex == -1){
37860 }else if(this.selectedIndex != 0){
37861 this.select(this.selectedIndex-1);
37867 onKeyUp : function(e){
37868 if(this.editable !== false && !e.isSpecialKey()){
37869 this.lastKey = e.getKey();
37870 this.dqTask.delay(this.queryDelay);
37875 validateBlur : function(){
37876 return !this.list || !this.list.isVisible();
37880 initQuery : function(){
37881 this.doQuery(this.getRawValue());
37885 doForce : function(){
37886 if(this.el.dom.value.length > 0){
37887 this.el.dom.value =
37888 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37889 this.applyEmptyText();
37894 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37895 * query allowing the query action to be canceled if needed.
37896 * @param {String} query The SQL query to execute
37897 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37898 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37899 * saved in the current store (defaults to false)
37901 doQuery : function(q, forceAll){
37902 if(q === undefined || q === null){
37907 forceAll: forceAll,
37911 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37915 forceAll = qe.forceAll;
37916 if(forceAll === true || (q.length >= this.minChars)){
37917 if(this.lastQuery != q || this.alwaysQuery){
37918 this.lastQuery = q;
37919 if(this.mode == 'local'){
37920 this.selectedIndex = -1;
37922 this.store.clearFilter();
37924 this.store.filter(this.displayField, q);
37928 this.store.baseParams[this.queryParam] = q;
37930 params: this.getParams(q)
37935 this.selectedIndex = -1;
37942 getParams : function(q){
37944 //p[this.queryParam] = q;
37947 p.limit = this.pageSize;
37953 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37955 collapse : function(){
37956 if(!this.isExpanded()){
37960 Roo.get(document).un('mousedown', this.collapseIf, this);
37961 Roo.get(document).un('mousewheel', this.collapseIf, this);
37962 if (!this.editable) {
37963 Roo.get(document).un('keydown', this.listKeyPress, this);
37965 this.fireEvent('collapse', this);
37969 collapseIf : function(e){
37970 if(!e.within(this.wrap) && !e.within(this.list)){
37976 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37978 expand : function(){
37979 if(this.isExpanded() || !this.hasFocus){
37982 this.list.alignTo(this.el, this.listAlign);
37984 Roo.get(document).on('mousedown', this.collapseIf, this);
37985 Roo.get(document).on('mousewheel', this.collapseIf, this);
37986 if (!this.editable) {
37987 Roo.get(document).on('keydown', this.listKeyPress, this);
37990 this.fireEvent('expand', this);
37994 // Implements the default empty TriggerField.onTriggerClick function
37995 onTriggerClick : function(){
37999 if(this.isExpanded()){
38001 if (!this.blockFocus) {
38006 this.hasFocus = true;
38007 if(this.triggerAction == 'all') {
38008 this.doQuery(this.allQuery, true);
38010 this.doQuery(this.getRawValue());
38012 if (!this.blockFocus) {
38017 listKeyPress : function(e)
38019 //Roo.log('listkeypress');
38020 // scroll to first matching element based on key pres..
38021 if (e.isSpecialKey()) {
38024 var k = String.fromCharCode(e.getKey()).toUpperCase();
38027 var csel = this.view.getSelectedNodes();
38028 var cselitem = false;
38030 var ix = this.view.indexOf(csel[0]);
38031 cselitem = this.store.getAt(ix);
38032 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
38038 this.store.each(function(v) {
38040 // start at existing selection.
38041 if (cselitem.id == v.id) {
38047 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
38048 match = this.store.indexOf(v);
38053 if (match === false) {
38054 return true; // no more action?
38057 this.view.select(match);
38058 var sn = Roo.get(this.view.getSelectedNodes()[0])
38059 sn.scrollIntoView(sn.dom.parentNode, false);
38063 * @cfg {Boolean} grow
38067 * @cfg {Number} growMin
38071 * @cfg {Number} growMax
38080 * Ext JS Library 1.1.1
38081 * Copyright(c) 2006-2007, Ext JS, LLC.
38083 * Originally Released Under LGPL - original licence link has changed is not relivant.
38086 * <script type="text/javascript">
38089 * @class Roo.form.Checkbox
38090 * @extends Roo.form.Field
38091 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
38093 * Creates a new Checkbox
38094 * @param {Object} config Configuration options
38096 Roo.form.Checkbox = function(config){
38097 Roo.form.Checkbox.superclass.constructor.call(this, config);
38101 * Fires when the checkbox is checked or unchecked.
38102 * @param {Roo.form.Checkbox} this This checkbox
38103 * @param {Boolean} checked The new checked value
38109 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38111 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38113 focusClass : undefined,
38115 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38117 fieldClass: "x-form-field",
38119 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38123 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38124 * {tag: "input", type: "checkbox", autocomplete: "off"})
38126 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38128 * @cfg {String} boxLabel The text that appears beside the checkbox
38132 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38136 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38138 valueOff: '0', // value when not checked..
38140 actionMode : 'viewEl',
38143 itemCls : 'x-menu-check-item x-form-item',
38144 groupClass : 'x-menu-group-item',
38145 inputType : 'hidden',
38148 inSetChecked: false, // check that we are not calling self...
38150 inputElement: false, // real input element?
38151 basedOn: false, // ????
38153 isFormField: true, // not sure where this is needed!!!!
38155 onResize : function(){
38156 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38157 if(!this.boxLabel){
38158 this.el.alignTo(this.wrap, 'c-c');
38162 initEvents : function(){
38163 Roo.form.Checkbox.superclass.initEvents.call(this);
38164 this.el.on("click", this.onClick, this);
38165 this.el.on("change", this.onClick, this);
38169 getResizeEl : function(){
38173 getPositionEl : function(){
38178 onRender : function(ct, position){
38179 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38181 if(this.inputValue !== undefined){
38182 this.el.dom.value = this.inputValue;
38185 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38186 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38187 var viewEl = this.wrap.createChild({
38188 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38189 this.viewEl = viewEl;
38190 this.wrap.on('click', this.onClick, this);
38192 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38193 this.el.on('propertychange', this.setFromHidden, this); //ie
38198 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38199 // viewEl.on('click', this.onClick, this);
38201 //if(this.checked){
38202 this.setChecked(this.checked);
38204 //this.checked = this.el.dom;
38210 initValue : Roo.emptyFn,
38213 * Returns the checked state of the checkbox.
38214 * @return {Boolean} True if checked, else false
38216 getValue : function(){
38218 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38220 return this.valueOff;
38225 onClick : function(){
38226 this.setChecked(!this.checked);
38228 //if(this.el.dom.checked != this.checked){
38229 // this.setValue(this.el.dom.checked);
38234 * Sets the checked state of the checkbox.
38235 * On is always based on a string comparison between inputValue and the param.
38236 * @param {Boolean/String} value - the value to set
38237 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38239 setValue : function(v,suppressEvent){
38242 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38243 //if(this.el && this.el.dom){
38244 // this.el.dom.checked = this.checked;
38245 // this.el.dom.defaultChecked = this.checked;
38247 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38248 //this.fireEvent("check", this, this.checked);
38251 setChecked : function(state,suppressEvent)
38253 if (this.inSetChecked) {
38254 this.checked = state;
38260 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38262 this.checked = state;
38263 if(suppressEvent !== true){
38264 this.fireEvent('check', this, state);
38266 this.inSetChecked = true;
38267 this.el.dom.value = state ? this.inputValue : this.valueOff;
38268 this.inSetChecked = false;
38271 // handle setting of hidden value by some other method!!?!?
38272 setFromHidden: function()
38277 //console.log("SET FROM HIDDEN");
38278 //alert('setFrom hidden');
38279 this.setValue(this.el.dom.value);
38282 onDestroy : function()
38285 Roo.get(this.viewEl).remove();
38288 Roo.form.Checkbox.superclass.onDestroy.call(this);
38293 * Ext JS Library 1.1.1
38294 * Copyright(c) 2006-2007, Ext JS, LLC.
38296 * Originally Released Under LGPL - original licence link has changed is not relivant.
38299 * <script type="text/javascript">
38303 * @class Roo.form.Radio
38304 * @extends Roo.form.Checkbox
38305 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38306 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38308 * Creates a new Radio
38309 * @param {Object} config Configuration options
38311 Roo.form.Radio = function(){
38312 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38314 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38315 inputType: 'radio',
38318 * If this radio is part of a group, it will return the selected value
38321 getGroupValue : function(){
38322 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38324 });//<script type="text/javascript">
38327 * Ext JS Library 1.1.1
38328 * Copyright(c) 2006-2007, Ext JS, LLC.
38329 * licensing@extjs.com
38331 * http://www.extjs.com/license
38337 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38338 * - IE ? - no idea how much works there.
38346 * @class Ext.form.HtmlEditor
38347 * @extends Ext.form.Field
38348 * Provides a lightweight HTML Editor component.
38349 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38351 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38352 * supported by this editor.</b><br/><br/>
38353 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38354 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38356 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38358 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38362 * @cfg {String} createLinkText The default text for the create link prompt
38364 createLinkText : 'Please enter the URL for the link:',
38366 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38368 defaultLinkValue : 'http:/'+'/',
38374 // private properties
38375 validationEvent : false,
38377 initialized : false,
38379 sourceEditMode : false,
38380 onFocus : Roo.emptyFn,
38382 hideMode:'offsets',
38383 defaultAutoCreate : {
38385 style:"width:500px;height:300px;",
38386 autocomplete: "off"
38390 initComponent : function(){
38393 * @event initialize
38394 * Fires when the editor is fully initialized (including the iframe)
38395 * @param {HtmlEditor} this
38400 * Fires when the editor is first receives the focus. Any insertion must wait
38401 * until after this event.
38402 * @param {HtmlEditor} this
38406 * @event beforesync
38407 * Fires before the textarea is updated with content from the editor iframe. Return false
38408 * to cancel the sync.
38409 * @param {HtmlEditor} this
38410 * @param {String} html
38414 * @event beforepush
38415 * Fires before the iframe editor is updated with content from the textarea. Return false
38416 * to cancel the push.
38417 * @param {HtmlEditor} this
38418 * @param {String} html
38423 * Fires when the textarea is updated with content from the editor iframe.
38424 * @param {HtmlEditor} this
38425 * @param {String} html
38430 * Fires when the iframe editor is updated with content from the textarea.
38431 * @param {HtmlEditor} this
38432 * @param {String} html
38436 * @event editmodechange
38437 * Fires when the editor switches edit modes
38438 * @param {HtmlEditor} this
38439 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38441 editmodechange: true,
38443 * @event editorevent
38444 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38445 * @param {HtmlEditor} this
38452 * Protected method that will not generally be called directly. It
38453 * is called when the editor creates its toolbar. Override this method if you need to
38454 * add custom toolbar buttons.
38455 * @param {HtmlEditor} editor
38457 createToolbar : function(editor){
38458 if (!editor.toolbars || !editor.toolbars.length) {
38459 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38462 for (var i =0 ; i < editor.toolbars.length;i++) {
38463 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38464 editor.toolbars[i].init(editor);
38471 * Protected method that will not generally be called directly. It
38472 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38473 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38475 getDocMarkup : function(){
38476 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
38480 onRender : function(ct, position){
38481 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38482 this.el.dom.style.border = '0 none';
38483 this.el.dom.setAttribute('tabIndex', -1);
38484 this.el.addClass('x-hidden');
38485 if(Roo.isIE){ // fix IE 1px bogus margin
38486 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38488 this.wrap = this.el.wrap({
38489 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38492 this.frameId = Roo.id();
38493 this.createToolbar(this);
38500 var iframe = this.wrap.createChild({
38503 name: this.frameId,
38504 frameBorder : 'no',
38505 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38508 // console.log(iframe);
38509 //this.wrap.dom.appendChild(iframe);
38511 this.iframe = iframe.dom;
38513 this.assignDocWin();
38515 this.doc.designMode = 'on';
38518 this.doc.write(this.getDocMarkup());
38522 var task = { // must defer to wait for browser to be ready
38524 //console.log("run task?" + this.doc.readyState);
38525 this.assignDocWin();
38526 if(this.doc.body || this.doc.readyState == 'complete'){
38528 this.doc.designMode="on";
38532 Roo.TaskMgr.stop(task);
38533 this.initEditor.defer(10, this);
38540 Roo.TaskMgr.start(task);
38543 this.setSize(this.el.getSize());
38548 onResize : function(w, h){
38549 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38550 if(this.el && this.iframe){
38551 if(typeof w == 'number'){
38552 var aw = w - this.wrap.getFrameWidth('lr');
38553 this.el.setWidth(this.adjustWidth('textarea', aw));
38554 this.iframe.style.width = aw + 'px';
38556 if(typeof h == 'number'){
38558 for (var i =0; i < this.toolbars.length;i++) {
38559 // fixme - ask toolbars for heights?
38560 tbh += this.toolbars[i].tb.el.getHeight();
38566 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38567 this.el.setHeight(this.adjustWidth('textarea', ah));
38568 this.iframe.style.height = ah + 'px';
38570 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38577 * Toggles the editor between standard and source edit mode.
38578 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38580 toggleSourceEdit : function(sourceEditMode){
38582 this.sourceEditMode = sourceEditMode === true;
38584 if(this.sourceEditMode){
38587 this.iframe.className = 'x-hidden';
38588 this.el.removeClass('x-hidden');
38589 this.el.dom.removeAttribute('tabIndex');
38594 this.iframe.className = '';
38595 this.el.addClass('x-hidden');
38596 this.el.dom.setAttribute('tabIndex', -1);
38599 this.setSize(this.wrap.getSize());
38600 this.fireEvent('editmodechange', this, this.sourceEditMode);
38603 // private used internally
38604 createLink : function(){
38605 var url = prompt(this.createLinkText, this.defaultLinkValue);
38606 if(url && url != 'http:/'+'/'){
38607 this.relayCmd('createlink', url);
38611 // private (for BoxComponent)
38612 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38614 // private (for BoxComponent)
38615 getResizeEl : function(){
38619 // private (for BoxComponent)
38620 getPositionEl : function(){
38625 initEvents : function(){
38626 this.originalValue = this.getValue();
38630 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38633 markInvalid : Roo.emptyFn,
38635 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38638 clearInvalid : Roo.emptyFn,
38640 setValue : function(v){
38641 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38646 * Protected method that will not generally be called directly. If you need/want
38647 * custom HTML cleanup, this is the method you should override.
38648 * @param {String} html The HTML to be cleaned
38649 * return {String} The cleaned HTML
38651 cleanHtml : function(html){
38652 html = String(html);
38653 if(html.length > 5){
38654 if(Roo.isSafari){ // strip safari nonsense
38655 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38658 if(html == ' '){
38665 * Protected method that will not generally be called directly. Syncs the contents
38666 * of the editor iframe with the textarea.
38668 syncValue : function(){
38669 if(this.initialized){
38670 var bd = (this.doc.body || this.doc.documentElement);
38671 this.cleanUpPaste();
38672 var html = bd.innerHTML;
38674 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38675 var m = bs.match(/text-align:(.*?);/i);
38677 html = '<div style="'+m[0]+'">' + html + '</div>';
38680 html = this.cleanHtml(html);
38681 if(this.fireEvent('beforesync', this, html) !== false){
38682 this.el.dom.value = html;
38683 this.fireEvent('sync', this, html);
38689 * Protected method that will not generally be called directly. Pushes the value of the textarea
38690 * into the iframe editor.
38692 pushValue : function(){
38693 if(this.initialized){
38694 var v = this.el.dom.value;
38699 if(this.fireEvent('beforepush', this, v) !== false){
38700 var d = (this.doc.body || this.doc.documentElement);
38702 this.cleanUpPaste();
38703 this.el.dom.value = d.innerHTML;
38704 this.fireEvent('push', this, v);
38710 deferFocus : function(){
38711 this.focus.defer(10, this);
38715 focus : function(){
38716 if(this.win && !this.sourceEditMode){
38723 assignDocWin: function()
38725 var iframe = this.iframe;
38728 this.doc = iframe.contentWindow.document;
38729 this.win = iframe.contentWindow;
38731 if (!Roo.get(this.frameId)) {
38734 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38735 this.win = Roo.get(this.frameId).dom.contentWindow;
38740 initEditor : function(){
38741 //console.log("INIT EDITOR");
38742 this.assignDocWin();
38746 this.doc.designMode="on";
38748 this.doc.write(this.getDocMarkup());
38751 var dbody = (this.doc.body || this.doc.documentElement);
38752 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38753 // this copies styles from the containing element into thsi one..
38754 // not sure why we need all of this..
38755 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38756 ss['background-attachment'] = 'fixed'; // w3c
38757 dbody.bgProperties = 'fixed'; // ie
38758 Roo.DomHelper.applyStyles(dbody, ss);
38759 Roo.EventManager.on(this.doc, {
38760 'mousedown': this.onEditorEvent,
38761 'dblclick': this.onEditorEvent,
38762 'click': this.onEditorEvent,
38763 'keyup': this.onEditorEvent,
38768 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
38770 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38771 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38773 this.initialized = true;
38775 this.fireEvent('initialize', this);
38780 onDestroy : function(){
38786 for (var i =0; i < this.toolbars.length;i++) {
38787 // fixme - ask toolbars for heights?
38788 this.toolbars[i].onDestroy();
38791 this.wrap.dom.innerHTML = '';
38792 this.wrap.remove();
38797 onFirstFocus : function(){
38799 this.assignDocWin();
38802 this.activated = true;
38803 for (var i =0; i < this.toolbars.length;i++) {
38804 this.toolbars[i].onFirstFocus();
38807 if(Roo.isGecko){ // prevent silly gecko errors
38809 var s = this.win.getSelection();
38810 if(!s.focusNode || s.focusNode.nodeType != 3){
38811 var r = s.getRangeAt(0);
38812 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38817 this.execCmd('useCSS', true);
38818 this.execCmd('styleWithCSS', false);
38821 this.fireEvent('activate', this);
38825 adjustFont: function(btn){
38826 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38827 //if(Roo.isSafari){ // safari
38830 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38831 if(Roo.isSafari){ // safari
38832 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38833 v = (v < 10) ? 10 : v;
38834 v = (v > 48) ? 48 : v;
38835 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38840 v = Math.max(1, v+adjust);
38842 this.execCmd('FontSize', v );
38845 onEditorEvent : function(e){
38846 this.fireEvent('editorevent', this, e);
38847 // this.updateToolbar();
38851 insertTag : function(tg)
38853 // could be a bit smarter... -> wrap the current selected tRoo..
38855 this.execCmd("formatblock", tg);
38859 insertText : function(txt)
38863 range = this.createRange();
38864 range.deleteContents();
38865 //alert(Sender.getAttribute('label'));
38867 range.insertNode(this.doc.createTextNode(txt));
38871 relayBtnCmd : function(btn){
38872 this.relayCmd(btn.cmd);
38876 * Executes a Midas editor command on the editor document and performs necessary focus and
38877 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38878 * @param {String} cmd The Midas command
38879 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38881 relayCmd : function(cmd, value){
38883 this.execCmd(cmd, value);
38884 this.fireEvent('editorevent', this);
38885 //this.updateToolbar();
38890 * Executes a Midas editor command directly on the editor document.
38891 * For visual commands, you should use {@link #relayCmd} instead.
38892 * <b>This should only be called after the editor is initialized.</b>
38893 * @param {String} cmd The Midas command
38894 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38896 execCmd : function(cmd, value){
38897 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38903 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38905 * @param {String} text
38907 insertAtCursor : function(text){
38908 if(!this.activated){
38913 var r = this.doc.selection.createRange();
38920 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
38922 this.execCmd('InsertHTML', text);
38927 mozKeyPress : function(e){
38929 var c = e.getCharCode(), cmd;
38932 c = String.fromCharCode(c).toLowerCase();
38943 this.cleanUpPaste.defer(100, this);
38951 e.preventDefault();
38959 fixKeys : function(){ // load time branching for fastest keydown performance
38961 return function(e){
38962 var k = e.getKey(), r;
38965 r = this.doc.selection.createRange();
38968 r.pasteHTML('    ');
38975 r = this.doc.selection.createRange();
38977 var target = r.parentElement();
38978 if(!target || target.tagName.toLowerCase() != 'li'){
38980 r.pasteHTML('<br />');
38986 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38987 this.cleanUpPaste.defer(100, this);
38993 }else if(Roo.isOpera){
38994 return function(e){
38995 var k = e.getKey();
38999 this.execCmd('InsertHTML','    ');
39002 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39003 this.cleanUpPaste.defer(100, this);
39008 }else if(Roo.isSafari){
39009 return function(e){
39010 var k = e.getKey();
39014 this.execCmd('InsertText','\t');
39018 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39019 this.cleanUpPaste.defer(100, this);
39027 getAllAncestors: function()
39029 var p = this.getSelectedNode();
39032 a.push(p); // push blank onto stack..
39033 p = this.getParentElement();
39037 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
39041 a.push(this.doc.body);
39045 lastSelNode : false,
39048 getSelection : function()
39050 this.assignDocWin();
39051 return Roo.isIE ? this.doc.selection : this.win.getSelection();
39054 getSelectedNode: function()
39056 // this may only work on Gecko!!!
39058 // should we cache this!!!!
39063 var range = this.createRange(this.getSelection());
39066 var parent = range.parentElement();
39068 var testRange = range.duplicate();
39069 testRange.moveToElementText(parent);
39070 if (testRange.inRange(range)) {
39073 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
39076 parent = parent.parentElement;
39082 var ar = range.endContainer.childNodes;
39084 ar = range.commonAncestorContainer.childNodes;
39085 //alert(ar.length);
39088 var other_nodes = [];
39089 var has_other_nodes = false;
39090 for (var i=0;i<ar.length;i++) {
39091 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
39094 // fullly contained node.
39096 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
39101 // probably selected..
39102 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
39103 other_nodes.push(ar[i]);
39106 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39111 has_other_nodes = true;
39113 if (!nodes.length && other_nodes.length) {
39114 nodes= other_nodes;
39116 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39122 createRange: function(sel)
39124 // this has strange effects when using with
39125 // top toolbar - not sure if it's a great idea.
39126 //this.editor.contentWindow.focus();
39127 if (typeof sel != "undefined") {
39129 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39131 return this.doc.createRange();
39134 return this.doc.createRange();
39137 getParentElement: function()
39140 this.assignDocWin();
39141 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39143 var range = this.createRange(sel);
39146 var p = range.commonAncestorContainer;
39147 while (p.nodeType == 3) { // text node
39159 // BC Hacks - cause I cant work out what i was trying to do..
39160 rangeIntersectsNode : function(range, node)
39162 var nodeRange = node.ownerDocument.createRange();
39164 nodeRange.selectNode(node);
39167 nodeRange.selectNodeContents(node);
39170 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
39171 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
39173 rangeCompareNode : function(range, node) {
39174 var nodeRange = node.ownerDocument.createRange();
39176 nodeRange.selectNode(node);
39178 nodeRange.selectNodeContents(node);
39180 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
39181 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
39183 if (nodeIsBefore && !nodeIsAfter)
39185 if (!nodeIsBefore && nodeIsAfter)
39187 if (nodeIsBefore && nodeIsAfter)
39193 // private? - in a new class?
39194 cleanUpPaste : function()
39196 // cleans up the whole document..
39197 // console.log('cleanuppaste');
39198 this.cleanUpChildren(this.doc.body);
39202 cleanUpChildren : function (n)
39204 if (!n.childNodes.length) {
39207 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39208 this.cleanUpChild(n.childNodes[i]);
39215 cleanUpChild : function (node)
39217 //console.log(node);
39218 if (node.nodeName == "#text") {
39219 // clean up silly Windows -- stuff?
39222 if (node.nodeName == "#comment") {
39223 node.parentNode.removeChild(node);
39224 // clean up silly Windows -- stuff?
39228 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39230 node.parentNode.removeChild(node);
39234 if (!node.attributes || !node.attributes.length) {
39235 this.cleanUpChildren(node);
39239 function cleanAttr(n,v)
39242 if (v.match(/^\./) || v.match(/^\//)) {
39245 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39248 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39249 node.removeAttribute(n);
39253 function cleanStyle(n,v)
39255 if (v.match(/expression/)) { //XSS?? should we even bother..
39256 node.removeAttribute(n);
39261 var parts = v.split(/;/);
39262 Roo.each(parts, function(p) {
39263 p = p.replace(/\s+/g,'');
39267 var l = p.split(':').shift().replace(/\s+/g,'');
39269 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39270 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39271 node.removeAttribute(n);
39280 for (var i = node.attributes.length-1; i > -1 ; i--) {
39281 var a = node.attributes[i];
39283 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39284 node.removeAttribute(a.name);
39287 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39288 cleanAttr(a.name,a.value); // fixme..
39291 if (a.name == 'style') {
39292 cleanStyle(a.name,a.value);
39294 /// clean up MS crap..
39295 if (a.name == 'class') {
39296 if (a.value.match(/^Mso/)) {
39297 node.className = '';
39307 this.cleanUpChildren(node);
39313 // hide stuff that is not compatible
39327 * @event specialkey
39331 * @cfg {String} fieldClass @hide
39334 * @cfg {String} focusClass @hide
39337 * @cfg {String} autoCreate @hide
39340 * @cfg {String} inputType @hide
39343 * @cfg {String} invalidClass @hide
39346 * @cfg {String} invalidText @hide
39349 * @cfg {String} msgFx @hide
39352 * @cfg {String} validateOnBlur @hide
39356 Roo.form.HtmlEditor.white = [
39357 'area', 'br', 'img', 'input', 'hr', 'wbr',
39359 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39360 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39361 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39362 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39363 'table', 'ul', 'xmp',
39365 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39368 'dir', 'menu', 'ol', 'ul', 'dl',
39374 Roo.form.HtmlEditor.black = [
39375 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39377 'base', 'basefont', 'bgsound', 'blink', 'body',
39378 'frame', 'frameset', 'head', 'html', 'ilayer',
39379 'iframe', 'layer', 'link', 'meta', 'object',
39380 'script', 'style' ,'title', 'xml' // clean later..
39382 Roo.form.HtmlEditor.clean = [
39383 'script', 'style', 'title', 'xml'
39388 Roo.form.HtmlEditor.ablack = [
39392 Roo.form.HtmlEditor.aclean = [
39393 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39397 Roo.form.HtmlEditor.pwhite= [
39398 'http', 'https', 'mailto'
39401 Roo.form.HtmlEditor.cwhite= [
39406 // <script type="text/javascript">
39409 * Ext JS Library 1.1.1
39410 * Copyright(c) 2006-2007, Ext JS, LLC.
39416 * @class Roo.form.HtmlEditorToolbar1
39421 new Roo.form.HtmlEditor({
39424 new Roo.form.HtmlEditorToolbar1({
39425 disable : { fonts: 1 , format: 1, ..., ... , ...],
39431 * @cfg {Object} disable List of elements to disable..
39432 * @cfg {Array} btns List of additional buttons.
39436 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39439 Roo.form.HtmlEditor.ToolbarStandard = function(config)
39442 Roo.apply(this, config);
39443 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39444 // dont call parent... till later.
39447 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
39455 * @cfg {Object} disable List of toolbar elements to disable
39460 * @cfg {Array} fontFamilies An array of available font families
39478 // "á" , ?? a acute?
39483 "°" // , // degrees
39485 // "é" , // e ecute
39486 // "ú" , // u ecute?
39489 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
39490 "input:submit", "input:button", "select", "textarea", "label" ],
39493 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
39495 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39498 * @cfg {String} defaultFont default font to use.
39500 defaultFont: 'tahoma',
39502 fontSelect : false,
39505 formatCombo : false,
39507 init : function(editor)
39509 this.editor = editor;
39512 var fid = editor.frameId;
39514 function btn(id, toggle, handler){
39515 var xid = fid + '-'+ id ;
39519 cls : 'x-btn-icon x-edit-'+id,
39520 enableToggle:toggle !== false,
39521 scope: editor, // was editor...
39522 handler:handler||editor.relayBtnCmd,
39523 clickEvent:'mousedown',
39524 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39531 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
39533 // stop form submits
39534 tb.el.on('click', function(e){
39535 e.preventDefault(); // what does this do?
39538 if(!this.disable.font && !Roo.isSafari){
39539 /* why no safari for fonts
39540 editor.fontSelect = tb.el.createChild({
39543 cls:'x-font-select',
39544 html: editor.createFontOptions()
39546 editor.fontSelect.on('change', function(){
39547 var font = editor.fontSelect.dom.value;
39548 editor.relayCmd('fontname', font);
39549 editor.deferFocus();
39552 editor.fontSelect.dom,
39557 if(!this.disable.formats){
39558 this.formatCombo = new Roo.form.ComboBox({
39559 store: new Roo.data.SimpleStore({
39562 data : this.formats // from states.js
39565 //autoCreate : {tag: "div", size: "20"},
39566 displayField:'tag',
39570 triggerAction: 'all',
39571 emptyText:'Add tag',
39572 selectOnFocus:true,
39575 'select': function(c, r, i) {
39576 editor.insertTag(r.get('tag'));
39582 tb.addField(this.formatCombo);
39586 if(!this.disable.format){
39593 if(!this.disable.fontSize){
39598 btn('increasefontsize', false, editor.adjustFont),
39599 btn('decreasefontsize', false, editor.adjustFont)
39604 if(this.disable.colors){
39607 id:editor.frameId +'-forecolor',
39608 cls:'x-btn-icon x-edit-forecolor',
39609 clickEvent:'mousedown',
39610 tooltip: this.buttonTips['forecolor'] || undefined,
39612 menu : new Roo.menu.ColorMenu({
39613 allowReselect: true,
39614 focus: Roo.emptyFn,
39617 selectHandler: function(cp, color){
39618 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
39619 editor.deferFocus();
39622 clickEvent:'mousedown'
39625 id:editor.frameId +'backcolor',
39626 cls:'x-btn-icon x-edit-backcolor',
39627 clickEvent:'mousedown',
39628 tooltip: this.buttonTips['backcolor'] || undefined,
39630 menu : new Roo.menu.ColorMenu({
39631 focus: Roo.emptyFn,
39634 allowReselect: true,
39635 selectHandler: function(cp, color){
39637 editor.execCmd('useCSS', false);
39638 editor.execCmd('hilitecolor', color);
39639 editor.execCmd('useCSS', true);
39640 editor.deferFocus();
39642 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
39643 Roo.isSafari || Roo.isIE ? '#'+color : color);
39644 editor.deferFocus();
39648 clickEvent:'mousedown'
39653 // now add all the items...
39656 if(!this.disable.alignments){
39659 btn('justifyleft'),
39660 btn('justifycenter'),
39661 btn('justifyright')
39665 //if(!Roo.isSafari){
39666 if(!this.disable.links){
39669 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
39673 if(!this.disable.lists){
39676 btn('insertorderedlist'),
39677 btn('insertunorderedlist')
39680 if(!this.disable.sourceEdit){
39683 btn('sourceedit', true, function(btn){
39684 this.toggleSourceEdit(btn.pressed);
39691 // special menu.. - needs to be tidied up..
39692 if (!this.disable.special) {
39695 cls: 'x-edit-none',
39700 for (var i =0; i < this.specialChars.length; i++) {
39701 smenu.menu.items.push({
39703 html: this.specialChars[i],
39704 handler: function(a,b) {
39705 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
39718 for(var i =0; i< this.btns.length;i++) {
39719 var b = this.btns[i];
39720 b.cls = 'x-edit-none';
39729 // disable everything...
39731 this.tb.items.each(function(item){
39732 if(item.id != editor.frameId+ '-sourceedit'){
39736 this.rendered = true;
39738 // the all the btns;
39739 editor.on('editorevent', this.updateToolbar, this);
39740 // other toolbars need to implement this..
39741 //editor.on('editmodechange', this.updateToolbar, this);
39747 * Protected method that will not generally be called directly. It triggers
39748 * a toolbar update by reading the markup state of the current selection in the editor.
39750 updateToolbar: function(){
39752 if(!this.editor.activated){
39753 this.editor.onFirstFocus();
39757 var btns = this.tb.items.map,
39758 doc = this.editor.doc,
39759 frameId = this.editor.frameId;
39761 if(!this.disable.font && !Roo.isSafari){
39763 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39764 if(name != this.fontSelect.dom.value){
39765 this.fontSelect.dom.value = name;
39769 if(!this.disable.format){
39770 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39771 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39772 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39774 if(!this.disable.alignments){
39775 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39776 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39777 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39779 if(!Roo.isSafari && !this.disable.lists){
39780 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39781 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39784 var ans = this.editor.getAllAncestors();
39785 if (this.formatCombo) {
39788 var store = this.formatCombo.store;
39789 this.formatCombo.setValue("");
39790 for (var i =0; i < ans.length;i++) {
39791 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
39793 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39801 // hides menus... - so this cant be on a menu...
39802 Roo.menu.MenuMgr.hideAll();
39804 //this.editorsyncValue();
39808 createFontOptions : function(){
39809 var buf = [], fs = this.fontFamilies, ff, lc;
39810 for(var i = 0, len = fs.length; i< len; i++){
39812 lc = ff.toLowerCase();
39814 '<option value="',lc,'" style="font-family:',ff,';"',
39815 (this.defaultFont == lc ? ' selected="true">' : '>'),
39820 return buf.join('');
39823 toggleSourceEdit : function(sourceEditMode){
39824 if(sourceEditMode === undefined){
39825 sourceEditMode = !this.sourceEditMode;
39827 this.sourceEditMode = sourceEditMode === true;
39828 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39829 // just toggle the button?
39830 if(btn.pressed !== this.editor.sourceEditMode){
39831 btn.toggle(this.editor.sourceEditMode);
39835 if(this.sourceEditMode){
39836 this.tb.items.each(function(item){
39837 if(item.cmd != 'sourceedit'){
39843 if(this.initialized){
39844 this.tb.items.each(function(item){
39850 // tell the editor that it's been pressed..
39851 this.editor.toggleSourceEdit(sourceEditMode);
39855 * Object collection of toolbar tooltips for the buttons in the editor. The key
39856 * is the command id associated with that button and the value is a valid QuickTips object.
39861 title: 'Bold (Ctrl+B)',
39862 text: 'Make the selected text bold.',
39863 cls: 'x-html-editor-tip'
39866 title: 'Italic (Ctrl+I)',
39867 text: 'Make the selected text italic.',
39868 cls: 'x-html-editor-tip'
39876 title: 'Bold (Ctrl+B)',
39877 text: 'Make the selected text bold.',
39878 cls: 'x-html-editor-tip'
39881 title: 'Italic (Ctrl+I)',
39882 text: 'Make the selected text italic.',
39883 cls: 'x-html-editor-tip'
39886 title: 'Underline (Ctrl+U)',
39887 text: 'Underline the selected text.',
39888 cls: 'x-html-editor-tip'
39890 increasefontsize : {
39891 title: 'Grow Text',
39892 text: 'Increase the font size.',
39893 cls: 'x-html-editor-tip'
39895 decreasefontsize : {
39896 title: 'Shrink Text',
39897 text: 'Decrease the font size.',
39898 cls: 'x-html-editor-tip'
39901 title: 'Text Highlight Color',
39902 text: 'Change the background color of the selected text.',
39903 cls: 'x-html-editor-tip'
39906 title: 'Font Color',
39907 text: 'Change the color of the selected text.',
39908 cls: 'x-html-editor-tip'
39911 title: 'Align Text Left',
39912 text: 'Align text to the left.',
39913 cls: 'x-html-editor-tip'
39916 title: 'Center Text',
39917 text: 'Center text in the editor.',
39918 cls: 'x-html-editor-tip'
39921 title: 'Align Text Right',
39922 text: 'Align text to the right.',
39923 cls: 'x-html-editor-tip'
39925 insertunorderedlist : {
39926 title: 'Bullet List',
39927 text: 'Start a bulleted list.',
39928 cls: 'x-html-editor-tip'
39930 insertorderedlist : {
39931 title: 'Numbered List',
39932 text: 'Start a numbered list.',
39933 cls: 'x-html-editor-tip'
39936 title: 'Hyperlink',
39937 text: 'Make the selected text a hyperlink.',
39938 cls: 'x-html-editor-tip'
39941 title: 'Source Edit',
39942 text: 'Switch to source editing mode.',
39943 cls: 'x-html-editor-tip'
39947 onDestroy : function(){
39950 this.tb.items.each(function(item){
39952 item.menu.removeAll();
39954 item.menu.el.destroy();
39962 onFirstFocus: function() {
39963 this.tb.items.each(function(item){
39972 // <script type="text/javascript">
39975 * Ext JS Library 1.1.1
39976 * Copyright(c) 2006-2007, Ext JS, LLC.
39983 * @class Roo.form.HtmlEditor.ToolbarContext
39988 new Roo.form.HtmlEditor({
39991 new Roo.form.HtmlEditor.ToolbarStandard(),
39992 new Roo.form.HtmlEditor.ToolbarContext()
39997 * @config : {Object} disable List of elements to disable.. (not done yet.)
40002 Roo.form.HtmlEditor.ToolbarContext = function(config)
40005 Roo.apply(this, config);
40006 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
40007 // dont call parent... till later.
40009 Roo.form.HtmlEditor.ToolbarContext.types = {
40021 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
40083 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
40088 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40152 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40160 * @cfg {Object} disable List of toolbar elements to disable
40169 init : function(editor)
40171 this.editor = editor;
40174 var fid = editor.frameId;
40176 function btn(id, toggle, handler){
40177 var xid = fid + '-'+ id ;
40181 cls : 'x-btn-icon x-edit-'+id,
40182 enableToggle:toggle !== false,
40183 scope: editor, // was editor...
40184 handler:handler||editor.relayBtnCmd,
40185 clickEvent:'mousedown',
40186 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40190 // create a new element.
40191 var wdiv = editor.wrap.createChild({
40193 }, editor.wrap.dom.firstChild.nextSibling, true);
40195 // can we do this more than once??
40197 // stop form submits
40200 // disable everything...
40201 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40202 this.toolbars = {};
40204 for (var i in ty) {
40206 this.toolbars[i] = this.buildToolbar(ty[i],i);
40208 this.tb = this.toolbars.BODY;
40212 this.rendered = true;
40214 // the all the btns;
40215 editor.on('editorevent', this.updateToolbar, this);
40216 // other toolbars need to implement this..
40217 //editor.on('editmodechange', this.updateToolbar, this);
40223 * Protected method that will not generally be called directly. It triggers
40224 * a toolbar update by reading the markup state of the current selection in the editor.
40226 updateToolbar: function(){
40228 if(!this.editor.activated){
40229 this.editor.onFirstFocus();
40234 var ans = this.editor.getAllAncestors();
40237 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40238 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40239 sel = sel ? sel : this.editor.doc.body;
40240 sel = sel.tagName.length ? sel : this.editor.doc.body;
40241 var tn = sel.tagName.toUpperCase();
40242 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40243 tn = sel.tagName.toUpperCase();
40244 if (this.tb.name == tn) {
40245 return; // no change
40248 ///console.log("show: " + tn);
40249 this.tb = this.toolbars[tn];
40251 this.tb.fields.each(function(e) {
40252 e.setValue(sel.getAttribute(e.name));
40254 this.tb.selectedNode = sel;
40257 Roo.menu.MenuMgr.hideAll();
40259 //this.editorsyncValue();
40264 onDestroy : function(){
40267 this.tb.items.each(function(item){
40269 item.menu.removeAll();
40271 item.menu.el.destroy();
40279 onFirstFocus: function() {
40280 // need to do this for all the toolbars..
40281 this.tb.items.each(function(item){
40285 buildToolbar: function(tlist, nm)
40287 var editor = this.editor;
40288 // create a new element.
40289 var wdiv = editor.wrap.createChild({
40291 }, editor.wrap.dom.firstChild.nextSibling, true);
40294 var tb = new Roo.Toolbar(wdiv);
40295 tb.add(nm+ ": ");
40296 for (var i in tlist) {
40297 var item = tlist[i];
40298 tb.add(item.title + ": ");
40303 tb.addField( new Roo.form.ComboBox({
40304 store: new Roo.data.SimpleStore({
40307 data : item.opts // from states.js
40310 displayField:'val',
40314 triggerAction: 'all',
40315 emptyText:'Select',
40316 selectOnFocus:true,
40317 width: item.width ? item.width : 130,
40319 'select': function(c, r, i) {
40320 tb.selectedNode.setAttribute(c.name, r.get('val'));
40331 tb.addField( new Roo.form.TextField({
40334 //allowBlank:false,
40339 tb.addField( new Roo.form.TextField({
40345 'change' : function(f, nv, ov) {
40346 tb.selectedNode.setAttribute(f.name, nv);
40352 tb.el.on('click', function(e){
40353 e.preventDefault(); // what does this do?
40355 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40358 // dont need to disable them... as they will get hidden
40375 * Ext JS Library 1.1.1
40376 * Copyright(c) 2006-2007, Ext JS, LLC.
40378 * Originally Released Under LGPL - original licence link has changed is not relivant.
40381 * <script type="text/javascript">
40385 * @class Roo.form.BasicForm
40386 * @extends Roo.util.Observable
40387 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
40389 * @param {String/HTMLElement/Roo.Element} el The form element or its id
40390 * @param {Object} config Configuration options
40392 Roo.form.BasicForm = function(el, config){
40393 this.allItems = [];
40394 this.childForms = [];
40395 Roo.apply(this, config);
40397 * The Roo.form.Field items in this form.
40398 * @type MixedCollection
40402 this.items = new Roo.util.MixedCollection(false, function(o){
40403 return o.id || (o.id = Roo.id());
40407 * @event beforeaction
40408 * Fires before any action is performed. Return false to cancel the action.
40409 * @param {Form} this
40410 * @param {Action} action The action to be performed
40412 beforeaction: true,
40414 * @event actionfailed
40415 * Fires when an action fails.
40416 * @param {Form} this
40417 * @param {Action} action The action that failed
40419 actionfailed : true,
40421 * @event actioncomplete
40422 * Fires when an action is completed.
40423 * @param {Form} this
40424 * @param {Action} action The action that completed
40426 actioncomplete : true
40431 Roo.form.BasicForm.superclass.constructor.call(this);
40434 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
40436 * @cfg {String} method
40437 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
40440 * @cfg {DataReader} reader
40441 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
40442 * This is optional as there is built-in support for processing JSON.
40445 * @cfg {DataReader} errorReader
40446 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
40447 * This is completely optional as there is built-in support for processing JSON.
40450 * @cfg {String} url
40451 * The URL to use for form actions if one isn't supplied in the action options.
40454 * @cfg {Boolean} fileUpload
40455 * Set to true if this form is a file upload.
40459 * @cfg {Object} baseParams
40460 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
40465 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
40470 activeAction : null,
40473 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
40474 * or setValues() data instead of when the form was first created.
40476 trackResetOnLoad : false,
40480 * childForms - used for multi-tab forms
40483 childForms : false,
40486 * allItems - full list of fields.
40492 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
40493 * element by passing it or its id or mask the form itself by passing in true.
40496 waitMsgTarget : false,
40499 initEl : function(el){
40500 this.el = Roo.get(el);
40501 this.id = this.el.id || Roo.id();
40502 this.el.on('submit', this.onSubmit, this);
40503 this.el.addClass('x-form');
40507 onSubmit : function(e){
40512 * Returns true if client-side validation on the form is successful.
40515 isValid : function(){
40517 this.items.each(function(f){
40526 * Returns true if any fields in this form have changed since their original load.
40529 isDirty : function(){
40531 this.items.each(function(f){
40541 * Performs a predefined action (submit or load) or custom actions you define on this form.
40542 * @param {String} actionName The name of the action type
40543 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
40544 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
40545 * accept other config options):
40547 Property Type Description
40548 ---------------- --------------- ----------------------------------------------------------------------------------
40549 url String The url for the action (defaults to the form's url)
40550 method String The form method to use (defaults to the form's method, or POST if not defined)
40551 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
40552 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
40553 validate the form on the client (defaults to false)
40555 * @return {BasicForm} this
40557 doAction : function(action, options){
40558 if(typeof action == 'string'){
40559 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
40561 if(this.fireEvent('beforeaction', this, action) !== false){
40562 this.beforeAction(action);
40563 action.run.defer(100, action);
40569 * Shortcut to do a submit action.
40570 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40571 * @return {BasicForm} this
40573 submit : function(options){
40574 this.doAction('submit', options);
40579 * Shortcut to do a load action.
40580 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40581 * @return {BasicForm} this
40583 load : function(options){
40584 this.doAction('load', options);
40589 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
40590 * @param {Record} record The record to edit
40591 * @return {BasicForm} this
40593 updateRecord : function(record){
40594 record.beginEdit();
40595 var fs = record.fields;
40596 fs.each(function(f){
40597 var field = this.findField(f.name);
40599 record.set(f.name, field.getValue());
40607 * Loads an Roo.data.Record into this form.
40608 * @param {Record} record The record to load
40609 * @return {BasicForm} this
40611 loadRecord : function(record){
40612 this.setValues(record.data);
40617 beforeAction : function(action){
40618 var o = action.options;
40621 if(this.waitMsgTarget === true){
40622 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
40623 }else if(this.waitMsgTarget){
40624 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
40625 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
40627 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
40633 afterAction : function(action, success){
40634 this.activeAction = null;
40635 var o = action.options;
40637 if(this.waitMsgTarget === true){
40639 }else if(this.waitMsgTarget){
40640 this.waitMsgTarget.unmask();
40642 Roo.MessageBox.updateProgress(1);
40643 Roo.MessageBox.hide();
40650 Roo.callback(o.success, o.scope, [this, action]);
40651 this.fireEvent('actioncomplete', this, action);
40654 Roo.callback(o.failure, o.scope, [this, action]);
40655 // show an error message if no failed handler is set..
40656 if (!this.hasListener('actionfailed')) {
40657 Roo.MessageBox.alert("Error", "Saving Failed, please check your entries");
40660 this.fireEvent('actionfailed', this, action);
40666 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
40667 * @param {String} id The value to search for
40670 findField : function(id){
40671 var field = this.items.get(id);
40673 this.items.each(function(f){
40674 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
40680 return field || null;
40684 * Add a secondary form to this one,
40685 * Used to provide tabbed forms. One form is primary, with hidden values
40686 * which mirror the elements from the other forms.
40688 * @param {Roo.form.Form} form to add.
40691 addForm : function(form)
40694 if (this.childForms.indexOf(form) > -1) {
40698 this.childForms.push(form);
40700 Roo.each(form.allItems, function (fe) {
40702 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
40703 if (this.findField(n)) { // already added..
40706 var add = new Roo.form.Hidden({
40709 add.render(this.el);
40716 * Mark fields in this form invalid in bulk.
40717 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
40718 * @return {BasicForm} this
40720 markInvalid : function(errors){
40721 if(errors instanceof Array){
40722 for(var i = 0, len = errors.length; i < len; i++){
40723 var fieldError = errors[i];
40724 var f = this.findField(fieldError.id);
40726 f.markInvalid(fieldError.msg);
40732 if(typeof errors[id] != 'function' && (field = this.findField(id))){
40733 field.markInvalid(errors[id]);
40737 Roo.each(this.childForms || [], function (f) {
40738 f.markInvalid(errors);
40745 * Set values for fields in this form in bulk.
40746 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
40747 * @return {BasicForm} this
40749 setValues : function(values){
40750 if(values instanceof Array){ // array of objects
40751 for(var i = 0, len = values.length; i < len; i++){
40753 var f = this.findField(v.id);
40755 f.setValue(v.value);
40756 if(this.trackResetOnLoad){
40757 f.originalValue = f.getValue();
40761 }else{ // object hash
40764 if(typeof values[id] != 'function' && (field = this.findField(id))){
40766 if (field.setFromData &&
40767 field.valueField &&
40768 field.displayField &&
40769 // combos' with local stores can
40770 // be queried via setValue()
40771 // to set their value..
40772 (field.store && !field.store.isLocal)
40776 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40777 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40778 field.setFromData(sd);
40781 field.setValue(values[id]);
40785 if(this.trackResetOnLoad){
40786 field.originalValue = field.getValue();
40792 Roo.each(this.childForms || [], function (f) {
40793 f.setValues(values);
40800 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40801 * they are returned as an array.
40802 * @param {Boolean} asString
40805 getValues : function(asString){
40806 if (this.childForms) {
40807 // copy values from the child forms
40808 Roo.each(this.childForms, function (f) {
40809 this.setValues(f.getValues());
40815 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40816 if(asString === true){
40819 return Roo.urlDecode(fs);
40823 * Returns the fields in this form as an object with key/value pairs.
40824 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
40827 getFieldValues : function()
40829 if (this.childForms) {
40830 // copy values from the child forms
40831 Roo.each(this.childForms, function (f) {
40832 this.setValues(f.getValues());
40837 this.items.each(function(f){
40838 if (!f.getName()) {
40841 var v = f.getValue();
40842 if ((typeof(v) == 'object') && f.getRawValue) {
40843 v = f.getRawValue() ; // dates..
40845 ret[f.getName()] = v;
40852 * Clears all invalid messages in this form.
40853 * @return {BasicForm} this
40855 clearInvalid : function(){
40856 this.items.each(function(f){
40860 Roo.each(this.childForms || [], function (f) {
40869 * Resets this form.
40870 * @return {BasicForm} this
40872 reset : function(){
40873 this.items.each(function(f){
40877 Roo.each(this.childForms || [], function (f) {
40886 * Add Roo.form components to this form.
40887 * @param {Field} field1
40888 * @param {Field} field2 (optional)
40889 * @param {Field} etc (optional)
40890 * @return {BasicForm} this
40893 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40899 * Removes a field from the items collection (does NOT remove its markup).
40900 * @param {Field} field
40901 * @return {BasicForm} this
40903 remove : function(field){
40904 this.items.remove(field);
40909 * Looks at the fields in this form, checks them for an id attribute,
40910 * and calls applyTo on the existing dom element with that id.
40911 * @return {BasicForm} this
40913 render : function(){
40914 this.items.each(function(f){
40915 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40923 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40924 * @param {Object} values
40925 * @return {BasicForm} this
40927 applyToFields : function(o){
40928 this.items.each(function(f){
40935 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40936 * @param {Object} values
40937 * @return {BasicForm} this
40939 applyIfToFields : function(o){
40940 this.items.each(function(f){
40948 Roo.BasicForm = Roo.form.BasicForm;/*
40950 * Ext JS Library 1.1.1
40951 * Copyright(c) 2006-2007, Ext JS, LLC.
40953 * Originally Released Under LGPL - original licence link has changed is not relivant.
40956 * <script type="text/javascript">
40960 * @class Roo.form.Form
40961 * @extends Roo.form.BasicForm
40962 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40964 * @param {Object} config Configuration options
40966 Roo.form.Form = function(config){
40968 if (config.items) {
40969 xitems = config.items;
40970 delete config.items;
40974 Roo.form.Form.superclass.constructor.call(this, null, config);
40975 this.url = this.url || this.action;
40977 this.root = new Roo.form.Layout(Roo.applyIf({
40981 this.active = this.root;
40983 * Array of all the buttons that have been added to this form via {@link addButton}
40987 this.allItems = [];
40990 * @event clientvalidation
40991 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40992 * @param {Form} this
40993 * @param {Boolean} valid true if the form has passed client-side validation
40995 clientvalidation: true,
40998 * Fires when the form is rendered
40999 * @param {Roo.form.Form} form
41004 if (this.progressUrl) {
41005 // push a hidden field onto the list of fields..
41009 name : 'UPLOAD_IDENTIFIER'
41014 Roo.each(xitems, this.addxtype, this);
41020 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
41022 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
41025 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
41028 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
41030 buttonAlign:'center',
41033 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
41038 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
41039 * This property cascades to child containers if not set.
41044 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
41045 * fires a looping event with that state. This is required to bind buttons to the valid
41046 * state using the config value formBind:true on the button.
41048 monitorValid : false,
41051 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
41056 * @cfg {String} progressUrl - Url to return progress data
41059 progressUrl : false,
41062 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
41063 * fields are added and the column is closed. If no fields are passed the column remains open
41064 * until end() is called.
41065 * @param {Object} config The config to pass to the column
41066 * @param {Field} field1 (optional)
41067 * @param {Field} field2 (optional)
41068 * @param {Field} etc (optional)
41069 * @return Column The column container object
41071 column : function(c){
41072 var col = new Roo.form.Column(c);
41074 if(arguments.length > 1){ // duplicate code required because of Opera
41075 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41082 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
41083 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
41084 * until end() is called.
41085 * @param {Object} config The config to pass to the fieldset
41086 * @param {Field} field1 (optional)
41087 * @param {Field} field2 (optional)
41088 * @param {Field} etc (optional)
41089 * @return FieldSet The fieldset container object
41091 fieldset : function(c){
41092 var fs = new Roo.form.FieldSet(c);
41094 if(arguments.length > 1){ // duplicate code required because of Opera
41095 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41102 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
41103 * fields are added and the container is closed. If no fields are passed the container remains open
41104 * until end() is called.
41105 * @param {Object} config The config to pass to the Layout
41106 * @param {Field} field1 (optional)
41107 * @param {Field} field2 (optional)
41108 * @param {Field} etc (optional)
41109 * @return Layout The container object
41111 container : function(c){
41112 var l = new Roo.form.Layout(c);
41114 if(arguments.length > 1){ // duplicate code required because of Opera
41115 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41122 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41123 * @param {Object} container A Roo.form.Layout or subclass of Layout
41124 * @return {Form} this
41126 start : function(c){
41127 // cascade label info
41128 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
41129 this.active.stack.push(c);
41130 c.ownerCt = this.active;
41136 * Closes the current open container
41137 * @return {Form} this
41140 if(this.active == this.root){
41143 this.active = this.active.ownerCt;
41148 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
41149 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
41150 * as the label of the field.
41151 * @param {Field} field1
41152 * @param {Field} field2 (optional)
41153 * @param {Field} etc. (optional)
41154 * @return {Form} this
41157 this.active.stack.push.apply(this.active.stack, arguments);
41158 this.allItems.push.apply(this.allItems,arguments);
41160 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
41161 if(a[i].isFormField){
41166 Roo.form.Form.superclass.add.apply(this, r);
41176 * Find any element that has been added to a form, using it's ID or name
41177 * This can include framesets, columns etc. along with regular fields..
41178 * @param {String} id - id or name to find.
41180 * @return {Element} e - or false if nothing found.
41182 findbyId : function(id)
41188 Ext.each(this.allItems, function(f){
41189 if (f.id == id || f.name == id ){
41200 * Render this form into the passed container. This should only be called once!
41201 * @param {String/HTMLElement/Element} container The element this component should be rendered into
41202 * @return {Form} this
41204 render : function(ct)
41210 var o = this.autoCreate || {
41212 method : this.method || 'POST',
41213 id : this.id || Roo.id()
41215 this.initEl(ct.createChild(o));
41217 this.root.render(this.el);
41221 this.items.each(function(f){
41222 f.render('x-form-el-'+f.id);
41225 if(this.buttons.length > 0){
41226 // tables are required to maintain order and for correct IE layout
41227 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
41228 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
41229 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
41231 var tr = tb.getElementsByTagName('tr')[0];
41232 for(var i = 0, len = this.buttons.length; i < len; i++) {
41233 var b = this.buttons[i];
41234 var td = document.createElement('td');
41235 td.className = 'x-form-btn-td';
41236 b.render(tr.appendChild(td));
41239 if(this.monitorValid){ // initialize after render
41240 this.startMonitoring();
41242 this.fireEvent('rendered', this);
41247 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
41248 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
41249 * object or a valid Roo.DomHelper element config
41250 * @param {Function} handler The function called when the button is clicked
41251 * @param {Object} scope (optional) The scope of the handler function
41252 * @return {Roo.Button}
41254 addButton : function(config, handler, scope){
41258 minWidth: this.minButtonWidth,
41261 if(typeof config == "string"){
41264 Roo.apply(bc, config);
41266 var btn = new Roo.Button(null, bc);
41267 this.buttons.push(btn);
41272 * Adds a series of form elements (using the xtype property as the factory method.
41273 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41274 * @param {Object} config
41277 addxtype : function()
41279 var ar = Array.prototype.slice.call(arguments, 0);
41281 for(var i = 0; i < ar.length; i++) {
41283 continue; // skip -- if this happends something invalid got sent, we
41284 // should ignore it, as basically that interface element will not show up
41285 // and that should be pretty obvious!!
41288 if (Roo.form[ar[i].xtype]) {
41290 var fe = Roo.factory(ar[i], Roo.form);
41296 fe.store.form = this;
41301 this.allItems.push(fe);
41302 if (fe.items && fe.addxtype) {
41303 fe.addxtype.apply(fe, fe.items);
41313 // console.log('adding ' + ar[i].xtype);
41315 if (ar[i].xtype == 'Button') {
41316 //console.log('adding button');
41317 //console.log(ar[i]);
41318 this.addButton(ar[i]);
41319 this.allItems.push(fe);
41323 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
41324 alert('end is not supported on xtype any more, use items');
41326 // //console.log('adding end');
41334 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
41335 * option "monitorValid"
41337 startMonitoring : function(){
41340 Roo.TaskMgr.start({
41341 run : this.bindHandler,
41342 interval : this.monitorPoll || 200,
41349 * Stops monitoring of the valid state of this form
41351 stopMonitoring : function(){
41352 this.bound = false;
41356 bindHandler : function(){
41358 return false; // stops binding
41361 this.items.each(function(f){
41362 if(!f.isValid(true)){
41367 for(var i = 0, len = this.buttons.length; i < len; i++){
41368 var btn = this.buttons[i];
41369 if(btn.formBind === true && btn.disabled === valid){
41370 btn.setDisabled(!valid);
41373 this.fireEvent('clientvalidation', this, valid);
41387 Roo.Form = Roo.form.Form;
41390 * Ext JS Library 1.1.1
41391 * Copyright(c) 2006-2007, Ext JS, LLC.
41393 * Originally Released Under LGPL - original licence link has changed is not relivant.
41396 * <script type="text/javascript">
41400 * @class Roo.form.Action
41401 * Internal Class used to handle form actions
41403 * @param {Roo.form.BasicForm} el The form element or its id
41404 * @param {Object} config Configuration options
41408 // define the action interface
41409 Roo.form.Action = function(form, options){
41411 this.options = options || {};
41414 * Client Validation Failed
41417 Roo.form.Action.CLIENT_INVALID = 'client';
41419 * Server Validation Failed
41422 Roo.form.Action.SERVER_INVALID = 'server';
41424 * Connect to Server Failed
41427 Roo.form.Action.CONNECT_FAILURE = 'connect';
41429 * Reading Data from Server Failed
41432 Roo.form.Action.LOAD_FAILURE = 'load';
41434 Roo.form.Action.prototype = {
41436 failureType : undefined,
41437 response : undefined,
41438 result : undefined,
41440 // interface method
41441 run : function(options){
41445 // interface method
41446 success : function(response){
41450 // interface method
41451 handleResponse : function(response){
41455 // default connection failure
41456 failure : function(response){
41458 this.response = response;
41459 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41460 this.form.afterAction(this, false);
41463 processResponse : function(response){
41464 this.response = response;
41465 if(!response.responseText){
41468 this.result = this.handleResponse(response);
41469 return this.result;
41472 // utility functions used internally
41473 getUrl : function(appendParams){
41474 var url = this.options.url || this.form.url || this.form.el.dom.action;
41476 var p = this.getParams();
41478 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
41484 getMethod : function(){
41485 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
41488 getParams : function(){
41489 var bp = this.form.baseParams;
41490 var p = this.options.params;
41492 if(typeof p == "object"){
41493 p = Roo.urlEncode(Roo.applyIf(p, bp));
41494 }else if(typeof p == 'string' && bp){
41495 p += '&' + Roo.urlEncode(bp);
41498 p = Roo.urlEncode(bp);
41503 createCallback : function(){
41505 success: this.success,
41506 failure: this.failure,
41508 timeout: (this.form.timeout*1000),
41509 upload: this.form.fileUpload ? this.success : undefined
41514 Roo.form.Action.Submit = function(form, options){
41515 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
41518 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
41521 haveProgress : false,
41522 uploadComplete : false,
41524 // uploadProgress indicator.
41525 uploadProgress : function()
41527 if (!this.form.progressUrl) {
41531 if (!this.haveProgress) {
41532 Roo.MessageBox.progress("Uploading", "Uploading");
41534 if (this.uploadComplete) {
41535 Roo.MessageBox.hide();
41539 this.haveProgress = true;
41541 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
41543 var c = new Roo.data.Connection();
41545 url : this.form.progressUrl,
41550 success : function(req){
41551 //console.log(data);
41555 rdata = Roo.decode(req.responseText)
41557 Roo.log("Invalid data from server..");
41561 if (!rdata || !rdata.success) {
41565 var data = rdata.data;
41567 if (this.uploadComplete) {
41568 Roo.MessageBox.hide();
41573 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
41574 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
41577 this.uploadProgress.defer(2000,this);
41580 failure: function(data) {
41581 Roo.log('progress url failed ');
41592 // run get Values on the form, so it syncs any secondary forms.
41593 this.form.getValues();
41595 var o = this.options;
41596 var method = this.getMethod();
41597 var isPost = method == 'POST';
41598 if(o.clientValidation === false || this.form.isValid()){
41600 if (this.form.progressUrl) {
41601 this.form.findField('UPLOAD_IDENTIFIER').setValue(
41602 (new Date() * 1) + '' + Math.random());
41607 Roo.Ajax.request(Roo.apply(this.createCallback(), {
41608 form:this.form.el.dom,
41609 url:this.getUrl(!isPost),
41611 params:isPost ? this.getParams() : null,
41612 isUpload: this.form.fileUpload
41615 this.uploadProgress();
41617 }else if (o.clientValidation !== false){ // client validation failed
41618 this.failureType = Roo.form.Action.CLIENT_INVALID;
41619 this.form.afterAction(this, false);
41623 success : function(response)
41625 this.uploadComplete= true;
41626 if (this.haveProgress) {
41627 Roo.MessageBox.hide();
41631 var result = this.processResponse(response);
41632 if(result === true || result.success){
41633 this.form.afterAction(this, true);
41637 this.form.markInvalid(result.errors);
41638 this.failureType = Roo.form.Action.SERVER_INVALID;
41640 this.form.afterAction(this, false);
41642 failure : function(response)
41644 this.uploadComplete= true;
41645 if (this.haveProgress) {
41646 Roo.MessageBox.hide();
41650 this.response = response;
41651 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41652 this.form.afterAction(this, false);
41655 handleResponse : function(response){
41656 if(this.form.errorReader){
41657 var rs = this.form.errorReader.read(response);
41660 for(var i = 0, len = rs.records.length; i < len; i++) {
41661 var r = rs.records[i];
41662 errors[i] = r.data;
41665 if(errors.length < 1){
41669 success : rs.success,
41675 ret = Roo.decode(response.responseText);
41679 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
41689 Roo.form.Action.Load = function(form, options){
41690 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
41691 this.reader = this.form.reader;
41694 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
41699 Roo.Ajax.request(Roo.apply(
41700 this.createCallback(), {
41701 method:this.getMethod(),
41702 url:this.getUrl(false),
41703 params:this.getParams()
41707 success : function(response){
41709 var result = this.processResponse(response);
41710 if(result === true || !result.success || !result.data){
41711 this.failureType = Roo.form.Action.LOAD_FAILURE;
41712 this.form.afterAction(this, false);
41715 this.form.clearInvalid();
41716 this.form.setValues(result.data);
41717 this.form.afterAction(this, true);
41720 handleResponse : function(response){
41721 if(this.form.reader){
41722 var rs = this.form.reader.read(response);
41723 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
41725 success : rs.success,
41729 return Roo.decode(response.responseText);
41733 Roo.form.Action.ACTION_TYPES = {
41734 'load' : Roo.form.Action.Load,
41735 'submit' : Roo.form.Action.Submit
41738 * Ext JS Library 1.1.1
41739 * Copyright(c) 2006-2007, Ext JS, LLC.
41741 * Originally Released Under LGPL - original licence link has changed is not relivant.
41744 * <script type="text/javascript">
41748 * @class Roo.form.Layout
41749 * @extends Roo.Component
41750 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
41752 * @param {Object} config Configuration options
41754 Roo.form.Layout = function(config){
41756 if (config.items) {
41757 xitems = config.items;
41758 delete config.items;
41760 Roo.form.Layout.superclass.constructor.call(this, config);
41762 Roo.each(xitems, this.addxtype, this);
41766 Roo.extend(Roo.form.Layout, Roo.Component, {
41768 * @cfg {String/Object} autoCreate
41769 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
41772 * @cfg {String/Object/Function} style
41773 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
41774 * a function which returns such a specification.
41777 * @cfg {String} labelAlign
41778 * Valid values are "left," "top" and "right" (defaults to "left")
41781 * @cfg {Number} labelWidth
41782 * Fixed width in pixels of all field labels (defaults to undefined)
41785 * @cfg {Boolean} clear
41786 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
41790 * @cfg {String} labelSeparator
41791 * The separator to use after field labels (defaults to ':')
41793 labelSeparator : ':',
41795 * @cfg {Boolean} hideLabels
41796 * True to suppress the display of field labels in this layout (defaults to false)
41798 hideLabels : false,
41801 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
41806 onRender : function(ct, position){
41807 if(this.el){ // from markup
41808 this.el = Roo.get(this.el);
41809 }else { // generate
41810 var cfg = this.getAutoCreate();
41811 this.el = ct.createChild(cfg, position);
41814 this.el.applyStyles(this.style);
41816 if(this.labelAlign){
41817 this.el.addClass('x-form-label-'+this.labelAlign);
41819 if(this.hideLabels){
41820 this.labelStyle = "display:none";
41821 this.elementStyle = "padding-left:0;";
41823 if(typeof this.labelWidth == 'number'){
41824 this.labelStyle = "width:"+this.labelWidth+"px;";
41825 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
41827 if(this.labelAlign == 'top'){
41828 this.labelStyle = "width:auto;";
41829 this.elementStyle = "padding-left:0;";
41832 var stack = this.stack;
41833 var slen = stack.length;
41835 if(!this.fieldTpl){
41836 var t = new Roo.Template(
41837 '<div class="x-form-item {5}">',
41838 '<label for="{0}" style="{2}">{1}{4}</label>',
41839 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41841 '</div><div class="x-form-clear-left"></div>'
41843 t.disableFormats = true;
41845 Roo.form.Layout.prototype.fieldTpl = t;
41847 for(var i = 0; i < slen; i++) {
41848 if(stack[i].isFormField){
41849 this.renderField(stack[i]);
41851 this.renderComponent(stack[i]);
41856 this.el.createChild({cls:'x-form-clear'});
41861 renderField : function(f){
41862 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
41865 f.labelStyle||this.labelStyle||'', //2
41866 this.elementStyle||'', //3
41867 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
41868 f.itemCls||this.itemCls||'' //5
41869 ], true).getPrevSibling());
41873 renderComponent : function(c){
41874 c.render(c.isLayout ? this.el : this.el.createChild());
41877 * Adds a object form elements (using the xtype property as the factory method.)
41878 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
41879 * @param {Object} config
41881 addxtype : function(o)
41883 // create the lement.
41884 o.form = this.form;
41885 var fe = Roo.factory(o, Roo.form);
41886 this.form.allItems.push(fe);
41887 this.stack.push(fe);
41889 if (fe.isFormField) {
41890 this.form.items.add(fe);
41898 * @class Roo.form.Column
41899 * @extends Roo.form.Layout
41900 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
41902 * @param {Object} config Configuration options
41904 Roo.form.Column = function(config){
41905 Roo.form.Column.superclass.constructor.call(this, config);
41908 Roo.extend(Roo.form.Column, Roo.form.Layout, {
41910 * @cfg {Number/String} width
41911 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41914 * @cfg {String/Object} autoCreate
41915 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41919 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41922 onRender : function(ct, position){
41923 Roo.form.Column.superclass.onRender.call(this, ct, position);
41925 this.el.setWidth(this.width);
41932 * @class Roo.form.Row
41933 * @extends Roo.form.Layout
41934 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41936 * @param {Object} config Configuration options
41940 Roo.form.Row = function(config){
41941 Roo.form.Row.superclass.constructor.call(this, config);
41944 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41946 * @cfg {Number/String} width
41947 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41950 * @cfg {Number/String} height
41951 * The fixed height of the column in pixels or CSS value (defaults to "auto")
41953 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
41957 onRender : function(ct, position){
41958 //console.log('row render');
41960 var t = new Roo.Template(
41961 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
41962 '<label for="{0}" style="{2}">{1}{4}</label>',
41963 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41967 t.disableFormats = true;
41969 Roo.form.Layout.prototype.rowTpl = t;
41971 this.fieldTpl = this.rowTpl;
41973 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
41974 var labelWidth = 100;
41976 if ((this.labelAlign != 'top')) {
41977 if (typeof this.labelWidth == 'number') {
41978 labelWidth = this.labelWidth
41980 this.padWidth = 20 + labelWidth;
41984 Roo.form.Column.superclass.onRender.call(this, ct, position);
41986 this.el.setWidth(this.width);
41989 this.el.setHeight(this.height);
41994 renderField : function(f){
41995 f.fieldEl = this.fieldTpl.append(this.el, [
41996 f.id, f.fieldLabel,
41997 f.labelStyle||this.labelStyle||'',
41998 this.elementStyle||'',
41999 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
42000 f.itemCls||this.itemCls||'',
42001 f.width ? f.width + this.padWidth : 160 + this.padWidth
42008 * @class Roo.form.FieldSet
42009 * @extends Roo.form.Layout
42010 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
42012 * @param {Object} config Configuration options
42014 Roo.form.FieldSet = function(config){
42015 Roo.form.FieldSet.superclass.constructor.call(this, config);
42018 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
42020 * @cfg {String} legend
42021 * The text to display as the legend for the FieldSet (defaults to '')
42024 * @cfg {String/Object} autoCreate
42025 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
42029 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
42032 onRender : function(ct, position){
42033 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
42035 this.setLegend(this.legend);
42040 setLegend : function(text){
42042 this.el.child('legend').update(text);
42047 * Ext JS Library 1.1.1
42048 * Copyright(c) 2006-2007, Ext JS, LLC.
42050 * Originally Released Under LGPL - original licence link has changed is not relivant.
42053 * <script type="text/javascript">
42056 * @class Roo.form.VTypes
42057 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
42060 Roo.form.VTypes = function(){
42061 // closure these in so they are only created once.
42062 var alpha = /^[a-zA-Z_]+$/;
42063 var alphanum = /^[a-zA-Z0-9_]+$/;
42064 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
42065 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
42067 // All these messages and functions are configurable
42070 * The function used to validate email addresses
42071 * @param {String} value The email address
42073 'email' : function(v){
42074 return email.test(v);
42077 * The error text to display when the email validation function returns false
42080 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
42082 * The keystroke filter mask to be applied on email input
42085 'emailMask' : /[a-z0-9_\.\-@]/i,
42088 * The function used to validate URLs
42089 * @param {String} value The URL
42091 'url' : function(v){
42092 return url.test(v);
42095 * The error text to display when the url validation function returns false
42098 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
42101 * The function used to validate alpha values
42102 * @param {String} value The value
42104 'alpha' : function(v){
42105 return alpha.test(v);
42108 * The error text to display when the alpha validation function returns false
42111 'alphaText' : 'This field should only contain letters and _',
42113 * The keystroke filter mask to be applied on alpha input
42116 'alphaMask' : /[a-z_]/i,
42119 * The function used to validate alphanumeric values
42120 * @param {String} value The value
42122 'alphanum' : function(v){
42123 return alphanum.test(v);
42126 * The error text to display when the alphanumeric validation function returns false
42129 'alphanumText' : 'This field should only contain letters, numbers and _',
42131 * The keystroke filter mask to be applied on alphanumeric input
42134 'alphanumMask' : /[a-z0-9_]/i
42136 }();//<script type="text/javascript">
42139 * @class Roo.form.FCKeditor
42140 * @extends Roo.form.TextArea
42141 * Wrapper around the FCKEditor http://www.fckeditor.net
42143 * Creates a new FCKeditor
42144 * @param {Object} config Configuration options
42146 Roo.form.FCKeditor = function(config){
42147 Roo.form.FCKeditor.superclass.constructor.call(this, config);
42150 * @event editorinit
42151 * Fired when the editor is initialized - you can add extra handlers here..
42152 * @param {FCKeditor} this
42153 * @param {Object} the FCK object.
42160 Roo.form.FCKeditor.editors = { };
42161 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
42163 //defaultAutoCreate : {
42164 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
42168 * @cfg {Object} fck options - see fck manual for details.
42173 * @cfg {Object} fck toolbar set (Basic or Default)
42175 toolbarSet : 'Basic',
42177 * @cfg {Object} fck BasePath
42179 basePath : '/fckeditor/',
42187 onRender : function(ct, position)
42190 this.defaultAutoCreate = {
42192 style:"width:300px;height:60px;",
42193 autocomplete: "off"
42196 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
42199 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
42200 if(this.preventScrollbars){
42201 this.el.setStyle("overflow", "hidden");
42203 this.el.setHeight(this.growMin);
42206 //console.log('onrender' + this.getId() );
42207 Roo.form.FCKeditor.editors[this.getId()] = this;
42210 this.replaceTextarea() ;
42214 getEditor : function() {
42215 return this.fckEditor;
42218 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
42219 * @param {Mixed} value The value to set
42223 setValue : function(value)
42225 //console.log('setValue: ' + value);
42227 if(typeof(value) == 'undefined') { // not sure why this is happending...
42230 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42232 //if(!this.el || !this.getEditor()) {
42233 // this.value = value;
42234 //this.setValue.defer(100,this,[value]);
42238 if(!this.getEditor()) {
42242 this.getEditor().SetData(value);
42249 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
42250 * @return {Mixed} value The field value
42252 getValue : function()
42255 if (this.frame && this.frame.dom.style.display == 'none') {
42256 return Roo.form.FCKeditor.superclass.getValue.call(this);
42259 if(!this.el || !this.getEditor()) {
42261 // this.getValue.defer(100,this);
42266 var value=this.getEditor().GetData();
42267 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42268 return Roo.form.FCKeditor.superclass.getValue.call(this);
42274 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
42275 * @return {Mixed} value The field value
42277 getRawValue : function()
42279 if (this.frame && this.frame.dom.style.display == 'none') {
42280 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42283 if(!this.el || !this.getEditor()) {
42284 //this.getRawValue.defer(100,this);
42291 var value=this.getEditor().GetData();
42292 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
42293 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42297 setSize : function(w,h) {
42301 //if (this.frame && this.frame.dom.style.display == 'none') {
42302 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42305 //if(!this.el || !this.getEditor()) {
42306 // this.setSize.defer(100,this, [w,h]);
42312 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42314 this.frame.dom.setAttribute('width', w);
42315 this.frame.dom.setAttribute('height', h);
42316 this.frame.setSize(w,h);
42320 toggleSourceEdit : function(value) {
42324 this.el.dom.style.display = value ? '' : 'none';
42325 this.frame.dom.style.display = value ? 'none' : '';
42330 focus: function(tag)
42332 if (this.frame.dom.style.display == 'none') {
42333 return Roo.form.FCKeditor.superclass.focus.call(this);
42335 if(!this.el || !this.getEditor()) {
42336 this.focus.defer(100,this, [tag]);
42343 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
42344 this.getEditor().Focus();
42346 if (!this.getEditor().Selection.GetSelection()) {
42347 this.focus.defer(100,this, [tag]);
42352 var r = this.getEditor().EditorDocument.createRange();
42353 r.setStart(tgs[0],0);
42354 r.setEnd(tgs[0],0);
42355 this.getEditor().Selection.GetSelection().removeAllRanges();
42356 this.getEditor().Selection.GetSelection().addRange(r);
42357 this.getEditor().Focus();
42364 replaceTextarea : function()
42366 if ( document.getElementById( this.getId() + '___Frame' ) )
42368 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
42370 // We must check the elements firstly using the Id and then the name.
42371 var oTextarea = document.getElementById( this.getId() );
42373 var colElementsByName = document.getElementsByName( this.getId() ) ;
42375 oTextarea.style.display = 'none' ;
42377 if ( oTextarea.tabIndex ) {
42378 this.TabIndex = oTextarea.tabIndex ;
42381 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
42382 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
42383 this.frame = Roo.get(this.getId() + '___Frame')
42386 _getConfigHtml : function()
42390 for ( var o in this.fckconfig ) {
42391 sConfig += sConfig.length > 0 ? '&' : '';
42392 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
42395 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
42399 _getIFrameHtml : function()
42401 var sFile = 'fckeditor.html' ;
42402 /* no idea what this is about..
42405 if ( (/fcksource=true/i).test( window.top.location.search ) )
42406 sFile = 'fckeditor.original.html' ;
42411 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
42412 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
42415 var html = '<iframe id="' + this.getId() +
42416 '___Frame" src="' + sLink +
42417 '" width="' + this.width +
42418 '" height="' + this.height + '"' +
42419 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
42420 ' frameborder="0" scrolling="no"></iframe>' ;
42425 _insertHtmlBefore : function( html, element )
42427 if ( element.insertAdjacentHTML ) {
42429 element.insertAdjacentHTML( 'beforeBegin', html ) ;
42431 var oRange = document.createRange() ;
42432 oRange.setStartBefore( element ) ;
42433 var oFragment = oRange.createContextualFragment( html );
42434 element.parentNode.insertBefore( oFragment, element ) ;
42447 //Roo.reg('fckeditor', Roo.form.FCKeditor);
42449 function FCKeditor_OnComplete(editorInstance){
42450 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
42451 f.fckEditor = editorInstance;
42452 //console.log("loaded");
42453 f.fireEvent('editorinit', f, editorInstance);
42473 //<script type="text/javascript">
42475 * @class Roo.form.GridField
42476 * @extends Roo.form.Field
42477 * Embed a grid (or editable grid into a form)
42480 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
42482 * xgrid.store = Roo.data.Store
42483 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
42484 * xgrid.store.reader = Roo.data.JsonReader
42488 * Creates a new GridField
42489 * @param {Object} config Configuration options
42491 Roo.form.GridField = function(config){
42492 Roo.form.GridField.superclass.constructor.call(this, config);
42496 Roo.extend(Roo.form.GridField, Roo.form.Field, {
42498 * @cfg {Number} width - used to restrict width of grid..
42502 * @cfg {Number} height - used to restrict height of grid..
42506 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
42512 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42513 * {tag: "input", type: "checkbox", autocomplete: "off"})
42515 // defaultAutoCreate : { tag: 'div' },
42516 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42518 * @cfg {String} addTitle Text to include for adding a title.
42522 onResize : function(){
42523 Roo.form.Field.superclass.onResize.apply(this, arguments);
42526 initEvents : function(){
42527 // Roo.form.Checkbox.superclass.initEvents.call(this);
42528 // has no events...
42533 getResizeEl : function(){
42537 getPositionEl : function(){
42542 onRender : function(ct, position){
42544 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
42545 var style = this.style;
42548 Roo.form.GridField.superclass.onRender.call(this, ct, position);
42549 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
42550 this.viewEl = this.wrap.createChild({ tag: 'div' });
42552 this.viewEl.applyStyles(style);
42555 this.viewEl.setWidth(this.width);
42558 this.viewEl.setHeight(this.height);
42560 //if(this.inputValue !== undefined){
42561 //this.setValue(this.value);
42564 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
42567 this.grid.render();
42568 this.grid.getDataSource().on('remove', this.refreshValue, this);
42569 this.grid.getDataSource().on('update', this.refreshValue, this);
42570 this.grid.on('afteredit', this.refreshValue, this);
42576 * Sets the value of the item.
42577 * @param {String} either an object or a string..
42579 setValue : function(v){
42581 v = v || []; // empty set..
42582 // this does not seem smart - it really only affects memoryproxy grids..
42583 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
42584 var ds = this.grid.getDataSource();
42585 // assumes a json reader..
42587 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
42588 ds.loadData( data);
42590 Roo.form.GridField.superclass.setValue.call(this, v);
42591 this.refreshValue();
42592 // should load data in the grid really....
42596 refreshValue: function() {
42598 this.grid.getDataSource().each(function(r) {
42601 this.el.dom.value = Roo.encode(val);
42609 * Ext JS Library 1.1.1
42610 * Copyright(c) 2006-2007, Ext JS, LLC.
42612 * Originally Released Under LGPL - original licence link has changed is not relivant.
42615 * <script type="text/javascript">
42618 * @class Roo.form.DisplayField
42619 * @extends Roo.form.Field
42620 * A generic Field to display non-editable data.
42622 * Creates a new Display Field item.
42623 * @param {Object} config Configuration options
42625 Roo.form.DisplayField = function(config){
42626 Roo.form.DisplayField.superclass.constructor.call(this, config);
42630 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
42631 inputType: 'hidden',
42637 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42639 focusClass : undefined,
42641 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42643 fieldClass: 'x-form-field',
42646 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
42648 valueRenderer: undefined,
42652 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42653 * {tag: "input", type: "checkbox", autocomplete: "off"})
42656 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42658 onResize : function(){
42659 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
42663 initEvents : function(){
42664 // Roo.form.Checkbox.superclass.initEvents.call(this);
42665 // has no events...
42670 getResizeEl : function(){
42674 getPositionEl : function(){
42679 onRender : function(ct, position){
42681 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
42682 //if(this.inputValue !== undefined){
42683 this.wrap = this.el.wrap();
42685 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
42687 if (this.bodyStyle) {
42688 this.viewEl.applyStyles(this.bodyStyle);
42690 //this.viewEl.setStyle('padding', '2px');
42692 this.setValue(this.value);
42697 initValue : Roo.emptyFn,
42702 onClick : function(){
42707 * Sets the checked state of the checkbox.
42708 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
42710 setValue : function(v){
42712 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
42713 // this might be called before we have a dom element..
42714 if (!this.viewEl) {
42717 this.viewEl.dom.innerHTML = html;
42718 Roo.form.DisplayField.superclass.setValue.call(this, v);
42728 * @class Roo.form.DayPicker
42729 * @extends Roo.form.Field
42730 * A Day picker show [M] [T] [W] ....
42732 * Creates a new Day Picker
42733 * @param {Object} config Configuration options
42735 Roo.form.DayPicker= function(config){
42736 Roo.form.DayPicker.superclass.constructor.call(this, config);
42740 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
42742 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42744 focusClass : undefined,
42746 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42748 fieldClass: "x-form-field",
42751 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42752 * {tag: "input", type: "checkbox", autocomplete: "off"})
42754 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42757 actionMode : 'viewEl',
42761 inputType : 'hidden',
42764 inputElement: false, // real input element?
42765 basedOn: false, // ????
42767 isFormField: true, // not sure where this is needed!!!!
42769 onResize : function(){
42770 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42771 if(!this.boxLabel){
42772 this.el.alignTo(this.wrap, 'c-c');
42776 initEvents : function(){
42777 Roo.form.Checkbox.superclass.initEvents.call(this);
42778 this.el.on("click", this.onClick, this);
42779 this.el.on("change", this.onClick, this);
42783 getResizeEl : function(){
42787 getPositionEl : function(){
42793 onRender : function(ct, position){
42794 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42796 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
42798 var r1 = '<table><tr>';
42799 var r2 = '<tr class="x-form-daypick-icons">';
42800 for (var i=0; i < 7; i++) {
42801 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
42802 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
42805 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
42806 viewEl.select('img').on('click', this.onClick, this);
42807 this.viewEl = viewEl;
42810 // this will not work on Chrome!!!
42811 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42812 this.el.on('propertychange', this.setFromHidden, this); //ie
42820 initValue : Roo.emptyFn,
42823 * Returns the checked state of the checkbox.
42824 * @return {Boolean} True if checked, else false
42826 getValue : function(){
42827 return this.el.dom.value;
42832 onClick : function(e){
42833 //this.setChecked(!this.checked);
42834 Roo.get(e.target).toggleClass('x-menu-item-checked');
42835 this.refreshValue();
42836 //if(this.el.dom.checked != this.checked){
42837 // this.setValue(this.el.dom.checked);
42842 refreshValue : function()
42845 this.viewEl.select('img',true).each(function(e,i,n) {
42846 val += e.is(".x-menu-item-checked") ? String(n) : '';
42848 this.setValue(val, true);
42852 * Sets the checked state of the checkbox.
42853 * On is always based on a string comparison between inputValue and the param.
42854 * @param {Boolean/String} value - the value to set
42855 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42857 setValue : function(v,suppressEvent){
42858 if (!this.el.dom) {
42861 var old = this.el.dom.value ;
42862 this.el.dom.value = v;
42863 if (suppressEvent) {
42867 // update display..
42868 this.viewEl.select('img',true).each(function(e,i,n) {
42870 var on = e.is(".x-menu-item-checked");
42871 var newv = v.indexOf(String(n)) > -1;
42873 e.toggleClass('x-menu-item-checked');
42879 this.fireEvent('change', this, v, old);
42884 // handle setting of hidden value by some other method!!?!?
42885 setFromHidden: function()
42890 //console.log("SET FROM HIDDEN");
42891 //alert('setFrom hidden');
42892 this.setValue(this.el.dom.value);
42895 onDestroy : function()
42898 Roo.get(this.viewEl).remove();
42901 Roo.form.DayPicker.superclass.onDestroy.call(this);
42904 });//<script type="text/javasscript">
42908 * @class Roo.DDView
42909 * A DnD enabled version of Roo.View.
42910 * @param {Element/String} container The Element in which to create the View.
42911 * @param {String} tpl The template string used to create the markup for each element of the View
42912 * @param {Object} config The configuration properties. These include all the config options of
42913 * {@link Roo.View} plus some specific to this class.<br>
42915 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
42916 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
42918 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
42919 .x-view-drag-insert-above {
42920 border-top:1px dotted #3366cc;
42922 .x-view-drag-insert-below {
42923 border-bottom:1px dotted #3366cc;
42929 Roo.DDView = function(container, tpl, config) {
42930 Roo.DDView.superclass.constructor.apply(this, arguments);
42931 this.getEl().setStyle("outline", "0px none");
42932 this.getEl().unselectable();
42933 if (this.dragGroup) {
42934 this.setDraggable(this.dragGroup.split(","));
42936 if (this.dropGroup) {
42937 this.setDroppable(this.dropGroup.split(","));
42939 if (this.deletable) {
42940 this.setDeletable();
42942 this.isDirtyFlag = false;
42948 Roo.extend(Roo.DDView, Roo.View, {
42949 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
42950 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
42951 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
42952 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
42956 reset: Roo.emptyFn,
42958 clearInvalid: Roo.form.Field.prototype.clearInvalid,
42960 validate: function() {
42964 destroy: function() {
42965 this.purgeListeners();
42966 this.getEl.removeAllListeners();
42967 this.getEl().remove();
42968 if (this.dragZone) {
42969 if (this.dragZone.destroy) {
42970 this.dragZone.destroy();
42973 if (this.dropZone) {
42974 if (this.dropZone.destroy) {
42975 this.dropZone.destroy();
42980 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
42981 getName: function() {
42985 /** Loads the View from a JSON string representing the Records to put into the Store. */
42986 setValue: function(v) {
42988 throw "DDView.setValue(). DDView must be constructed with a valid Store";
42991 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
42992 this.store.proxy = new Roo.data.MemoryProxy(data);
42996 /** @return {String} a parenthesised list of the ids of the Records in the View. */
42997 getValue: function() {
42999 this.store.each(function(rec) {
43000 result += rec.id + ',';
43002 return result.substr(0, result.length - 1) + ')';
43005 getIds: function() {
43006 var i = 0, result = new Array(this.store.getCount());
43007 this.store.each(function(rec) {
43008 result[i++] = rec.id;
43013 isDirty: function() {
43014 return this.isDirtyFlag;
43018 * Part of the Roo.dd.DropZone interface. If no target node is found, the
43019 * whole Element becomes the target, and this causes the drop gesture to append.
43021 getTargetFromEvent : function(e) {
43022 var target = e.getTarget();
43023 while ((target !== null) && (target.parentNode != this.el.dom)) {
43024 target = target.parentNode;
43027 target = this.el.dom.lastChild || this.el.dom;
43033 * Create the drag data which consists of an object which has the property "ddel" as
43034 * the drag proxy element.
43036 getDragData : function(e) {
43037 var target = this.findItemFromChild(e.getTarget());
43039 this.handleSelection(e);
43040 var selNodes = this.getSelectedNodes();
43043 copy: this.copy || (this.allowCopy && e.ctrlKey),
43047 var selectedIndices = this.getSelectedIndexes();
43048 for (var i = 0; i < selectedIndices.length; i++) {
43049 dragData.records.push(this.store.getAt(selectedIndices[i]));
43051 if (selNodes.length == 1) {
43052 dragData.ddel = target.cloneNode(true); // the div element
43054 var div = document.createElement('div'); // create the multi element drag "ghost"
43055 div.className = 'multi-proxy';
43056 for (var i = 0, len = selNodes.length; i < len; i++) {
43057 div.appendChild(selNodes[i].cloneNode(true));
43059 dragData.ddel = div;
43061 //console.log(dragData)
43062 //console.log(dragData.ddel.innerHTML)
43065 //console.log('nodragData')
43069 /** Specify to which ddGroup items in this DDView may be dragged. */
43070 setDraggable: function(ddGroup) {
43071 if (ddGroup instanceof Array) {
43072 Roo.each(ddGroup, this.setDraggable, this);
43075 if (this.dragZone) {
43076 this.dragZone.addToGroup(ddGroup);
43078 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
43079 containerScroll: true,
43083 // Draggability implies selection. DragZone's mousedown selects the element.
43084 if (!this.multiSelect) { this.singleSelect = true; }
43086 // Wire the DragZone's handlers up to methods in *this*
43087 this.dragZone.getDragData = this.getDragData.createDelegate(this);
43091 /** Specify from which ddGroup this DDView accepts drops. */
43092 setDroppable: function(ddGroup) {
43093 if (ddGroup instanceof Array) {
43094 Roo.each(ddGroup, this.setDroppable, this);
43097 if (this.dropZone) {
43098 this.dropZone.addToGroup(ddGroup);
43100 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
43101 containerScroll: true,
43105 // Wire the DropZone's handlers up to methods in *this*
43106 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
43107 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
43108 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
43109 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
43110 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
43114 /** Decide whether to drop above or below a View node. */
43115 getDropPoint : function(e, n, dd){
43116 if (n == this.el.dom) { return "above"; }
43117 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
43118 var c = t + (b - t) / 2;
43119 var y = Roo.lib.Event.getPageY(e);
43127 onNodeEnter : function(n, dd, e, data){
43131 onNodeOver : function(n, dd, e, data){
43132 var pt = this.getDropPoint(e, n, dd);
43133 // set the insert point style on the target node
43134 var dragElClass = this.dropNotAllowed;
43137 if (pt == "above"){
43138 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
43139 targetElClass = "x-view-drag-insert-above";
43141 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
43142 targetElClass = "x-view-drag-insert-below";
43144 if (this.lastInsertClass != targetElClass){
43145 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
43146 this.lastInsertClass = targetElClass;
43149 return dragElClass;
43152 onNodeOut : function(n, dd, e, data){
43153 this.removeDropIndicators(n);
43156 onNodeDrop : function(n, dd, e, data){
43157 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
43160 var pt = this.getDropPoint(e, n, dd);
43161 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
43162 if (pt == "below") { insertAt++; }
43163 for (var i = 0; i < data.records.length; i++) {
43164 var r = data.records[i];
43165 var dup = this.store.getById(r.id);
43166 if (dup && (dd != this.dragZone)) {
43167 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
43170 this.store.insert(insertAt++, r.copy());
43172 data.source.isDirtyFlag = true;
43174 this.store.insert(insertAt++, r);
43176 this.isDirtyFlag = true;
43179 this.dragZone.cachedTarget = null;
43183 removeDropIndicators : function(n){
43185 Roo.fly(n).removeClass([
43186 "x-view-drag-insert-above",
43187 "x-view-drag-insert-below"]);
43188 this.lastInsertClass = "_noclass";
43193 * Utility method. Add a delete option to the DDView's context menu.
43194 * @param {String} imageUrl The URL of the "delete" icon image.
43196 setDeletable: function(imageUrl) {
43197 if (!this.singleSelect && !this.multiSelect) {
43198 this.singleSelect = true;
43200 var c = this.getContextMenu();
43201 this.contextMenu.on("itemclick", function(item) {
43204 this.remove(this.getSelectedIndexes());
43208 this.contextMenu.add({
43215 /** Return the context menu for this DDView. */
43216 getContextMenu: function() {
43217 if (!this.contextMenu) {
43218 // Create the View's context menu
43219 this.contextMenu = new Roo.menu.Menu({
43220 id: this.id + "-contextmenu"
43222 this.el.on("contextmenu", this.showContextMenu, this);
43224 return this.contextMenu;
43227 disableContextMenu: function() {
43228 if (this.contextMenu) {
43229 this.el.un("contextmenu", this.showContextMenu, this);
43233 showContextMenu: function(e, item) {
43234 item = this.findItemFromChild(e.getTarget());
43237 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
43238 this.contextMenu.showAt(e.getXY());
43243 * Remove {@link Roo.data.Record}s at the specified indices.
43244 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
43246 remove: function(selectedIndices) {
43247 selectedIndices = [].concat(selectedIndices);
43248 for (var i = 0; i < selectedIndices.length; i++) {
43249 var rec = this.store.getAt(selectedIndices[i]);
43250 this.store.remove(rec);
43255 * Double click fires the event, but also, if this is draggable, and there is only one other
43256 * related DropZone, it transfers the selected node.
43258 onDblClick : function(e){
43259 var item = this.findItemFromChild(e.getTarget());
43261 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
43264 if (this.dragGroup) {
43265 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
43266 while (targets.indexOf(this.dropZone) > -1) {
43267 targets.remove(this.dropZone);
43269 if (targets.length == 1) {
43270 this.dragZone.cachedTarget = null;
43271 var el = Roo.get(targets[0].getEl());
43272 var box = el.getBox(true);
43273 targets[0].onNodeDrop(el.dom, {
43275 xy: [box.x, box.y + box.height - 1]
43276 }, null, this.getDragData(e));
43282 handleSelection: function(e) {
43283 this.dragZone.cachedTarget = null;
43284 var item = this.findItemFromChild(e.getTarget());
43286 this.clearSelections(true);
43289 if (item && (this.multiSelect || this.singleSelect)){
43290 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
43291 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
43292 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
43293 this.unselect(item);
43295 this.select(item, this.multiSelect && e.ctrlKey);
43296 this.lastSelection = item;
43301 onItemClick : function(item, index, e){
43302 if(this.fireEvent("beforeclick", this, index, item, e) === false){
43308 unselect : function(nodeInfo, suppressEvent){
43309 var node = this.getNode(nodeInfo);
43310 if(node && this.isSelected(node)){
43311 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
43312 Roo.fly(node).removeClass(this.selectedClass);
43313 this.selections.remove(node);
43314 if(!suppressEvent){
43315 this.fireEvent("selectionchange", this, this.selections);
43323 * Ext JS Library 1.1.1
43324 * Copyright(c) 2006-2007, Ext JS, LLC.
43326 * Originally Released Under LGPL - original licence link has changed is not relivant.
43329 * <script type="text/javascript">
43333 * @class Roo.LayoutManager
43334 * @extends Roo.util.Observable
43335 * Base class for layout managers.
43337 Roo.LayoutManager = function(container, config){
43338 Roo.LayoutManager.superclass.constructor.call(this);
43339 this.el = Roo.get(container);
43340 // ie scrollbar fix
43341 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
43342 document.body.scroll = "no";
43343 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
43344 this.el.position('relative');
43346 this.id = this.el.id;
43347 this.el.addClass("x-layout-container");
43348 /** false to disable window resize monitoring @type Boolean */
43349 this.monitorWindowResize = true;
43354 * Fires when a layout is performed.
43355 * @param {Roo.LayoutManager} this
43359 * @event regionresized
43360 * Fires when the user resizes a region.
43361 * @param {Roo.LayoutRegion} region The resized region
43362 * @param {Number} newSize The new size (width for east/west, height for north/south)
43364 "regionresized" : true,
43366 * @event regioncollapsed
43367 * Fires when a region is collapsed.
43368 * @param {Roo.LayoutRegion} region The collapsed region
43370 "regioncollapsed" : true,
43372 * @event regionexpanded
43373 * Fires when a region is expanded.
43374 * @param {Roo.LayoutRegion} region The expanded region
43376 "regionexpanded" : true
43378 this.updating = false;
43379 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
43382 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
43384 * Returns true if this layout is currently being updated
43385 * @return {Boolean}
43387 isUpdating : function(){
43388 return this.updating;
43392 * Suspend the LayoutManager from doing auto-layouts while
43393 * making multiple add or remove calls
43395 beginUpdate : function(){
43396 this.updating = true;
43400 * Restore auto-layouts and optionally disable the manager from performing a layout
43401 * @param {Boolean} noLayout true to disable a layout update
43403 endUpdate : function(noLayout){
43404 this.updating = false;
43410 layout: function(){
43414 onRegionResized : function(region, newSize){
43415 this.fireEvent("regionresized", region, newSize);
43419 onRegionCollapsed : function(region){
43420 this.fireEvent("regioncollapsed", region);
43423 onRegionExpanded : function(region){
43424 this.fireEvent("regionexpanded", region);
43428 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
43429 * performs box-model adjustments.
43430 * @return {Object} The size as an object {width: (the width), height: (the height)}
43432 getViewSize : function(){
43434 if(this.el.dom != document.body){
43435 size = this.el.getSize();
43437 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
43439 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
43440 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
43445 * Returns the Element this layout is bound to.
43446 * @return {Roo.Element}
43448 getEl : function(){
43453 * Returns the specified region.
43454 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
43455 * @return {Roo.LayoutRegion}
43457 getRegion : function(target){
43458 return this.regions[target.toLowerCase()];
43461 onWindowResize : function(){
43462 if(this.monitorWindowResize){
43468 * Ext JS Library 1.1.1
43469 * Copyright(c) 2006-2007, Ext JS, LLC.
43471 * Originally Released Under LGPL - original licence link has changed is not relivant.
43474 * <script type="text/javascript">
43477 * @class Roo.BorderLayout
43478 * @extends Roo.LayoutManager
43479 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
43480 * please see: <br><br>
43481 * <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>
43482 * <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>
43485 var layout = new Roo.BorderLayout(document.body, {
43519 preferredTabWidth: 150
43524 var CP = Roo.ContentPanel;
43526 layout.beginUpdate();
43527 layout.add("north", new CP("north", "North"));
43528 layout.add("south", new CP("south", {title: "South", closable: true}));
43529 layout.add("west", new CP("west", {title: "West"}));
43530 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
43531 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
43532 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
43533 layout.getRegion("center").showPanel("center1");
43534 layout.endUpdate();
43537 <b>The container the layout is rendered into can be either the body element or any other element.
43538 If it is not the body element, the container needs to either be an absolute positioned element,
43539 or you will need to add "position:relative" to the css of the container. You will also need to specify
43540 the container size if it is not the body element.</b>
43543 * Create a new BorderLayout
43544 * @param {String/HTMLElement/Element} container The container this layout is bound to
43545 * @param {Object} config Configuration options
43547 Roo.BorderLayout = function(container, config){
43548 config = config || {};
43549 Roo.BorderLayout.superclass.constructor.call(this, container, config);
43550 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
43551 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
43552 var target = this.factory.validRegions[i];
43553 if(config[target]){
43554 this.addRegion(target, config[target]);
43559 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
43561 * Creates and adds a new region if it doesn't already exist.
43562 * @param {String} target The target region key (north, south, east, west or center).
43563 * @param {Object} config The regions config object
43564 * @return {BorderLayoutRegion} The new region
43566 addRegion : function(target, config){
43567 if(!this.regions[target]){
43568 var r = this.factory.create(target, this, config);
43569 this.bindRegion(target, r);
43571 return this.regions[target];
43575 bindRegion : function(name, r){
43576 this.regions[name] = r;
43577 r.on("visibilitychange", this.layout, this);
43578 r.on("paneladded", this.layout, this);
43579 r.on("panelremoved", this.layout, this);
43580 r.on("invalidated", this.layout, this);
43581 r.on("resized", this.onRegionResized, this);
43582 r.on("collapsed", this.onRegionCollapsed, this);
43583 r.on("expanded", this.onRegionExpanded, this);
43587 * Performs a layout update.
43589 layout : function(){
43590 if(this.updating) return;
43591 var size = this.getViewSize();
43592 var w = size.width;
43593 var h = size.height;
43598 //var x = 0, y = 0;
43600 var rs = this.regions;
43601 var north = rs["north"];
43602 var south = rs["south"];
43603 var west = rs["west"];
43604 var east = rs["east"];
43605 var center = rs["center"];
43606 //if(this.hideOnLayout){ // not supported anymore
43607 //c.el.setStyle("display", "none");
43609 if(north && north.isVisible()){
43610 var b = north.getBox();
43611 var m = north.getMargins();
43612 b.width = w - (m.left+m.right);
43615 centerY = b.height + b.y + m.bottom;
43616 centerH -= centerY;
43617 north.updateBox(this.safeBox(b));
43619 if(south && south.isVisible()){
43620 var b = south.getBox();
43621 var m = south.getMargins();
43622 b.width = w - (m.left+m.right);
43624 var totalHeight = (b.height + m.top + m.bottom);
43625 b.y = h - totalHeight + m.top;
43626 centerH -= totalHeight;
43627 south.updateBox(this.safeBox(b));
43629 if(west && west.isVisible()){
43630 var b = west.getBox();
43631 var m = west.getMargins();
43632 b.height = centerH - (m.top+m.bottom);
43634 b.y = centerY + m.top;
43635 var totalWidth = (b.width + m.left + m.right);
43636 centerX += totalWidth;
43637 centerW -= totalWidth;
43638 west.updateBox(this.safeBox(b));
43640 if(east && east.isVisible()){
43641 var b = east.getBox();
43642 var m = east.getMargins();
43643 b.height = centerH - (m.top+m.bottom);
43644 var totalWidth = (b.width + m.left + m.right);
43645 b.x = w - totalWidth + m.left;
43646 b.y = centerY + m.top;
43647 centerW -= totalWidth;
43648 east.updateBox(this.safeBox(b));
43651 var m = center.getMargins();
43653 x: centerX + m.left,
43654 y: centerY + m.top,
43655 width: centerW - (m.left+m.right),
43656 height: centerH - (m.top+m.bottom)
43658 //if(this.hideOnLayout){
43659 //center.el.setStyle("display", "block");
43661 center.updateBox(this.safeBox(centerBox));
43664 this.fireEvent("layout", this);
43668 safeBox : function(box){
43669 box.width = Math.max(0, box.width);
43670 box.height = Math.max(0, box.height);
43675 * Adds a ContentPanel (or subclass) to this layout.
43676 * @param {String} target The target region key (north, south, east, west or center).
43677 * @param {Roo.ContentPanel} panel The panel to add
43678 * @return {Roo.ContentPanel} The added panel
43680 add : function(target, panel){
43682 target = target.toLowerCase();
43683 return this.regions[target].add(panel);
43687 * Remove a ContentPanel (or subclass) to this layout.
43688 * @param {String} target The target region key (north, south, east, west or center).
43689 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
43690 * @return {Roo.ContentPanel} The removed panel
43692 remove : function(target, panel){
43693 target = target.toLowerCase();
43694 return this.regions[target].remove(panel);
43698 * Searches all regions for a panel with the specified id
43699 * @param {String} panelId
43700 * @return {Roo.ContentPanel} The panel or null if it wasn't found
43702 findPanel : function(panelId){
43703 var rs = this.regions;
43704 for(var target in rs){
43705 if(typeof rs[target] != "function"){
43706 var p = rs[target].getPanel(panelId);
43716 * Searches all regions for a panel with the specified id and activates (shows) it.
43717 * @param {String/ContentPanel} panelId The panels id or the panel itself
43718 * @return {Roo.ContentPanel} The shown panel or null
43720 showPanel : function(panelId) {
43721 var rs = this.regions;
43722 for(var target in rs){
43723 var r = rs[target];
43724 if(typeof r != "function"){
43725 if(r.hasPanel(panelId)){
43726 return r.showPanel(panelId);
43734 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
43735 * @param {Roo.state.Provider} provider (optional) An alternate state provider
43737 restoreState : function(provider){
43739 provider = Roo.state.Manager;
43741 var sm = new Roo.LayoutStateManager();
43742 sm.init(this, provider);
43746 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
43747 * object should contain properties for each region to add ContentPanels to, and each property's value should be
43748 * a valid ContentPanel config object. Example:
43750 // Create the main layout
43751 var layout = new Roo.BorderLayout('main-ct', {
43762 // Create and add multiple ContentPanels at once via configs
43765 id: 'source-files',
43767 title:'Ext Source Files',
43780 * @param {Object} regions An object containing ContentPanel configs by region name
43782 batchAdd : function(regions){
43783 this.beginUpdate();
43784 for(var rname in regions){
43785 var lr = this.regions[rname];
43787 this.addTypedPanels(lr, regions[rname]);
43794 addTypedPanels : function(lr, ps){
43795 if(typeof ps == 'string'){
43796 lr.add(new Roo.ContentPanel(ps));
43798 else if(ps instanceof Array){
43799 for(var i =0, len = ps.length; i < len; i++){
43800 this.addTypedPanels(lr, ps[i]);
43803 else if(!ps.events){ // raw config?
43805 delete ps.el; // prevent conflict
43806 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
43808 else { // panel object assumed!
43813 * Adds a xtype elements to the layout.
43817 xtype : 'ContentPanel',
43824 xtype : 'NestedLayoutPanel',
43830 items : [ ... list of content panels or nested layout panels.. ]
43834 * @param {Object} cfg Xtype definition of item to add.
43836 addxtype : function(cfg)
43838 // basically accepts a pannel...
43839 // can accept a layout region..!?!?
43840 // console.log('BorderLayout add ' + cfg.xtype)
43842 if (!cfg.xtype.match(/Panel$/)) {
43846 var region = cfg.region;
43852 xitems = cfg.items;
43859 case 'ContentPanel': // ContentPanel (el, cfg)
43860 case 'ScrollPanel': // ContentPanel (el, cfg)
43861 if(cfg.autoCreate) {
43862 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43864 var el = this.el.createChild();
43865 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
43868 this.add(region, ret);
43872 case 'TreePanel': // our new panel!
43873 cfg.el = this.el.createChild();
43874 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43875 this.add(region, ret);
43878 case 'NestedLayoutPanel':
43879 // create a new Layout (which is a Border Layout...
43880 var el = this.el.createChild();
43881 var clayout = cfg.layout;
43883 clayout.items = clayout.items || [];
43884 // replace this exitems with the clayout ones..
43885 xitems = clayout.items;
43888 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
43889 cfg.background = false;
43891 var layout = new Roo.BorderLayout(el, clayout);
43893 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
43894 //console.log('adding nested layout panel ' + cfg.toSource());
43895 this.add(region, ret);
43901 // needs grid and region
43903 //var el = this.getRegion(region).el.createChild();
43904 var el = this.el.createChild();
43905 // create the grid first...
43907 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
43909 if (region == 'center' && this.active ) {
43910 cfg.background = false;
43912 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
43914 this.add(region, ret);
43915 if (cfg.background) {
43916 ret.on('activate', function(gp) {
43917 if (!gp.grid.rendered) {
43930 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
43932 // GridPanel (grid, cfg)
43935 this.beginUpdate();
43937 Roo.each(xitems, function(i) {
43947 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
43948 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
43949 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
43950 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
43953 var CP = Roo.ContentPanel;
43955 var layout = Roo.BorderLayout.create({
43959 panels: [new CP("north", "North")]
43968 panels: [new CP("west", {title: "West"})]
43977 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
43986 panels: [new CP("south", {title: "South", closable: true})]
43993 preferredTabWidth: 150,
43995 new CP("center1", {title: "Close Me", closable: true}),
43996 new CP("center2", {title: "Center Panel", closable: false})
44001 layout.getRegion("center").showPanel("center1");
44006 Roo.BorderLayout.create = function(config, targetEl){
44007 var layout = new Roo.BorderLayout(targetEl || document.body, config);
44008 layout.beginUpdate();
44009 var regions = Roo.BorderLayout.RegionFactory.validRegions;
44010 for(var j = 0, jlen = regions.length; j < jlen; j++){
44011 var lr = regions[j];
44012 if(layout.regions[lr] && config[lr].panels){
44013 var r = layout.regions[lr];
44014 var ps = config[lr].panels;
44015 layout.addTypedPanels(r, ps);
44018 layout.endUpdate();
44023 Roo.BorderLayout.RegionFactory = {
44025 validRegions : ["north","south","east","west","center"],
44028 create : function(target, mgr, config){
44029 target = target.toLowerCase();
44030 if(config.lightweight || config.basic){
44031 return new Roo.BasicLayoutRegion(mgr, config, target);
44035 return new Roo.NorthLayoutRegion(mgr, config);
44037 return new Roo.SouthLayoutRegion(mgr, config);
44039 return new Roo.EastLayoutRegion(mgr, config);
44041 return new Roo.WestLayoutRegion(mgr, config);
44043 return new Roo.CenterLayoutRegion(mgr, config);
44045 throw 'Layout region "'+target+'" not supported.';
44049 * Ext JS Library 1.1.1
44050 * Copyright(c) 2006-2007, Ext JS, LLC.
44052 * Originally Released Under LGPL - original licence link has changed is not relivant.
44055 * <script type="text/javascript">
44059 * @class Roo.BasicLayoutRegion
44060 * @extends Roo.util.Observable
44061 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
44062 * and does not have a titlebar, tabs or any other features. All it does is size and position
44063 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
44065 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
44067 this.position = pos;
44070 * @scope Roo.BasicLayoutRegion
44074 * @event beforeremove
44075 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
44076 * @param {Roo.LayoutRegion} this
44077 * @param {Roo.ContentPanel} panel The panel
44078 * @param {Object} e The cancel event object
44080 "beforeremove" : true,
44082 * @event invalidated
44083 * Fires when the layout for this region is changed.
44084 * @param {Roo.LayoutRegion} this
44086 "invalidated" : true,
44088 * @event visibilitychange
44089 * Fires when this region is shown or hidden
44090 * @param {Roo.LayoutRegion} this
44091 * @param {Boolean} visibility true or false
44093 "visibilitychange" : true,
44095 * @event paneladded
44096 * Fires when a panel is added.
44097 * @param {Roo.LayoutRegion} this
44098 * @param {Roo.ContentPanel} panel The panel
44100 "paneladded" : true,
44102 * @event panelremoved
44103 * Fires when a panel is removed.
44104 * @param {Roo.LayoutRegion} this
44105 * @param {Roo.ContentPanel} panel The panel
44107 "panelremoved" : true,
44110 * Fires when this region is collapsed.
44111 * @param {Roo.LayoutRegion} this
44113 "collapsed" : true,
44116 * Fires when this region is expanded.
44117 * @param {Roo.LayoutRegion} this
44122 * Fires when this region is slid into view.
44123 * @param {Roo.LayoutRegion} this
44125 "slideshow" : true,
44128 * Fires when this region slides out of view.
44129 * @param {Roo.LayoutRegion} this
44131 "slidehide" : true,
44133 * @event panelactivated
44134 * Fires when a panel is activated.
44135 * @param {Roo.LayoutRegion} this
44136 * @param {Roo.ContentPanel} panel The activated panel
44138 "panelactivated" : true,
44141 * Fires when the user resizes this region.
44142 * @param {Roo.LayoutRegion} this
44143 * @param {Number} newSize The new size (width for east/west, height for north/south)
44147 /** A collection of panels in this region. @type Roo.util.MixedCollection */
44148 this.panels = new Roo.util.MixedCollection();
44149 this.panels.getKey = this.getPanelId.createDelegate(this);
44151 this.activePanel = null;
44152 // ensure listeners are added...
44154 if (config.listeners || config.events) {
44155 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
44156 listeners : config.listeners || {},
44157 events : config.events || {}
44161 if(skipConfig !== true){
44162 this.applyConfig(config);
44166 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
44167 getPanelId : function(p){
44171 applyConfig : function(config){
44172 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44173 this.config = config;
44178 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
44179 * the width, for horizontal (north, south) the height.
44180 * @param {Number} newSize The new width or height
44182 resizeTo : function(newSize){
44183 var el = this.el ? this.el :
44184 (this.activePanel ? this.activePanel.getEl() : null);
44186 switch(this.position){
44189 el.setWidth(newSize);
44190 this.fireEvent("resized", this, newSize);
44194 el.setHeight(newSize);
44195 this.fireEvent("resized", this, newSize);
44201 getBox : function(){
44202 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
44205 getMargins : function(){
44206 return this.margins;
44209 updateBox : function(box){
44211 var el = this.activePanel.getEl();
44212 el.dom.style.left = box.x + "px";
44213 el.dom.style.top = box.y + "px";
44214 this.activePanel.setSize(box.width, box.height);
44218 * Returns the container element for this region.
44219 * @return {Roo.Element}
44221 getEl : function(){
44222 return this.activePanel;
44226 * Returns true if this region is currently visible.
44227 * @return {Boolean}
44229 isVisible : function(){
44230 return this.activePanel ? true : false;
44233 setActivePanel : function(panel){
44234 panel = this.getPanel(panel);
44235 if(this.activePanel && this.activePanel != panel){
44236 this.activePanel.setActiveState(false);
44237 this.activePanel.getEl().setLeftTop(-10000,-10000);
44239 this.activePanel = panel;
44240 panel.setActiveState(true);
44242 panel.setSize(this.box.width, this.box.height);
44244 this.fireEvent("panelactivated", this, panel);
44245 this.fireEvent("invalidated");
44249 * Show the specified panel.
44250 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
44251 * @return {Roo.ContentPanel} The shown panel or null
44253 showPanel : function(panel){
44254 if(panel = this.getPanel(panel)){
44255 this.setActivePanel(panel);
44261 * Get the active panel for this region.
44262 * @return {Roo.ContentPanel} The active panel or null
44264 getActivePanel : function(){
44265 return this.activePanel;
44269 * Add the passed ContentPanel(s)
44270 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44271 * @return {Roo.ContentPanel} The panel added (if only one was added)
44273 add : function(panel){
44274 if(arguments.length > 1){
44275 for(var i = 0, len = arguments.length; i < len; i++) {
44276 this.add(arguments[i]);
44280 if(this.hasPanel(panel)){
44281 this.showPanel(panel);
44284 var el = panel.getEl();
44285 if(el.dom.parentNode != this.mgr.el.dom){
44286 this.mgr.el.dom.appendChild(el.dom);
44288 if(panel.setRegion){
44289 panel.setRegion(this);
44291 this.panels.add(panel);
44292 el.setStyle("position", "absolute");
44293 if(!panel.background){
44294 this.setActivePanel(panel);
44295 if(this.config.initialSize && this.panels.getCount()==1){
44296 this.resizeTo(this.config.initialSize);
44299 this.fireEvent("paneladded", this, panel);
44304 * Returns true if the panel is in this region.
44305 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44306 * @return {Boolean}
44308 hasPanel : function(panel){
44309 if(typeof panel == "object"){ // must be panel obj
44310 panel = panel.getId();
44312 return this.getPanel(panel) ? true : false;
44316 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44317 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44318 * @param {Boolean} preservePanel Overrides the config preservePanel option
44319 * @return {Roo.ContentPanel} The panel that was removed
44321 remove : function(panel, preservePanel){
44322 panel = this.getPanel(panel);
44327 this.fireEvent("beforeremove", this, panel, e);
44328 if(e.cancel === true){
44331 var panelId = panel.getId();
44332 this.panels.removeKey(panelId);
44337 * Returns the panel specified or null if it's not in this region.
44338 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44339 * @return {Roo.ContentPanel}
44341 getPanel : function(id){
44342 if(typeof id == "object"){ // must be panel obj
44345 return this.panels.get(id);
44349 * Returns this regions position (north/south/east/west/center).
44352 getPosition: function(){
44353 return this.position;
44357 * Ext JS Library 1.1.1
44358 * Copyright(c) 2006-2007, Ext JS, LLC.
44360 * Originally Released Under LGPL - original licence link has changed is not relivant.
44363 * <script type="text/javascript">
44367 * @class Roo.LayoutRegion
44368 * @extends Roo.BasicLayoutRegion
44369 * This class represents a region in a layout manager.
44370 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
44371 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
44372 * @cfg {Boolean} floatable False to disable floating (defaults to true)
44373 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
44374 * @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})
44375 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
44376 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
44377 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
44378 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
44379 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
44380 * @cfg {String} title The title for the region (overrides panel titles)
44381 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
44382 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
44383 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
44384 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
44385 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
44386 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
44387 * the space available, similar to FireFox 1.5 tabs (defaults to false)
44388 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
44389 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
44390 * @cfg {Boolean} showPin True to show a pin button
44391 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
44392 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
44393 * @cfg {Boolean} disableTabTips True to disable tab tooltips
44394 * @cfg {Number} width For East/West panels
44395 * @cfg {Number} height For North/South panels
44396 * @cfg {Boolean} split To show the splitter
44398 Roo.LayoutRegion = function(mgr, config, pos){
44399 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
44400 var dh = Roo.DomHelper;
44401 /** This region's container element
44402 * @type Roo.Element */
44403 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
44404 /** This region's title element
44405 * @type Roo.Element */
44407 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
44408 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
44409 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
44411 this.titleEl.enableDisplayMode();
44412 /** This region's title text element
44413 * @type HTMLElement */
44414 this.titleTextEl = this.titleEl.dom.firstChild;
44415 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
44416 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
44417 this.closeBtn.enableDisplayMode();
44418 this.closeBtn.on("click", this.closeClicked, this);
44419 this.closeBtn.hide();
44421 this.createBody(config);
44422 this.visible = true;
44423 this.collapsed = false;
44425 if(config.hideWhenEmpty){
44427 this.on("paneladded", this.validateVisibility, this);
44428 this.on("panelremoved", this.validateVisibility, this);
44430 this.applyConfig(config);
44433 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
44435 createBody : function(){
44436 /** This region's body element
44437 * @type Roo.Element */
44438 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
44441 applyConfig : function(c){
44442 if(c.collapsible && this.position != "center" && !this.collapsedEl){
44443 var dh = Roo.DomHelper;
44444 if(c.titlebar !== false){
44445 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
44446 this.collapseBtn.on("click", this.collapse, this);
44447 this.collapseBtn.enableDisplayMode();
44449 if(c.showPin === true || this.showPin){
44450 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
44451 this.stickBtn.enableDisplayMode();
44452 this.stickBtn.on("click", this.expand, this);
44453 this.stickBtn.hide();
44456 /** This region's collapsed element
44457 * @type Roo.Element */
44458 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
44459 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
44461 if(c.floatable !== false){
44462 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
44463 this.collapsedEl.on("click", this.collapseClick, this);
44466 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
44467 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
44468 id: "message", unselectable: "on", style:{"float":"left"}});
44469 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
44471 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
44472 this.expandBtn.on("click", this.expand, this);
44474 if(this.collapseBtn){
44475 this.collapseBtn.setVisible(c.collapsible == true);
44477 this.cmargins = c.cmargins || this.cmargins ||
44478 (this.position == "west" || this.position == "east" ?
44479 {top: 0, left: 2, right:2, bottom: 0} :
44480 {top: 2, left: 0, right:0, bottom: 2});
44481 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44482 this.bottomTabs = c.tabPosition != "top";
44483 this.autoScroll = c.autoScroll || false;
44484 if(this.autoScroll){
44485 this.bodyEl.setStyle("overflow", "auto");
44487 this.bodyEl.setStyle("overflow", "hidden");
44489 //if(c.titlebar !== false){
44490 if((!c.titlebar && !c.title) || c.titlebar === false){
44491 this.titleEl.hide();
44493 this.titleEl.show();
44495 this.titleTextEl.innerHTML = c.title;
44499 this.duration = c.duration || .30;
44500 this.slideDuration = c.slideDuration || .45;
44503 this.collapse(true);
44510 * Returns true if this region is currently visible.
44511 * @return {Boolean}
44513 isVisible : function(){
44514 return this.visible;
44518 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
44519 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
44521 setCollapsedTitle : function(title){
44522 title = title || " ";
44523 if(this.collapsedTitleTextEl){
44524 this.collapsedTitleTextEl.innerHTML = title;
44528 getBox : function(){
44530 if(!this.collapsed){
44531 b = this.el.getBox(false, true);
44533 b = this.collapsedEl.getBox(false, true);
44538 getMargins : function(){
44539 return this.collapsed ? this.cmargins : this.margins;
44542 highlight : function(){
44543 this.el.addClass("x-layout-panel-dragover");
44546 unhighlight : function(){
44547 this.el.removeClass("x-layout-panel-dragover");
44550 updateBox : function(box){
44552 if(!this.collapsed){
44553 this.el.dom.style.left = box.x + "px";
44554 this.el.dom.style.top = box.y + "px";
44555 this.updateBody(box.width, box.height);
44557 this.collapsedEl.dom.style.left = box.x + "px";
44558 this.collapsedEl.dom.style.top = box.y + "px";
44559 this.collapsedEl.setSize(box.width, box.height);
44562 this.tabs.autoSizeTabs();
44566 updateBody : function(w, h){
44568 this.el.setWidth(w);
44569 w -= this.el.getBorderWidth("rl");
44570 if(this.config.adjustments){
44571 w += this.config.adjustments[0];
44575 this.el.setHeight(h);
44576 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
44577 h -= this.el.getBorderWidth("tb");
44578 if(this.config.adjustments){
44579 h += this.config.adjustments[1];
44581 this.bodyEl.setHeight(h);
44583 h = this.tabs.syncHeight(h);
44586 if(this.panelSize){
44587 w = w !== null ? w : this.panelSize.width;
44588 h = h !== null ? h : this.panelSize.height;
44590 if(this.activePanel){
44591 var el = this.activePanel.getEl();
44592 w = w !== null ? w : el.getWidth();
44593 h = h !== null ? h : el.getHeight();
44594 this.panelSize = {width: w, height: h};
44595 this.activePanel.setSize(w, h);
44597 if(Roo.isIE && this.tabs){
44598 this.tabs.el.repaint();
44603 * Returns the container element for this region.
44604 * @return {Roo.Element}
44606 getEl : function(){
44611 * Hides this region.
44614 if(!this.collapsed){
44615 this.el.dom.style.left = "-2000px";
44618 this.collapsedEl.dom.style.left = "-2000px";
44619 this.collapsedEl.hide();
44621 this.visible = false;
44622 this.fireEvent("visibilitychange", this, false);
44626 * Shows this region if it was previously hidden.
44629 if(!this.collapsed){
44632 this.collapsedEl.show();
44634 this.visible = true;
44635 this.fireEvent("visibilitychange", this, true);
44638 closeClicked : function(){
44639 if(this.activePanel){
44640 this.remove(this.activePanel);
44644 collapseClick : function(e){
44646 e.stopPropagation();
44649 e.stopPropagation();
44655 * Collapses this region.
44656 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
44658 collapse : function(skipAnim){
44659 if(this.collapsed) return;
44660 this.collapsed = true;
44662 this.split.el.hide();
44664 if(this.config.animate && skipAnim !== true){
44665 this.fireEvent("invalidated", this);
44666 this.animateCollapse();
44668 this.el.setLocation(-20000,-20000);
44670 this.collapsedEl.show();
44671 this.fireEvent("collapsed", this);
44672 this.fireEvent("invalidated", this);
44676 animateCollapse : function(){
44681 * Expands this region if it was previously collapsed.
44682 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
44683 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
44685 expand : function(e, skipAnim){
44686 if(e) e.stopPropagation();
44687 if(!this.collapsed || this.el.hasActiveFx()) return;
44689 this.afterSlideIn();
44692 this.collapsed = false;
44693 if(this.config.animate && skipAnim !== true){
44694 this.animateExpand();
44698 this.split.el.show();
44700 this.collapsedEl.setLocation(-2000,-2000);
44701 this.collapsedEl.hide();
44702 this.fireEvent("invalidated", this);
44703 this.fireEvent("expanded", this);
44707 animateExpand : function(){
44711 initTabs : function(){
44712 this.bodyEl.setStyle("overflow", "hidden");
44713 var ts = new Roo.TabPanel(this.bodyEl.dom, {
44714 tabPosition: this.bottomTabs ? 'bottom' : 'top',
44715 disableTooltips: this.config.disableTabTips
44717 if(this.config.hideTabs){
44718 ts.stripWrap.setDisplayed(false);
44721 ts.resizeTabs = this.config.resizeTabs === true;
44722 ts.minTabWidth = this.config.minTabWidth || 40;
44723 ts.maxTabWidth = this.config.maxTabWidth || 250;
44724 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
44725 ts.monitorResize = false;
44726 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44727 ts.bodyEl.addClass('x-layout-tabs-body');
44728 this.panels.each(this.initPanelAsTab, this);
44731 initPanelAsTab : function(panel){
44732 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
44733 this.config.closeOnTab && panel.isClosable());
44734 if(panel.tabTip !== undefined){
44735 ti.setTooltip(panel.tabTip);
44737 ti.on("activate", function(){
44738 this.setActivePanel(panel);
44740 if(this.config.closeOnTab){
44741 ti.on("beforeclose", function(t, e){
44743 this.remove(panel);
44749 updatePanelTitle : function(panel, title){
44750 if(this.activePanel == panel){
44751 this.updateTitle(title);
44754 var ti = this.tabs.getTab(panel.getEl().id);
44756 if(panel.tabTip !== undefined){
44757 ti.setTooltip(panel.tabTip);
44762 updateTitle : function(title){
44763 if(this.titleTextEl && !this.config.title){
44764 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
44768 setActivePanel : function(panel){
44769 panel = this.getPanel(panel);
44770 if(this.activePanel && this.activePanel != panel){
44771 this.activePanel.setActiveState(false);
44773 this.activePanel = panel;
44774 panel.setActiveState(true);
44775 if(this.panelSize){
44776 panel.setSize(this.panelSize.width, this.panelSize.height);
44779 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
44781 this.updateTitle(panel.getTitle());
44783 this.fireEvent("invalidated", this);
44785 this.fireEvent("panelactivated", this, panel);
44789 * Shows the specified panel.
44790 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
44791 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
44793 showPanel : function(panel){
44794 if(panel = this.getPanel(panel)){
44796 var tab = this.tabs.getTab(panel.getEl().id);
44797 if(tab.isHidden()){
44798 this.tabs.unhideTab(tab.id);
44802 this.setActivePanel(panel);
44809 * Get the active panel for this region.
44810 * @return {Roo.ContentPanel} The active panel or null
44812 getActivePanel : function(){
44813 return this.activePanel;
44816 validateVisibility : function(){
44817 if(this.panels.getCount() < 1){
44818 this.updateTitle(" ");
44819 this.closeBtn.hide();
44822 if(!this.isVisible()){
44829 * Adds the passed ContentPanel(s) to this region.
44830 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44831 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
44833 add : function(panel){
44834 if(arguments.length > 1){
44835 for(var i = 0, len = arguments.length; i < len; i++) {
44836 this.add(arguments[i]);
44840 if(this.hasPanel(panel)){
44841 this.showPanel(panel);
44844 panel.setRegion(this);
44845 this.panels.add(panel);
44846 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
44847 this.bodyEl.dom.appendChild(panel.getEl().dom);
44848 if(panel.background !== true){
44849 this.setActivePanel(panel);
44851 this.fireEvent("paneladded", this, panel);
44857 this.initPanelAsTab(panel);
44859 if(panel.background !== true){
44860 this.tabs.activate(panel.getEl().id);
44862 this.fireEvent("paneladded", this, panel);
44867 * Hides the tab for the specified panel.
44868 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44870 hidePanel : function(panel){
44871 if(this.tabs && (panel = this.getPanel(panel))){
44872 this.tabs.hideTab(panel.getEl().id);
44877 * Unhides the tab for a previously hidden panel.
44878 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44880 unhidePanel : function(panel){
44881 if(this.tabs && (panel = this.getPanel(panel))){
44882 this.tabs.unhideTab(panel.getEl().id);
44886 clearPanels : function(){
44887 while(this.panels.getCount() > 0){
44888 this.remove(this.panels.first());
44893 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44894 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44895 * @param {Boolean} preservePanel Overrides the config preservePanel option
44896 * @return {Roo.ContentPanel} The panel that was removed
44898 remove : function(panel, preservePanel){
44899 panel = this.getPanel(panel);
44904 this.fireEvent("beforeremove", this, panel, e);
44905 if(e.cancel === true){
44908 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
44909 var panelId = panel.getId();
44910 this.panels.removeKey(panelId);
44912 document.body.appendChild(panel.getEl().dom);
44915 this.tabs.removeTab(panel.getEl().id);
44916 }else if (!preservePanel){
44917 this.bodyEl.dom.removeChild(panel.getEl().dom);
44919 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
44920 var p = this.panels.first();
44921 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
44922 tempEl.appendChild(p.getEl().dom);
44923 this.bodyEl.update("");
44924 this.bodyEl.dom.appendChild(p.getEl().dom);
44926 this.updateTitle(p.getTitle());
44928 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44929 this.setActivePanel(p);
44931 panel.setRegion(null);
44932 if(this.activePanel == panel){
44933 this.activePanel = null;
44935 if(this.config.autoDestroy !== false && preservePanel !== true){
44936 try{panel.destroy();}catch(e){}
44938 this.fireEvent("panelremoved", this, panel);
44943 * Returns the TabPanel component used by this region
44944 * @return {Roo.TabPanel}
44946 getTabs : function(){
44950 createTool : function(parentEl, className){
44951 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
44952 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
44953 btn.addClassOnOver("x-layout-tools-button-over");
44958 * Ext JS Library 1.1.1
44959 * Copyright(c) 2006-2007, Ext JS, LLC.
44961 * Originally Released Under LGPL - original licence link has changed is not relivant.
44964 * <script type="text/javascript">
44970 * @class Roo.SplitLayoutRegion
44971 * @extends Roo.LayoutRegion
44972 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
44974 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
44975 this.cursor = cursor;
44976 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
44979 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
44980 splitTip : "Drag to resize.",
44981 collapsibleSplitTip : "Drag to resize. Double click to hide.",
44982 useSplitTips : false,
44984 applyConfig : function(config){
44985 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
44988 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
44989 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
44990 /** The SplitBar for this region
44991 * @type Roo.SplitBar */
44992 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
44993 this.split.on("moved", this.onSplitMove, this);
44994 this.split.useShim = config.useShim === true;
44995 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
44996 if(this.useSplitTips){
44997 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
44999 if(config.collapsible){
45000 this.split.el.on("dblclick", this.collapse, this);
45003 if(typeof config.minSize != "undefined"){
45004 this.split.minSize = config.minSize;
45006 if(typeof config.maxSize != "undefined"){
45007 this.split.maxSize = config.maxSize;
45009 if(config.hideWhenEmpty || config.hidden || config.collapsed){
45010 this.hideSplitter();
45015 getHMaxSize : function(){
45016 var cmax = this.config.maxSize || 10000;
45017 var center = this.mgr.getRegion("center");
45018 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
45021 getVMaxSize : function(){
45022 var cmax = this.config.maxSize || 10000;
45023 var center = this.mgr.getRegion("center");
45024 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
45027 onSplitMove : function(split, newSize){
45028 this.fireEvent("resized", this, newSize);
45032 * Returns the {@link Roo.SplitBar} for this region.
45033 * @return {Roo.SplitBar}
45035 getSplitBar : function(){
45040 this.hideSplitter();
45041 Roo.SplitLayoutRegion.superclass.hide.call(this);
45044 hideSplitter : function(){
45046 this.split.el.setLocation(-2000,-2000);
45047 this.split.el.hide();
45053 this.split.el.show();
45055 Roo.SplitLayoutRegion.superclass.show.call(this);
45058 beforeSlide: function(){
45059 if(Roo.isGecko){// firefox overflow auto bug workaround
45060 this.bodyEl.clip();
45061 if(this.tabs) this.tabs.bodyEl.clip();
45062 if(this.activePanel){
45063 this.activePanel.getEl().clip();
45065 if(this.activePanel.beforeSlide){
45066 this.activePanel.beforeSlide();
45072 afterSlide : function(){
45073 if(Roo.isGecko){// firefox overflow auto bug workaround
45074 this.bodyEl.unclip();
45075 if(this.tabs) this.tabs.bodyEl.unclip();
45076 if(this.activePanel){
45077 this.activePanel.getEl().unclip();
45078 if(this.activePanel.afterSlide){
45079 this.activePanel.afterSlide();
45085 initAutoHide : function(){
45086 if(this.autoHide !== false){
45087 if(!this.autoHideHd){
45088 var st = new Roo.util.DelayedTask(this.slideIn, this);
45089 this.autoHideHd = {
45090 "mouseout": function(e){
45091 if(!e.within(this.el, true)){
45095 "mouseover" : function(e){
45101 this.el.on(this.autoHideHd);
45105 clearAutoHide : function(){
45106 if(this.autoHide !== false){
45107 this.el.un("mouseout", this.autoHideHd.mouseout);
45108 this.el.un("mouseover", this.autoHideHd.mouseover);
45112 clearMonitor : function(){
45113 Roo.get(document).un("click", this.slideInIf, this);
45116 // these names are backwards but not changed for compat
45117 slideOut : function(){
45118 if(this.isSlid || this.el.hasActiveFx()){
45121 this.isSlid = true;
45122 if(this.collapseBtn){
45123 this.collapseBtn.hide();
45125 this.closeBtnState = this.closeBtn.getStyle('display');
45126 this.closeBtn.hide();
45128 this.stickBtn.show();
45131 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
45132 this.beforeSlide();
45133 this.el.setStyle("z-index", 10001);
45134 this.el.slideIn(this.getSlideAnchor(), {
45135 callback: function(){
45137 this.initAutoHide();
45138 Roo.get(document).on("click", this.slideInIf, this);
45139 this.fireEvent("slideshow", this);
45146 afterSlideIn : function(){
45147 this.clearAutoHide();
45148 this.isSlid = false;
45149 this.clearMonitor();
45150 this.el.setStyle("z-index", "");
45151 if(this.collapseBtn){
45152 this.collapseBtn.show();
45154 this.closeBtn.setStyle('display', this.closeBtnState);
45156 this.stickBtn.hide();
45158 this.fireEvent("slidehide", this);
45161 slideIn : function(cb){
45162 if(!this.isSlid || this.el.hasActiveFx()){
45166 this.isSlid = false;
45167 this.beforeSlide();
45168 this.el.slideOut(this.getSlideAnchor(), {
45169 callback: function(){
45170 this.el.setLeftTop(-10000, -10000);
45172 this.afterSlideIn();
45180 slideInIf : function(e){
45181 if(!e.within(this.el)){
45186 animateCollapse : function(){
45187 this.beforeSlide();
45188 this.el.setStyle("z-index", 20000);
45189 var anchor = this.getSlideAnchor();
45190 this.el.slideOut(anchor, {
45191 callback : function(){
45192 this.el.setStyle("z-index", "");
45193 this.collapsedEl.slideIn(anchor, {duration:.3});
45195 this.el.setLocation(-10000,-10000);
45197 this.fireEvent("collapsed", this);
45204 animateExpand : function(){
45205 this.beforeSlide();
45206 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
45207 this.el.setStyle("z-index", 20000);
45208 this.collapsedEl.hide({
45211 this.el.slideIn(this.getSlideAnchor(), {
45212 callback : function(){
45213 this.el.setStyle("z-index", "");
45216 this.split.el.show();
45218 this.fireEvent("invalidated", this);
45219 this.fireEvent("expanded", this);
45247 getAnchor : function(){
45248 return this.anchors[this.position];
45251 getCollapseAnchor : function(){
45252 return this.canchors[this.position];
45255 getSlideAnchor : function(){
45256 return this.sanchors[this.position];
45259 getAlignAdj : function(){
45260 var cm = this.cmargins;
45261 switch(this.position){
45277 getExpandAdj : function(){
45278 var c = this.collapsedEl, cm = this.cmargins;
45279 switch(this.position){
45281 return [-(cm.right+c.getWidth()+cm.left), 0];
45284 return [cm.right+c.getWidth()+cm.left, 0];
45287 return [0, -(cm.top+cm.bottom+c.getHeight())];
45290 return [0, cm.top+cm.bottom+c.getHeight()];
45296 * Ext JS Library 1.1.1
45297 * Copyright(c) 2006-2007, Ext JS, LLC.
45299 * Originally Released Under LGPL - original licence link has changed is not relivant.
45302 * <script type="text/javascript">
45305 * These classes are private internal classes
45307 Roo.CenterLayoutRegion = function(mgr, config){
45308 Roo.LayoutRegion.call(this, mgr, config, "center");
45309 this.visible = true;
45310 this.minWidth = config.minWidth || 20;
45311 this.minHeight = config.minHeight || 20;
45314 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
45316 // center panel can't be hidden
45320 // center panel can't be hidden
45323 getMinWidth: function(){
45324 return this.minWidth;
45327 getMinHeight: function(){
45328 return this.minHeight;
45333 Roo.NorthLayoutRegion = function(mgr, config){
45334 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
45336 this.split.placement = Roo.SplitBar.TOP;
45337 this.split.orientation = Roo.SplitBar.VERTICAL;
45338 this.split.el.addClass("x-layout-split-v");
45340 var size = config.initialSize || config.height;
45341 if(typeof size != "undefined"){
45342 this.el.setHeight(size);
45345 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
45346 orientation: Roo.SplitBar.VERTICAL,
45347 getBox : function(){
45348 if(this.collapsed){
45349 return this.collapsedEl.getBox();
45351 var box = this.el.getBox();
45353 box.height += this.split.el.getHeight();
45358 updateBox : function(box){
45359 if(this.split && !this.collapsed){
45360 box.height -= this.split.el.getHeight();
45361 this.split.el.setLeft(box.x);
45362 this.split.el.setTop(box.y+box.height);
45363 this.split.el.setWidth(box.width);
45365 if(this.collapsed){
45366 this.updateBody(box.width, null);
45368 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45372 Roo.SouthLayoutRegion = function(mgr, config){
45373 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
45375 this.split.placement = Roo.SplitBar.BOTTOM;
45376 this.split.orientation = Roo.SplitBar.VERTICAL;
45377 this.split.el.addClass("x-layout-split-v");
45379 var size = config.initialSize || config.height;
45380 if(typeof size != "undefined"){
45381 this.el.setHeight(size);
45384 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
45385 orientation: Roo.SplitBar.VERTICAL,
45386 getBox : function(){
45387 if(this.collapsed){
45388 return this.collapsedEl.getBox();
45390 var box = this.el.getBox();
45392 var sh = this.split.el.getHeight();
45399 updateBox : function(box){
45400 if(this.split && !this.collapsed){
45401 var sh = this.split.el.getHeight();
45404 this.split.el.setLeft(box.x);
45405 this.split.el.setTop(box.y-sh);
45406 this.split.el.setWidth(box.width);
45408 if(this.collapsed){
45409 this.updateBody(box.width, null);
45411 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45415 Roo.EastLayoutRegion = function(mgr, config){
45416 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
45418 this.split.placement = Roo.SplitBar.RIGHT;
45419 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45420 this.split.el.addClass("x-layout-split-h");
45422 var size = config.initialSize || config.width;
45423 if(typeof size != "undefined"){
45424 this.el.setWidth(size);
45427 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
45428 orientation: Roo.SplitBar.HORIZONTAL,
45429 getBox : function(){
45430 if(this.collapsed){
45431 return this.collapsedEl.getBox();
45433 var box = this.el.getBox();
45435 var sw = this.split.el.getWidth();
45442 updateBox : function(box){
45443 if(this.split && !this.collapsed){
45444 var sw = this.split.el.getWidth();
45446 this.split.el.setLeft(box.x);
45447 this.split.el.setTop(box.y);
45448 this.split.el.setHeight(box.height);
45451 if(this.collapsed){
45452 this.updateBody(null, box.height);
45454 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45458 Roo.WestLayoutRegion = function(mgr, config){
45459 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
45461 this.split.placement = Roo.SplitBar.LEFT;
45462 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45463 this.split.el.addClass("x-layout-split-h");
45465 var size = config.initialSize || config.width;
45466 if(typeof size != "undefined"){
45467 this.el.setWidth(size);
45470 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
45471 orientation: Roo.SplitBar.HORIZONTAL,
45472 getBox : function(){
45473 if(this.collapsed){
45474 return this.collapsedEl.getBox();
45476 var box = this.el.getBox();
45478 box.width += this.split.el.getWidth();
45483 updateBox : function(box){
45484 if(this.split && !this.collapsed){
45485 var sw = this.split.el.getWidth();
45487 this.split.el.setLeft(box.x+box.width);
45488 this.split.el.setTop(box.y);
45489 this.split.el.setHeight(box.height);
45491 if(this.collapsed){
45492 this.updateBody(null, box.height);
45494 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45499 * Ext JS Library 1.1.1
45500 * Copyright(c) 2006-2007, Ext JS, LLC.
45502 * Originally Released Under LGPL - original licence link has changed is not relivant.
45505 * <script type="text/javascript">
45510 * Private internal class for reading and applying state
45512 Roo.LayoutStateManager = function(layout){
45513 // default empty state
45522 Roo.LayoutStateManager.prototype = {
45523 init : function(layout, provider){
45524 this.provider = provider;
45525 var state = provider.get(layout.id+"-layout-state");
45527 var wasUpdating = layout.isUpdating();
45529 layout.beginUpdate();
45531 for(var key in state){
45532 if(typeof state[key] != "function"){
45533 var rstate = state[key];
45534 var r = layout.getRegion(key);
45537 r.resizeTo(rstate.size);
45539 if(rstate.collapsed == true){
45542 r.expand(null, true);
45548 layout.endUpdate();
45550 this.state = state;
45552 this.layout = layout;
45553 layout.on("regionresized", this.onRegionResized, this);
45554 layout.on("regioncollapsed", this.onRegionCollapsed, this);
45555 layout.on("regionexpanded", this.onRegionExpanded, this);
45558 storeState : function(){
45559 this.provider.set(this.layout.id+"-layout-state", this.state);
45562 onRegionResized : function(region, newSize){
45563 this.state[region.getPosition()].size = newSize;
45567 onRegionCollapsed : function(region){
45568 this.state[region.getPosition()].collapsed = true;
45572 onRegionExpanded : function(region){
45573 this.state[region.getPosition()].collapsed = false;
45578 * Ext JS Library 1.1.1
45579 * Copyright(c) 2006-2007, Ext JS, LLC.
45581 * Originally Released Under LGPL - original licence link has changed is not relivant.
45584 * <script type="text/javascript">
45587 * @class Roo.ContentPanel
45588 * @extends Roo.util.Observable
45589 * A basic ContentPanel element.
45590 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
45591 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
45592 * @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
45593 * @cfg {Boolean} closable True if the panel can be closed/removed
45594 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
45595 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
45596 * @cfg {Toolbar} toolbar A toolbar for this panel
45597 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
45598 * @cfg {String} title The title for this panel
45599 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
45600 * @cfg {String} url Calls {@link #setUrl} with this value
45601 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
45602 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
45603 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
45605 * Create a new ContentPanel.
45606 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
45607 * @param {String/Object} config A string to set only the title or a config object
45608 * @param {String} content (optional) Set the HTML content for this panel
45609 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
45611 Roo.ContentPanel = function(el, config, content){
45615 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
45619 if (config && config.parentLayout) {
45620 el = config.parentLayout.el.createChild();
45623 if(el.autoCreate){ // xtype is available if this is called from factory
45627 this.el = Roo.get(el);
45628 if(!this.el && config && config.autoCreate){
45629 if(typeof config.autoCreate == "object"){
45630 if(!config.autoCreate.id){
45631 config.autoCreate.id = config.id||el;
45633 this.el = Roo.DomHelper.append(document.body,
45634 config.autoCreate, true);
45636 this.el = Roo.DomHelper.append(document.body,
45637 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
45640 this.closable = false;
45641 this.loaded = false;
45642 this.active = false;
45643 if(typeof config == "string"){
45644 this.title = config;
45646 Roo.apply(this, config);
45649 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
45650 this.wrapEl = this.el.wrap();
45651 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
45658 this.resizeEl = Roo.get(this.resizeEl, true);
45660 this.resizeEl = this.el;
45665 * Fires when this panel is activated.
45666 * @param {Roo.ContentPanel} this
45670 * @event deactivate
45671 * Fires when this panel is activated.
45672 * @param {Roo.ContentPanel} this
45674 "deactivate" : true,
45678 * Fires when this panel is resized if fitToFrame is true.
45679 * @param {Roo.ContentPanel} this
45680 * @param {Number} width The width after any component adjustments
45681 * @param {Number} height The height after any component adjustments
45685 if(this.autoScroll){
45686 this.resizeEl.setStyle("overflow", "auto");
45688 // fix randome scrolling
45689 this.el.on('scroll', function() {
45690 Roo.log('fix random scolling');
45691 this.scrollTo('top',0);
45694 content = content || this.content;
45696 this.setContent(content);
45698 if(config && config.url){
45699 this.setUrl(this.url, this.params, this.loadOnce);
45704 Roo.ContentPanel.superclass.constructor.call(this);
45707 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
45709 setRegion : function(region){
45710 this.region = region;
45712 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
45714 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
45719 * Returns the toolbar for this Panel if one was configured.
45720 * @return {Roo.Toolbar}
45722 getToolbar : function(){
45723 return this.toolbar;
45726 setActiveState : function(active){
45727 this.active = active;
45729 this.fireEvent("deactivate", this);
45731 this.fireEvent("activate", this);
45735 * Updates this panel's element
45736 * @param {String} content The new content
45737 * @param {Boolean} loadScripts (optional) true to look for and process scripts
45739 setContent : function(content, loadScripts){
45740 this.el.update(content, loadScripts);
45743 ignoreResize : function(w, h){
45744 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
45747 this.lastSize = {width: w, height: h};
45752 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
45753 * @return {Roo.UpdateManager} The UpdateManager
45755 getUpdateManager : function(){
45756 return this.el.getUpdateManager();
45759 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
45760 * @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:
45763 url: "your-url.php",
45764 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
45765 callback: yourFunction,
45766 scope: yourObject, //(optional scope)
45769 text: "Loading...",
45774 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
45775 * 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.
45776 * @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}
45777 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
45778 * @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.
45779 * @return {Roo.ContentPanel} this
45782 var um = this.el.getUpdateManager();
45783 um.update.apply(um, arguments);
45789 * 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.
45790 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
45791 * @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)
45792 * @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)
45793 * @return {Roo.UpdateManager} The UpdateManager
45795 setUrl : function(url, params, loadOnce){
45796 if(this.refreshDelegate){
45797 this.removeListener("activate", this.refreshDelegate);
45799 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
45800 this.on("activate", this.refreshDelegate);
45801 return this.el.getUpdateManager();
45804 _handleRefresh : function(url, params, loadOnce){
45805 if(!loadOnce || !this.loaded){
45806 var updater = this.el.getUpdateManager();
45807 updater.update(url, params, this._setLoaded.createDelegate(this));
45811 _setLoaded : function(){
45812 this.loaded = true;
45816 * Returns this panel's id
45819 getId : function(){
45824 * Returns this panel's element - used by regiosn to add.
45825 * @return {Roo.Element}
45827 getEl : function(){
45828 return this.wrapEl || this.el;
45831 adjustForComponents : function(width, height){
45832 if(this.resizeEl != this.el){
45833 width -= this.el.getFrameWidth('lr');
45834 height -= this.el.getFrameWidth('tb');
45837 var te = this.toolbar.getEl();
45838 height -= te.getHeight();
45839 te.setWidth(width);
45841 if(this.adjustments){
45842 width += this.adjustments[0];
45843 height += this.adjustments[1];
45845 return {"width": width, "height": height};
45848 setSize : function(width, height){
45849 if(this.fitToFrame && !this.ignoreResize(width, height)){
45850 if(this.fitContainer && this.resizeEl != this.el){
45851 this.el.setSize(width, height);
45853 var size = this.adjustForComponents(width, height);
45854 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
45855 this.fireEvent('resize', this, size.width, size.height);
45860 * Returns this panel's title
45863 getTitle : function(){
45868 * Set this panel's title
45869 * @param {String} title
45871 setTitle : function(title){
45872 this.title = title;
45874 this.region.updatePanelTitle(this, title);
45879 * Returns true is this panel was configured to be closable
45880 * @return {Boolean}
45882 isClosable : function(){
45883 return this.closable;
45886 beforeSlide : function(){
45888 this.resizeEl.clip();
45891 afterSlide : function(){
45893 this.resizeEl.unclip();
45897 * Force a content refresh from the URL specified in the {@link #setUrl} method.
45898 * Will fail silently if the {@link #setUrl} method has not been called.
45899 * This does not activate the panel, just updates its content.
45901 refresh : function(){
45902 if(this.refreshDelegate){
45903 this.loaded = false;
45904 this.refreshDelegate();
45909 * Destroys this panel
45911 destroy : function(){
45912 this.el.removeAllListeners();
45913 var tempEl = document.createElement("span");
45914 tempEl.appendChild(this.el.dom);
45915 tempEl.innerHTML = "";
45921 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
45931 * @param {Object} cfg Xtype definition of item to add.
45934 addxtype : function(cfg) {
45936 if (cfg.xtype.match(/^Form$/)) {
45937 var el = this.el.createChild();
45939 this.form = new Roo.form.Form(cfg);
45942 if ( this.form.allItems.length) this.form.render(el.dom);
45945 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
45947 cfg.el = this.el.appendChild(document.createElement("div"));
45949 var ret = new Roo[cfg.xtype](cfg);
45950 ret.render(false, ''); // render blank..
45960 * @class Roo.GridPanel
45961 * @extends Roo.ContentPanel
45963 * Create a new GridPanel.
45964 * @param {Roo.grid.Grid} grid The grid for this panel
45965 * @param {String/Object} config A string to set only the panel's title, or a config object
45967 Roo.GridPanel = function(grid, config){
45970 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
45971 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
45973 this.wrapper.dom.appendChild(grid.getGridEl().dom);
45975 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
45978 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
45980 // xtype created footer. - not sure if will work as we normally have to render first..
45981 if (this.footer && !this.footer.el && this.footer.xtype) {
45983 this.footer.container = this.grid.getView().getFooterPanel(true);
45984 this.footer.dataSource = this.grid.dataSource;
45985 this.footer = Roo.factory(this.footer, Roo);
45989 grid.monitorWindowResize = false; // turn off autosizing
45990 grid.autoHeight = false;
45991 grid.autoWidth = false;
45993 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
45996 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
45997 getId : function(){
45998 return this.grid.id;
46002 * Returns the grid for this panel
46003 * @return {Roo.grid.Grid}
46005 getGrid : function(){
46009 setSize : function(width, height){
46010 if(!this.ignoreResize(width, height)){
46011 var grid = this.grid;
46012 var size = this.adjustForComponents(width, height);
46013 grid.getGridEl().setSize(size.width, size.height);
46018 beforeSlide : function(){
46019 this.grid.getView().scroller.clip();
46022 afterSlide : function(){
46023 this.grid.getView().scroller.unclip();
46026 destroy : function(){
46027 this.grid.destroy();
46029 Roo.GridPanel.superclass.destroy.call(this);
46035 * @class Roo.NestedLayoutPanel
46036 * @extends Roo.ContentPanel
46038 * Create a new NestedLayoutPanel.
46041 * @param {Roo.BorderLayout} layout The layout for this panel
46042 * @param {String/Object} config A string to set only the title or a config object
46044 Roo.NestedLayoutPanel = function(layout, config)
46046 // construct with only one argument..
46047 /* FIXME - implement nicer consturctors
46048 if (layout.layout) {
46050 layout = config.layout;
46051 delete config.layout;
46053 if (layout.xtype && !layout.getEl) {
46054 // then layout needs constructing..
46055 layout = Roo.factory(layout, Roo);
46060 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
46062 layout.monitorWindowResize = false; // turn off autosizing
46063 this.layout = layout;
46064 this.layout.getEl().addClass("x-layout-nested-layout");
46071 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
46073 setSize : function(width, height){
46074 if(!this.ignoreResize(width, height)){
46075 var size = this.adjustForComponents(width, height);
46076 var el = this.layout.getEl();
46077 el.setSize(size.width, size.height);
46078 var touch = el.dom.offsetWidth;
46079 this.layout.layout();
46080 // ie requires a double layout on the first pass
46081 if(Roo.isIE && !this.initialized){
46082 this.initialized = true;
46083 this.layout.layout();
46088 // activate all subpanels if not currently active..
46090 setActiveState : function(active){
46091 this.active = active;
46093 this.fireEvent("deactivate", this);
46097 this.fireEvent("activate", this);
46098 // not sure if this should happen before or after..
46099 if (!this.layout) {
46100 return; // should not happen..
46103 for (var r in this.layout.regions) {
46104 reg = this.layout.getRegion(r);
46105 if (reg.getActivePanel()) {
46106 //reg.showPanel(reg.getActivePanel()); // force it to activate..
46107 reg.setActivePanel(reg.getActivePanel());
46110 if (!reg.panels.length) {
46113 reg.showPanel(reg.getPanel(0));
46122 * Returns the nested BorderLayout for this panel
46123 * @return {Roo.BorderLayout}
46125 getLayout : function(){
46126 return this.layout;
46130 * Adds a xtype elements to the layout of the nested panel
46134 xtype : 'ContentPanel',
46141 xtype : 'NestedLayoutPanel',
46147 items : [ ... list of content panels or nested layout panels.. ]
46151 * @param {Object} cfg Xtype definition of item to add.
46153 addxtype : function(cfg) {
46154 return this.layout.addxtype(cfg);
46159 Roo.ScrollPanel = function(el, config, content){
46160 config = config || {};
46161 config.fitToFrame = true;
46162 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
46164 this.el.dom.style.overflow = "hidden";
46165 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
46166 this.el.removeClass("x-layout-inactive-content");
46167 this.el.on("mousewheel", this.onWheel, this);
46169 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
46170 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
46171 up.unselectable(); down.unselectable();
46172 up.on("click", this.scrollUp, this);
46173 down.on("click", this.scrollDown, this);
46174 up.addClassOnOver("x-scroller-btn-over");
46175 down.addClassOnOver("x-scroller-btn-over");
46176 up.addClassOnClick("x-scroller-btn-click");
46177 down.addClassOnClick("x-scroller-btn-click");
46178 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
46180 this.resizeEl = this.el;
46181 this.el = wrap; this.up = up; this.down = down;
46184 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
46186 wheelIncrement : 5,
46187 scrollUp : function(){
46188 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
46191 scrollDown : function(){
46192 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
46195 afterScroll : function(){
46196 var el = this.resizeEl;
46197 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
46198 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
46199 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
46202 setSize : function(){
46203 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
46204 this.afterScroll();
46207 onWheel : function(e){
46208 var d = e.getWheelDelta();
46209 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
46210 this.afterScroll();
46214 setContent : function(content, loadScripts){
46215 this.resizeEl.update(content, loadScripts);
46229 * @class Roo.TreePanel
46230 * @extends Roo.ContentPanel
46232 * Create a new TreePanel. - defaults to fit/scoll contents.
46233 * @param {String/Object} config A string to set only the panel's title, or a config object
46234 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
46236 Roo.TreePanel = function(config){
46237 var el = config.el;
46238 var tree = config.tree;
46239 delete config.tree;
46240 delete config.el; // hopefull!
46242 // wrapper for IE7 strict & safari scroll issue
46244 var treeEl = el.createChild();
46245 config.resizeEl = treeEl;
46249 Roo.TreePanel.superclass.constructor.call(this, el, config);
46252 this.tree = new Roo.tree.TreePanel(treeEl , tree);
46253 //console.log(tree);
46254 this.on('activate', function()
46256 if (this.tree.rendered) {
46259 //console.log('render tree');
46260 this.tree.render();
46263 this.on('resize', function (cp, w, h) {
46264 this.tree.innerCt.setWidth(w);
46265 this.tree.innerCt.setHeight(h);
46266 this.tree.innerCt.setStyle('overflow-y', 'auto');
46273 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
46290 * Ext JS Library 1.1.1
46291 * Copyright(c) 2006-2007, Ext JS, LLC.
46293 * Originally Released Under LGPL - original licence link has changed is not relivant.
46296 * <script type="text/javascript">
46301 * @class Roo.ReaderLayout
46302 * @extends Roo.BorderLayout
46303 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
46304 * center region containing two nested regions (a top one for a list view and one for item preview below),
46305 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
46306 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
46307 * expedites the setup of the overall layout and regions for this common application style.
46310 var reader = new Roo.ReaderLayout();
46311 var CP = Roo.ContentPanel; // shortcut for adding
46313 reader.beginUpdate();
46314 reader.add("north", new CP("north", "North"));
46315 reader.add("west", new CP("west", {title: "West"}));
46316 reader.add("east", new CP("east", {title: "East"}));
46318 reader.regions.listView.add(new CP("listView", "List"));
46319 reader.regions.preview.add(new CP("preview", "Preview"));
46320 reader.endUpdate();
46323 * Create a new ReaderLayout
46324 * @param {Object} config Configuration options
46325 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
46326 * document.body if omitted)
46328 Roo.ReaderLayout = function(config, renderTo){
46329 var c = config || {size:{}};
46330 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
46331 north: c.north !== false ? Roo.apply({
46335 }, c.north) : false,
46336 west: c.west !== false ? Roo.apply({
46344 margins:{left:5,right:0,bottom:5,top:5},
46345 cmargins:{left:5,right:5,bottom:5,top:5}
46346 }, c.west) : false,
46347 east: c.east !== false ? Roo.apply({
46355 margins:{left:0,right:5,bottom:5,top:5},
46356 cmargins:{left:5,right:5,bottom:5,top:5}
46357 }, c.east) : false,
46358 center: Roo.apply({
46359 tabPosition: 'top',
46363 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
46367 this.el.addClass('x-reader');
46369 this.beginUpdate();
46371 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
46372 south: c.preview !== false ? Roo.apply({
46379 cmargins:{top:5,left:0, right:0, bottom:0}
46380 }, c.preview) : false,
46381 center: Roo.apply({
46387 this.add('center', new Roo.NestedLayoutPanel(inner,
46388 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
46392 this.regions.preview = inner.getRegion('south');
46393 this.regions.listView = inner.getRegion('center');
46396 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
46398 * Ext JS Library 1.1.1
46399 * Copyright(c) 2006-2007, Ext JS, LLC.
46401 * Originally Released Under LGPL - original licence link has changed is not relivant.
46404 * <script type="text/javascript">
46408 * @class Roo.grid.Grid
46409 * @extends Roo.util.Observable
46410 * This class represents the primary interface of a component based grid control.
46411 * <br><br>Usage:<pre><code>
46412 var grid = new Roo.grid.Grid("my-container-id", {
46415 selModel: mySelectionModel,
46416 autoSizeColumns: true,
46417 monitorWindowResize: false,
46418 trackMouseOver: true
46423 * <b>Common Problems:</b><br/>
46424 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
46425 * element will correct this<br/>
46426 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
46427 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
46428 * are unpredictable.<br/>
46429 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
46430 * grid to calculate dimensions/offsets.<br/>
46432 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
46433 * The container MUST have some type of size defined for the grid to fill. The container will be
46434 * automatically set to position relative if it isn't already.
46435 * @param {Object} config A config object that sets properties on this grid.
46437 Roo.grid.Grid = function(container, config){
46438 // initialize the container
46439 this.container = Roo.get(container);
46440 this.container.update("");
46441 this.container.setStyle("overflow", "hidden");
46442 this.container.addClass('x-grid-container');
46444 this.id = this.container.id;
46446 Roo.apply(this, config);
46447 // check and correct shorthanded configs
46449 this.dataSource = this.ds;
46453 this.colModel = this.cm;
46457 this.selModel = this.sm;
46461 if (this.selModel) {
46462 this.selModel = Roo.factory(this.selModel, Roo.grid);
46463 this.sm = this.selModel;
46464 this.sm.xmodule = this.xmodule || false;
46466 if (typeof(this.colModel.config) == 'undefined') {
46467 this.colModel = new Roo.grid.ColumnModel(this.colModel);
46468 this.cm = this.colModel;
46469 this.cm.xmodule = this.xmodule || false;
46471 if (this.dataSource) {
46472 this.dataSource= Roo.factory(this.dataSource, Roo.data);
46473 this.ds = this.dataSource;
46474 this.ds.xmodule = this.xmodule || false;
46475 this.ds.multiSort = this.multiSort || false;
46481 this.container.setWidth(this.width);
46485 this.container.setHeight(this.height);
46492 * The raw click event for the entire grid.
46493 * @param {Roo.EventObject} e
46498 * The raw dblclick event for the entire grid.
46499 * @param {Roo.EventObject} e
46503 * @event contextmenu
46504 * The raw contextmenu event for the entire grid.
46505 * @param {Roo.EventObject} e
46507 "contextmenu" : true,
46510 * The raw mousedown event for the entire grid.
46511 * @param {Roo.EventObject} e
46513 "mousedown" : true,
46516 * The raw mouseup event for the entire grid.
46517 * @param {Roo.EventObject} e
46522 * The raw mouseover event for the entire grid.
46523 * @param {Roo.EventObject} e
46525 "mouseover" : true,
46528 * The raw mouseout event for the entire grid.
46529 * @param {Roo.EventObject} e
46534 * The raw keypress event for the entire grid.
46535 * @param {Roo.EventObject} e
46540 * The raw keydown event for the entire grid.
46541 * @param {Roo.EventObject} e
46549 * Fires when a cell is clicked
46550 * @param {Grid} this
46551 * @param {Number} rowIndex
46552 * @param {Number} columnIndex
46553 * @param {Roo.EventObject} e
46555 "cellclick" : true,
46557 * @event celldblclick
46558 * Fires when a cell is double clicked
46559 * @param {Grid} this
46560 * @param {Number} rowIndex
46561 * @param {Number} columnIndex
46562 * @param {Roo.EventObject} e
46564 "celldblclick" : true,
46567 * Fires when a row is clicked
46568 * @param {Grid} this
46569 * @param {Number} rowIndex
46570 * @param {Roo.EventObject} e
46574 * @event rowdblclick
46575 * Fires when a row is double clicked
46576 * @param {Grid} this
46577 * @param {Number} rowIndex
46578 * @param {Roo.EventObject} e
46580 "rowdblclick" : true,
46582 * @event headerclick
46583 * Fires when a header is clicked
46584 * @param {Grid} this
46585 * @param {Number} columnIndex
46586 * @param {Roo.EventObject} e
46588 "headerclick" : true,
46590 * @event headerdblclick
46591 * Fires when a header cell is double clicked
46592 * @param {Grid} this
46593 * @param {Number} columnIndex
46594 * @param {Roo.EventObject} e
46596 "headerdblclick" : true,
46598 * @event rowcontextmenu
46599 * Fires when a row is right clicked
46600 * @param {Grid} this
46601 * @param {Number} rowIndex
46602 * @param {Roo.EventObject} e
46604 "rowcontextmenu" : true,
46606 * @event cellcontextmenu
46607 * Fires when a cell is right clicked
46608 * @param {Grid} this
46609 * @param {Number} rowIndex
46610 * @param {Number} cellIndex
46611 * @param {Roo.EventObject} e
46613 "cellcontextmenu" : true,
46615 * @event headercontextmenu
46616 * Fires when a header is right clicked
46617 * @param {Grid} this
46618 * @param {Number} columnIndex
46619 * @param {Roo.EventObject} e
46621 "headercontextmenu" : true,
46623 * @event bodyscroll
46624 * Fires when the body element is scrolled
46625 * @param {Number} scrollLeft
46626 * @param {Number} scrollTop
46628 "bodyscroll" : true,
46630 * @event columnresize
46631 * Fires when the user resizes a column
46632 * @param {Number} columnIndex
46633 * @param {Number} newSize
46635 "columnresize" : true,
46637 * @event columnmove
46638 * Fires when the user moves a column
46639 * @param {Number} oldIndex
46640 * @param {Number} newIndex
46642 "columnmove" : true,
46645 * Fires when row(s) start being dragged
46646 * @param {Grid} this
46647 * @param {Roo.GridDD} dd The drag drop object
46648 * @param {event} e The raw browser event
46650 "startdrag" : true,
46653 * Fires when a drag operation is complete
46654 * @param {Grid} this
46655 * @param {Roo.GridDD} dd The drag drop object
46656 * @param {event} e The raw browser event
46661 * Fires when dragged row(s) are dropped on a valid DD target
46662 * @param {Grid} this
46663 * @param {Roo.GridDD} dd The drag drop object
46664 * @param {String} targetId The target drag drop object
46665 * @param {event} e The raw browser event
46670 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
46671 * @param {Grid} this
46672 * @param {Roo.GridDD} dd The drag drop object
46673 * @param {String} targetId The target drag drop object
46674 * @param {event} e The raw browser event
46679 * Fires when the dragged row(s) first cross another DD target while being dragged
46680 * @param {Grid} this
46681 * @param {Roo.GridDD} dd The drag drop object
46682 * @param {String} targetId The target drag drop object
46683 * @param {event} e The raw browser event
46685 "dragenter" : true,
46688 * Fires when the dragged row(s) leave another DD target while being dragged
46689 * @param {Grid} this
46690 * @param {Roo.GridDD} dd The drag drop object
46691 * @param {String} targetId The target drag drop object
46692 * @param {event} e The raw browser event
46697 * Fires when a row is rendered, so you can change add a style to it.
46698 * @param {GridView} gridview The grid view
46699 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
46705 * Fires when the grid is rendered
46706 * @param {Grid} grid
46711 Roo.grid.Grid.superclass.constructor.call(this);
46713 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
46716 * @cfg {String} ddGroup - drag drop group.
46720 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
46722 minColumnWidth : 25,
46725 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
46726 * <b>on initial render.</b> It is more efficient to explicitly size the columns
46727 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
46729 autoSizeColumns : false,
46732 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
46734 autoSizeHeaders : true,
46737 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
46739 monitorWindowResize : true,
46742 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
46743 * rows measured to get a columns size. Default is 0 (all rows).
46745 maxRowsToMeasure : 0,
46748 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
46750 trackMouseOver : true,
46753 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
46757 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
46759 enableDragDrop : false,
46762 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
46764 enableColumnMove : true,
46767 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
46769 enableColumnHide : true,
46772 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
46774 enableRowHeightSync : false,
46777 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
46782 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
46784 autoHeight : false,
46787 * @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.
46789 autoExpandColumn : false,
46792 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
46795 autoExpandMin : 50,
46798 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
46800 autoExpandMax : 1000,
46803 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
46808 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
46812 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
46817 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns)
46825 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
46826 * of a fixed width. Default is false.
46829 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
46832 * Called once after all setup has been completed and the grid is ready to be rendered.
46833 * @return {Roo.grid.Grid} this
46835 render : function()
46837 var c = this.container;
46838 // try to detect autoHeight/width mode
46839 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
46840 this.autoHeight = true;
46842 var view = this.getView();
46845 c.on("click", this.onClick, this);
46846 c.on("dblclick", this.onDblClick, this);
46847 c.on("contextmenu", this.onContextMenu, this);
46848 c.on("keydown", this.onKeyDown, this);
46850 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
46852 this.getSelectionModel().init(this);
46857 this.loadMask = new Roo.LoadMask(this.container,
46858 Roo.apply({store:this.dataSource}, this.loadMask));
46862 if (this.toolbar && this.toolbar.xtype) {
46863 this.toolbar.container = this.getView().getHeaderPanel(true);
46864 this.toolbar = new Roo.Toolbar(this.toolbar);
46866 if (this.footer && this.footer.xtype) {
46867 this.footer.dataSource = this.getDataSource();
46868 this.footer.container = this.getView().getFooterPanel(true);
46869 this.footer = Roo.factory(this.footer, Roo);
46871 if (this.dropTarget && this.dropTarget.xtype) {
46872 delete this.dropTarget.xtype;
46873 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
46877 this.rendered = true;
46878 this.fireEvent('render', this);
46883 * Reconfigures the grid to use a different Store and Column Model.
46884 * The View will be bound to the new objects and refreshed.
46885 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
46886 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
46888 reconfigure : function(dataSource, colModel){
46890 this.loadMask.destroy();
46891 this.loadMask = new Roo.LoadMask(this.container,
46892 Roo.apply({store:dataSource}, this.loadMask));
46894 this.view.bind(dataSource, colModel);
46895 this.dataSource = dataSource;
46896 this.colModel = colModel;
46897 this.view.refresh(true);
46901 onKeyDown : function(e){
46902 this.fireEvent("keydown", e);
46906 * Destroy this grid.
46907 * @param {Boolean} removeEl True to remove the element
46909 destroy : function(removeEl, keepListeners){
46911 this.loadMask.destroy();
46913 var c = this.container;
46914 c.removeAllListeners();
46915 this.view.destroy();
46916 this.colModel.purgeListeners();
46917 if(!keepListeners){
46918 this.purgeListeners();
46921 if(removeEl === true){
46927 processEvent : function(name, e){
46928 this.fireEvent(name, e);
46929 var t = e.getTarget();
46931 var header = v.findHeaderIndex(t);
46932 if(header !== false){
46933 this.fireEvent("header" + name, this, header, e);
46935 var row = v.findRowIndex(t);
46936 var cell = v.findCellIndex(t);
46938 this.fireEvent("row" + name, this, row, e);
46939 if(cell !== false){
46940 this.fireEvent("cell" + name, this, row, cell, e);
46947 onClick : function(e){
46948 this.processEvent("click", e);
46952 onContextMenu : function(e, t){
46953 this.processEvent("contextmenu", e);
46957 onDblClick : function(e){
46958 this.processEvent("dblclick", e);
46962 walkCells : function(row, col, step, fn, scope){
46963 var cm = this.colModel, clen = cm.getColumnCount();
46964 var ds = this.dataSource, rlen = ds.getCount(), first = true;
46976 if(fn.call(scope || this, row, col, cm) === true){
46994 if(fn.call(scope || this, row, col, cm) === true){
47006 getSelections : function(){
47007 return this.selModel.getSelections();
47011 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
47012 * but if manual update is required this method will initiate it.
47014 autoSize : function(){
47016 this.view.layout();
47017 if(this.view.adjustForScroll){
47018 this.view.adjustForScroll();
47024 * Returns the grid's underlying element.
47025 * @return {Element} The element
47027 getGridEl : function(){
47028 return this.container;
47031 // private for compatibility, overridden by editor grid
47032 stopEditing : function(){},
47035 * Returns the grid's SelectionModel.
47036 * @return {SelectionModel}
47038 getSelectionModel : function(){
47039 if(!this.selModel){
47040 this.selModel = new Roo.grid.RowSelectionModel();
47042 return this.selModel;
47046 * Returns the grid's DataSource.
47047 * @return {DataSource}
47049 getDataSource : function(){
47050 return this.dataSource;
47054 * Returns the grid's ColumnModel.
47055 * @return {ColumnModel}
47057 getColumnModel : function(){
47058 return this.colModel;
47062 * Returns the grid's GridView object.
47063 * @return {GridView}
47065 getView : function(){
47067 this.view = new Roo.grid.GridView(this.viewConfig);
47072 * Called to get grid's drag proxy text, by default returns this.ddText.
47075 getDragDropText : function(){
47076 var count = this.selModel.getCount();
47077 return String.format(this.ddText, count, count == 1 ? '' : 's');
47081 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
47082 * %0 is replaced with the number of selected rows.
47085 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
47087 * Ext JS Library 1.1.1
47088 * Copyright(c) 2006-2007, Ext JS, LLC.
47090 * Originally Released Under LGPL - original licence link has changed is not relivant.
47093 * <script type="text/javascript">
47096 Roo.grid.AbstractGridView = function(){
47100 "beforerowremoved" : true,
47101 "beforerowsinserted" : true,
47102 "beforerefresh" : true,
47103 "rowremoved" : true,
47104 "rowsinserted" : true,
47105 "rowupdated" : true,
47108 Roo.grid.AbstractGridView.superclass.constructor.call(this);
47111 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
47112 rowClass : "x-grid-row",
47113 cellClass : "x-grid-cell",
47114 tdClass : "x-grid-td",
47115 hdClass : "x-grid-hd",
47116 splitClass : "x-grid-hd-split",
47118 init: function(grid){
47120 var cid = this.grid.getGridEl().id;
47121 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
47122 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
47123 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
47124 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
47127 getColumnRenderers : function(){
47128 var renderers = [];
47129 var cm = this.grid.colModel;
47130 var colCount = cm.getColumnCount();
47131 for(var i = 0; i < colCount; i++){
47132 renderers[i] = cm.getRenderer(i);
47137 getColumnIds : function(){
47139 var cm = this.grid.colModel;
47140 var colCount = cm.getColumnCount();
47141 for(var i = 0; i < colCount; i++){
47142 ids[i] = cm.getColumnId(i);
47147 getDataIndexes : function(){
47148 if(!this.indexMap){
47149 this.indexMap = this.buildIndexMap();
47151 return this.indexMap.colToData;
47154 getColumnIndexByDataIndex : function(dataIndex){
47155 if(!this.indexMap){
47156 this.indexMap = this.buildIndexMap();
47158 return this.indexMap.dataToCol[dataIndex];
47162 * Set a css style for a column dynamically.
47163 * @param {Number} colIndex The index of the column
47164 * @param {String} name The css property name
47165 * @param {String} value The css value
47167 setCSSStyle : function(colIndex, name, value){
47168 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
47169 Roo.util.CSS.updateRule(selector, name, value);
47172 generateRules : function(cm){
47173 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
47174 Roo.util.CSS.removeStyleSheet(rulesId);
47175 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47176 var cid = cm.getColumnId(i);
47177 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
47178 this.tdSelector, cid, " {\n}\n",
47179 this.hdSelector, cid, " {\n}\n",
47180 this.splitSelector, cid, " {\n}\n");
47182 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
47186 * Ext JS Library 1.1.1
47187 * Copyright(c) 2006-2007, Ext JS, LLC.
47189 * Originally Released Under LGPL - original licence link has changed is not relivant.
47192 * <script type="text/javascript">
47196 // This is a support class used internally by the Grid components
47197 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
47199 this.view = grid.getView();
47200 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
47201 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
47203 this.setHandleElId(Roo.id(hd));
47204 this.setOuterHandleElId(Roo.id(hd2));
47206 this.scroll = false;
47208 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
47210 getDragData : function(e){
47211 var t = Roo.lib.Event.getTarget(e);
47212 var h = this.view.findHeaderCell(t);
47214 return {ddel: h.firstChild, header:h};
47219 onInitDrag : function(e){
47220 this.view.headersDisabled = true;
47221 var clone = this.dragData.ddel.cloneNode(true);
47222 clone.id = Roo.id();
47223 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
47224 this.proxy.update(clone);
47228 afterValidDrop : function(){
47230 setTimeout(function(){
47231 v.headersDisabled = false;
47235 afterInvalidDrop : function(){
47237 setTimeout(function(){
47238 v.headersDisabled = false;
47244 * Ext JS Library 1.1.1
47245 * Copyright(c) 2006-2007, Ext JS, LLC.
47247 * Originally Released Under LGPL - original licence link has changed is not relivant.
47250 * <script type="text/javascript">
47253 // This is a support class used internally by the Grid components
47254 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
47256 this.view = grid.getView();
47257 // split the proxies so they don't interfere with mouse events
47258 this.proxyTop = Roo.DomHelper.append(document.body, {
47259 cls:"col-move-top", html:" "
47261 this.proxyBottom = Roo.DomHelper.append(document.body, {
47262 cls:"col-move-bottom", html:" "
47264 this.proxyTop.hide = this.proxyBottom.hide = function(){
47265 this.setLeftTop(-100,-100);
47266 this.setStyle("visibility", "hidden");
47268 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
47269 // temporarily disabled
47270 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
47271 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
47273 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
47274 proxyOffsets : [-4, -9],
47275 fly: Roo.Element.fly,
47277 getTargetFromEvent : function(e){
47278 var t = Roo.lib.Event.getTarget(e);
47279 var cindex = this.view.findCellIndex(t);
47280 if(cindex !== false){
47281 return this.view.getHeaderCell(cindex);
47285 nextVisible : function(h){
47286 var v = this.view, cm = this.grid.colModel;
47289 if(!cm.isHidden(v.getCellIndex(h))){
47297 prevVisible : function(h){
47298 var v = this.view, cm = this.grid.colModel;
47301 if(!cm.isHidden(v.getCellIndex(h))){
47309 positionIndicator : function(h, n, e){
47310 var x = Roo.lib.Event.getPageX(e);
47311 var r = Roo.lib.Dom.getRegion(n.firstChild);
47312 var px, pt, py = r.top + this.proxyOffsets[1];
47313 if((r.right - x) <= (r.right-r.left)/2){
47314 px = r.right+this.view.borderWidth;
47320 var oldIndex = this.view.getCellIndex(h);
47321 var newIndex = this.view.getCellIndex(n);
47323 if(this.grid.colModel.isFixed(newIndex)){
47327 var locked = this.grid.colModel.isLocked(newIndex);
47332 if(oldIndex < newIndex){
47335 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
47338 px += this.proxyOffsets[0];
47339 this.proxyTop.setLeftTop(px, py);
47340 this.proxyTop.show();
47341 if(!this.bottomOffset){
47342 this.bottomOffset = this.view.mainHd.getHeight();
47344 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
47345 this.proxyBottom.show();
47349 onNodeEnter : function(n, dd, e, data){
47350 if(data.header != n){
47351 this.positionIndicator(data.header, n, e);
47355 onNodeOver : function(n, dd, e, data){
47356 var result = false;
47357 if(data.header != n){
47358 result = this.positionIndicator(data.header, n, e);
47361 this.proxyTop.hide();
47362 this.proxyBottom.hide();
47364 return result ? this.dropAllowed : this.dropNotAllowed;
47367 onNodeOut : function(n, dd, e, data){
47368 this.proxyTop.hide();
47369 this.proxyBottom.hide();
47372 onNodeDrop : function(n, dd, e, data){
47373 var h = data.header;
47375 var cm = this.grid.colModel;
47376 var x = Roo.lib.Event.getPageX(e);
47377 var r = Roo.lib.Dom.getRegion(n.firstChild);
47378 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
47379 var oldIndex = this.view.getCellIndex(h);
47380 var newIndex = this.view.getCellIndex(n);
47381 var locked = cm.isLocked(newIndex);
47385 if(oldIndex < newIndex){
47388 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
47391 cm.setLocked(oldIndex, locked, true);
47392 cm.moveColumn(oldIndex, newIndex);
47393 this.grid.fireEvent("columnmove", oldIndex, newIndex);
47401 * Ext JS Library 1.1.1
47402 * Copyright(c) 2006-2007, Ext JS, LLC.
47404 * Originally Released Under LGPL - original licence link has changed is not relivant.
47407 * <script type="text/javascript">
47411 * @class Roo.grid.GridView
47412 * @extends Roo.util.Observable
47415 * @param {Object} config
47417 Roo.grid.GridView = function(config){
47418 Roo.grid.GridView.superclass.constructor.call(this);
47421 Roo.apply(this, config);
47424 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
47427 * Override this function to apply custom css classes to rows during rendering
47428 * @param {Record} record The record
47429 * @param {Number} index
47430 * @method getRowClass
47432 rowClass : "x-grid-row",
47434 cellClass : "x-grid-col",
47436 tdClass : "x-grid-td",
47438 hdClass : "x-grid-hd",
47440 splitClass : "x-grid-split",
47442 sortClasses : ["sort-asc", "sort-desc"],
47444 enableMoveAnim : false,
47448 dh : Roo.DomHelper,
47450 fly : Roo.Element.fly,
47452 css : Roo.util.CSS,
47458 scrollIncrement : 22,
47460 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
47462 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
47464 bind : function(ds, cm){
47466 this.ds.un("load", this.onLoad, this);
47467 this.ds.un("datachanged", this.onDataChange, this);
47468 this.ds.un("add", this.onAdd, this);
47469 this.ds.un("remove", this.onRemove, this);
47470 this.ds.un("update", this.onUpdate, this);
47471 this.ds.un("clear", this.onClear, this);
47474 ds.on("load", this.onLoad, this);
47475 ds.on("datachanged", this.onDataChange, this);
47476 ds.on("add", this.onAdd, this);
47477 ds.on("remove", this.onRemove, this);
47478 ds.on("update", this.onUpdate, this);
47479 ds.on("clear", this.onClear, this);
47484 this.cm.un("widthchange", this.onColWidthChange, this);
47485 this.cm.un("headerchange", this.onHeaderChange, this);
47486 this.cm.un("hiddenchange", this.onHiddenChange, this);
47487 this.cm.un("columnmoved", this.onColumnMove, this);
47488 this.cm.un("columnlockchange", this.onColumnLock, this);
47491 this.generateRules(cm);
47492 cm.on("widthchange", this.onColWidthChange, this);
47493 cm.on("headerchange", this.onHeaderChange, this);
47494 cm.on("hiddenchange", this.onHiddenChange, this);
47495 cm.on("columnmoved", this.onColumnMove, this);
47496 cm.on("columnlockchange", this.onColumnLock, this);
47501 init: function(grid){
47502 Roo.grid.GridView.superclass.init.call(this, grid);
47504 this.bind(grid.dataSource, grid.colModel);
47506 grid.on("headerclick", this.handleHeaderClick, this);
47508 if(grid.trackMouseOver){
47509 grid.on("mouseover", this.onRowOver, this);
47510 grid.on("mouseout", this.onRowOut, this);
47512 grid.cancelTextSelection = function(){};
47513 this.gridId = grid.id;
47515 var tpls = this.templates || {};
47518 tpls.master = new Roo.Template(
47519 '<div class="x-grid" hidefocus="true">',
47520 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
47521 '<div class="x-grid-topbar"></div>',
47522 '<div class="x-grid-scroller"><div></div></div>',
47523 '<div class="x-grid-locked">',
47524 '<div class="x-grid-header">{lockedHeader}</div>',
47525 '<div class="x-grid-body">{lockedBody}</div>',
47527 '<div class="x-grid-viewport">',
47528 '<div class="x-grid-header">{header}</div>',
47529 '<div class="x-grid-body">{body}</div>',
47531 '<div class="x-grid-bottombar"></div>',
47533 '<div class="x-grid-resize-proxy"> </div>',
47536 tpls.master.disableformats = true;
47540 tpls.header = new Roo.Template(
47541 '<table border="0" cellspacing="0" cellpadding="0">',
47542 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
47545 tpls.header.disableformats = true;
47547 tpls.header.compile();
47550 tpls.hcell = new Roo.Template(
47551 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
47552 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
47555 tpls.hcell.disableFormats = true;
47557 tpls.hcell.compile();
47560 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
47561 tpls.hsplit.disableFormats = true;
47563 tpls.hsplit.compile();
47566 tpls.body = new Roo.Template(
47567 '<table border="0" cellspacing="0" cellpadding="0">',
47568 "<tbody>{rows}</tbody>",
47571 tpls.body.disableFormats = true;
47573 tpls.body.compile();
47576 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
47577 tpls.row.disableFormats = true;
47579 tpls.row.compile();
47582 tpls.cell = new Roo.Template(
47583 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
47584 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
47587 tpls.cell.disableFormats = true;
47589 tpls.cell.compile();
47591 this.templates = tpls;
47594 // remap these for backwards compat
47595 onColWidthChange : function(){
47596 this.updateColumns.apply(this, arguments);
47598 onHeaderChange : function(){
47599 this.updateHeaders.apply(this, arguments);
47601 onHiddenChange : function(){
47602 this.handleHiddenChange.apply(this, arguments);
47604 onColumnMove : function(){
47605 this.handleColumnMove.apply(this, arguments);
47607 onColumnLock : function(){
47608 this.handleLockChange.apply(this, arguments);
47611 onDataChange : function(){
47613 this.updateHeaderSortState();
47616 onClear : function(){
47620 onUpdate : function(ds, record){
47621 this.refreshRow(record);
47624 refreshRow : function(record){
47625 var ds = this.ds, index;
47626 if(typeof record == 'number'){
47628 record = ds.getAt(index);
47630 index = ds.indexOf(record);
47632 this.insertRows(ds, index, index, true);
47633 this.onRemove(ds, record, index+1, true);
47634 this.syncRowHeights(index, index);
47636 this.fireEvent("rowupdated", this, index, record);
47639 onAdd : function(ds, records, index){
47640 this.insertRows(ds, index, index + (records.length-1));
47643 onRemove : function(ds, record, index, isUpdate){
47644 if(isUpdate !== true){
47645 this.fireEvent("beforerowremoved", this, index, record);
47647 var bt = this.getBodyTable(), lt = this.getLockedTable();
47648 if(bt.rows[index]){
47649 bt.firstChild.removeChild(bt.rows[index]);
47651 if(lt.rows[index]){
47652 lt.firstChild.removeChild(lt.rows[index]);
47654 if(isUpdate !== true){
47655 this.stripeRows(index);
47656 this.syncRowHeights(index, index);
47658 this.fireEvent("rowremoved", this, index, record);
47662 onLoad : function(){
47663 this.scrollToTop();
47667 * Scrolls the grid to the top
47669 scrollToTop : function(){
47671 this.scroller.dom.scrollTop = 0;
47677 * Gets a panel in the header of the grid that can be used for toolbars etc.
47678 * After modifying the contents of this panel a call to grid.autoSize() may be
47679 * required to register any changes in size.
47680 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
47681 * @return Roo.Element
47683 getHeaderPanel : function(doShow){
47685 this.headerPanel.show();
47687 return this.headerPanel;
47691 * Gets a panel in the footer of the grid that can be used for toolbars etc.
47692 * After modifying the contents of this panel a call to grid.autoSize() may be
47693 * required to register any changes in size.
47694 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
47695 * @return Roo.Element
47697 getFooterPanel : function(doShow){
47699 this.footerPanel.show();
47701 return this.footerPanel;
47704 initElements : function(){
47705 var E = Roo.Element;
47706 var el = this.grid.getGridEl().dom.firstChild;
47707 var cs = el.childNodes;
47709 this.el = new E(el);
47711 this.focusEl = new E(el.firstChild);
47712 this.focusEl.swallowEvent("click", true);
47714 this.headerPanel = new E(cs[1]);
47715 this.headerPanel.enableDisplayMode("block");
47717 this.scroller = new E(cs[2]);
47718 this.scrollSizer = new E(this.scroller.dom.firstChild);
47720 this.lockedWrap = new E(cs[3]);
47721 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
47722 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
47724 this.mainWrap = new E(cs[4]);
47725 this.mainHd = new E(this.mainWrap.dom.firstChild);
47726 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
47728 this.footerPanel = new E(cs[5]);
47729 this.footerPanel.enableDisplayMode("block");
47731 this.resizeProxy = new E(cs[6]);
47733 this.headerSelector = String.format(
47734 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
47735 this.lockedHd.id, this.mainHd.id
47738 this.splitterSelector = String.format(
47739 '#{0} div.x-grid-split, #{1} div.x-grid-split',
47740 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
47743 idToCssName : function(s)
47745 return s.replace(/[^a-z0-9]+/ig, '-');
47748 getHeaderCell : function(index){
47749 return Roo.DomQuery.select(this.headerSelector)[index];
47752 getHeaderCellMeasure : function(index){
47753 return this.getHeaderCell(index).firstChild;
47756 getHeaderCellText : function(index){
47757 return this.getHeaderCell(index).firstChild.firstChild;
47760 getLockedTable : function(){
47761 return this.lockedBody.dom.firstChild;
47764 getBodyTable : function(){
47765 return this.mainBody.dom.firstChild;
47768 getLockedRow : function(index){
47769 return this.getLockedTable().rows[index];
47772 getRow : function(index){
47773 return this.getBodyTable().rows[index];
47776 getRowComposite : function(index){
47778 this.rowEl = new Roo.CompositeElementLite();
47780 var els = [], lrow, mrow;
47781 if(lrow = this.getLockedRow(index)){
47784 if(mrow = this.getRow(index)){
47787 this.rowEl.elements = els;
47791 getCell : function(rowIndex, colIndex){
47792 var locked = this.cm.getLockedCount();
47794 if(colIndex < locked){
47795 source = this.lockedBody.dom.firstChild;
47797 source = this.mainBody.dom.firstChild;
47798 colIndex -= locked;
47800 return source.rows[rowIndex].childNodes[colIndex];
47803 getCellText : function(rowIndex, colIndex){
47804 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
47807 getCellBox : function(cell){
47808 var b = this.fly(cell).getBox();
47809 if(Roo.isOpera){ // opera fails to report the Y
47810 b.y = cell.offsetTop + this.mainBody.getY();
47815 getCellIndex : function(cell){
47816 var id = String(cell.className).match(this.cellRE);
47818 return parseInt(id[1], 10);
47823 findHeaderIndex : function(n){
47824 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47825 return r ? this.getCellIndex(r) : false;
47828 findHeaderCell : function(n){
47829 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47830 return r ? r : false;
47833 findRowIndex : function(n){
47837 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
47838 return r ? r.rowIndex : false;
47841 findCellIndex : function(node){
47842 var stop = this.el.dom;
47843 while(node && node != stop){
47844 if(this.findRE.test(node.className)){
47845 return this.getCellIndex(node);
47847 node = node.parentNode;
47852 getColumnId : function(index){
47853 return this.cm.getColumnId(index);
47856 getSplitters : function()
47858 if(this.splitterSelector){
47859 return Roo.DomQuery.select(this.splitterSelector);
47865 getSplitter : function(index){
47866 return this.getSplitters()[index];
47869 onRowOver : function(e, t){
47871 if((row = this.findRowIndex(t)) !== false){
47872 this.getRowComposite(row).addClass("x-grid-row-over");
47876 onRowOut : function(e, t){
47878 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
47879 this.getRowComposite(row).removeClass("x-grid-row-over");
47883 renderHeaders : function(){
47885 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
47886 var cb = [], lb = [], sb = [], lsb = [], p = {};
47887 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47888 p.cellId = "x-grid-hd-0-" + i;
47889 p.splitId = "x-grid-csplit-0-" + i;
47890 p.id = cm.getColumnId(i);
47891 p.title = cm.getColumnTooltip(i) || "";
47892 p.value = cm.getColumnHeader(i) || "";
47893 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
47894 if(!cm.isLocked(i)){
47895 cb[cb.length] = ct.apply(p);
47896 sb[sb.length] = st.apply(p);
47898 lb[lb.length] = ct.apply(p);
47899 lsb[lsb.length] = st.apply(p);
47902 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
47903 ht.apply({cells: cb.join(""), splits:sb.join("")})];
47906 updateHeaders : function(){
47907 var html = this.renderHeaders();
47908 this.lockedHd.update(html[0]);
47909 this.mainHd.update(html[1]);
47913 * Focuses the specified row.
47914 * @param {Number} row The row index
47916 focusRow : function(row)
47918 //Roo.log('GridView.focusRow');
47919 var x = this.scroller.dom.scrollLeft;
47920 this.focusCell(row, 0, false);
47921 this.scroller.dom.scrollLeft = x;
47925 * Focuses the specified cell.
47926 * @param {Number} row The row index
47927 * @param {Number} col The column index
47928 * @param {Boolean} hscroll false to disable horizontal scrolling
47930 focusCell : function(row, col, hscroll)
47932 //Roo.log('GridView.focusCell');
47933 var el = this.ensureVisible(row, col, hscroll);
47934 this.focusEl.alignTo(el, "tl-tl");
47936 this.focusEl.focus();
47938 this.focusEl.focus.defer(1, this.focusEl);
47943 * Scrolls the specified cell into view
47944 * @param {Number} row The row index
47945 * @param {Number} col The column index
47946 * @param {Boolean} hscroll false to disable horizontal scrolling
47948 ensureVisible : function(row, col, hscroll)
47950 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
47951 //return null; //disable for testing.
47952 if(typeof row != "number"){
47953 row = row.rowIndex;
47955 if(row < 0 && row >= this.ds.getCount()){
47958 col = (col !== undefined ? col : 0);
47959 var cm = this.grid.colModel;
47960 while(cm.isHidden(col)){
47964 var el = this.getCell(row, col);
47968 var c = this.scroller.dom;
47970 var ctop = parseInt(el.offsetTop, 10);
47971 var cleft = parseInt(el.offsetLeft, 10);
47972 var cbot = ctop + el.offsetHeight;
47973 var cright = cleft + el.offsetWidth;
47975 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
47976 var stop = parseInt(c.scrollTop, 10);
47977 var sleft = parseInt(c.scrollLeft, 10);
47978 var sbot = stop + ch;
47979 var sright = sleft + c.clientWidth;
47981 Roo.log('GridView.ensureVisible:' +
47983 ' c.clientHeight:' + c.clientHeight +
47984 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
47992 c.scrollTop = ctop;
47993 //Roo.log("set scrolltop to ctop DISABLE?");
47994 }else if(cbot > sbot){
47995 //Roo.log("set scrolltop to cbot-ch");
47996 c.scrollTop = cbot-ch;
47999 if(hscroll !== false){
48001 c.scrollLeft = cleft;
48002 }else if(cright > sright){
48003 c.scrollLeft = cright-c.clientWidth;
48010 updateColumns : function(){
48011 this.grid.stopEditing();
48012 var cm = this.grid.colModel, colIds = this.getColumnIds();
48013 //var totalWidth = cm.getTotalWidth();
48015 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48016 //if(cm.isHidden(i)) continue;
48017 var w = cm.getColumnWidth(i);
48018 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48019 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48021 this.updateSplitters();
48024 generateRules : function(cm){
48025 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
48026 Roo.util.CSS.removeStyleSheet(rulesId);
48027 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48028 var cid = cm.getColumnId(i);
48030 if(cm.config[i].align){
48031 align = 'text-align:'+cm.config[i].align+';';
48034 if(cm.isHidden(i)){
48035 hidden = 'display:none;';
48037 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
48039 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
48040 this.hdSelector, cid, " {\n", align, width, "}\n",
48041 this.tdSelector, cid, " {\n",hidden,"\n}\n",
48042 this.splitSelector, cid, " {\n", hidden , "\n}\n");
48044 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
48047 updateSplitters : function(){
48048 var cm = this.cm, s = this.getSplitters();
48049 if(s){ // splitters not created yet
48050 var pos = 0, locked = true;
48051 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48052 if(cm.isHidden(i)) continue;
48053 var w = cm.getColumnWidth(i); // make sure it's a number
48054 if(!cm.isLocked(i) && locked){
48059 s[i].style.left = (pos-this.splitOffset) + "px";
48064 handleHiddenChange : function(colModel, colIndex, hidden){
48066 this.hideColumn(colIndex);
48068 this.unhideColumn(colIndex);
48072 hideColumn : function(colIndex){
48073 var cid = this.getColumnId(colIndex);
48074 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
48075 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
48077 this.updateHeaders();
48079 this.updateSplitters();
48083 unhideColumn : function(colIndex){
48084 var cid = this.getColumnId(colIndex);
48085 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
48086 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
48089 this.updateHeaders();
48091 this.updateSplitters();
48095 insertRows : function(dm, firstRow, lastRow, isUpdate){
48096 if(firstRow == 0 && lastRow == dm.getCount()-1){
48100 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
48102 var s = this.getScrollState();
48103 var markup = this.renderRows(firstRow, lastRow);
48104 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
48105 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
48106 this.restoreScroll(s);
48108 this.fireEvent("rowsinserted", this, firstRow, lastRow);
48109 this.syncRowHeights(firstRow, lastRow);
48110 this.stripeRows(firstRow);
48116 bufferRows : function(markup, target, index){
48117 var before = null, trows = target.rows, tbody = target.tBodies[0];
48118 if(index < trows.length){
48119 before = trows[index];
48121 var b = document.createElement("div");
48122 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
48123 var rows = b.firstChild.rows;
48124 for(var i = 0, len = rows.length; i < len; i++){
48126 tbody.insertBefore(rows[0], before);
48128 tbody.appendChild(rows[0]);
48135 deleteRows : function(dm, firstRow, lastRow){
48136 if(dm.getRowCount()<1){
48137 this.fireEvent("beforerefresh", this);
48138 this.mainBody.update("");
48139 this.lockedBody.update("");
48140 this.fireEvent("refresh", this);
48142 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
48143 var bt = this.getBodyTable();
48144 var tbody = bt.firstChild;
48145 var rows = bt.rows;
48146 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
48147 tbody.removeChild(rows[firstRow]);
48149 this.stripeRows(firstRow);
48150 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
48154 updateRows : function(dataSource, firstRow, lastRow){
48155 var s = this.getScrollState();
48157 this.restoreScroll(s);
48160 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
48164 this.updateHeaderSortState();
48167 getScrollState : function(){
48169 var sb = this.scroller.dom;
48170 return {left: sb.scrollLeft, top: sb.scrollTop};
48173 stripeRows : function(startRow){
48174 if(!this.grid.stripeRows || this.ds.getCount() < 1){
48177 startRow = startRow || 0;
48178 var rows = this.getBodyTable().rows;
48179 var lrows = this.getLockedTable().rows;
48180 var cls = ' x-grid-row-alt ';
48181 for(var i = startRow, len = rows.length; i < len; i++){
48182 var row = rows[i], lrow = lrows[i];
48183 var isAlt = ((i+1) % 2 == 0);
48184 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
48185 if(isAlt == hasAlt){
48189 row.className += " x-grid-row-alt";
48191 row.className = row.className.replace("x-grid-row-alt", "");
48194 lrow.className = row.className;
48199 restoreScroll : function(state){
48200 //Roo.log('GridView.restoreScroll');
48201 var sb = this.scroller.dom;
48202 sb.scrollLeft = state.left;
48203 sb.scrollTop = state.top;
48207 syncScroll : function(){
48208 //Roo.log('GridView.syncScroll');
48209 var sb = this.scroller.dom;
48210 var sh = this.mainHd.dom;
48211 var bs = this.mainBody.dom;
48212 var lv = this.lockedBody.dom;
48213 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
48214 lv.scrollTop = bs.scrollTop = sb.scrollTop;
48217 handleScroll : function(e){
48219 var sb = this.scroller.dom;
48220 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
48224 handleWheel : function(e){
48225 var d = e.getWheelDelta();
48226 this.scroller.dom.scrollTop -= d*22;
48227 // set this here to prevent jumpy scrolling on large tables
48228 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
48232 renderRows : function(startRow, endRow){
48233 // pull in all the crap needed to render rows
48234 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
48235 var colCount = cm.getColumnCount();
48237 if(ds.getCount() < 1){
48241 // build a map for all the columns
48243 for(var i = 0; i < colCount; i++){
48244 var name = cm.getDataIndex(i);
48246 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
48247 renderer : cm.getRenderer(i),
48248 id : cm.getColumnId(i),
48249 locked : cm.isLocked(i)
48253 startRow = startRow || 0;
48254 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
48256 // records to render
48257 var rs = ds.getRange(startRow, endRow);
48259 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
48262 // As much as I hate to duplicate code, this was branched because FireFox really hates
48263 // [].join("") on strings. The performance difference was substantial enough to
48264 // branch this function
48265 doRender : Roo.isGecko ?
48266 function(cs, rs, ds, startRow, colCount, stripe){
48267 var ts = this.templates, ct = ts.cell, rt = ts.row;
48269 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
48271 var hasListener = this.grid.hasListener('rowclass');
48273 for(var j = 0, len = rs.length; j < len; j++){
48274 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
48275 for(var i = 0; i < colCount; i++){
48277 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
48279 p.css = p.attr = "";
48280 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
48281 if(p.value == undefined || p.value === "") p.value = " ";
48282 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
48283 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
48285 var markup = ct.apply(p);
48293 if(stripe && ((rowIndex+1) % 2 == 0)){
48294 alt.push("x-grid-row-alt")
48297 alt.push( " x-grid-dirty-row");
48300 if(this.getRowClass){
48301 alt.push(this.getRowClass(r, rowIndex));
48307 rowIndex : rowIndex,
48310 this.grid.fireEvent('rowclass', this, rowcfg);
48311 alt.push(rowcfg.rowClass);
48313 rp.alt = alt.join(" ");
48314 lbuf+= rt.apply(rp);
48316 buf+= rt.apply(rp);
48318 return [lbuf, buf];
48320 function(cs, rs, ds, startRow, colCount, stripe){
48321 var ts = this.templates, ct = ts.cell, rt = ts.row;
48323 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
48324 var hasListener = this.grid.hasListener('rowclass');
48326 for(var j = 0, len = rs.length; j < len; j++){
48327 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
48328 for(var i = 0; i < colCount; i++){
48330 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
48332 p.css = p.attr = "";
48333 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
48334 if(p.value == undefined || p.value === "") p.value = " ";
48335 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
48336 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
48338 var markup = ct.apply(p);
48340 cb[cb.length] = markup;
48342 lcb[lcb.length] = markup;
48346 if(stripe && ((rowIndex+1) % 2 == 0)){
48347 alt.push( "x-grid-row-alt");
48350 alt.push(" x-grid-dirty-row");
48353 if(this.getRowClass){
48354 alt.push( this.getRowClass(r, rowIndex));
48360 rowIndex : rowIndex,
48363 this.grid.fireEvent('rowclass', this, rowcfg);
48364 alt.push(rowcfg.rowClass);
48366 rp.alt = alt.join(" ");
48367 rp.cells = lcb.join("");
48368 lbuf[lbuf.length] = rt.apply(rp);
48369 rp.cells = cb.join("");
48370 buf[buf.length] = rt.apply(rp);
48372 return [lbuf.join(""), buf.join("")];
48375 renderBody : function(){
48376 var markup = this.renderRows();
48377 var bt = this.templates.body;
48378 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
48382 * Refreshes the grid
48383 * @param {Boolean} headersToo
48385 refresh : function(headersToo){
48386 this.fireEvent("beforerefresh", this);
48387 this.grid.stopEditing();
48388 var result = this.renderBody();
48389 this.lockedBody.update(result[0]);
48390 this.mainBody.update(result[1]);
48391 if(headersToo === true){
48392 this.updateHeaders();
48393 this.updateColumns();
48394 this.updateSplitters();
48395 this.updateHeaderSortState();
48397 this.syncRowHeights();
48399 this.fireEvent("refresh", this);
48402 handleColumnMove : function(cm, oldIndex, newIndex){
48403 this.indexMap = null;
48404 var s = this.getScrollState();
48405 this.refresh(true);
48406 this.restoreScroll(s);
48407 this.afterMove(newIndex);
48410 afterMove : function(colIndex){
48411 if(this.enableMoveAnim && Roo.enableFx){
48412 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
48416 updateCell : function(dm, rowIndex, dataIndex){
48417 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
48418 if(typeof colIndex == "undefined"){ // not present in grid
48421 var cm = this.grid.colModel;
48422 var cell = this.getCell(rowIndex, colIndex);
48423 var cellText = this.getCellText(rowIndex, colIndex);
48426 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
48427 id : cm.getColumnId(colIndex),
48428 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
48430 var renderer = cm.getRenderer(colIndex);
48431 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
48432 if(typeof val == "undefined" || val === "") val = " ";
48433 cellText.innerHTML = val;
48434 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
48435 this.syncRowHeights(rowIndex, rowIndex);
48438 calcColumnWidth : function(colIndex, maxRowsToMeasure){
48440 if(this.grid.autoSizeHeaders){
48441 var h = this.getHeaderCellMeasure(colIndex);
48442 maxWidth = Math.max(maxWidth, h.scrollWidth);
48445 if(this.cm.isLocked(colIndex)){
48446 tb = this.getLockedTable();
48449 tb = this.getBodyTable();
48450 index = colIndex - this.cm.getLockedCount();
48453 var rows = tb.rows;
48454 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
48455 for(var i = 0; i < stopIndex; i++){
48456 var cell = rows[i].childNodes[index].firstChild;
48457 maxWidth = Math.max(maxWidth, cell.scrollWidth);
48460 return maxWidth + /*margin for error in IE*/ 5;
48463 * Autofit a column to its content.
48464 * @param {Number} colIndex
48465 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
48467 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
48468 if(this.cm.isHidden(colIndex)){
48469 return; // can't calc a hidden column
48472 var cid = this.cm.getColumnId(colIndex);
48473 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
48474 if(this.grid.autoSizeHeaders){
48475 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
48478 var newWidth = this.calcColumnWidth(colIndex);
48479 this.cm.setColumnWidth(colIndex,
48480 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
48481 if(!suppressEvent){
48482 this.grid.fireEvent("columnresize", colIndex, newWidth);
48487 * Autofits all columns to their content and then expands to fit any extra space in the grid
48489 autoSizeColumns : function(){
48490 var cm = this.grid.colModel;
48491 var colCount = cm.getColumnCount();
48492 for(var i = 0; i < colCount; i++){
48493 this.autoSizeColumn(i, true, true);
48495 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
48498 this.updateColumns();
48504 * Autofits all columns to the grid's width proportionate with their current size
48505 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
48507 fitColumns : function(reserveScrollSpace){
48508 var cm = this.grid.colModel;
48509 var colCount = cm.getColumnCount();
48513 for (i = 0; i < colCount; i++){
48514 if(!cm.isHidden(i) && !cm.isFixed(i)){
48515 w = cm.getColumnWidth(i);
48521 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
48522 if(reserveScrollSpace){
48525 var frac = (avail - cm.getTotalWidth())/width;
48526 while (cols.length){
48529 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
48531 this.updateColumns();
48535 onRowSelect : function(rowIndex){
48536 var row = this.getRowComposite(rowIndex);
48537 row.addClass("x-grid-row-selected");
48540 onRowDeselect : function(rowIndex){
48541 var row = this.getRowComposite(rowIndex);
48542 row.removeClass("x-grid-row-selected");
48545 onCellSelect : function(row, col){
48546 var cell = this.getCell(row, col);
48548 Roo.fly(cell).addClass("x-grid-cell-selected");
48552 onCellDeselect : function(row, col){
48553 var cell = this.getCell(row, col);
48555 Roo.fly(cell).removeClass("x-grid-cell-selected");
48559 updateHeaderSortState : function(){
48561 // sort state can be single { field: xxx, direction : yyy}
48562 // or { xxx=>ASC , yyy : DESC ..... }
48565 if (!this.ds.multiSort) {
48566 var state = this.ds.getSortState();
48570 mstate[state.field] = state.direction;
48571 // FIXME... - this is not used here.. but might be elsewhere..
48572 this.sortState = state;
48575 mstate = this.ds.sortToggle;
48577 //remove existing sort classes..
48579 var sc = this.sortClasses;
48580 var hds = this.el.select(this.headerSelector).removeClass(sc);
48582 for(var f in mstate) {
48584 var sortColumn = this.cm.findColumnIndex(f);
48586 if(sortColumn != -1){
48587 var sortDir = mstate[f];
48588 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
48593 handleHeaderClick : function(g, index){
48594 if(this.headersDisabled){
48597 var dm = g.dataSource, cm = g.colModel;
48598 if(!cm.isSortable(index)){
48602 dm.sort(cm.getDataIndex(index));
48606 destroy : function(){
48608 this.colMenu.removeAll();
48609 Roo.menu.MenuMgr.unregister(this.colMenu);
48610 this.colMenu.getEl().remove();
48611 delete this.colMenu;
48614 this.hmenu.removeAll();
48615 Roo.menu.MenuMgr.unregister(this.hmenu);
48616 this.hmenu.getEl().remove();
48619 if(this.grid.enableColumnMove){
48620 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48622 for(var dd in dds){
48623 if(!dds[dd].config.isTarget && dds[dd].dragElId){
48624 var elid = dds[dd].dragElId;
48626 Roo.get(elid).remove();
48627 } else if(dds[dd].config.isTarget){
48628 dds[dd].proxyTop.remove();
48629 dds[dd].proxyBottom.remove();
48632 if(Roo.dd.DDM.locationCache[dd]){
48633 delete Roo.dd.DDM.locationCache[dd];
48636 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48639 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
48640 this.bind(null, null);
48641 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
48644 handleLockChange : function(){
48645 this.refresh(true);
48648 onDenyColumnLock : function(){
48652 onDenyColumnHide : function(){
48656 handleHdMenuClick : function(item){
48657 var index = this.hdCtxIndex;
48658 var cm = this.cm, ds = this.ds;
48661 ds.sort(cm.getDataIndex(index), "ASC");
48664 ds.sort(cm.getDataIndex(index), "DESC");
48667 var lc = cm.getLockedCount();
48668 if(cm.getColumnCount(true) <= lc+1){
48669 this.onDenyColumnLock();
48673 cm.setLocked(index, true, true);
48674 cm.moveColumn(index, lc);
48675 this.grid.fireEvent("columnmove", index, lc);
48677 cm.setLocked(index, true);
48681 var lc = cm.getLockedCount();
48682 if((lc-1) != index){
48683 cm.setLocked(index, false, true);
48684 cm.moveColumn(index, lc-1);
48685 this.grid.fireEvent("columnmove", index, lc-1);
48687 cm.setLocked(index, false);
48691 index = cm.getIndexById(item.id.substr(4));
48693 if(item.checked && cm.getColumnCount(true) <= 1){
48694 this.onDenyColumnHide();
48697 cm.setHidden(index, item.checked);
48703 beforeColMenuShow : function(){
48704 var cm = this.cm, colCount = cm.getColumnCount();
48705 this.colMenu.removeAll();
48706 for(var i = 0; i < colCount; i++){
48707 this.colMenu.add(new Roo.menu.CheckItem({
48708 id: "col-"+cm.getColumnId(i),
48709 text: cm.getColumnHeader(i),
48710 checked: !cm.isHidden(i),
48716 handleHdCtx : function(g, index, e){
48718 var hd = this.getHeaderCell(index);
48719 this.hdCtxIndex = index;
48720 var ms = this.hmenu.items, cm = this.cm;
48721 ms.get("asc").setDisabled(!cm.isSortable(index));
48722 ms.get("desc").setDisabled(!cm.isSortable(index));
48723 if(this.grid.enableColLock !== false){
48724 ms.get("lock").setDisabled(cm.isLocked(index));
48725 ms.get("unlock").setDisabled(!cm.isLocked(index));
48727 this.hmenu.show(hd, "tl-bl");
48730 handleHdOver : function(e){
48731 var hd = this.findHeaderCell(e.getTarget());
48732 if(hd && !this.headersDisabled){
48733 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
48734 this.fly(hd).addClass("x-grid-hd-over");
48739 handleHdOut : function(e){
48740 var hd = this.findHeaderCell(e.getTarget());
48742 this.fly(hd).removeClass("x-grid-hd-over");
48746 handleSplitDblClick : function(e, t){
48747 var i = this.getCellIndex(t);
48748 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
48749 this.autoSizeColumn(i, true);
48754 render : function(){
48757 var colCount = cm.getColumnCount();
48759 if(this.grid.monitorWindowResize === true){
48760 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48762 var header = this.renderHeaders();
48763 var body = this.templates.body.apply({rows:""});
48764 var html = this.templates.master.apply({
48767 lockedHeader: header[0],
48771 //this.updateColumns();
48773 this.grid.getGridEl().dom.innerHTML = html;
48775 this.initElements();
48777 // a kludge to fix the random scolling effect in webkit
48778 this.el.on("scroll", function() {
48779 this.el.dom.scrollTop=0; // hopefully not recursive..
48782 this.scroller.on("scroll", this.handleScroll, this);
48783 this.lockedBody.on("mousewheel", this.handleWheel, this);
48784 this.mainBody.on("mousewheel", this.handleWheel, this);
48786 this.mainHd.on("mouseover", this.handleHdOver, this);
48787 this.mainHd.on("mouseout", this.handleHdOut, this);
48788 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
48789 {delegate: "."+this.splitClass});
48791 this.lockedHd.on("mouseover", this.handleHdOver, this);
48792 this.lockedHd.on("mouseout", this.handleHdOut, this);
48793 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
48794 {delegate: "."+this.splitClass});
48796 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
48797 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48800 this.updateSplitters();
48802 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
48803 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48804 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48807 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
48808 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
48810 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
48811 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
48813 if(this.grid.enableColLock !== false){
48814 this.hmenu.add('-',
48815 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
48816 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
48819 if(this.grid.enableColumnHide !== false){
48821 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
48822 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
48823 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
48825 this.hmenu.add('-',
48826 {id:"columns", text: this.columnsText, menu: this.colMenu}
48829 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
48831 this.grid.on("headercontextmenu", this.handleHdCtx, this);
48834 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
48835 this.dd = new Roo.grid.GridDragZone(this.grid, {
48836 ddGroup : this.grid.ddGroup || 'GridDD'
48841 for(var i = 0; i < colCount; i++){
48842 if(cm.isHidden(i)){
48843 this.hideColumn(i);
48845 if(cm.config[i].align){
48846 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
48847 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
48851 this.updateHeaderSortState();
48853 this.beforeInitialResize();
48856 // two part rendering gives faster view to the user
48857 this.renderPhase2.defer(1, this);
48860 renderPhase2 : function(){
48861 // render the rows now
48863 if(this.grid.autoSizeColumns){
48864 this.autoSizeColumns();
48868 beforeInitialResize : function(){
48872 onColumnSplitterMoved : function(i, w){
48873 this.userResized = true;
48874 var cm = this.grid.colModel;
48875 cm.setColumnWidth(i, w, true);
48876 var cid = cm.getColumnId(i);
48877 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48878 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48879 this.updateSplitters();
48881 this.grid.fireEvent("columnresize", i, w);
48884 syncRowHeights : function(startIndex, endIndex){
48885 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
48886 startIndex = startIndex || 0;
48887 var mrows = this.getBodyTable().rows;
48888 var lrows = this.getLockedTable().rows;
48889 var len = mrows.length-1;
48890 endIndex = Math.min(endIndex || len, len);
48891 for(var i = startIndex; i <= endIndex; i++){
48892 var m = mrows[i], l = lrows[i];
48893 var h = Math.max(m.offsetHeight, l.offsetHeight);
48894 m.style.height = l.style.height = h + "px";
48899 layout : function(initialRender, is2ndPass){
48901 var auto = g.autoHeight;
48902 var scrollOffset = 16;
48903 var c = g.getGridEl(), cm = this.cm,
48904 expandCol = g.autoExpandColumn,
48906 //c.beginMeasure();
48908 if(!c.dom.offsetWidth){ // display:none?
48910 this.lockedWrap.show();
48911 this.mainWrap.show();
48916 var hasLock = this.cm.isLocked(0);
48918 var tbh = this.headerPanel.getHeight();
48919 var bbh = this.footerPanel.getHeight();
48922 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
48923 var newHeight = ch + c.getBorderWidth("tb");
48925 newHeight = Math.min(g.maxHeight, newHeight);
48927 c.setHeight(newHeight);
48931 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
48934 var s = this.scroller;
48936 var csize = c.getSize(true);
48938 this.el.setSize(csize.width, csize.height);
48940 this.headerPanel.setWidth(csize.width);
48941 this.footerPanel.setWidth(csize.width);
48943 var hdHeight = this.mainHd.getHeight();
48944 var vw = csize.width;
48945 var vh = csize.height - (tbh + bbh);
48949 var bt = this.getBodyTable();
48950 var ltWidth = hasLock ?
48951 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
48953 var scrollHeight = bt.offsetHeight;
48954 var scrollWidth = ltWidth + bt.offsetWidth;
48955 var vscroll = false, hscroll = false;
48957 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
48959 var lw = this.lockedWrap, mw = this.mainWrap;
48960 var lb = this.lockedBody, mb = this.mainBody;
48962 setTimeout(function(){
48963 var t = s.dom.offsetTop;
48964 var w = s.dom.clientWidth,
48965 h = s.dom.clientHeight;
48968 lw.setSize(ltWidth, h);
48970 mw.setLeftTop(ltWidth, t);
48971 mw.setSize(w-ltWidth, h);
48973 lb.setHeight(h-hdHeight);
48974 mb.setHeight(h-hdHeight);
48976 if(is2ndPass !== true && !gv.userResized && expandCol){
48977 // high speed resize without full column calculation
48979 var ci = cm.getIndexById(expandCol);
48981 ci = cm.findColumnIndex(expandCol);
48983 ci = Math.max(0, ci); // make sure it's got at least the first col.
48984 var expandId = cm.getColumnId(ci);
48985 var tw = cm.getTotalWidth(false);
48986 var currentWidth = cm.getColumnWidth(ci);
48987 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
48988 if(currentWidth != cw){
48989 cm.setColumnWidth(ci, cw, true);
48990 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48991 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48992 gv.updateSplitters();
48993 gv.layout(false, true);
49005 onWindowResize : function(){
49006 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
49012 appendFooter : function(parentEl){
49016 sortAscText : "Sort Ascending",
49017 sortDescText : "Sort Descending",
49018 lockText : "Lock Column",
49019 unlockText : "Unlock Column",
49020 columnsText : "Columns"
49024 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
49025 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
49026 this.proxy.el.addClass('x-grid3-col-dd');
49029 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
49030 handleMouseDown : function(e){
49034 callHandleMouseDown : function(e){
49035 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
49040 * Ext JS Library 1.1.1
49041 * Copyright(c) 2006-2007, Ext JS, LLC.
49043 * Originally Released Under LGPL - original licence link has changed is not relivant.
49046 * <script type="text/javascript">
49050 // This is a support class used internally by the Grid components
49051 Roo.grid.SplitDragZone = function(grid, hd, hd2){
49053 this.view = grid.getView();
49054 this.proxy = this.view.resizeProxy;
49055 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
49056 "gridSplitters" + this.grid.getGridEl().id, {
49057 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
49059 this.setHandleElId(Roo.id(hd));
49060 this.setOuterHandleElId(Roo.id(hd2));
49061 this.scroll = false;
49063 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
49064 fly: Roo.Element.fly,
49066 b4StartDrag : function(x, y){
49067 this.view.headersDisabled = true;
49068 this.proxy.setHeight(this.view.mainWrap.getHeight());
49069 var w = this.cm.getColumnWidth(this.cellIndex);
49070 var minw = Math.max(w-this.grid.minColumnWidth, 0);
49071 this.resetConstraints();
49072 this.setXConstraint(minw, 1000);
49073 this.setYConstraint(0, 0);
49074 this.minX = x - minw;
49075 this.maxX = x + 1000;
49077 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
49081 handleMouseDown : function(e){
49082 ev = Roo.EventObject.setEvent(e);
49083 var t = this.fly(ev.getTarget());
49084 if(t.hasClass("x-grid-split")){
49085 this.cellIndex = this.view.getCellIndex(t.dom);
49086 this.split = t.dom;
49087 this.cm = this.grid.colModel;
49088 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
49089 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
49094 endDrag : function(e){
49095 this.view.headersDisabled = false;
49096 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
49097 var diff = endX - this.startPos;
49098 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
49101 autoOffset : function(){
49102 this.setDelta(0,0);
49106 * Ext JS Library 1.1.1
49107 * Copyright(c) 2006-2007, Ext JS, LLC.
49109 * Originally Released Under LGPL - original licence link has changed is not relivant.
49112 * <script type="text/javascript">
49116 // This is a support class used internally by the Grid components
49117 Roo.grid.GridDragZone = function(grid, config){
49118 this.view = grid.getView();
49119 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
49120 if(this.view.lockedBody){
49121 this.setHandleElId(Roo.id(this.view.mainBody.dom));
49122 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
49124 this.scroll = false;
49126 this.ddel = document.createElement('div');
49127 this.ddel.className = 'x-grid-dd-wrap';
49130 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
49131 ddGroup : "GridDD",
49133 getDragData : function(e){
49134 var t = Roo.lib.Event.getTarget(e);
49135 var rowIndex = this.view.findRowIndex(t);
49136 if(rowIndex !== false){
49137 var sm = this.grid.selModel;
49138 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
49139 // sm.mouseDown(e, t);
49141 if (e.hasModifier()){
49142 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
49144 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
49149 onInitDrag : function(e){
49150 var data = this.dragData;
49151 this.ddel.innerHTML = this.grid.getDragDropText();
49152 this.proxy.update(this.ddel);
49153 // fire start drag?
49156 afterRepair : function(){
49157 this.dragging = false;
49160 getRepairXY : function(e, data){
49164 onEndDrag : function(data, e){
49168 onValidDrop : function(dd, e, id){
49173 beforeInvalidDrop : function(e, id){
49178 * Ext JS Library 1.1.1
49179 * Copyright(c) 2006-2007, Ext JS, LLC.
49181 * Originally Released Under LGPL - original licence link has changed is not relivant.
49184 * <script type="text/javascript">
49189 * @class Roo.grid.ColumnModel
49190 * @extends Roo.util.Observable
49191 * This is the default implementation of a ColumnModel used by the Grid. It defines
49192 * the columns in the grid.
49195 var colModel = new Roo.grid.ColumnModel([
49196 {header: "Ticker", width: 60, sortable: true, locked: true},
49197 {header: "Company Name", width: 150, sortable: true},
49198 {header: "Market Cap.", width: 100, sortable: true},
49199 {header: "$ Sales", width: 100, sortable: true, renderer: money},
49200 {header: "Employees", width: 100, sortable: true, resizable: false}
49205 * The config options listed for this class are options which may appear in each
49206 * individual column definition.
49207 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
49209 * @param {Object} config An Array of column config objects. See this class's
49210 * config objects for details.
49212 Roo.grid.ColumnModel = function(config){
49214 * The config passed into the constructor
49216 this.config = config;
49219 // if no id, create one
49220 // if the column does not have a dataIndex mapping,
49221 // map it to the order it is in the config
49222 for(var i = 0, len = config.length; i < len; i++){
49224 if(typeof c.dataIndex == "undefined"){
49227 if(typeof c.renderer == "string"){
49228 c.renderer = Roo.util.Format[c.renderer];
49230 if(typeof c.id == "undefined"){
49233 if(c.editor && c.editor.xtype){
49234 c.editor = Roo.factory(c.editor, Roo.grid);
49236 if(c.editor && c.editor.isFormField){
49237 c.editor = new Roo.grid.GridEditor(c.editor);
49239 this.lookup[c.id] = c;
49243 * The width of columns which have no width specified (defaults to 100)
49246 this.defaultWidth = 100;
49249 * Default sortable of columns which have no sortable specified (defaults to false)
49252 this.defaultSortable = false;
49256 * @event widthchange
49257 * Fires when the width of a column changes.
49258 * @param {ColumnModel} this
49259 * @param {Number} columnIndex The column index
49260 * @param {Number} newWidth The new width
49262 "widthchange": true,
49264 * @event headerchange
49265 * Fires when the text of a header changes.
49266 * @param {ColumnModel} this
49267 * @param {Number} columnIndex The column index
49268 * @param {Number} newText The new header text
49270 "headerchange": true,
49272 * @event hiddenchange
49273 * Fires when a column is hidden or "unhidden".
49274 * @param {ColumnModel} this
49275 * @param {Number} columnIndex The column index
49276 * @param {Boolean} hidden true if hidden, false otherwise
49278 "hiddenchange": true,
49280 * @event columnmoved
49281 * Fires when a column is moved.
49282 * @param {ColumnModel} this
49283 * @param {Number} oldIndex
49284 * @param {Number} newIndex
49286 "columnmoved" : true,
49288 * @event columlockchange
49289 * Fires when a column's locked state is changed
49290 * @param {ColumnModel} this
49291 * @param {Number} colIndex
49292 * @param {Boolean} locked true if locked
49294 "columnlockchange" : true
49296 Roo.grid.ColumnModel.superclass.constructor.call(this);
49298 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
49300 * @cfg {String} header The header text to display in the Grid view.
49303 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
49304 * {@link Roo.data.Record} definition from which to draw the column's value. If not
49305 * specified, the column's index is used as an index into the Record's data Array.
49308 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
49309 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
49312 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
49313 * Defaults to the value of the {@link #defaultSortable} property.
49314 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
49317 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
49320 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
49323 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
49326 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
49329 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
49330 * given the cell's data value. See {@link #setRenderer}. If not specified, the
49331 * default renderer uses the raw data value.
49334 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
49337 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
49341 * Returns the id of the column at the specified index.
49342 * @param {Number} index The column index
49343 * @return {String} the id
49345 getColumnId : function(index){
49346 return this.config[index].id;
49350 * Returns the column for a specified id.
49351 * @param {String} id The column id
49352 * @return {Object} the column
49354 getColumnById : function(id){
49355 return this.lookup[id];
49360 * Returns the column for a specified dataIndex.
49361 * @param {String} dataIndex The column dataIndex
49362 * @return {Object|Boolean} the column or false if not found
49364 getColumnByDataIndex: function(dataIndex){
49365 var index = this.findColumnIndex(dataIndex);
49366 return index > -1 ? this.config[index] : false;
49370 * Returns the index for a specified column id.
49371 * @param {String} id The column id
49372 * @return {Number} the index, or -1 if not found
49374 getIndexById : function(id){
49375 for(var i = 0, len = this.config.length; i < len; i++){
49376 if(this.config[i].id == id){
49384 * Returns the index for a specified column dataIndex.
49385 * @param {String} dataIndex The column dataIndex
49386 * @return {Number} the index, or -1 if not found
49389 findColumnIndex : function(dataIndex){
49390 for(var i = 0, len = this.config.length; i < len; i++){
49391 if(this.config[i].dataIndex == dataIndex){
49399 moveColumn : function(oldIndex, newIndex){
49400 var c = this.config[oldIndex];
49401 this.config.splice(oldIndex, 1);
49402 this.config.splice(newIndex, 0, c);
49403 this.dataMap = null;
49404 this.fireEvent("columnmoved", this, oldIndex, newIndex);
49407 isLocked : function(colIndex){
49408 return this.config[colIndex].locked === true;
49411 setLocked : function(colIndex, value, suppressEvent){
49412 if(this.isLocked(colIndex) == value){
49415 this.config[colIndex].locked = value;
49416 if(!suppressEvent){
49417 this.fireEvent("columnlockchange", this, colIndex, value);
49421 getTotalLockedWidth : function(){
49422 var totalWidth = 0;
49423 for(var i = 0; i < this.config.length; i++){
49424 if(this.isLocked(i) && !this.isHidden(i)){
49425 this.totalWidth += this.getColumnWidth(i);
49431 getLockedCount : function(){
49432 for(var i = 0, len = this.config.length; i < len; i++){
49433 if(!this.isLocked(i)){
49440 * Returns the number of columns.
49443 getColumnCount : function(visibleOnly){
49444 if(visibleOnly === true){
49446 for(var i = 0, len = this.config.length; i < len; i++){
49447 if(!this.isHidden(i)){
49453 return this.config.length;
49457 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
49458 * @param {Function} fn
49459 * @param {Object} scope (optional)
49460 * @return {Array} result
49462 getColumnsBy : function(fn, scope){
49464 for(var i = 0, len = this.config.length; i < len; i++){
49465 var c = this.config[i];
49466 if(fn.call(scope||this, c, i) === true){
49474 * Returns true if the specified column is sortable.
49475 * @param {Number} col The column index
49476 * @return {Boolean}
49478 isSortable : function(col){
49479 if(typeof this.config[col].sortable == "undefined"){
49480 return this.defaultSortable;
49482 return this.config[col].sortable;
49486 * Returns the rendering (formatting) function defined for the column.
49487 * @param {Number} col The column index.
49488 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
49490 getRenderer : function(col){
49491 if(!this.config[col].renderer){
49492 return Roo.grid.ColumnModel.defaultRenderer;
49494 return this.config[col].renderer;
49498 * Sets the rendering (formatting) function for a column.
49499 * @param {Number} col The column index
49500 * @param {Function} fn The function to use to process the cell's raw data
49501 * to return HTML markup for the grid view. The render function is called with
49502 * the following parameters:<ul>
49503 * <li>Data value.</li>
49504 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
49505 * <li>css A CSS style string to apply to the table cell.</li>
49506 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
49507 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
49508 * <li>Row index</li>
49509 * <li>Column index</li>
49510 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
49512 setRenderer : function(col, fn){
49513 this.config[col].renderer = fn;
49517 * Returns the width for the specified column.
49518 * @param {Number} col The column index
49521 getColumnWidth : function(col){
49522 return this.config[col].width * 1 || this.defaultWidth;
49526 * Sets the width for a column.
49527 * @param {Number} col The column index
49528 * @param {Number} width The new width
49530 setColumnWidth : function(col, width, suppressEvent){
49531 this.config[col].width = width;
49532 this.totalWidth = null;
49533 if(!suppressEvent){
49534 this.fireEvent("widthchange", this, col, width);
49539 * Returns the total width of all columns.
49540 * @param {Boolean} includeHidden True to include hidden column widths
49543 getTotalWidth : function(includeHidden){
49544 if(!this.totalWidth){
49545 this.totalWidth = 0;
49546 for(var i = 0, len = this.config.length; i < len; i++){
49547 if(includeHidden || !this.isHidden(i)){
49548 this.totalWidth += this.getColumnWidth(i);
49552 return this.totalWidth;
49556 * Returns the header for the specified column.
49557 * @param {Number} col The column index
49560 getColumnHeader : function(col){
49561 return this.config[col].header;
49565 * Sets the header for a column.
49566 * @param {Number} col The column index
49567 * @param {String} header The new header
49569 setColumnHeader : function(col, header){
49570 this.config[col].header = header;
49571 this.fireEvent("headerchange", this, col, header);
49575 * Returns the tooltip for the specified column.
49576 * @param {Number} col The column index
49579 getColumnTooltip : function(col){
49580 return this.config[col].tooltip;
49583 * Sets the tooltip for a column.
49584 * @param {Number} col The column index
49585 * @param {String} tooltip The new tooltip
49587 setColumnTooltip : function(col, tooltip){
49588 this.config[col].tooltip = tooltip;
49592 * Returns the dataIndex for the specified column.
49593 * @param {Number} col The column index
49596 getDataIndex : function(col){
49597 return this.config[col].dataIndex;
49601 * Sets the dataIndex for a column.
49602 * @param {Number} col The column index
49603 * @param {Number} dataIndex The new dataIndex
49605 setDataIndex : function(col, dataIndex){
49606 this.config[col].dataIndex = dataIndex;
49612 * Returns true if the cell is editable.
49613 * @param {Number} colIndex The column index
49614 * @param {Number} rowIndex The row index
49615 * @return {Boolean}
49617 isCellEditable : function(colIndex, rowIndex){
49618 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
49622 * Returns the editor defined for the cell/column.
49623 * return false or null to disable editing.
49624 * @param {Number} colIndex The column index
49625 * @param {Number} rowIndex The row index
49628 getCellEditor : function(colIndex, rowIndex){
49629 return this.config[colIndex].editor;
49633 * Sets if a column is editable.
49634 * @param {Number} col The column index
49635 * @param {Boolean} editable True if the column is editable
49637 setEditable : function(col, editable){
49638 this.config[col].editable = editable;
49643 * Returns true if the column is hidden.
49644 * @param {Number} colIndex The column index
49645 * @return {Boolean}
49647 isHidden : function(colIndex){
49648 return this.config[colIndex].hidden;
49653 * Returns true if the column width cannot be changed
49655 isFixed : function(colIndex){
49656 return this.config[colIndex].fixed;
49660 * Returns true if the column can be resized
49661 * @return {Boolean}
49663 isResizable : function(colIndex){
49664 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
49667 * Sets if a column is hidden.
49668 * @param {Number} colIndex The column index
49669 * @param {Boolean} hidden True if the column is hidden
49671 setHidden : function(colIndex, hidden){
49672 this.config[colIndex].hidden = hidden;
49673 this.totalWidth = null;
49674 this.fireEvent("hiddenchange", this, colIndex, hidden);
49678 * Sets the editor for a column.
49679 * @param {Number} col The column index
49680 * @param {Object} editor The editor object
49682 setEditor : function(col, editor){
49683 this.config[col].editor = editor;
49687 Roo.grid.ColumnModel.defaultRenderer = function(value){
49688 if(typeof value == "string" && value.length < 1){
49694 // Alias for backwards compatibility
49695 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
49698 * Ext JS Library 1.1.1
49699 * Copyright(c) 2006-2007, Ext JS, LLC.
49701 * Originally Released Under LGPL - original licence link has changed is not relivant.
49704 * <script type="text/javascript">
49708 * @class Roo.grid.AbstractSelectionModel
49709 * @extends Roo.util.Observable
49710 * Abstract base class for grid SelectionModels. It provides the interface that should be
49711 * implemented by descendant classes. This class should not be directly instantiated.
49714 Roo.grid.AbstractSelectionModel = function(){
49715 this.locked = false;
49716 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
49719 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
49720 /** @ignore Called by the grid automatically. Do not call directly. */
49721 init : function(grid){
49727 * Locks the selections.
49730 this.locked = true;
49734 * Unlocks the selections.
49736 unlock : function(){
49737 this.locked = false;
49741 * Returns true if the selections are locked.
49742 * @return {Boolean}
49744 isLocked : function(){
49745 return this.locked;
49749 * Ext JS Library 1.1.1
49750 * Copyright(c) 2006-2007, Ext JS, LLC.
49752 * Originally Released Under LGPL - original licence link has changed is not relivant.
49755 * <script type="text/javascript">
49758 * @extends Roo.grid.AbstractSelectionModel
49759 * @class Roo.grid.RowSelectionModel
49760 * The default SelectionModel used by {@link Roo.grid.Grid}.
49761 * It supports multiple selections and keyboard selection/navigation.
49763 * @param {Object} config
49765 Roo.grid.RowSelectionModel = function(config){
49766 Roo.apply(this, config);
49767 this.selections = new Roo.util.MixedCollection(false, function(o){
49772 this.lastActive = false;
49776 * @event selectionchange
49777 * Fires when the selection changes
49778 * @param {SelectionModel} this
49780 "selectionchange" : true,
49782 * @event afterselectionchange
49783 * Fires after the selection changes (eg. by key press or clicking)
49784 * @param {SelectionModel} this
49786 "afterselectionchange" : true,
49788 * @event beforerowselect
49789 * Fires when a row is selected being selected, return false to cancel.
49790 * @param {SelectionModel} this
49791 * @param {Number} rowIndex The selected index
49792 * @param {Boolean} keepExisting False if other selections will be cleared
49794 "beforerowselect" : true,
49797 * Fires when a row is selected.
49798 * @param {SelectionModel} this
49799 * @param {Number} rowIndex The selected index
49800 * @param {Roo.data.Record} r The record
49802 "rowselect" : true,
49804 * @event rowdeselect
49805 * Fires when a row is deselected.
49806 * @param {SelectionModel} this
49807 * @param {Number} rowIndex The selected index
49809 "rowdeselect" : true
49811 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
49812 this.locked = false;
49815 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
49817 * @cfg {Boolean} singleSelect
49818 * True to allow selection of only one row at a time (defaults to false)
49820 singleSelect : false,
49823 initEvents : function(){
49825 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
49826 this.grid.on("mousedown", this.handleMouseDown, this);
49827 }else{ // allow click to work like normal
49828 this.grid.on("rowclick", this.handleDragableRowClick, this);
49831 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
49832 "up" : function(e){
49834 this.selectPrevious(e.shiftKey);
49835 }else if(this.last !== false && this.lastActive !== false){
49836 var last = this.last;
49837 this.selectRange(this.last, this.lastActive-1);
49838 this.grid.getView().focusRow(this.lastActive);
49839 if(last !== false){
49843 this.selectFirstRow();
49845 this.fireEvent("afterselectionchange", this);
49847 "down" : function(e){
49849 this.selectNext(e.shiftKey);
49850 }else if(this.last !== false && this.lastActive !== false){
49851 var last = this.last;
49852 this.selectRange(this.last, this.lastActive+1);
49853 this.grid.getView().focusRow(this.lastActive);
49854 if(last !== false){
49858 this.selectFirstRow();
49860 this.fireEvent("afterselectionchange", this);
49865 var view = this.grid.view;
49866 view.on("refresh", this.onRefresh, this);
49867 view.on("rowupdated", this.onRowUpdated, this);
49868 view.on("rowremoved", this.onRemove, this);
49872 onRefresh : function(){
49873 var ds = this.grid.dataSource, i, v = this.grid.view;
49874 var s = this.selections;
49875 s.each(function(r){
49876 if((i = ds.indexOfId(r.id)) != -1){
49885 onRemove : function(v, index, r){
49886 this.selections.remove(r);
49890 onRowUpdated : function(v, index, r){
49891 if(this.isSelected(r)){
49892 v.onRowSelect(index);
49898 * @param {Array} records The records to select
49899 * @param {Boolean} keepExisting (optional) True to keep existing selections
49901 selectRecords : function(records, keepExisting){
49903 this.clearSelections();
49905 var ds = this.grid.dataSource;
49906 for(var i = 0, len = records.length; i < len; i++){
49907 this.selectRow(ds.indexOf(records[i]), true);
49912 * Gets the number of selected rows.
49915 getCount : function(){
49916 return this.selections.length;
49920 * Selects the first row in the grid.
49922 selectFirstRow : function(){
49927 * Select the last row.
49928 * @param {Boolean} keepExisting (optional) True to keep existing selections
49930 selectLastRow : function(keepExisting){
49931 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
49935 * Selects the row immediately following the last selected row.
49936 * @param {Boolean} keepExisting (optional) True to keep existing selections
49938 selectNext : function(keepExisting){
49939 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
49940 this.selectRow(this.last+1, keepExisting);
49941 this.grid.getView().focusRow(this.last);
49946 * Selects the row that precedes the last selected row.
49947 * @param {Boolean} keepExisting (optional) True to keep existing selections
49949 selectPrevious : function(keepExisting){
49951 this.selectRow(this.last-1, keepExisting);
49952 this.grid.getView().focusRow(this.last);
49957 * Returns the selected records
49958 * @return {Array} Array of selected records
49960 getSelections : function(){
49961 return [].concat(this.selections.items);
49965 * Returns the first selected record.
49968 getSelected : function(){
49969 return this.selections.itemAt(0);
49974 * Clears all selections.
49976 clearSelections : function(fast){
49977 if(this.locked) return;
49979 var ds = this.grid.dataSource;
49980 var s = this.selections;
49981 s.each(function(r){
49982 this.deselectRow(ds.indexOfId(r.id));
49986 this.selections.clear();
49993 * Selects all rows.
49995 selectAll : function(){
49996 if(this.locked) return;
49997 this.selections.clear();
49998 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
49999 this.selectRow(i, true);
50004 * Returns True if there is a selection.
50005 * @return {Boolean}
50007 hasSelection : function(){
50008 return this.selections.length > 0;
50012 * Returns True if the specified row is selected.
50013 * @param {Number/Record} record The record or index of the record to check
50014 * @return {Boolean}
50016 isSelected : function(index){
50017 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
50018 return (r && this.selections.key(r.id) ? true : false);
50022 * Returns True if the specified record id is selected.
50023 * @param {String} id The id of record to check
50024 * @return {Boolean}
50026 isIdSelected : function(id){
50027 return (this.selections.key(id) ? true : false);
50031 handleMouseDown : function(e, t){
50032 var view = this.grid.getView(), rowIndex;
50033 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
50036 if(e.shiftKey && this.last !== false){
50037 var last = this.last;
50038 this.selectRange(last, rowIndex, e.ctrlKey);
50039 this.last = last; // reset the last
50040 view.focusRow(rowIndex);
50042 var isSelected = this.isSelected(rowIndex);
50043 if(e.button !== 0 && isSelected){
50044 view.focusRow(rowIndex);
50045 }else if(e.ctrlKey && isSelected){
50046 this.deselectRow(rowIndex);
50047 }else if(!isSelected){
50048 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
50049 view.focusRow(rowIndex);
50052 this.fireEvent("afterselectionchange", this);
50055 handleDragableRowClick : function(grid, rowIndex, e)
50057 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
50058 this.selectRow(rowIndex, false);
50059 grid.view.focusRow(rowIndex);
50060 this.fireEvent("afterselectionchange", this);
50065 * Selects multiple rows.
50066 * @param {Array} rows Array of the indexes of the row to select
50067 * @param {Boolean} keepExisting (optional) True to keep existing selections
50069 selectRows : function(rows, keepExisting){
50071 this.clearSelections();
50073 for(var i = 0, len = rows.length; i < len; i++){
50074 this.selectRow(rows[i], true);
50079 * Selects a range of rows. All rows in between startRow and endRow are also selected.
50080 * @param {Number} startRow The index of the first row in the range
50081 * @param {Number} endRow The index of the last row in the range
50082 * @param {Boolean} keepExisting (optional) True to retain existing selections
50084 selectRange : function(startRow, endRow, keepExisting){
50085 if(this.locked) return;
50087 this.clearSelections();
50089 if(startRow <= endRow){
50090 for(var i = startRow; i <= endRow; i++){
50091 this.selectRow(i, true);
50094 for(var i = startRow; i >= endRow; i--){
50095 this.selectRow(i, true);
50101 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
50102 * @param {Number} startRow The index of the first row in the range
50103 * @param {Number} endRow The index of the last row in the range
50105 deselectRange : function(startRow, endRow, preventViewNotify){
50106 if(this.locked) return;
50107 for(var i = startRow; i <= endRow; i++){
50108 this.deselectRow(i, preventViewNotify);
50114 * @param {Number} row The index of the row to select
50115 * @param {Boolean} keepExisting (optional) True to keep existing selections
50117 selectRow : function(index, keepExisting, preventViewNotify){
50118 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
50119 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
50120 if(!keepExisting || this.singleSelect){
50121 this.clearSelections();
50123 var r = this.grid.dataSource.getAt(index);
50124 this.selections.add(r);
50125 this.last = this.lastActive = index;
50126 if(!preventViewNotify){
50127 this.grid.getView().onRowSelect(index);
50129 this.fireEvent("rowselect", this, index, r);
50130 this.fireEvent("selectionchange", this);
50136 * @param {Number} row The index of the row to deselect
50138 deselectRow : function(index, preventViewNotify){
50139 if(this.locked) return;
50140 if(this.last == index){
50143 if(this.lastActive == index){
50144 this.lastActive = false;
50146 var r = this.grid.dataSource.getAt(index);
50147 this.selections.remove(r);
50148 if(!preventViewNotify){
50149 this.grid.getView().onRowDeselect(index);
50151 this.fireEvent("rowdeselect", this, index);
50152 this.fireEvent("selectionchange", this);
50156 restoreLast : function(){
50158 this.last = this._last;
50163 acceptsNav : function(row, col, cm){
50164 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50168 onEditorKey : function(field, e){
50169 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50174 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50176 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50178 }else if(k == e.ENTER && !e.ctrlKey){
50182 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
50184 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
50186 }else if(k == e.ESC){
50190 g.startEditing(newCell[0], newCell[1]);
50195 * Ext JS Library 1.1.1
50196 * Copyright(c) 2006-2007, Ext JS, LLC.
50198 * Originally Released Under LGPL - original licence link has changed is not relivant.
50201 * <script type="text/javascript">
50204 * @class Roo.grid.CellSelectionModel
50205 * @extends Roo.grid.AbstractSelectionModel
50206 * This class provides the basic implementation for cell selection in a grid.
50208 * @param {Object} config The object containing the configuration of this model.
50210 Roo.grid.CellSelectionModel = function(config){
50211 Roo.apply(this, config);
50213 this.selection = null;
50217 * @event beforerowselect
50218 * Fires before a cell is selected.
50219 * @param {SelectionModel} this
50220 * @param {Number} rowIndex The selected row index
50221 * @param {Number} colIndex The selected cell index
50223 "beforecellselect" : true,
50225 * @event cellselect
50226 * Fires when a cell is selected.
50227 * @param {SelectionModel} this
50228 * @param {Number} rowIndex The selected row index
50229 * @param {Number} colIndex The selected cell index
50231 "cellselect" : true,
50233 * @event selectionchange
50234 * Fires when the active selection changes.
50235 * @param {SelectionModel} this
50236 * @param {Object} selection null for no selection or an object (o) with two properties
50238 <li>o.record: the record object for the row the selection is in</li>
50239 <li>o.cell: An array of [rowIndex, columnIndex]</li>
50242 "selectionchange" : true
50244 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
50247 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
50250 initEvents : function(){
50251 this.grid.on("mousedown", this.handleMouseDown, this);
50252 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
50253 var view = this.grid.view;
50254 view.on("refresh", this.onViewChange, this);
50255 view.on("rowupdated", this.onRowUpdated, this);
50256 view.on("beforerowremoved", this.clearSelections, this);
50257 view.on("beforerowsinserted", this.clearSelections, this);
50258 if(this.grid.isEditor){
50259 this.grid.on("beforeedit", this.beforeEdit, this);
50264 beforeEdit : function(e){
50265 this.select(e.row, e.column, false, true, e.record);
50269 onRowUpdated : function(v, index, r){
50270 if(this.selection && this.selection.record == r){
50271 v.onCellSelect(index, this.selection.cell[1]);
50276 onViewChange : function(){
50277 this.clearSelections(true);
50281 * Returns the currently selected cell,.
50282 * @return {Array} The selected cell (row, column) or null if none selected.
50284 getSelectedCell : function(){
50285 return this.selection ? this.selection.cell : null;
50289 * Clears all selections.
50290 * @param {Boolean} true to prevent the gridview from being notified about the change.
50292 clearSelections : function(preventNotify){
50293 var s = this.selection;
50295 if(preventNotify !== true){
50296 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
50298 this.selection = null;
50299 this.fireEvent("selectionchange", this, null);
50304 * Returns true if there is a selection.
50305 * @return {Boolean}
50307 hasSelection : function(){
50308 return this.selection ? true : false;
50312 handleMouseDown : function(e, t){
50313 var v = this.grid.getView();
50314 if(this.isLocked()){
50317 var row = v.findRowIndex(t);
50318 var cell = v.findCellIndex(t);
50319 if(row !== false && cell !== false){
50320 this.select(row, cell);
50326 * @param {Number} rowIndex
50327 * @param {Number} collIndex
50329 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
50330 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
50331 this.clearSelections();
50332 r = r || this.grid.dataSource.getAt(rowIndex);
50335 cell : [rowIndex, colIndex]
50337 if(!preventViewNotify){
50338 var v = this.grid.getView();
50339 v.onCellSelect(rowIndex, colIndex);
50340 if(preventFocus !== true){
50341 v.focusCell(rowIndex, colIndex);
50344 this.fireEvent("cellselect", this, rowIndex, colIndex);
50345 this.fireEvent("selectionchange", this, this.selection);
50350 isSelectable : function(rowIndex, colIndex, cm){
50351 return !cm.isHidden(colIndex);
50355 handleKeyDown : function(e){
50356 Roo.log('Cell Sel Model handleKeyDown');
50357 if(!e.isNavKeyPress()){
50360 var g = this.grid, s = this.selection;
50363 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
50365 this.select(cell[0], cell[1]);
50370 var walk = function(row, col, step){
50371 return g.walkCells(row, col, step, sm.isSelectable, sm);
50373 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
50378 // handled by onEditorKey
50379 if (g.isEditor && g.editing) {
50383 newCell = walk(r, c-1, -1);
50385 newCell = walk(r, c+1, 1);
50389 newCell = walk(r+1, c, 1);
50392 newCell = walk(r-1, c, -1);
50395 newCell = walk(r, c+1, 1);
50398 newCell = walk(r, c-1, -1);
50401 if(g.isEditor && !g.editing){
50402 g.startEditing(r, c);
50409 this.select(newCell[0], newCell[1]);
50414 acceptsNav : function(row, col, cm){
50415 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50418 onEditorKey : function(field, e){
50420 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50421 ///Roo.log('onEditorKey' + k);
50425 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50427 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50430 }else if(k == e.ENTER && !e.ctrlKey){
50433 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50434 }else if(k == e.ESC){
50440 //Roo.log('next cell after edit');
50441 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
50446 * Ext JS Library 1.1.1
50447 * Copyright(c) 2006-2007, Ext JS, LLC.
50449 * Originally Released Under LGPL - original licence link has changed is not relivant.
50452 * <script type="text/javascript">
50456 * @class Roo.grid.EditorGrid
50457 * @extends Roo.grid.Grid
50458 * Class for creating and editable grid.
50459 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50460 * The container MUST have some type of size defined for the grid to fill. The container will be
50461 * automatically set to position relative if it isn't already.
50462 * @param {Object} dataSource The data model to bind to
50463 * @param {Object} colModel The column model with info about this grid's columns
50465 Roo.grid.EditorGrid = function(container, config){
50466 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
50467 this.getGridEl().addClass("xedit-grid");
50469 if(!this.selModel){
50470 this.selModel = new Roo.grid.CellSelectionModel();
50473 this.activeEditor = null;
50477 * @event beforeedit
50478 * Fires before cell editing is triggered. The edit event object has the following properties <br />
50479 * <ul style="padding:5px;padding-left:16px;">
50480 * <li>grid - This grid</li>
50481 * <li>record - The record being edited</li>
50482 * <li>field - The field name being edited</li>
50483 * <li>value - The value for the field being edited.</li>
50484 * <li>row - The grid row index</li>
50485 * <li>column - The grid column index</li>
50486 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50488 * @param {Object} e An edit event (see above for description)
50490 "beforeedit" : true,
50493 * Fires after a cell is edited. <br />
50494 * <ul style="padding:5px;padding-left:16px;">
50495 * <li>grid - This grid</li>
50496 * <li>record - The record being edited</li>
50497 * <li>field - The field name being edited</li>
50498 * <li>value - The value being set</li>
50499 * <li>originalValue - The original value for the field, before the edit.</li>
50500 * <li>row - The grid row index</li>
50501 * <li>column - The grid column index</li>
50503 * @param {Object} e An edit event (see above for description)
50505 "afteredit" : true,
50507 * @event validateedit
50508 * Fires after a cell is edited, but before the value is set in the record.
50509 * You can use this to modify the value being set in the field, Return false
50510 * to cancel the change. The edit event object has the following properties <br />
50511 * <ul style="padding:5px;padding-left:16px;">
50512 * <li>editor - This editor</li>
50513 * <li>grid - This grid</li>
50514 * <li>record - The record being edited</li>
50515 * <li>field - The field name being edited</li>
50516 * <li>value - The value being set</li>
50517 * <li>originalValue - The original value for the field, before the edit.</li>
50518 * <li>row - The grid row index</li>
50519 * <li>column - The grid column index</li>
50520 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50522 * @param {Object} e An edit event (see above for description)
50524 "validateedit" : true
50526 this.on("bodyscroll", this.stopEditing, this);
50527 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
50530 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
50532 * @cfg {Number} clicksToEdit
50533 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
50540 trackMouseOver: false, // causes very odd FF errors
50542 onCellDblClick : function(g, row, col){
50543 this.startEditing(row, col);
50546 onEditComplete : function(ed, value, startValue){
50547 this.editing = false;
50548 this.activeEditor = null;
50549 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
50551 var field = this.colModel.getDataIndex(ed.col);
50556 originalValue: startValue,
50563 if(String(value) !== String(startValue)){
50565 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
50566 r.set(field, e.value);
50567 // if we are dealing with a combo box..
50568 // then we also set the 'name' colum to be the displayField
50569 if (ed.field.displayField && ed.field.name) {
50570 r.set(ed.field.name, ed.field.el.dom.value);
50573 delete e.cancel; //?? why!!!
50574 this.fireEvent("afteredit", e);
50577 this.fireEvent("afteredit", e); // always fire it!
50579 this.view.focusCell(ed.row, ed.col);
50583 * Starts editing the specified for the specified row/column
50584 * @param {Number} rowIndex
50585 * @param {Number} colIndex
50587 startEditing : function(row, col){
50588 this.stopEditing();
50589 if(this.colModel.isCellEditable(col, row)){
50590 this.view.ensureVisible(row, col, true);
50591 var r = this.dataSource.getAt(row);
50592 var field = this.colModel.getDataIndex(col);
50597 value: r.data[field],
50602 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
50603 this.editing = true;
50604 var ed = this.colModel.getCellEditor(col, row);
50610 ed.render(ed.parentEl || document.body);
50613 (function(){ // complex but required for focus issues in safari, ie and opera
50617 ed.on("complete", this.onEditComplete, this, {single: true});
50618 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
50619 this.activeEditor = ed;
50620 var v = r.data[field];
50621 ed.startEdit(this.view.getCell(row, col), v);
50622 // combo's with 'displayField and name set
50623 if (ed.field.displayField && ed.field.name) {
50624 ed.field.el.dom.value = r.data[ed.field.name];
50628 }).defer(50, this);
50634 * Stops any active editing
50636 stopEditing : function(){
50637 if(this.activeEditor){
50638 this.activeEditor.completeEdit();
50640 this.activeEditor = null;
50644 * Ext JS Library 1.1.1
50645 * Copyright(c) 2006-2007, Ext JS, LLC.
50647 * Originally Released Under LGPL - original licence link has changed is not relivant.
50650 * <script type="text/javascript">
50653 // private - not really -- you end up using it !
50654 // This is a support class used internally by the Grid components
50657 * @class Roo.grid.GridEditor
50658 * @extends Roo.Editor
50659 * Class for creating and editable grid elements.
50660 * @param {Object} config any settings (must include field)
50662 Roo.grid.GridEditor = function(field, config){
50663 if (!config && field.field) {
50665 field = Roo.factory(config.field, Roo.form);
50667 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
50668 field.monitorTab = false;
50671 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
50674 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
50677 alignment: "tl-tl",
50680 cls: "x-small-editor x-grid-editor",
50685 * Ext JS Library 1.1.1
50686 * Copyright(c) 2006-2007, Ext JS, LLC.
50688 * Originally Released Under LGPL - original licence link has changed is not relivant.
50691 * <script type="text/javascript">
50696 Roo.grid.PropertyRecord = Roo.data.Record.create([
50697 {name:'name',type:'string'}, 'value'
50701 Roo.grid.PropertyStore = function(grid, source){
50703 this.store = new Roo.data.Store({
50704 recordType : Roo.grid.PropertyRecord
50706 this.store.on('update', this.onUpdate, this);
50708 this.setSource(source);
50710 Roo.grid.PropertyStore.superclass.constructor.call(this);
50715 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
50716 setSource : function(o){
50718 this.store.removeAll();
50721 if(this.isEditableValue(o[k])){
50722 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
50725 this.store.loadRecords({records: data}, {}, true);
50728 onUpdate : function(ds, record, type){
50729 if(type == Roo.data.Record.EDIT){
50730 var v = record.data['value'];
50731 var oldValue = record.modified['value'];
50732 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
50733 this.source[record.id] = v;
50735 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
50742 getProperty : function(row){
50743 return this.store.getAt(row);
50746 isEditableValue: function(val){
50747 if(val && val instanceof Date){
50749 }else if(typeof val == 'object' || typeof val == 'function'){
50755 setValue : function(prop, value){
50756 this.source[prop] = value;
50757 this.store.getById(prop).set('value', value);
50760 getSource : function(){
50761 return this.source;
50765 Roo.grid.PropertyColumnModel = function(grid, store){
50768 g.PropertyColumnModel.superclass.constructor.call(this, [
50769 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
50770 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
50772 this.store = store;
50773 this.bselect = Roo.DomHelper.append(document.body, {
50774 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
50775 {tag: 'option', value: 'true', html: 'true'},
50776 {tag: 'option', value: 'false', html: 'false'}
50779 Roo.id(this.bselect);
50782 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
50783 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
50784 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
50785 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
50786 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
50788 this.renderCellDelegate = this.renderCell.createDelegate(this);
50789 this.renderPropDelegate = this.renderProp.createDelegate(this);
50792 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
50796 valueText : 'Value',
50798 dateFormat : 'm/j/Y',
50801 renderDate : function(dateVal){
50802 return dateVal.dateFormat(this.dateFormat);
50805 renderBool : function(bVal){
50806 return bVal ? 'true' : 'false';
50809 isCellEditable : function(colIndex, rowIndex){
50810 return colIndex == 1;
50813 getRenderer : function(col){
50815 this.renderCellDelegate : this.renderPropDelegate;
50818 renderProp : function(v){
50819 return this.getPropertyName(v);
50822 renderCell : function(val){
50824 if(val instanceof Date){
50825 rv = this.renderDate(val);
50826 }else if(typeof val == 'boolean'){
50827 rv = this.renderBool(val);
50829 return Roo.util.Format.htmlEncode(rv);
50832 getPropertyName : function(name){
50833 var pn = this.grid.propertyNames;
50834 return pn && pn[name] ? pn[name] : name;
50837 getCellEditor : function(colIndex, rowIndex){
50838 var p = this.store.getProperty(rowIndex);
50839 var n = p.data['name'], val = p.data['value'];
50841 if(typeof(this.grid.customEditors[n]) == 'string'){
50842 return this.editors[this.grid.customEditors[n]];
50844 if(typeof(this.grid.customEditors[n]) != 'undefined'){
50845 return this.grid.customEditors[n];
50847 if(val instanceof Date){
50848 return this.editors['date'];
50849 }else if(typeof val == 'number'){
50850 return this.editors['number'];
50851 }else if(typeof val == 'boolean'){
50852 return this.editors['boolean'];
50854 return this.editors['string'];
50860 * @class Roo.grid.PropertyGrid
50861 * @extends Roo.grid.EditorGrid
50862 * This class represents the interface of a component based property grid control.
50863 * <br><br>Usage:<pre><code>
50864 var grid = new Roo.grid.PropertyGrid("my-container-id", {
50872 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50873 * The container MUST have some type of size defined for the grid to fill. The container will be
50874 * automatically set to position relative if it isn't already.
50875 * @param {Object} config A config object that sets properties on this grid.
50877 Roo.grid.PropertyGrid = function(container, config){
50878 config = config || {};
50879 var store = new Roo.grid.PropertyStore(this);
50880 this.store = store;
50881 var cm = new Roo.grid.PropertyColumnModel(this, store);
50882 store.store.sort('name', 'ASC');
50883 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
50886 enableColLock:false,
50887 enableColumnMove:false,
50889 trackMouseOver: false,
50892 this.getGridEl().addClass('x-props-grid');
50893 this.lastEditRow = null;
50894 this.on('columnresize', this.onColumnResize, this);
50897 * @event beforepropertychange
50898 * Fires before a property changes (return false to stop?)
50899 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50900 * @param {String} id Record Id
50901 * @param {String} newval New Value
50902 * @param {String} oldval Old Value
50904 "beforepropertychange": true,
50906 * @event propertychange
50907 * Fires after a property changes
50908 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50909 * @param {String} id Record Id
50910 * @param {String} newval New Value
50911 * @param {String} oldval Old Value
50913 "propertychange": true
50915 this.customEditors = this.customEditors || {};
50917 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
50920 * @cfg {Object} customEditors map of colnames=> custom editors.
50921 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
50922 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
50923 * false disables editing of the field.
50927 * @cfg {Object} propertyNames map of property Names to their displayed value
50930 render : function(){
50931 Roo.grid.PropertyGrid.superclass.render.call(this);
50932 this.autoSize.defer(100, this);
50935 autoSize : function(){
50936 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
50938 this.view.fitColumns();
50942 onColumnResize : function(){
50943 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
50947 * Sets the data for the Grid
50948 * accepts a Key => Value object of all the elements avaiable.
50949 * @param {Object} data to appear in grid.
50951 setSource : function(source){
50952 this.store.setSource(source);
50956 * Gets all the data from the grid.
50957 * @return {Object} data data stored in grid
50959 getSource : function(){
50960 return this.store.getSource();
50964 * Ext JS Library 1.1.1
50965 * Copyright(c) 2006-2007, Ext JS, LLC.
50967 * Originally Released Under LGPL - original licence link has changed is not relivant.
50970 * <script type="text/javascript">
50974 * @class Roo.LoadMask
50975 * A simple utility class for generically masking elements while loading data. If the element being masked has
50976 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
50977 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
50978 * element's UpdateManager load indicator and will be destroyed after the initial load.
50980 * Create a new LoadMask
50981 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
50982 * @param {Object} config The config object
50984 Roo.LoadMask = function(el, config){
50985 this.el = Roo.get(el);
50986 Roo.apply(this, config);
50988 this.store.on('beforeload', this.onBeforeLoad, this);
50989 this.store.on('load', this.onLoad, this);
50990 this.store.on('loadexception', this.onLoad, this);
50991 this.removeMask = false;
50993 var um = this.el.getUpdateManager();
50994 um.showLoadIndicator = false; // disable the default indicator
50995 um.on('beforeupdate', this.onBeforeLoad, this);
50996 um.on('update', this.onLoad, this);
50997 um.on('failure', this.onLoad, this);
50998 this.removeMask = true;
51002 Roo.LoadMask.prototype = {
51004 * @cfg {Boolean} removeMask
51005 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
51006 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
51009 * @cfg {String} msg
51010 * The text to display in a centered loading message box (defaults to 'Loading...')
51012 msg : 'Loading...',
51014 * @cfg {String} msgCls
51015 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
51017 msgCls : 'x-mask-loading',
51020 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
51026 * Disables the mask to prevent it from being displayed
51028 disable : function(){
51029 this.disabled = true;
51033 * Enables the mask so that it can be displayed
51035 enable : function(){
51036 this.disabled = false;
51040 onLoad : function(){
51041 this.el.unmask(this.removeMask);
51045 onBeforeLoad : function(){
51046 if(!this.disabled){
51047 this.el.mask(this.msg, this.msgCls);
51052 destroy : function(){
51054 this.store.un('beforeload', this.onBeforeLoad, this);
51055 this.store.un('load', this.onLoad, this);
51056 this.store.un('loadexception', this.onLoad, this);
51058 var um = this.el.getUpdateManager();
51059 um.un('beforeupdate', this.onBeforeLoad, this);
51060 um.un('update', this.onLoad, this);
51061 um.un('failure', this.onLoad, this);
51066 * Ext JS Library 1.1.1
51067 * Copyright(c) 2006-2007, Ext JS, LLC.
51069 * Originally Released Under LGPL - original licence link has changed is not relivant.
51072 * <script type="text/javascript">
51074 Roo.XTemplate = function(){
51075 Roo.XTemplate.superclass.constructor.apply(this, arguments);
51078 s = ['<tpl>', s, '</tpl>'].join('');
51080 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
51082 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
51083 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
51084 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
51088 while(m = s.match(re)){
51089 var m2 = m[0].match(nameRe);
51090 var m3 = m[0].match(ifRe);
51091 var m4 = m[0].match(execRe);
51092 var exp = null, fn = null, exec = null;
51093 var name = m2 && m2[1] ? m2[1] : '';
51095 exp = m3 && m3[1] ? m3[1] : null;
51097 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
51101 exp = m4 && m4[1] ? m4[1] : null;
51103 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
51108 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
51109 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
51110 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
51120 s = s.replace(m[0], '{xtpl'+ id + '}');
51123 for(var i = tpls.length-1; i >= 0; --i){
51124 this.compileTpl(tpls[i]);
51126 this.master = tpls[tpls.length-1];
51129 Roo.extend(Roo.XTemplate, Roo.Template, {
51131 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
51133 applySubTemplate : function(id, values, parent){
51134 var t = this.tpls[id];
51135 if(t.test && !t.test.call(this, values, parent)){
51138 if(t.exec && t.exec.call(this, values, parent)){
51141 var vs = t.target ? t.target.call(this, values, parent) : values;
51142 parent = t.target ? values : parent;
51143 if(t.target && vs instanceof Array){
51145 for(var i = 0, len = vs.length; i < len; i++){
51146 buf[buf.length] = t.compiled.call(this, vs[i], parent);
51148 return buf.join('');
51150 return t.compiled.call(this, vs, parent);
51153 compileTpl : function(tpl){
51154 var fm = Roo.util.Format;
51155 var useF = this.disableFormats !== true;
51156 var sep = Roo.isGecko ? "+" : ",";
51157 var fn = function(m, name, format, args){
51158 if(name.substr(0, 4) == 'xtpl'){
51159 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
51162 if(name.indexOf('.') != -1){
51165 v = "values['" + name + "']";
51167 if(format && useF){
51168 args = args ? ',' + args : "";
51169 if(format.substr(0, 5) != "this."){
51170 format = "fm." + format + '(';
51172 format = 'this.call("'+ format.substr(5) + '", ';
51176 args= ''; format = "("+v+" === undefined ? '' : ";
51178 return "'"+ sep + format + v + args + ")"+sep+"'";
51181 // branched to use + in gecko and [].join() in others
51183 body = "tpl.compiled = function(values, parent){ return '" +
51184 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
51187 body = ["tpl.compiled = function(values, parent){ return ['"];
51188 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
51189 body.push("'].join('');};");
51190 body = body.join('');
51192 /** eval:var:zzzzzzz */
51197 applyTemplate : function(values){
51198 return this.master.compiled.call(this, values, {});
51202 apply : function(){
51203 return this.applyTemplate.apply(this, arguments);
51206 compile : function(){return this;}
51209 Roo.XTemplate.from = function(el){
51210 el = Roo.getDom(el);
51211 return new Roo.XTemplate(el.value || el.innerHTML);
51213 * Original code for Roojs - LGPL
51214 * <script type="text/javascript">
51218 * @class Roo.XComponent
51219 * A delayed Element creator...
51221 * Mypart.xyx = new Roo.XComponent({
51223 parent : 'Mypart.xyz', // empty == document.element.!!
51227 disabled : function() {}
51229 tree : function() { // return an tree of xtype declared components
51233 xtype : 'NestedLayoutPanel',
51239 * Roo.onReady(function() {
51240 Roo.XComponent.build();
51243 * @extends Roo.util.Observable
51245 * @param cfg {Object} configuration of component
51248 Roo.XComponent = function(cfg) {
51249 Roo.apply(this, cfg);
51253 * Fires when this the componnt is built
51254 * @param {Roo.XComponent} c the component
51258 * @event buildcomplete
51259 * Fires on the top level element when all elements have been built
51260 * @param {Roo.XComponent} c the top level component.
51262 'buildcomplete' : true
51266 Roo.XComponent.register(this);
51267 this.modules = false;
51268 this.el = false; // where the layout goes..
51272 Roo.extend(Roo.XComponent, Roo.util.Observable, {
51275 * The created element (with Roo.factory())
51276 * @type {Roo.Layout}
51282 * for BC - use el in new code
51283 * @type {Roo.Layout}
51289 * for BC - use el in new code
51290 * @type {Roo.Layout}
51295 * @cfg {Function|boolean} disabled
51296 * If this module is disabled by some rule, return true from the funtion
51301 * @cfg {String} parent
51302 * Name of parent element which it get xtype added to..
51307 * @cfg {String} order
51308 * Used to set the order in which elements are created (usefull for multiple tabs)
51313 * @cfg {String} name
51314 * String to display while loading.
51318 * @cfg {Array} items
51319 * A single item array - the first element is the root of the tree..
51320 * It's done this way to stay compatible with the Xtype system...
51326 Roo.apply(Roo.XComponent, {
51329 * @property buildCompleted
51330 * True when the builder has completed building the interface.
51333 buildCompleted : false,
51336 * @property topModule
51337 * the upper most module - uses document.element as it's constructor.
51344 * @property modules
51345 * array of modules to be created by registration system.
51346 * @type {Array} of Roo.XComponent
51352 * @property elmodules
51353 * array of modules to be created by which use #ID
51354 * @type {Array} of Roo.XComponent
51359 * Register components to be built later.
51361 * This solves the following issues
51362 * - Building is not done on page load, but after an authentication process has occured.
51363 * - Interface elements are registered on page load
51364 * - Parent Interface elements may not be loaded before child, so this handles that..
51371 module : 'Pman.Tab.projectMgr',
51373 parent : 'Pman.layout',
51374 disabled : false, // or use a function..
51377 * * @param {Object} details about module
51379 register : function(obj) {
51380 this.modules.push(obj);
51384 * convert a string to an object..
51385 * eg. 'AAA.BBB' -> finds AAA.BBB
51389 toObject : function(str)
51391 if (!str || typeof(str) == 'object') {
51397 var ar = str.split('.');
51401 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
51406 throw "Module not found : " + str;
51408 Roo.each(ar, function(e) {
51409 if (typeof(o[e]) == 'undefined') {
51410 throw "Module not found : " + str;
51420 * move modules into their correct place in the tree..
51423 preBuild : function ()
51426 Roo.each(this.modules , function (obj)
51428 obj.parent = this.toObject(obj.parent);
51431 this.topModule = obj;
51434 if (typeof(obj.parent) == 'string') {
51435 this.elmodules.push(obj);
51439 if (!obj.parent.modules) {
51440 obj.parent.modules = new Roo.util.MixedCollection(false,
51441 function(o) { return o.order + '' }
51445 obj.parent.modules.add(obj);
51450 * make a list of modules to build.
51451 * @return {Array} list of modules.
51454 buildOrder : function()
51457 var cmp = function(a,b) {
51458 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
51461 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
51462 throw "No top level modules to build";
51465 // make a flat list in order of modules to build.
51466 var mods = this.topModule ? [ this.topModule ] : [];
51467 Roo.each(this.elmodules,function(e) { mods.push(e) });
51470 // add modules to their parents..
51471 var addMod = function(m) {
51472 // Roo.debug && Roo.log(m.modKey);
51476 m.modules.keySort('ASC', cmp );
51477 m.modules.each(addMod);
51479 // not sure if this is used any more..
51481 m.finalize.name = m.name + " (clean up) ";
51482 mods.push(m.finalize);
51486 if (this.topModule) {
51487 this.topModule.modules.keySort('ASC', cmp );
51488 this.topModule.modules.each(addMod);
51494 * Build the registered modules.
51495 * @param {Object} parent element.
51496 * @param {Function} optional method to call after module has been added.
51504 var mods = this.buildOrder();
51506 //this.allmods = mods;
51507 //Roo.debug && Roo.log(mods);
51509 if (!mods.length) { // should not happen
51510 throw "NO modules!!!";
51515 // flash it up as modal - so we store the mask!?
51516 Roo.MessageBox.show({ title: 'loading' });
51517 Roo.MessageBox.show({
51518 title: "Please wait...",
51519 msg: "Building Interface...",
51526 var total = mods.length;
51529 var progressRun = function() {
51530 if (!mods.length) {
51531 Roo.debug && Roo.log('hide?');
51532 Roo.MessageBox.hide();
51533 if (_this.topModule) {
51534 _this.topModule.fireEvent('buildcomplete', _this.topModule);
51540 var m = mods.shift();
51541 Roo.debug && Roo.log(m);
51542 if (typeof(m) == 'function') { // not sure if this is supported any more..
51544 return progressRun.defer(10, _this);
51547 Roo.MessageBox.updateProgress(
51548 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
51550 (m.name ? (' - ' + m.name) : '')
51555 var disabled = (typeof(m.disabled) == 'function') ?
51556 m.disabled.call(m.module.disabled) : m.disabled;
51560 return progressRun(); // we do not update the display!
51563 if (!m.parent || (typeof(m.parent) == 'string' && m.parent[0] == '#')) {
51564 // it's a top level one..
51565 var ctr = m.parent ? Roo.get(m.parent.substr(1)) : document.body;
51567 Roo.log("not rendering module " + m.name + " " + m.parent + " no found");
51568 return progressRun.defer(10, _this);
51573 var layoutbase = new Ext.BorderLayout(
51574 m.parent ? Roo.get(m.parent.substr(1)) : document.body,
51580 tabPosition: 'top',
51581 //resizeTabs: true,
51582 alwaysShowTabs: m.parent ? false : true,
51583 hideTabs : m.parent ? true : false,
51587 var tree = m.tree();
51588 tree.region = 'center';
51589 m.el = layoutbase.addxtype(tree);
51591 m.layout = m.panel.layout;
51592 return progressRun.defer(10, _this);
51595 var tree = m.tree();
51596 tree.region = tree.region || m.region;
51597 m.el = m.parent.el.addxtype(tree);
51598 m.fireEvent('built', m);
51600 m.layout = m.panel.layout;
51601 return progressRun.defer(10, _this);
51604 progressRun.defer(1, _this);
51614 //<script type="text/javascript">
51619 * @extends Roo.LayoutDialog
51620 * A generic Login Dialog..... - only one needed in theory!?!?
51622 * Fires XComponent builder on success...
51625 * username,password, lang = for login actions.
51626 * check = 1 for periodic checking that sesion is valid.
51627 * passwordRequest = email request password
51628 * logout = 1 = to logout
51630 * Affects: (this id="????" elements)
51631 * loading (removed) (used to indicate application is loading)
51632 * loading-mask (hides) (used to hide application when it's building loading)
51638 * Myapp.login = Roo.Login({
51654 Roo.Login = function(cfg)
51660 Roo.apply(this,cfg);
51662 Roo.onReady(function() {
51668 Roo.Login.superclass.constructor.call(this, this);
51669 //this.addxtype(this.items[0]);
51675 Roo.extend(Roo.Login, Roo.LayoutDialog, {
51678 * @cfg {String} method
51679 * Method used to query for login details.
51684 * @cfg {String} url
51685 * URL to query login data. - eg. baseURL + '/Login.php'
51691 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
51696 * @property checkFails
51697 * Number of times we have attempted to get authentication check, and failed.
51702 * @property intervalID
51703 * The window interval that does the constant login checking.
51709 onLoad : function() // called on page load...
51713 if (Roo.get('loading')) { // clear any loading indicator..
51714 Roo.get('loading').remove();
51717 //this.switchLang('en'); // set the language to english..
51720 success: function(response, opts) { // check successfull...
51722 var res = this.processResponse(response);
51723 this.checkFails =0;
51724 if (!res.success) { // error!
51725 this.checkFails = 5;
51726 //console.log('call failure');
51727 return this.failure(response,opts);
51730 if (!res.data.id) { // id=0 == login failure.
51731 return this.show();
51735 //console.log(success);
51736 this.fillAuth(res.data);
51737 this.checkFails =0;
51738 Roo.XComponent.build();
51740 failure : this.show
51746 check: function(cfg) // called every so often to refresh cookie etc..
51748 if (cfg.again) { // could be undefined..
51751 this.checkFails = 0;
51754 if (this.sending) {
51755 if ( this.checkFails > 4) {
51756 Roo.MessageBox.alert("Error",
51757 "Error getting authentication status. - try reloading, or wait a while", function() {
51758 _this.sending = false;
51763 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
51766 this.sending = true;
51773 method: this.method,
51774 success: cfg.success || this.success,
51775 failure : cfg.failure || this.failure,
51785 window.onbeforeunload = function() { }; // false does not work for IE..
51795 failure : function() {
51796 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
51797 document.location = document.location.toString() + '?ts=' + Math.random();
51801 success : function() {
51802 _this.user = false;
51803 this.checkFails =0;
51805 document.location = document.location.toString() + '?ts=' + Math.random();
51812 processResponse : function (response)
51816 res = Roo.decode(response.responseText);
51818 if (typeof(res) != 'object') {
51819 res = { success : false, errorMsg : res, errors : true };
51821 if (typeof(res.success) == 'undefined') {
51822 res.success = false;
51826 res = { success : false, errorMsg : response.responseText, errors : true };
51831 success : function(response, opts) // check successfull...
51833 this.sending = false;
51834 var res = this.processResponse(response);
51835 if (!res.success) {
51836 return this.failure(response, opts);
51838 if (!res.data || !res.data.id) {
51839 return this.failure(response,opts);
51841 //console.log(res);
51842 this.fillAuth(res.data);
51844 this.checkFails =0;
51849 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
51851 this.authUser = -1;
51852 this.sending = false;
51853 var res = this.processResponse(response);
51854 //console.log(res);
51855 if ( this.checkFails > 2) {
51857 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
51858 "Error getting authentication status. - try reloading");
51861 opts.callCfg.again = true;
51862 this.check.defer(1000, this, [ opts.callCfg ]);
51868 fillAuth: function(au) {
51869 this.startAuthCheck();
51870 this.authUserId = au.id;
51871 this.authUser = au;
51872 this.lastChecked = new Date();
51873 this.fireEvent('refreshed', au);
51874 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
51875 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
51876 au.lang = au.lang || 'en';
51877 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
51878 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
51879 this.switchLang(au.lang );
51882 // open system... - -on setyp..
51883 if (this.authUserId < 0) {
51884 Roo.MessageBox.alert("Warning",
51885 "This is an open system - please set up a admin user with a password.");
51888 //Pman.onload(); // which should do nothing if it's a re-auth result...
51893 startAuthCheck : function() // starter for timeout checking..
51895 if (this.intervalID) { // timer already in place...
51899 this.intervalID = window.setInterval(function() {
51900 _this.check(false);
51901 }, 120000); // every 120 secs = 2mins..
51907 switchLang : function (lang)
51909 _T = typeof(_T) == 'undefined' ? false : _T;
51910 if (!_T || !lang.length) {
51914 if (!_T && lang != 'en') {
51915 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51919 if (typeof(_T.en) == 'undefined') {
51921 Roo.apply(_T.en, _T);
51924 if (typeof(_T[lang]) == 'undefined') {
51925 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51930 Roo.apply(_T, _T[lang]);
51931 // just need to set the text values for everything...
51933 /* this will not work ...
51937 function formLabel(name, val) {
51938 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
51941 formLabel('password', "Password"+':');
51942 formLabel('username', "Email Address"+':');
51943 formLabel('lang', "Language"+':');
51944 this.dialog.setTitle("Login");
51945 this.dialog.buttons[0].setText("Forgot Password");
51946 this.dialog.buttons[1].setText("Login");
51965 collapsible: false,
51967 center: { // needed??
51970 // tabPosition: 'top',
51973 alwaysShowTabs: false
51977 show : function(dlg)
51979 //console.log(this);
51980 this.form = this.layout.getRegion('center').activePanel.form;
51981 this.form.dialog = dlg;
51982 this.buttons[0].form = this.form;
51983 this.buttons[0].dialog = dlg;
51984 this.buttons[1].form = this.form;
51985 this.buttons[1].dialog = dlg;
51987 //this.resizeToLogo.defer(1000,this);
51988 // this is all related to resizing for logos..
51989 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
51991 // this.resizeToLogo.defer(1000,this);
51994 //var w = Ext.lib.Dom.getViewWidth() - 100;
51995 //var h = Ext.lib.Dom.getViewHeight() - 100;
51996 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
51998 if (this.disabled) {
52003 if (this.user.id < 0) { // used for inital setup situations.
52007 if (this.intervalID) {
52008 // remove the timer
52009 window.clearInterval(this.intervalID);
52010 this.intervalID = false;
52014 if (Roo.get('loading')) {
52015 Roo.get('loading').remove();
52017 if (Roo.get('loading-mask')) {
52018 Roo.get('loading-mask').hide();
52021 //incomming._node = tnode;
52023 //this.dialog.modal = !modal;
52024 //this.dialog.show();
52028 this.form.setValues({
52029 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
52030 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
52033 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
52034 if (this.form.findField('username').getValue().length > 0 ){
52035 this.form.findField('password').focus();
52037 this.form.findField('username').focus();
52045 xtype : 'ContentPanel',
52057 style : 'margin: 10px;',
52060 actionfailed : function(f, act) {
52061 // form can return { errors: .... }
52063 //act.result.errors // invalid form element list...
52064 //act.result.errorMsg// invalid form element list...
52066 this.dialog.el.unmask();
52067 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
52068 "Login failed - communication error - try again.");
52071 actioncomplete: function(re, act) {
52073 Roo.state.Manager.set(
52074 this.dialog.realm + '.username',
52075 this.findField('username').getValue()
52077 Roo.state.Manager.set(
52078 this.dialog.realm + '.lang',
52079 this.findField('lang').getValue()
52082 this.dialog.fillAuth(act.result.data);
52084 this.dialog.hide();
52086 if (Roo.get('loading-mask')) {
52087 Roo.get('loading-mask').show();
52089 Roo.XComponent.build();
52097 xtype : 'TextField',
52099 fieldLabel: "Email Address",
52102 autoCreate : {tag: "input", type: "text", size: "20"}
52105 xtype : 'TextField',
52107 fieldLabel: "Password",
52108 inputType: 'password',
52111 autoCreate : {tag: "input", type: "text", size: "20"},
52113 specialkey : function(e,ev) {
52114 if (ev.keyCode == 13) {
52115 this.form.dialog.el.mask("Logging in");
52116 this.form.doAction('submit', {
52117 url: this.form.dialog.url,
52118 method: this.form.dialog.method
52125 xtype : 'ComboBox',
52127 fieldLabel: "Language",
52130 xtype : 'SimpleStore',
52131 fields: ['lang', 'ldisp'],
52133 [ 'en', 'English' ],
52134 [ 'zh_HK' , '\u7E41\u4E2D' ],
52135 [ 'zh_CN', '\u7C21\u4E2D' ]
52139 valueField : 'lang',
52140 hiddenName: 'lang',
52142 displayField:'ldisp',
52146 triggerAction: 'all',
52147 emptyText:'Select a Language...',
52148 selectOnFocus:true,
52150 select : function(cb, rec, ix) {
52151 this.form.switchLang(rec.data.lang);
52167 text : "Forgot Password",
52169 click : function() {
52170 //console.log(this);
52171 var n = this.form.findField('username').getValue();
52173 Roo.MessageBox.alert("Error", "Fill in your email address");
52177 url: this.dialog.url,
52181 method: this.dialog.method,
52182 success: function(response, opts) { // check successfull...
52184 var res = this.dialog.processResponse(response);
52185 if (!res.success) { // error!
52186 Roo.MessageBox.alert("Error" ,
52187 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
52190 Roo.MessageBox.alert("Notice" ,
52191 "Please check you email for the Password Reset message");
52193 failure : function() {
52194 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
52207 click : function () {
52209 this.dialog.el.mask("Logging in");
52210 this.form.doAction('submit', {
52211 url: this.dialog.url,
52212 method: this.dialog.method