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 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1011 T CST Timezone setting of the machine running the code
1012 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1015 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1017 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1018 document.write(dt.format('Y-m-d')); //2007-01-10
1019 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1020 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
1023 * Here are some standard date/time patterns that you might find helpful. They
1024 * are not part of the source of Date.js, but to use them you can simply copy this
1025 * block of code into any script that is included after Date.js and they will also become
1026 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1029 ISO8601Long:"Y-m-d H:i:s",
1030 ISO8601Short:"Y-m-d",
1032 LongDate: "l, F d, Y",
1033 FullDateTime: "l, F d, Y g:i:s A",
1036 LongTime: "g:i:s A",
1037 SortableDateTime: "Y-m-d\\TH:i:s",
1038 UniversalSortableDateTime: "Y-m-d H:i:sO",
1045 var dt = new Date();
1046 document.write(dt.format(Date.patterns.ShortDate));
1051 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1052 * They generate precompiled functions from date formats instead of parsing and
1053 * processing the pattern every time you format a date. These functions are available
1054 * on every Date object (any javascript function).
1056 * The original article and download are here:
1057 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1064 Returns the number of milliseconds between this date and date
1065 @param {Date} date (optional) Defaults to now
1066 @return {Number} The diff in milliseconds
1067 @member Date getElapsed
1069 Date.prototype.getElapsed = function(date) {
1070 return Math.abs((date || new Date()).getTime()-this.getTime());
1072 // was in date file..
1076 Date.parseFunctions = {count:0};
1078 Date.parseRegexes = [];
1080 Date.formatFunctions = {count:0};
1083 Date.prototype.dateFormat = function(format) {
1084 if (Date.formatFunctions[format] == null) {
1085 Date.createNewFormat(format);
1087 var func = Date.formatFunctions[format];
1088 return this[func]();
1093 * Formats a date given the supplied format string
1094 * @param {String} format The format string
1095 * @return {String} The formatted date
1098 Date.prototype.format = Date.prototype.dateFormat;
1101 Date.createNewFormat = function(format) {
1102 var funcName = "format" + Date.formatFunctions.count++;
1103 Date.formatFunctions[format] = funcName;
1104 var code = "Date.prototype." + funcName + " = function(){return ";
1105 var special = false;
1107 for (var i = 0; i < format.length; ++i) {
1108 ch = format.charAt(i);
1109 if (!special && ch == "\\") {
1114 code += "'" + String.escape(ch) + "' + ";
1117 code += Date.getFormatCode(ch);
1120 /** eval:var:zzzzzzzzzzzzz */
1121 eval(code.substring(0, code.length - 3) + ";}");
1125 Date.getFormatCode = function(character) {
1126 switch (character) {
1128 return "String.leftPad(this.getDate(), 2, '0') + ";
1130 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1132 return "this.getDate() + ";
1134 return "Date.dayNames[this.getDay()] + ";
1136 return "this.getSuffix() + ";
1138 return "this.getDay() + ";
1140 return "this.getDayOfYear() + ";
1142 return "this.getWeekOfYear() + ";
1144 return "Date.monthNames[this.getMonth()] + ";
1146 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1148 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1150 return "(this.getMonth() + 1) + ";
1152 return "this.getDaysInMonth() + ";
1154 return "(this.isLeapYear() ? 1 : 0) + ";
1156 return "this.getFullYear() + ";
1158 return "('' + this.getFullYear()).substring(2, 4) + ";
1160 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1162 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1164 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1166 return "this.getHours() + ";
1168 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1170 return "String.leftPad(this.getHours(), 2, '0') + ";
1172 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1174 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1176 return "this.getGMTOffset() + ";
1178 return "this.getGMTColonOffset() + ";
1180 return "this.getTimezone() + ";
1182 return "(this.getTimezoneOffset() * -60) + ";
1184 return "'" + String.escape(character) + "' + ";
1189 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1190 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1191 * the date format that is not specified will default to the current date value for that part. Time parts can also
1192 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1193 * string or the parse operation will fail.
1196 //dt = Fri May 25 2007 (current date)
1197 var dt = new Date();
1199 //dt = Thu May 25 2006 (today's month/day in 2006)
1200 dt = Date.parseDate("2006", "Y");
1202 //dt = Sun Jan 15 2006 (all date parts specified)
1203 dt = Date.parseDate("2006-1-15", "Y-m-d");
1205 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1206 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1208 * @param {String} input The unparsed date as a string
1209 * @param {String} format The format the date is in
1210 * @return {Date} The parsed date
1213 Date.parseDate = function(input, format) {
1214 if (Date.parseFunctions[format] == null) {
1215 Date.createParser(format);
1217 var func = Date.parseFunctions[format];
1218 return Date[func](input);
1223 Date.createParser = function(format) {
1224 var funcName = "parse" + Date.parseFunctions.count++;
1225 var regexNum = Date.parseRegexes.length;
1226 var currentGroup = 1;
1227 Date.parseFunctions[format] = funcName;
1229 var code = "Date." + funcName + " = function(input){\n"
1230 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1231 + "var d = new Date();\n"
1232 + "y = d.getFullYear();\n"
1233 + "m = d.getMonth();\n"
1234 + "d = d.getDate();\n"
1235 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1236 + "if (results && results.length > 0) {";
1239 var special = false;
1241 for (var i = 0; i < format.length; ++i) {
1242 ch = format.charAt(i);
1243 if (!special && ch == "\\") {
1248 regex += String.escape(ch);
1251 var obj = Date.formatCodeToRegex(ch, currentGroup);
1252 currentGroup += obj.g;
1254 if (obj.g && obj.c) {
1260 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1261 + "{v = new Date(y, m, d, h, i, s);}\n"
1262 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1263 + "{v = new Date(y, m, d, h, i);}\n"
1264 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1265 + "{v = new Date(y, m, d, h);}\n"
1266 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1267 + "{v = new Date(y, m, d);}\n"
1268 + "else if (y >= 0 && m >= 0)\n"
1269 + "{v = new Date(y, m);}\n"
1270 + "else if (y >= 0)\n"
1271 + "{v = new Date(y);}\n"
1272 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1273 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1274 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1277 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1278 /** eval:var:zzzzzzzzzzzzz */
1283 Date.formatCodeToRegex = function(character, currentGroup) {
1284 switch (character) {
1288 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1291 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1292 s:"(\\d{1,2})"}; // day of month without leading zeroes
1295 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1296 s:"(\\d{2})"}; // day of month with leading zeroes
1300 s:"(?:" + Date.dayNames.join("|") + ")"};
1304 s:"(?:st|nd|rd|th)"};
1319 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1320 s:"(" + Date.monthNames.join("|") + ")"};
1323 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1324 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1327 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1328 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1331 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1332 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1343 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1347 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1348 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1352 c:"if (results[" + currentGroup + "] == 'am') {\n"
1353 + "if (h == 12) { h = 0; }\n"
1354 + "} else { if (h < 12) { h += 12; }}",
1358 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1359 + "if (h == 12) { h = 0; }\n"
1360 + "} else { if (h < 12) { h += 12; }}",
1365 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1366 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1370 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1371 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1374 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1378 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1383 "o = results[", currentGroup, "];\n",
1384 "var sn = o.substring(0,1);\n", // get + / - sign
1385 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1386 "var mn = o.substring(3,5) % 60;\n", // get minutes
1387 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1388 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1394 "o = results[", currentGroup, "];\n",
1395 "var sn = o.substring(0,1);\n",
1396 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1397 "var mn = o.substring(4,6) % 60;\n",
1398 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1399 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1405 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1408 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1409 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1410 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1414 s:String.escape(character)};
1419 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1420 * @return {String} The abbreviated timezone name (e.g. 'CST')
1422 Date.prototype.getTimezone = function() {
1423 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1427 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1428 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1430 Date.prototype.getGMTOffset = function() {
1431 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1432 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1433 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1437 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1438 * @return {String} 2-characters representing hours and 2-characters representing minutes
1439 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1441 Date.prototype.getGMTColonOffset = function() {
1442 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1443 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1445 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1449 * Get the numeric day number of the year, adjusted for leap year.
1450 * @return {Number} 0 through 364 (365 in leap years)
1452 Date.prototype.getDayOfYear = function() {
1454 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1455 for (var i = 0; i < this.getMonth(); ++i) {
1456 num += Date.daysInMonth[i];
1458 return num + this.getDate() - 1;
1462 * Get the string representation of the numeric week number of the year
1463 * (equivalent to the format specifier 'W').
1464 * @return {String} '00' through '52'
1466 Date.prototype.getWeekOfYear = function() {
1467 // Skip to Thursday of this week
1468 var now = this.getDayOfYear() + (4 - this.getDay());
1469 // Find the first Thursday of the year
1470 var jan1 = new Date(this.getFullYear(), 0, 1);
1471 var then = (7 - jan1.getDay() + 4);
1472 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1476 * Whether or not the current date is in a leap year.
1477 * @return {Boolean} True if the current date is in a leap year, else false
1479 Date.prototype.isLeapYear = function() {
1480 var year = this.getFullYear();
1481 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1485 * Get the first day of the current month, adjusted for leap year. The returned value
1486 * is the numeric day index within the week (0-6) which can be used in conjunction with
1487 * the {@link #monthNames} array to retrieve the textual day name.
1490 var dt = new Date('1/10/2007');
1491 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1493 * @return {Number} The day number (0-6)
1495 Date.prototype.getFirstDayOfMonth = function() {
1496 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1497 return (day < 0) ? (day + 7) : day;
1501 * Get the last day of the current month, adjusted for leap year. The returned value
1502 * is the numeric day index within the week (0-6) which can be used in conjunction with
1503 * the {@link #monthNames} array to retrieve the textual day name.
1506 var dt = new Date('1/10/2007');
1507 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1509 * @return {Number} The day number (0-6)
1511 Date.prototype.getLastDayOfMonth = function() {
1512 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1513 return (day < 0) ? (day + 7) : day;
1518 * Get the first date of this date's month
1521 Date.prototype.getFirstDateOfMonth = function() {
1522 return new Date(this.getFullYear(), this.getMonth(), 1);
1526 * Get the last date of this date's month
1529 Date.prototype.getLastDateOfMonth = function() {
1530 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1533 * Get the number of days in the current month, adjusted for leap year.
1534 * @return {Number} The number of days in the month
1536 Date.prototype.getDaysInMonth = function() {
1537 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1538 return Date.daysInMonth[this.getMonth()];
1542 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1543 * @return {String} 'st, 'nd', 'rd' or 'th'
1545 Date.prototype.getSuffix = function() {
1546 switch (this.getDate()) {
1563 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1566 * An array of textual month names.
1567 * Override these values for international dates, for example...
1568 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1587 * An array of textual day names.
1588 * Override these values for international dates, for example...
1589 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1605 Date.monthNumbers = {
1620 * Creates and returns a new Date instance with the exact same date value as the called instance.
1621 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1622 * variable will also be changed. When the intention is to create a new variable that will not
1623 * modify the original instance, you should create a clone.
1625 * Example of correctly cloning a date:
1628 var orig = new Date('10/1/2006');
1631 document.write(orig); //returns 'Thu Oct 05 2006'!
1634 var orig = new Date('10/1/2006');
1635 var copy = orig.clone();
1637 document.write(orig); //returns 'Thu Oct 01 2006'
1639 * @return {Date} The new Date instance
1641 Date.prototype.clone = function() {
1642 return new Date(this.getTime());
1646 * Clears any time information from this date
1647 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1648 @return {Date} this or the clone
1650 Date.prototype.clearTime = function(clone){
1652 return this.clone().clearTime();
1657 this.setMilliseconds(0);
1662 // safari setMonth is broken
1664 Date.brokenSetMonth = Date.prototype.setMonth;
1665 Date.prototype.setMonth = function(num){
1667 var n = Math.ceil(-num);
1668 var back_year = Math.ceil(n/12);
1669 var month = (n % 12) ? 12 - n % 12 : 0 ;
1670 this.setFullYear(this.getFullYear() - back_year);
1671 return Date.brokenSetMonth.call(this, month);
1673 return Date.brokenSetMonth.apply(this, arguments);
1678 /** Date interval constant
1682 /** Date interval constant
1686 /** Date interval constant
1690 /** Date interval constant
1694 /** Date interval constant
1698 /** Date interval constant
1702 /** Date interval constant
1708 * Provides a convenient method of performing basic date arithmetic. This method
1709 * does not modify the Date instance being called - it creates and returns
1710 * a new Date instance containing the resulting date value.
1715 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1716 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1718 //Negative values will subtract correctly:
1719 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1720 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1722 //You can even chain several calls together in one line!
1723 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1724 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1727 * @param {String} interval A valid date interval enum value
1728 * @param {Number} value The amount to add to the current date
1729 * @return {Date} The new Date instance
1731 Date.prototype.add = function(interval, value){
1732 var d = this.clone();
1733 if (!interval || value === 0) return d;
1734 switch(interval.toLowerCase()){
1736 d.setMilliseconds(this.getMilliseconds() + value);
1739 d.setSeconds(this.getSeconds() + value);
1742 d.setMinutes(this.getMinutes() + value);
1745 d.setHours(this.getHours() + value);
1748 d.setDate(this.getDate() + value);
1751 var day = this.getDate();
1753 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1756 d.setMonth(this.getMonth() + value);
1759 d.setFullYear(this.getFullYear() + value);
1766 * Ext JS Library 1.1.1
1767 * Copyright(c) 2006-2007, Ext JS, LLC.
1769 * Originally Released Under LGPL - original licence link has changed is not relivant.
1772 * <script type="text/javascript">
1776 getViewWidth : function(full) {
1777 return full ? this.getDocumentWidth() : this.getViewportWidth();
1780 getViewHeight : function(full) {
1781 return full ? this.getDocumentHeight() : this.getViewportHeight();
1784 getDocumentHeight: function() {
1785 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1786 return Math.max(scrollHeight, this.getViewportHeight());
1789 getDocumentWidth: function() {
1790 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1791 return Math.max(scrollWidth, this.getViewportWidth());
1794 getViewportHeight: function() {
1795 var height = self.innerHeight;
1796 var mode = document.compatMode;
1798 if ((mode || Roo.isIE) && !Roo.isOpera) {
1799 height = (mode == "CSS1Compat") ?
1800 document.documentElement.clientHeight :
1801 document.body.clientHeight;
1807 getViewportWidth: function() {
1808 var width = self.innerWidth;
1809 var mode = document.compatMode;
1811 if (mode || Roo.isIE) {
1812 width = (mode == "CSS1Compat") ?
1813 document.documentElement.clientWidth :
1814 document.body.clientWidth;
1819 isAncestor : function(p, c) {
1826 if (p.contains && !Roo.isSafari) {
1827 return p.contains(c);
1828 } else if (p.compareDocumentPosition) {
1829 return !!(p.compareDocumentPosition(c) & 16);
1831 var parent = c.parentNode;
1836 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1839 parent = parent.parentNode;
1845 getRegion : function(el) {
1846 return Roo.lib.Region.getRegion(el);
1849 getY : function(el) {
1850 return this.getXY(el)[1];
1853 getX : function(el) {
1854 return this.getXY(el)[0];
1857 getXY : function(el) {
1858 var p, pe, b, scroll, bd = document.body;
1859 el = Roo.getDom(el);
1860 var fly = Roo.lib.AnimBase.fly;
1861 if (el.getBoundingClientRect) {
1862 b = el.getBoundingClientRect();
1863 scroll = fly(document).getScroll();
1864 return [b.left + scroll.left, b.top + scroll.top];
1870 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1877 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1884 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1885 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1892 if (p != el && pe.getStyle('overflow') != 'visible') {
1900 if (Roo.isSafari && hasAbsolute) {
1905 if (Roo.isGecko && !hasAbsolute) {
1907 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1908 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1912 while (p && p != bd) {
1913 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1925 setXY : function(el, xy) {
1926 el = Roo.fly(el, '_setXY');
1928 var pts = el.translatePoints(xy);
1929 if (xy[0] !== false) {
1930 el.dom.style.left = pts.left + "px";
1932 if (xy[1] !== false) {
1933 el.dom.style.top = pts.top + "px";
1937 setX : function(el, x) {
1938 this.setXY(el, [x, false]);
1941 setY : function(el, y) {
1942 this.setXY(el, [false, y]);
1946 * Portions of this file are based on pieces of Yahoo User Interface Library
1947 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1948 * YUI licensed under the BSD License:
1949 * http://developer.yahoo.net/yui/license.txt
1950 * <script type="text/javascript">
1954 Roo.lib.Event = function() {
1955 var loadComplete = false;
1957 var unloadListeners = [];
1959 var onAvailStack = [];
1961 var lastError = null;
1974 startInterval: function() {
1975 if (!this._interval) {
1977 var callback = function() {
1978 self._tryPreloadAttach();
1980 this._interval = setInterval(callback, this.POLL_INTERVAL);
1985 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1986 onAvailStack.push({ id: p_id,
1989 override: p_override,
1990 checkReady: false });
1992 retryCount = this.POLL_RETRYS;
1993 this.startInterval();
1997 addListener: function(el, eventName, fn) {
1998 el = Roo.getDom(el);
2003 if ("unload" == eventName) {
2004 unloadListeners[unloadListeners.length] =
2005 [el, eventName, fn];
2009 var wrappedFn = function(e) {
2010 return fn(Roo.lib.Event.getEvent(e));
2013 var li = [el, eventName, fn, wrappedFn];
2015 var index = listeners.length;
2016 listeners[index] = li;
2018 this.doAdd(el, eventName, wrappedFn, false);
2024 removeListener: function(el, eventName, fn) {
2027 el = Roo.getDom(el);
2030 return this.purgeElement(el, false, eventName);
2034 if ("unload" == eventName) {
2036 for (i = 0,len = unloadListeners.length; i < len; i++) {
2037 var li = unloadListeners[i];
2040 li[1] == eventName &&
2042 unloadListeners.splice(i, 1);
2050 var cacheItem = null;
2053 var index = arguments[3];
2055 if ("undefined" == typeof index) {
2056 index = this._getCacheIndex(el, eventName, fn);
2060 cacheItem = listeners[index];
2063 if (!el || !cacheItem) {
2067 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2069 delete listeners[index][this.WFN];
2070 delete listeners[index][this.FN];
2071 listeners.splice(index, 1);
2078 getTarget: function(ev, resolveTextNode) {
2079 ev = ev.browserEvent || ev;
2080 var t = ev.target || ev.srcElement;
2081 return this.resolveTextNode(t);
2085 resolveTextNode: function(node) {
2086 if (Roo.isSafari && node && 3 == node.nodeType) {
2087 return node.parentNode;
2094 getPageX: function(ev) {
2095 ev = ev.browserEvent || ev;
2097 if (!x && 0 !== x) {
2098 x = ev.clientX || 0;
2101 x += this.getScroll()[1];
2109 getPageY: function(ev) {
2110 ev = ev.browserEvent || ev;
2112 if (!y && 0 !== y) {
2113 y = ev.clientY || 0;
2116 y += this.getScroll()[0];
2125 getXY: function(ev) {
2126 ev = ev.browserEvent || ev;
2127 return [this.getPageX(ev), this.getPageY(ev)];
2131 getRelatedTarget: function(ev) {
2132 ev = ev.browserEvent || ev;
2133 var t = ev.relatedTarget;
2135 if (ev.type == "mouseout") {
2137 } else if (ev.type == "mouseover") {
2142 return this.resolveTextNode(t);
2146 getTime: function(ev) {
2147 ev = ev.browserEvent || ev;
2149 var t = new Date().getTime();
2153 this.lastError = ex;
2162 stopEvent: function(ev) {
2163 this.stopPropagation(ev);
2164 this.preventDefault(ev);
2168 stopPropagation: function(ev) {
2169 ev = ev.browserEvent || ev;
2170 if (ev.stopPropagation) {
2171 ev.stopPropagation();
2173 ev.cancelBubble = true;
2178 preventDefault: function(ev) {
2179 ev = ev.browserEvent || ev;
2180 if(ev.preventDefault) {
2181 ev.preventDefault();
2183 ev.returnValue = false;
2188 getEvent: function(e) {
2189 var ev = e || window.event;
2191 var c = this.getEvent.caller;
2193 ev = c.arguments[0];
2194 if (ev && Event == ev.constructor) {
2204 getCharCode: function(ev) {
2205 ev = ev.browserEvent || ev;
2206 return ev.charCode || ev.keyCode || 0;
2210 _getCacheIndex: function(el, eventName, fn) {
2211 for (var i = 0,len = listeners.length; i < len; ++i) {
2212 var li = listeners[i];
2214 li[this.FN] == fn &&
2215 li[this.EL] == el &&
2216 li[this.TYPE] == eventName) {
2228 getEl: function(id) {
2229 return document.getElementById(id);
2233 clearCache: function() {
2237 _load: function(e) {
2238 loadComplete = true;
2239 var EU = Roo.lib.Event;
2243 EU.doRemove(window, "load", EU._load);
2248 _tryPreloadAttach: function() {
2257 var tryAgain = !loadComplete;
2259 tryAgain = (retryCount > 0);
2264 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2265 var item = onAvailStack[i];
2267 var el = this.getEl(item.id);
2270 if (!item.checkReady ||
2273 (document && document.body)) {
2276 if (item.override) {
2277 if (item.override === true) {
2280 scope = item.override;
2283 item.fn.call(scope, item.obj);
2284 onAvailStack[i] = null;
2287 notAvail.push(item);
2292 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2296 this.startInterval();
2298 clearInterval(this._interval);
2299 this._interval = null;
2302 this.locked = false;
2309 purgeElement: function(el, recurse, eventName) {
2310 var elListeners = this.getListeners(el, eventName);
2312 for (var i = 0,len = elListeners.length; i < len; ++i) {
2313 var l = elListeners[i];
2314 this.removeListener(el, l.type, l.fn);
2318 if (recurse && el && el.childNodes) {
2319 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2320 this.purgeElement(el.childNodes[i], recurse, eventName);
2326 getListeners: function(el, eventName) {
2327 var results = [], searchLists;
2329 searchLists = [listeners, unloadListeners];
2330 } else if (eventName == "unload") {
2331 searchLists = [unloadListeners];
2333 searchLists = [listeners];
2336 for (var j = 0; j < searchLists.length; ++j) {
2337 var searchList = searchLists[j];
2338 if (searchList && searchList.length > 0) {
2339 for (var i = 0,len = searchList.length; i < len; ++i) {
2340 var l = searchList[i];
2341 if (l && l[this.EL] === el &&
2342 (!eventName || eventName === l[this.TYPE])) {
2347 adjust: l[this.ADJ_SCOPE],
2355 return (results.length) ? results : null;
2359 _unload: function(e) {
2361 var EU = Roo.lib.Event, i, j, l, len, index;
2363 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2364 l = unloadListeners[i];
2367 if (l[EU.ADJ_SCOPE]) {
2368 if (l[EU.ADJ_SCOPE] === true) {
2371 scope = l[EU.ADJ_SCOPE];
2374 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2375 unloadListeners[i] = null;
2381 unloadListeners = null;
2383 if (listeners && listeners.length > 0) {
2384 j = listeners.length;
2387 l = listeners[index];
2389 EU.removeListener(l[EU.EL], l[EU.TYPE],
2399 EU.doRemove(window, "unload", EU._unload);
2404 getScroll: function() {
2405 var dd = document.documentElement, db = document.body;
2406 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2407 return [dd.scrollTop, dd.scrollLeft];
2409 return [db.scrollTop, db.scrollLeft];
2416 doAdd: function () {
2417 if (window.addEventListener) {
2418 return function(el, eventName, fn, capture) {
2419 el.addEventListener(eventName, fn, (capture));
2421 } else if (window.attachEvent) {
2422 return function(el, eventName, fn, capture) {
2423 el.attachEvent("on" + eventName, fn);
2432 doRemove: function() {
2433 if (window.removeEventListener) {
2434 return function (el, eventName, fn, capture) {
2435 el.removeEventListener(eventName, fn, (capture));
2437 } else if (window.detachEvent) {
2438 return function (el, eventName, fn) {
2439 el.detachEvent("on" + eventName, fn);
2451 var E = Roo.lib.Event;
2452 E.on = E.addListener;
2453 E.un = E.removeListener;
2455 if (document && document.body) {
2458 E.doAdd(window, "load", E._load);
2460 E.doAdd(window, "unload", E._unload);
2461 E._tryPreloadAttach();
2465 * Portions of this file are based on pieces of Yahoo User Interface Library
2466 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2467 * YUI licensed under the BSD License:
2468 * http://developer.yahoo.net/yui/license.txt
2469 * <script type="text/javascript">
2475 * @class Roo.lib.Ajax
2482 request : function(method, uri, cb, data, options) {
2484 var hs = options.headers;
2487 if(hs.hasOwnProperty(h)){
2488 this.initHeader(h, hs[h], false);
2492 if(options.xmlData){
2493 this.initHeader('Content-Type', 'text/xml', false);
2495 data = options.xmlData;
2499 return this.asyncRequest(method, uri, cb, data);
2502 serializeForm : function(form) {
2503 if(typeof form == 'string') {
2504 form = (document.getElementById(form) || document.forms[form]);
2507 var el, name, val, disabled, data = '', hasSubmit = false;
2508 for (var i = 0; i < form.elements.length; i++) {
2509 el = form.elements[i];
2510 disabled = form.elements[i].disabled;
2511 name = form.elements[i].name;
2512 val = form.elements[i].value;
2514 if (!disabled && name){
2518 case 'select-multiple':
2519 for (var j = 0; j < el.options.length; j++) {
2520 if (el.options[j].selected) {
2522 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2525 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2533 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2546 if(hasSubmit == false) {
2547 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2552 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2557 data = data.substr(0, data.length - 1);
2565 useDefaultHeader:true,
2567 defaultPostHeader:'application/x-www-form-urlencoded',
2569 useDefaultXhrHeader:true,
2571 defaultXhrHeader:'XMLHttpRequest',
2573 hasDefaultHeaders:true,
2585 setProgId:function(id)
2587 this.activeX.unshift(id);
2590 setDefaultPostHeader:function(b)
2592 this.useDefaultHeader = b;
2595 setDefaultXhrHeader:function(b)
2597 this.useDefaultXhrHeader = b;
2600 setPollingInterval:function(i)
2602 if (typeof i == 'number' && isFinite(i)) {
2603 this.pollInterval = i;
2607 createXhrObject:function(transactionId)
2613 http = new XMLHttpRequest();
2615 obj = { conn:http, tId:transactionId };
2619 for (var i = 0; i < this.activeX.length; ++i) {
2623 http = new ActiveXObject(this.activeX[i]);
2625 obj = { conn:http, tId:transactionId };
2638 getConnectionObject:function()
2641 var tId = this.transactionId;
2645 o = this.createXhrObject(tId);
2647 this.transactionId++;
2658 asyncRequest:function(method, uri, callback, postData)
2660 var o = this.getConnectionObject();
2666 o.conn.open(method, uri, true);
2668 if (this.useDefaultXhrHeader) {
2669 if (!this.defaultHeaders['X-Requested-With']) {
2670 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2674 if(postData && this.useDefaultHeader){
2675 this.initHeader('Content-Type', this.defaultPostHeader);
2678 if (this.hasDefaultHeaders || this.hasHeaders) {
2682 this.handleReadyState(o, callback);
2683 o.conn.send(postData || null);
2689 handleReadyState:function(o, callback)
2693 if (callback && callback.timeout) {
2694 this.timeout[o.tId] = window.setTimeout(function() {
2695 oConn.abort(o, callback, true);
2696 }, callback.timeout);
2699 this.poll[o.tId] = window.setInterval(
2701 if (o.conn && o.conn.readyState == 4) {
2702 window.clearInterval(oConn.poll[o.tId]);
2703 delete oConn.poll[o.tId];
2705 if(callback && callback.timeout) {
2706 window.clearTimeout(oConn.timeout[o.tId]);
2707 delete oConn.timeout[o.tId];
2710 oConn.handleTransactionResponse(o, callback);
2713 , this.pollInterval);
2716 handleTransactionResponse:function(o, callback, isAbort)
2720 this.releaseObject(o);
2724 var httpStatus, responseObject;
2728 if (o.conn.status !== undefined && o.conn.status != 0) {
2729 httpStatus = o.conn.status;
2741 if (httpStatus >= 200 && httpStatus < 300) {
2742 responseObject = this.createResponseObject(o, callback.argument);
2743 if (callback.success) {
2744 if (!callback.scope) {
2745 callback.success(responseObject);
2750 callback.success.apply(callback.scope, [responseObject]);
2755 switch (httpStatus) {
2763 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2764 if (callback.failure) {
2765 if (!callback.scope) {
2766 callback.failure(responseObject);
2769 callback.failure.apply(callback.scope, [responseObject]);
2774 responseObject = this.createResponseObject(o, callback.argument);
2775 if (callback.failure) {
2776 if (!callback.scope) {
2777 callback.failure(responseObject);
2780 callback.failure.apply(callback.scope, [responseObject]);
2786 this.releaseObject(o);
2787 responseObject = null;
2790 createResponseObject:function(o, callbackArg)
2797 var headerStr = o.conn.getAllResponseHeaders();
2798 var header = headerStr.split('\n');
2799 for (var i = 0; i < header.length; i++) {
2800 var delimitPos = header[i].indexOf(':');
2801 if (delimitPos != -1) {
2802 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2810 obj.status = o.conn.status;
2811 obj.statusText = o.conn.statusText;
2812 obj.getResponseHeader = headerObj;
2813 obj.getAllResponseHeaders = headerStr;
2814 obj.responseText = o.conn.responseText;
2815 obj.responseXML = o.conn.responseXML;
2817 if (typeof callbackArg !== undefined) {
2818 obj.argument = callbackArg;
2824 createExceptionObject:function(tId, callbackArg, isAbort)
2827 var COMM_ERROR = 'communication failure';
2828 var ABORT_CODE = -1;
2829 var ABORT_ERROR = 'transaction aborted';
2835 obj.status = ABORT_CODE;
2836 obj.statusText = ABORT_ERROR;
2839 obj.status = COMM_CODE;
2840 obj.statusText = COMM_ERROR;
2844 obj.argument = callbackArg;
2850 initHeader:function(label, value, isDefault)
2852 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2854 if (headerObj[label] === undefined) {
2855 headerObj[label] = value;
2860 headerObj[label] = value + "," + headerObj[label];
2864 this.hasDefaultHeaders = true;
2867 this.hasHeaders = true;
2872 setHeader:function(o)
2874 if (this.hasDefaultHeaders) {
2875 for (var prop in this.defaultHeaders) {
2876 if (this.defaultHeaders.hasOwnProperty(prop)) {
2877 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2882 if (this.hasHeaders) {
2883 for (var prop in this.headers) {
2884 if (this.headers.hasOwnProperty(prop)) {
2885 o.conn.setRequestHeader(prop, this.headers[prop]);
2889 this.hasHeaders = false;
2893 resetDefaultHeaders:function() {
2894 delete this.defaultHeaders;
2895 this.defaultHeaders = {};
2896 this.hasDefaultHeaders = false;
2899 abort:function(o, callback, isTimeout)
2901 if(this.isCallInProgress(o)) {
2903 window.clearInterval(this.poll[o.tId]);
2904 delete this.poll[o.tId];
2906 delete this.timeout[o.tId];
2909 this.handleTransactionResponse(o, callback, true);
2919 isCallInProgress:function(o)
2922 return o.conn.readyState != 4 && o.conn.readyState != 0;
2931 releaseObject:function(o)
2940 'MSXML2.XMLHTTP.3.0',
2948 * Portions of this file are based on pieces of Yahoo User Interface Library
2949 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2950 * YUI licensed under the BSD License:
2951 * http://developer.yahoo.net/yui/license.txt
2952 * <script type="text/javascript">
2956 Roo.lib.Region = function(t, r, b, l) {
2966 Roo.lib.Region.prototype = {
2967 contains : function(region) {
2968 return ( region.left >= this.left &&
2969 region.right <= this.right &&
2970 region.top >= this.top &&
2971 region.bottom <= this.bottom );
2975 getArea : function() {
2976 return ( (this.bottom - this.top) * (this.right - this.left) );
2979 intersect : function(region) {
2980 var t = Math.max(this.top, region.top);
2981 var r = Math.min(this.right, region.right);
2982 var b = Math.min(this.bottom, region.bottom);
2983 var l = Math.max(this.left, region.left);
2985 if (b >= t && r >= l) {
2986 return new Roo.lib.Region(t, r, b, l);
2991 union : function(region) {
2992 var t = Math.min(this.top, region.top);
2993 var r = Math.max(this.right, region.right);
2994 var b = Math.max(this.bottom, region.bottom);
2995 var l = Math.min(this.left, region.left);
2997 return new Roo.lib.Region(t, r, b, l);
3000 adjust : function(t, l, b, r) {
3009 Roo.lib.Region.getRegion = function(el) {
3010 var p = Roo.lib.Dom.getXY(el);
3013 var r = p[0] + el.offsetWidth;
3014 var b = p[1] + el.offsetHeight;
3017 return new Roo.lib.Region(t, r, b, l);
3020 * Portions of this file are based on pieces of Yahoo User Interface Library
3021 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3022 * YUI licensed under the BSD License:
3023 * http://developer.yahoo.net/yui/license.txt
3024 * <script type="text/javascript">
3027 //@@dep Roo.lib.Region
3030 Roo.lib.Point = function(x, y) {
3031 if (x instanceof Array) {
3035 this.x = this.right = this.left = this[0] = x;
3036 this.y = this.top = this.bottom = this[1] = y;
3039 Roo.lib.Point.prototype = new Roo.lib.Region();
3041 * Portions of this file are based on pieces of Yahoo User Interface Library
3042 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3043 * YUI licensed under the BSD License:
3044 * http://developer.yahoo.net/yui/license.txt
3045 * <script type="text/javascript">
3052 scroll : function(el, args, duration, easing, cb, scope) {
3053 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3056 motion : function(el, args, duration, easing, cb, scope) {
3057 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3060 color : function(el, args, duration, easing, cb, scope) {
3061 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3064 run : function(el, args, duration, easing, cb, scope, type) {
3065 type = type || Roo.lib.AnimBase;
3066 if (typeof easing == "string") {
3067 easing = Roo.lib.Easing[easing];
3069 var anim = new type(el, args, duration, easing);
3070 anim.animateX(function() {
3071 Roo.callback(cb, scope);
3077 * Portions of this file are based on pieces of Yahoo User Interface Library
3078 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3079 * YUI licensed under the BSD License:
3080 * http://developer.yahoo.net/yui/license.txt
3081 * <script type="text/javascript">
3089 if (!libFlyweight) {
3090 libFlyweight = new Roo.Element.Flyweight();
3092 libFlyweight.dom = el;
3093 return libFlyweight;
3096 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3100 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3102 this.init(el, attributes, duration, method);
3106 Roo.lib.AnimBase.fly = fly;
3110 Roo.lib.AnimBase.prototype = {
3112 toString: function() {
3113 var el = this.getEl();
3114 var id = el.id || el.tagName;
3115 return ("Anim " + id);
3119 noNegatives: /width|height|opacity|padding/i,
3120 offsetAttribute: /^((width|height)|(top|left))$/,
3121 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3122 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3126 doMethod: function(attr, start, end) {
3127 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3131 setAttribute: function(attr, val, unit) {
3132 if (this.patterns.noNegatives.test(attr)) {
3133 val = (val > 0) ? val : 0;
3136 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3140 getAttribute: function(attr) {
3141 var el = this.getEl();
3142 var val = fly(el).getStyle(attr);
3144 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3145 return parseFloat(val);
3148 var a = this.patterns.offsetAttribute.exec(attr) || [];
3149 var pos = !!( a[3] );
3150 var box = !!( a[2] );
3153 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3154 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3163 getDefaultUnit: function(attr) {
3164 if (this.patterns.defaultUnit.test(attr)) {
3171 animateX : function(callback, scope) {
3172 var f = function() {
3173 this.onComplete.removeListener(f);
3174 if (typeof callback == "function") {
3175 callback.call(scope || this, this);
3178 this.onComplete.addListener(f, this);
3183 setRuntimeAttribute: function(attr) {
3186 var attributes = this.attributes;
3188 this.runtimeAttributes[attr] = {};
3190 var isset = function(prop) {
3191 return (typeof prop !== 'undefined');
3194 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3198 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3201 if (isset(attributes[attr]['to'])) {
3202 end = attributes[attr]['to'];
3203 } else if (isset(attributes[attr]['by'])) {
3204 if (start.constructor == Array) {
3206 for (var i = 0, len = start.length; i < len; ++i) {
3207 end[i] = start[i] + attributes[attr]['by'][i];
3210 end = start + attributes[attr]['by'];
3214 this.runtimeAttributes[attr].start = start;
3215 this.runtimeAttributes[attr].end = end;
3218 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3222 init: function(el, attributes, duration, method) {
3224 var isAnimated = false;
3227 var startTime = null;
3230 var actualFrames = 0;
3233 el = Roo.getDom(el);
3236 this.attributes = attributes || {};
3239 this.duration = duration || 1;
3242 this.method = method || Roo.lib.Easing.easeNone;
3245 this.useSeconds = true;
3248 this.currentFrame = 0;
3251 this.totalFrames = Roo.lib.AnimMgr.fps;
3254 this.getEl = function() {
3259 this.isAnimated = function() {
3264 this.getStartTime = function() {
3268 this.runtimeAttributes = {};
3271 this.animate = function() {
3272 if (this.isAnimated()) {
3276 this.currentFrame = 0;
3278 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3280 Roo.lib.AnimMgr.registerElement(this);
3284 this.stop = function(finish) {
3286 this.currentFrame = this.totalFrames;
3287 this._onTween.fire();
3289 Roo.lib.AnimMgr.stop(this);
3292 var onStart = function() {
3293 this.onStart.fire();
3295 this.runtimeAttributes = {};
3296 for (var attr in this.attributes) {
3297 this.setRuntimeAttribute(attr);
3302 startTime = new Date();
3306 var onTween = function() {
3308 duration: new Date() - this.getStartTime(),
3309 currentFrame: this.currentFrame
3312 data.toString = function() {
3314 'duration: ' + data.duration +
3315 ', currentFrame: ' + data.currentFrame
3319 this.onTween.fire(data);
3321 var runtimeAttributes = this.runtimeAttributes;
3323 for (var attr in runtimeAttributes) {
3324 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3330 var onComplete = function() {
3331 var actual_duration = (new Date() - startTime) / 1000 ;
3334 duration: actual_duration,
3335 frames: actualFrames,
3336 fps: actualFrames / actual_duration
3339 data.toString = function() {
3341 'duration: ' + data.duration +
3342 ', frames: ' + data.frames +
3343 ', fps: ' + data.fps
3349 this.onComplete.fire(data);
3353 this._onStart = new Roo.util.Event(this);
3354 this.onStart = new Roo.util.Event(this);
3355 this.onTween = new Roo.util.Event(this);
3356 this._onTween = new Roo.util.Event(this);
3357 this.onComplete = new Roo.util.Event(this);
3358 this._onComplete = new Roo.util.Event(this);
3359 this._onStart.addListener(onStart);
3360 this._onTween.addListener(onTween);
3361 this._onComplete.addListener(onComplete);
3366 * Portions of this file are based on pieces of Yahoo User Interface Library
3367 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3368 * YUI licensed under the BSD License:
3369 * http://developer.yahoo.net/yui/license.txt
3370 * <script type="text/javascript">
3374 Roo.lib.AnimMgr = new function() {
3391 this.registerElement = function(tween) {
3392 queue[queue.length] = tween;
3394 tween._onStart.fire();
3399 this.unRegister = function(tween, index) {
3400 tween._onComplete.fire();
3401 index = index || getIndex(tween);
3403 queue.splice(index, 1);
3407 if (tweenCount <= 0) {
3413 this.start = function() {
3414 if (thread === null) {
3415 thread = setInterval(this.run, this.delay);
3420 this.stop = function(tween) {
3422 clearInterval(thread);
3424 for (var i = 0, len = queue.length; i < len; ++i) {
3425 if (queue[0].isAnimated()) {
3426 this.unRegister(queue[0], 0);
3435 this.unRegister(tween);
3440 this.run = function() {
3441 for (var i = 0, len = queue.length; i < len; ++i) {
3442 var tween = queue[i];
3443 if (!tween || !tween.isAnimated()) {
3447 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3449 tween.currentFrame += 1;
3451 if (tween.useSeconds) {
3452 correctFrame(tween);
3454 tween._onTween.fire();
3457 Roo.lib.AnimMgr.stop(tween, i);
3462 var getIndex = function(anim) {
3463 for (var i = 0, len = queue.length; i < len; ++i) {
3464 if (queue[i] == anim) {
3472 var correctFrame = function(tween) {
3473 var frames = tween.totalFrames;
3474 var frame = tween.currentFrame;
3475 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3476 var elapsed = (new Date() - tween.getStartTime());
3479 if (elapsed < tween.duration * 1000) {
3480 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3482 tweak = frames - (frame + 1);
3484 if (tweak > 0 && isFinite(tweak)) {
3485 if (tween.currentFrame + tweak >= frames) {
3486 tweak = frames - (frame + 1);
3489 tween.currentFrame += tweak;
3493 * Portions of this file are based on pieces of Yahoo User Interface Library
3494 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3495 * YUI licensed under the BSD License:
3496 * http://developer.yahoo.net/yui/license.txt
3497 * <script type="text/javascript">
3500 Roo.lib.Bezier = new function() {
3502 this.getPosition = function(points, t) {
3503 var n = points.length;
3506 for (var i = 0; i < n; ++i) {
3507 tmp[i] = [points[i][0], points[i][1]];
3510 for (var j = 1; j < n; ++j) {
3511 for (i = 0; i < n - j; ++i) {
3512 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3513 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3517 return [ tmp[0][0], tmp[0][1] ];
3521 * Portions of this file are based on pieces of Yahoo User Interface Library
3522 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3523 * YUI licensed under the BSD License:
3524 * http://developer.yahoo.net/yui/license.txt
3525 * <script type="text/javascript">
3530 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3531 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3534 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3536 var fly = Roo.lib.AnimBase.fly;
3538 var superclass = Y.ColorAnim.superclass;
3539 var proto = Y.ColorAnim.prototype;
3541 proto.toString = function() {
3542 var el = this.getEl();
3543 var id = el.id || el.tagName;
3544 return ("ColorAnim " + id);
3547 proto.patterns.color = /color$/i;
3548 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3549 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3550 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3551 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3554 proto.parseColor = function(s) {
3555 if (s.length == 3) {
3559 var c = this.patterns.hex.exec(s);
3560 if (c && c.length == 4) {
3561 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3564 c = this.patterns.rgb.exec(s);
3565 if (c && c.length == 4) {
3566 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3569 c = this.patterns.hex3.exec(s);
3570 if (c && c.length == 4) {
3571 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3576 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3577 proto.getAttribute = function(attr) {
3578 var el = this.getEl();
3579 if (this.patterns.color.test(attr)) {
3580 var val = fly(el).getStyle(attr);
3582 if (this.patterns.transparent.test(val)) {
3583 var parent = el.parentNode;
3584 val = fly(parent).getStyle(attr);
3586 while (parent && this.patterns.transparent.test(val)) {
3587 parent = parent.parentNode;
3588 val = fly(parent).getStyle(attr);
3589 if (parent.tagName.toUpperCase() == 'HTML') {
3595 val = superclass.getAttribute.call(this, attr);
3600 proto.getAttribute = function(attr) {
3601 var el = this.getEl();
3602 if (this.patterns.color.test(attr)) {
3603 var val = fly(el).getStyle(attr);
3605 if (this.patterns.transparent.test(val)) {
3606 var parent = el.parentNode;
3607 val = fly(parent).getStyle(attr);
3609 while (parent && this.patterns.transparent.test(val)) {
3610 parent = parent.parentNode;
3611 val = fly(parent).getStyle(attr);
3612 if (parent.tagName.toUpperCase() == 'HTML') {
3618 val = superclass.getAttribute.call(this, attr);
3624 proto.doMethod = function(attr, start, end) {
3627 if (this.patterns.color.test(attr)) {
3629 for (var i = 0, len = start.length; i < len; ++i) {
3630 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3633 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3636 val = superclass.doMethod.call(this, attr, start, end);
3642 proto.setRuntimeAttribute = function(attr) {
3643 superclass.setRuntimeAttribute.call(this, attr);
3645 if (this.patterns.color.test(attr)) {
3646 var attributes = this.attributes;
3647 var start = this.parseColor(this.runtimeAttributes[attr].start);
3648 var end = this.parseColor(this.runtimeAttributes[attr].end);
3650 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3651 end = this.parseColor(attributes[attr].by);
3653 for (var i = 0, len = start.length; i < len; ++i) {
3654 end[i] = start[i] + end[i];
3658 this.runtimeAttributes[attr].start = start;
3659 this.runtimeAttributes[attr].end = end;
3665 * Portions of this file are based on pieces of Yahoo User Interface Library
3666 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3667 * YUI licensed under the BSD License:
3668 * http://developer.yahoo.net/yui/license.txt
3669 * <script type="text/javascript">
3675 easeNone: function (t, b, c, d) {
3676 return c * t / d + b;
3680 easeIn: function (t, b, c, d) {
3681 return c * (t /= d) * t + b;
3685 easeOut: function (t, b, c, d) {
3686 return -c * (t /= d) * (t - 2) + b;
3690 easeBoth: function (t, b, c, d) {
3691 if ((t /= d / 2) < 1) {
3692 return c / 2 * t * t + b;
3695 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3699 easeInStrong: function (t, b, c, d) {
3700 return c * (t /= d) * t * t * t + b;
3704 easeOutStrong: function (t, b, c, d) {
3705 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3709 easeBothStrong: function (t, b, c, d) {
3710 if ((t /= d / 2) < 1) {
3711 return c / 2 * t * t * t * t + b;
3714 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3719 elasticIn: function (t, b, c, d, a, p) {
3723 if ((t /= d) == 1) {
3730 if (!a || a < Math.abs(c)) {
3735 var s = p / (2 * Math.PI) * Math.asin(c / a);
3738 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3742 elasticOut: function (t, b, c, d, a, p) {
3746 if ((t /= d) == 1) {
3753 if (!a || a < Math.abs(c)) {
3758 var s = p / (2 * Math.PI) * Math.asin(c / a);
3761 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3765 elasticBoth: function (t, b, c, d, a, p) {
3770 if ((t /= d / 2) == 2) {
3778 if (!a || a < Math.abs(c)) {
3783 var s = p / (2 * Math.PI) * Math.asin(c / a);
3787 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3788 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3790 return a * Math.pow(2, -10 * (t -= 1)) *
3791 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3796 backIn: function (t, b, c, d, s) {
3797 if (typeof s == 'undefined') {
3800 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3804 backOut: function (t, b, c, d, s) {
3805 if (typeof s == 'undefined') {
3808 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3812 backBoth: function (t, b, c, d, s) {
3813 if (typeof s == 'undefined') {
3817 if ((t /= d / 2 ) < 1) {
3818 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3820 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3824 bounceIn: function (t, b, c, d) {
3825 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3829 bounceOut: function (t, b, c, d) {
3830 if ((t /= d) < (1 / 2.75)) {
3831 return c * (7.5625 * t * t) + b;
3832 } else if (t < (2 / 2.75)) {
3833 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3834 } else if (t < (2.5 / 2.75)) {
3835 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3837 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3841 bounceBoth: function (t, b, c, d) {
3843 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3845 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3848 * Portions of this file are based on pieces of Yahoo User Interface Library
3849 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3850 * YUI licensed under the BSD License:
3851 * http://developer.yahoo.net/yui/license.txt
3852 * <script type="text/javascript">
3856 Roo.lib.Motion = function(el, attributes, duration, method) {
3858 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3862 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3866 var superclass = Y.Motion.superclass;
3867 var proto = Y.Motion.prototype;
3869 proto.toString = function() {
3870 var el = this.getEl();
3871 var id = el.id || el.tagName;
3872 return ("Motion " + id);
3875 proto.patterns.points = /^points$/i;
3877 proto.setAttribute = function(attr, val, unit) {
3878 if (this.patterns.points.test(attr)) {
3879 unit = unit || 'px';
3880 superclass.setAttribute.call(this, 'left', val[0], unit);
3881 superclass.setAttribute.call(this, 'top', val[1], unit);
3883 superclass.setAttribute.call(this, attr, val, unit);
3887 proto.getAttribute = function(attr) {
3888 if (this.patterns.points.test(attr)) {
3890 superclass.getAttribute.call(this, 'left'),
3891 superclass.getAttribute.call(this, 'top')
3894 val = superclass.getAttribute.call(this, attr);
3900 proto.doMethod = function(attr, start, end) {
3903 if (this.patterns.points.test(attr)) {
3904 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3905 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3907 val = superclass.doMethod.call(this, attr, start, end);
3912 proto.setRuntimeAttribute = function(attr) {
3913 if (this.patterns.points.test(attr)) {
3914 var el = this.getEl();
3915 var attributes = this.attributes;
3917 var control = attributes['points']['control'] || [];
3921 if (control.length > 0 && !(control[0] instanceof Array)) {
3922 control = [control];
3925 for (i = 0,len = control.length; i < len; ++i) {
3926 tmp[i] = control[i];
3931 Roo.fly(el).position();
3933 if (isset(attributes['points']['from'])) {
3934 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3937 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3940 start = this.getAttribute('points');
3943 if (isset(attributes['points']['to'])) {
3944 end = translateValues.call(this, attributes['points']['to'], start);
3946 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3947 for (i = 0,len = control.length; i < len; ++i) {
3948 control[i] = translateValues.call(this, control[i], start);
3952 } else if (isset(attributes['points']['by'])) {
3953 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3955 for (i = 0,len = control.length; i < len; ++i) {
3956 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3960 this.runtimeAttributes[attr] = [start];
3962 if (control.length > 0) {
3963 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3966 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3969 superclass.setRuntimeAttribute.call(this, attr);
3973 var translateValues = function(val, start) {
3974 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3975 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3980 var isset = function(prop) {
3981 return (typeof prop !== 'undefined');
3985 * Portions of this file are based on pieces of Yahoo User Interface Library
3986 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3987 * YUI licensed under the BSD License:
3988 * http://developer.yahoo.net/yui/license.txt
3989 * <script type="text/javascript">
3993 Roo.lib.Scroll = function(el, attributes, duration, method) {
3995 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3999 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4003 var superclass = Y.Scroll.superclass;
4004 var proto = Y.Scroll.prototype;
4006 proto.toString = function() {
4007 var el = this.getEl();
4008 var id = el.id || el.tagName;
4009 return ("Scroll " + id);
4012 proto.doMethod = function(attr, start, end) {
4015 if (attr == 'scroll') {
4017 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4018 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4022 val = superclass.doMethod.call(this, attr, start, end);
4027 proto.getAttribute = function(attr) {
4029 var el = this.getEl();
4031 if (attr == 'scroll') {
4032 val = [ el.scrollLeft, el.scrollTop ];
4034 val = superclass.getAttribute.call(this, attr);
4040 proto.setAttribute = function(attr, val, unit) {
4041 var el = this.getEl();
4043 if (attr == 'scroll') {
4044 el.scrollLeft = val[0];
4045 el.scrollTop = val[1];
4047 superclass.setAttribute.call(this, attr, val, unit);
4053 * Ext JS Library 1.1.1
4054 * Copyright(c) 2006-2007, Ext JS, LLC.
4056 * Originally Released Under LGPL - original licence link has changed is not relivant.
4059 * <script type="text/javascript">
4063 // nasty IE9 hack - what a pile of crap that is..
4065 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4066 Range.prototype.createContextualFragment = function (html) {
4067 var doc = window.document;
4068 var container = doc.createElement("div");
4069 container.innerHTML = html;
4070 var frag = doc.createDocumentFragment(), n;
4071 while ((n = container.firstChild)) {
4072 frag.appendChild(n);
4079 * @class Roo.DomHelper
4080 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4081 * 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>.
4084 Roo.DomHelper = function(){
4085 var tempTableEl = null;
4086 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4087 var tableRe = /^table|tbody|tr|td$/i;
4089 // build as innerHTML where available
4091 var createHtml = function(o){
4092 if(typeof o == 'string'){
4101 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4102 if(attr == "style"){
4104 if(typeof s == "function"){
4107 if(typeof s == "string"){
4108 b += ' style="' + s + '"';
4109 }else if(typeof s == "object"){
4112 if(typeof s[key] != "function"){
4113 b += key + ":" + s[key] + ";";
4120 b += ' class="' + o["cls"] + '"';
4121 }else if(attr == "htmlFor"){
4122 b += ' for="' + o["htmlFor"] + '"';
4124 b += " " + attr + '="' + o[attr] + '"';
4128 if(emptyTags.test(o.tag)){
4132 var cn = o.children || o.cn;
4134 //http://bugs.kde.org/show_bug.cgi?id=71506
4135 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4136 for(var i = 0, len = cn.length; i < len; i++) {
4137 b += createHtml(cn[i], b);
4140 b += createHtml(cn, b);
4146 b += "</" + o.tag + ">";
4153 var createDom = function(o, parentNode){
4155 // defininition craeted..
4157 if (o.ns && o.ns != 'html') {
4159 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4160 xmlns[o.ns] = o.xmlns;
4163 if (typeof(xmlns[o.ns]) == 'undefined') {
4164 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4170 if (typeof(o) == 'string') {
4171 return parentNode.appendChild(document.createTextNode(o));
4173 o.tag = o.tag || div;
4174 if (o.ns && Roo.isIE) {
4176 o.tag = o.ns + ':' + o.tag;
4179 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4180 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4183 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4184 attr == "style" || typeof o[attr] == "function") continue;
4186 if(attr=="cls" && Roo.isIE){
4187 el.className = o["cls"];
4189 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4190 else el[attr] = o[attr];
4193 Roo.DomHelper.applyStyles(el, o.style);
4194 var cn = o.children || o.cn;
4196 //http://bugs.kde.org/show_bug.cgi?id=71506
4197 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4198 for(var i = 0, len = cn.length; i < len; i++) {
4199 createDom(cn[i], el);
4206 el.innerHTML = o.html;
4209 parentNode.appendChild(el);
4214 var ieTable = function(depth, s, h, e){
4215 tempTableEl.innerHTML = [s, h, e].join('');
4216 var i = -1, el = tempTableEl;
4223 // kill repeat to save bytes
4227 tbe = '</tbody>'+te,
4233 * Nasty code for IE's broken table implementation
4235 var insertIntoTable = function(tag, where, el, html){
4237 tempTableEl = document.createElement('div');
4242 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4245 if(where == 'beforebegin'){
4249 before = el.nextSibling;
4252 node = ieTable(4, trs, html, tre);
4254 else if(tag == 'tr'){
4255 if(where == 'beforebegin'){
4258 node = ieTable(3, tbs, html, tbe);
4259 } else if(where == 'afterend'){
4260 before = el.nextSibling;
4262 node = ieTable(3, tbs, html, tbe);
4263 } else{ // INTO a TR
4264 if(where == 'afterbegin'){
4265 before = el.firstChild;
4267 node = ieTable(4, trs, html, tre);
4269 } else if(tag == 'tbody'){
4270 if(where == 'beforebegin'){
4273 node = ieTable(2, ts, html, te);
4274 } else if(where == 'afterend'){
4275 before = el.nextSibling;
4277 node = ieTable(2, ts, html, te);
4279 if(where == 'afterbegin'){
4280 before = el.firstChild;
4282 node = ieTable(3, tbs, html, tbe);
4285 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4288 if(where == 'afterbegin'){
4289 before = el.firstChild;
4291 node = ieTable(2, ts, html, te);
4293 el.insertBefore(node, before);
4298 /** True to force the use of DOM instead of html fragments @type Boolean */
4302 * Returns the markup for the passed Element(s) config
4303 * @param {Object} o The Dom object spec (and children)
4306 markup : function(o){
4307 return createHtml(o);
4311 * Applies a style specification to an element
4312 * @param {String/HTMLElement} el The element to apply styles to
4313 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4314 * a function which returns such a specification.
4316 applyStyles : function(el, styles){
4319 if(typeof styles == "string"){
4320 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4322 while ((matches = re.exec(styles)) != null){
4323 el.setStyle(matches[1], matches[2]);
4325 }else if (typeof styles == "object"){
4326 for (var style in styles){
4327 el.setStyle(style, styles[style]);
4329 }else if (typeof styles == "function"){
4330 Roo.DomHelper.applyStyles(el, styles.call());
4336 * Inserts an HTML fragment into the Dom
4337 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4338 * @param {HTMLElement} el The context element
4339 * @param {String} html The HTML fragmenet
4340 * @return {HTMLElement} The new node
4342 insertHtml : function(where, el, html){
4343 where = where.toLowerCase();
4344 if(el.insertAdjacentHTML){
4345 if(tableRe.test(el.tagName)){
4347 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4353 el.insertAdjacentHTML('BeforeBegin', html);
4354 return el.previousSibling;
4356 el.insertAdjacentHTML('AfterBegin', html);
4357 return el.firstChild;
4359 el.insertAdjacentHTML('BeforeEnd', html);
4360 return el.lastChild;
4362 el.insertAdjacentHTML('AfterEnd', html);
4363 return el.nextSibling;
4365 throw 'Illegal insertion point -> "' + where + '"';
4367 var range = el.ownerDocument.createRange();
4371 range.setStartBefore(el);
4372 frag = range.createContextualFragment(html);
4373 el.parentNode.insertBefore(frag, el);
4374 return el.previousSibling;
4377 range.setStartBefore(el.firstChild);
4378 frag = range.createContextualFragment(html);
4379 el.insertBefore(frag, el.firstChild);
4380 return el.firstChild;
4382 el.innerHTML = html;
4383 return el.firstChild;
4387 range.setStartAfter(el.lastChild);
4388 frag = range.createContextualFragment(html);
4389 el.appendChild(frag);
4390 return el.lastChild;
4392 el.innerHTML = html;
4393 return el.lastChild;
4396 range.setStartAfter(el);
4397 frag = range.createContextualFragment(html);
4398 el.parentNode.insertBefore(frag, el.nextSibling);
4399 return el.nextSibling;
4401 throw 'Illegal insertion point -> "' + where + '"';
4405 * Creates new Dom element(s) and inserts them before el
4406 * @param {String/HTMLElement/Element} el The context element
4407 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4408 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4409 * @return {HTMLElement/Roo.Element} The new node
4411 insertBefore : function(el, o, returnElement){
4412 return this.doInsert(el, o, returnElement, "beforeBegin");
4416 * Creates new Dom element(s) and inserts them after el
4417 * @param {String/HTMLElement/Element} el The context element
4418 * @param {Object} o The Dom object spec (and children)
4419 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4420 * @return {HTMLElement/Roo.Element} The new node
4422 insertAfter : function(el, o, returnElement){
4423 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4427 * Creates new Dom element(s) and inserts them as the first child of el
4428 * @param {String/HTMLElement/Element} el The context element
4429 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4430 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4431 * @return {HTMLElement/Roo.Element} The new node
4433 insertFirst : function(el, o, returnElement){
4434 return this.doInsert(el, o, returnElement, "afterBegin");
4438 doInsert : function(el, o, returnElement, pos, sibling){
4439 el = Roo.getDom(el);
4441 if(this.useDom || o.ns){
4442 newNode = createDom(o, null);
4443 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4445 var html = createHtml(o);
4446 newNode = this.insertHtml(pos, el, html);
4448 return returnElement ? Roo.get(newNode, true) : newNode;
4452 * Creates new Dom element(s) and appends them to el
4453 * @param {String/HTMLElement/Element} el The context element
4454 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4455 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4456 * @return {HTMLElement/Roo.Element} The new node
4458 append : function(el, o, returnElement){
4459 el = Roo.getDom(el);
4461 if(this.useDom || o.ns){
4462 newNode = createDom(o, null);
4463 el.appendChild(newNode);
4465 var html = createHtml(o);
4466 newNode = this.insertHtml("beforeEnd", el, html);
4468 return returnElement ? Roo.get(newNode, true) : newNode;
4472 * Creates new Dom element(s) and overwrites the contents of el with them
4473 * @param {String/HTMLElement/Element} el The context element
4474 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4475 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4476 * @return {HTMLElement/Roo.Element} The new node
4478 overwrite : function(el, o, returnElement){
4479 el = Roo.getDom(el);
4482 while (el.childNodes.length) {
4483 el.removeChild(el.firstChild);
4487 el.innerHTML = createHtml(o);
4490 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4494 * Creates a new Roo.DomHelper.Template from the Dom object spec
4495 * @param {Object} o The Dom object spec (and children)
4496 * @return {Roo.DomHelper.Template} The new template
4498 createTemplate : function(o){
4499 var html = createHtml(o);
4500 return new Roo.Template(html);
4506 * Ext JS Library 1.1.1
4507 * Copyright(c) 2006-2007, Ext JS, LLC.
4509 * Originally Released Under LGPL - original licence link has changed is not relivant.
4512 * <script type="text/javascript">
4516 * @class Roo.Template
4517 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4518 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4521 var t = new Roo.Template({
4522 html : '<div name="{id}">' +
4523 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4525 myformat: function (value, allValues) {
4526 return 'XX' + value;
4529 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4531 * 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>.
4533 * @param {Object} cfg - Configuration object.
4535 Roo.Template = function(cfg){
4537 if(cfg instanceof Array){
4539 }else if(arguments.length > 1){
4540 cfg = Array.prototype.join.call(arguments, "");
4544 if (typeof(cfg) == 'object') {
4553 Roo.Template.prototype = {
4556 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4560 * Returns an HTML fragment of this template with the specified values applied.
4561 * @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'})
4562 * @return {String} The HTML fragment
4564 applyTemplate : function(values){
4568 return this.compiled(values);
4570 var useF = this.disableFormats !== true;
4571 var fm = Roo.util.Format, tpl = this;
4572 var fn = function(m, name, format, args){
4574 if(format.substr(0, 5) == "this."){
4575 return tpl.call(format.substr(5), values[name], values);
4578 // quoted values are required for strings in compiled templates,
4579 // but for non compiled we need to strip them
4580 // quoted reversed for jsmin
4581 var re = /^\s*['"](.*)["']\s*$/;
4582 args = args.split(',');
4583 for(var i = 0, len = args.length; i < len; i++){
4584 args[i] = args[i].replace(re, "$1");
4586 args = [values[name]].concat(args);
4588 args = [values[name]];
4590 return fm[format].apply(fm, args);
4593 return values[name] !== undefined ? values[name] : "";
4596 return this.html.replace(this.re, fn);
4605 * Sets the HTML used as the template and optionally compiles it.
4606 * @param {String} html
4607 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4608 * @return {Roo.Template} this
4610 set : function(html, compile){
4612 this.compiled = null;
4620 * True to disable format functions (defaults to false)
4623 disableFormats : false,
4626 * The regular expression used to match template variables
4630 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4633 * Compiles the template into an internal function, eliminating the RegEx overhead.
4634 * @return {Roo.Template} this
4636 compile : function(){
4637 var fm = Roo.util.Format;
4638 var useF = this.disableFormats !== true;
4639 var sep = Roo.isGecko ? "+" : ",";
4640 var fn = function(m, name, format, args){
4642 args = args ? ',' + args : "";
4643 if(format.substr(0, 5) != "this."){
4644 format = "fm." + format + '(';
4646 format = 'this.call("'+ format.substr(5) + '", ';
4650 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4652 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4655 // branched to use + in gecko and [].join() in others
4657 body = "this.compiled = function(values){ return '" +
4658 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4661 body = ["this.compiled = function(values){ return ['"];
4662 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4663 body.push("'].join('');};");
4664 body = body.join('');
4674 // private function used to call members
4675 call : function(fnName, value, allValues){
4676 return this[fnName](value, allValues);
4680 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4681 * @param {String/HTMLElement/Roo.Element} el The context element
4682 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4683 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4684 * @return {HTMLElement/Roo.Element} The new node or Element
4686 insertFirst: function(el, values, returnElement){
4687 return this.doInsert('afterBegin', el, values, returnElement);
4691 * Applies the supplied values to the template and inserts the new node(s) before el.
4692 * @param {String/HTMLElement/Roo.Element} el The context element
4693 * @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'})
4694 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4695 * @return {HTMLElement/Roo.Element} The new node or Element
4697 insertBefore: function(el, values, returnElement){
4698 return this.doInsert('beforeBegin', el, values, returnElement);
4702 * Applies the supplied values to the template and inserts the new node(s) after el.
4703 * @param {String/HTMLElement/Roo.Element} el The context element
4704 * @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'})
4705 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4706 * @return {HTMLElement/Roo.Element} The new node or Element
4708 insertAfter : function(el, values, returnElement){
4709 return this.doInsert('afterEnd', el, values, returnElement);
4713 * Applies the supplied values to the template and appends the new node(s) to el.
4714 * @param {String/HTMLElement/Roo.Element} el The context element
4715 * @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'})
4716 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4717 * @return {HTMLElement/Roo.Element} The new node or Element
4719 append : function(el, values, returnElement){
4720 return this.doInsert('beforeEnd', el, values, returnElement);
4723 doInsert : function(where, el, values, returnEl){
4724 el = Roo.getDom(el);
4725 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4726 return returnEl ? Roo.get(newNode, true) : newNode;
4730 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4731 * @param {String/HTMLElement/Roo.Element} el The context element
4732 * @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'})
4733 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4734 * @return {HTMLElement/Roo.Element} The new node or Element
4736 overwrite : function(el, values, returnElement){
4737 el = Roo.getDom(el);
4738 el.innerHTML = this.applyTemplate(values);
4739 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4743 * Alias for {@link #applyTemplate}
4746 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4749 Roo.DomHelper.Template = Roo.Template;
4752 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4753 * @param {String/HTMLElement} el A DOM element or its id
4754 * @returns {Roo.Template} The created template
4757 Roo.Template.from = function(el){
4758 el = Roo.getDom(el);
4759 return new Roo.Template(el.value || el.innerHTML);
4762 * Ext JS Library 1.1.1
4763 * Copyright(c) 2006-2007, Ext JS, LLC.
4765 * Originally Released Under LGPL - original licence link has changed is not relivant.
4768 * <script type="text/javascript">
4773 * This is code is also distributed under MIT license for use
4774 * with jQuery and prototype JavaScript libraries.
4777 * @class Roo.DomQuery
4778 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).
4780 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>
4783 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.
4785 <h4>Element Selectors:</h4>
4787 <li> <b>*</b> any element</li>
4788 <li> <b>E</b> an element with the tag E</li>
4789 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4790 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4791 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4792 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4794 <h4>Attribute Selectors:</h4>
4795 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4797 <li> <b>E[foo]</b> has an attribute "foo"</li>
4798 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4799 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4800 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4801 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4802 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4803 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4805 <h4>Pseudo Classes:</h4>
4807 <li> <b>E:first-child</b> E is the first child of its parent</li>
4808 <li> <b>E:last-child</b> E is the last child of its parent</li>
4809 <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>
4810 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4811 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4812 <li> <b>E:only-child</b> E is the only child of its parent</li>
4813 <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>
4814 <li> <b>E:first</b> the first E in the resultset</li>
4815 <li> <b>E:last</b> the last E in the resultset</li>
4816 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4817 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4818 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4819 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4820 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4821 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4822 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4823 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4824 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4826 <h4>CSS Value Selectors:</h4>
4828 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4829 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4830 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4831 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4832 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4833 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4837 Roo.DomQuery = function(){
4838 var cache = {}, simpleCache = {}, valueCache = {};
4839 var nonSpace = /\S/;
4840 var trimRe = /^\s+|\s+$/g;
4841 var tplRe = /\{(\d+)\}/g;
4842 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4843 var tagTokenRe = /^(#)?([\w-\*]+)/;
4844 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4846 function child(p, index){
4848 var n = p.firstChild;
4850 if(n.nodeType == 1){
4861 while((n = n.nextSibling) && n.nodeType != 1);
4866 while((n = n.previousSibling) && n.nodeType != 1);
4870 function children(d){
4871 var n = d.firstChild, ni = -1;
4873 var nx = n.nextSibling;
4874 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4884 function byClassName(c, a, v){
4888 var r = [], ri = -1, cn;
4889 for(var i = 0, ci; ci = c[i]; i++){
4890 if((' '+ci.className+' ').indexOf(v) != -1){
4897 function attrValue(n, attr){
4898 if(!n.tagName && typeof n.length != "undefined"){
4907 if(attr == "class" || attr == "className"){
4910 return n.getAttribute(attr) || n[attr];
4914 function getNodes(ns, mode, tagName){
4915 var result = [], ri = -1, cs;
4919 tagName = tagName || "*";
4920 if(typeof ns.getElementsByTagName != "undefined"){
4924 for(var i = 0, ni; ni = ns[i]; i++){
4925 cs = ni.getElementsByTagName(tagName);
4926 for(var j = 0, ci; ci = cs[j]; j++){
4930 }else if(mode == "/" || mode == ">"){
4931 var utag = tagName.toUpperCase();
4932 for(var i = 0, ni, cn; ni = ns[i]; i++){
4933 cn = ni.children || ni.childNodes;
4934 for(var j = 0, cj; cj = cn[j]; j++){
4935 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4940 }else if(mode == "+"){
4941 var utag = tagName.toUpperCase();
4942 for(var i = 0, n; n = ns[i]; i++){
4943 while((n = n.nextSibling) && n.nodeType != 1);
4944 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4948 }else if(mode == "~"){
4949 for(var i = 0, n; n = ns[i]; i++){
4950 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4959 function concat(a, b){
4963 for(var i = 0, l = b.length; i < l; i++){
4969 function byTag(cs, tagName){
4970 if(cs.tagName || cs == document){
4976 var r = [], ri = -1;
4977 tagName = tagName.toLowerCase();
4978 for(var i = 0, ci; ci = cs[i]; i++){
4979 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4986 function byId(cs, attr, id){
4987 if(cs.tagName || cs == document){
4993 var r = [], ri = -1;
4994 for(var i = 0,ci; ci = cs[i]; i++){
4995 if(ci && ci.id == id){
5003 function byAttribute(cs, attr, value, op, custom){
5004 var r = [], ri = -1, st = custom=="{";
5005 var f = Roo.DomQuery.operators[op];
5006 for(var i = 0, ci; ci = cs[i]; i++){
5009 a = Roo.DomQuery.getStyle(ci, attr);
5011 else if(attr == "class" || attr == "className"){
5013 }else if(attr == "for"){
5015 }else if(attr == "href"){
5016 a = ci.getAttribute("href", 2);
5018 a = ci.getAttribute(attr);
5020 if((f && f(a, value)) || (!f && a)){
5027 function byPseudo(cs, name, value){
5028 return Roo.DomQuery.pseudos[name](cs, value);
5031 // This is for IE MSXML which does not support expandos.
5032 // IE runs the same speed using setAttribute, however FF slows way down
5033 // and Safari completely fails so they need to continue to use expandos.
5034 var isIE = window.ActiveXObject ? true : false;
5036 // this eval is stop the compressor from
5037 // renaming the variable to something shorter
5039 /** eval:var:batch */
5044 function nodupIEXml(cs){
5046 cs[0].setAttribute("_nodup", d);
5048 for(var i = 1, len = cs.length; i < len; i++){
5050 if(!c.getAttribute("_nodup") != d){
5051 c.setAttribute("_nodup", d);
5055 for(var i = 0, len = cs.length; i < len; i++){
5056 cs[i].removeAttribute("_nodup");
5065 var len = cs.length, c, i, r = cs, cj, ri = -1;
5066 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5069 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5070 return nodupIEXml(cs);
5074 for(i = 1; c = cs[i]; i++){
5079 for(var j = 0; j < i; j++){
5082 for(j = i+1; cj = cs[j]; j++){
5094 function quickDiffIEXml(c1, c2){
5096 for(var i = 0, len = c1.length; i < len; i++){
5097 c1[i].setAttribute("_qdiff", d);
5100 for(var i = 0, len = c2.length; i < len; i++){
5101 if(c2[i].getAttribute("_qdiff") != d){
5102 r[r.length] = c2[i];
5105 for(var i = 0, len = c1.length; i < len; i++){
5106 c1[i].removeAttribute("_qdiff");
5111 function quickDiff(c1, c2){
5112 var len1 = c1.length;
5116 if(isIE && c1[0].selectSingleNode){
5117 return quickDiffIEXml(c1, c2);
5120 for(var i = 0; i < len1; i++){
5124 for(var i = 0, len = c2.length; i < len; i++){
5125 if(c2[i]._qdiff != d){
5126 r[r.length] = c2[i];
5132 function quickId(ns, mode, root, id){
5134 var d = root.ownerDocument || root;
5135 return d.getElementById(id);
5137 ns = getNodes(ns, mode, "*");
5138 return byId(ns, null, id);
5142 getStyle : function(el, name){
5143 return Roo.fly(el).getStyle(name);
5146 * Compiles a selector/xpath query into a reusable function. The returned function
5147 * takes one parameter "root" (optional), which is the context node from where the query should start.
5148 * @param {String} selector The selector/xpath query
5149 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5150 * @return {Function}
5152 compile : function(path, type){
5153 type = type || "select";
5155 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5156 var q = path, mode, lq;
5157 var tk = Roo.DomQuery.matchers;
5158 var tklen = tk.length;
5161 // accept leading mode switch
5162 var lmode = q.match(modeRe);
5163 if(lmode && lmode[1]){
5164 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5165 q = q.replace(lmode[1], "");
5167 // strip leading slashes
5168 while(path.substr(0, 1)=="/"){
5169 path = path.substr(1);
5172 while(q && lq != q){
5174 var tm = q.match(tagTokenRe);
5175 if(type == "select"){
5178 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5180 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5182 q = q.replace(tm[0], "");
5183 }else if(q.substr(0, 1) != '@'){
5184 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5189 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5191 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5193 q = q.replace(tm[0], "");
5196 while(!(mm = q.match(modeRe))){
5197 var matched = false;
5198 for(var j = 0; j < tklen; j++){
5200 var m = q.match(t.re);
5202 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5205 q = q.replace(m[0], "");
5210 // prevent infinite loop on bad selector
5212 throw 'Error parsing selector, parsing failed at "' + q + '"';
5216 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5217 q = q.replace(mm[1], "");
5220 fn[fn.length] = "return nodup(n);\n}";
5223 * list of variables that need from compression as they are used by eval.
5233 * eval:var:byClassName
5235 * eval:var:byAttribute
5236 * eval:var:attrValue
5244 * Selects a group of elements.
5245 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5246 * @param {Node} root (optional) The start of the query (defaults to document).
5249 select : function(path, root, type){
5250 if(!root || root == document){
5253 if(typeof root == "string"){
5254 root = document.getElementById(root);
5256 var paths = path.split(",");
5258 for(var i = 0, len = paths.length; i < len; i++){
5259 var p = paths[i].replace(trimRe, "");
5261 cache[p] = Roo.DomQuery.compile(p);
5263 throw p + " is not a valid selector";
5266 var result = cache[p](root);
5267 if(result && result != document){
5268 results = results.concat(result);
5271 if(paths.length > 1){
5272 return nodup(results);
5278 * Selects a single element.
5279 * @param {String} selector The selector/xpath query
5280 * @param {Node} root (optional) The start of the query (defaults to document).
5283 selectNode : function(path, root){
5284 return Roo.DomQuery.select(path, root)[0];
5288 * Selects the value of a node, optionally replacing null with the defaultValue.
5289 * @param {String} selector The selector/xpath query
5290 * @param {Node} root (optional) The start of the query (defaults to document).
5291 * @param {String} defaultValue
5293 selectValue : function(path, root, defaultValue){
5294 path = path.replace(trimRe, "");
5295 if(!valueCache[path]){
5296 valueCache[path] = Roo.DomQuery.compile(path, "select");
5298 var n = valueCache[path](root);
5299 n = n[0] ? n[0] : n;
5300 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5301 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5305 * Selects the value of a node, parsing integers and floats.
5306 * @param {String} selector The selector/xpath query
5307 * @param {Node} root (optional) The start of the query (defaults to document).
5308 * @param {Number} defaultValue
5311 selectNumber : function(path, root, defaultValue){
5312 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5313 return parseFloat(v);
5317 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5318 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5319 * @param {String} selector The simple selector to test
5322 is : function(el, ss){
5323 if(typeof el == "string"){
5324 el = document.getElementById(el);
5326 var isArray = (el instanceof Array);
5327 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5328 return isArray ? (result.length == el.length) : (result.length > 0);
5332 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5333 * @param {Array} el An array of elements to filter
5334 * @param {String} selector The simple selector to test
5335 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5336 * the selector instead of the ones that match
5339 filter : function(els, ss, nonMatches){
5340 ss = ss.replace(trimRe, "");
5341 if(!simpleCache[ss]){
5342 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5344 var result = simpleCache[ss](els);
5345 return nonMatches ? quickDiff(result, els) : result;
5349 * Collection of matching regular expressions and code snippets.
5353 select: 'n = byClassName(n, null, " {1} ");'
5355 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5356 select: 'n = byPseudo(n, "{1}", "{2}");'
5358 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5359 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5362 select: 'n = byId(n, null, "{1}");'
5365 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5370 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5371 * 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, > <.
5374 "=" : function(a, v){
5377 "!=" : function(a, v){
5380 "^=" : function(a, v){
5381 return a && a.substr(0, v.length) == v;
5383 "$=" : function(a, v){
5384 return a && a.substr(a.length-v.length) == v;
5386 "*=" : function(a, v){
5387 return a && a.indexOf(v) !== -1;
5389 "%=" : function(a, v){
5390 return (a % v) == 0;
5392 "|=" : function(a, v){
5393 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5395 "~=" : function(a, v){
5396 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5401 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5402 * and the argument (if any) supplied in the selector.
5405 "first-child" : function(c){
5406 var r = [], ri = -1, n;
5407 for(var i = 0, ci; ci = n = c[i]; i++){
5408 while((n = n.previousSibling) && n.nodeType != 1);
5416 "last-child" : function(c){
5417 var r = [], ri = -1, n;
5418 for(var i = 0, ci; ci = n = c[i]; i++){
5419 while((n = n.nextSibling) && n.nodeType != 1);
5427 "nth-child" : function(c, a) {
5428 var r = [], ri = -1;
5429 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5430 var f = (m[1] || 1) - 0, l = m[2] - 0;
5431 for(var i = 0, n; n = c[i]; i++){
5432 var pn = n.parentNode;
5433 if (batch != pn._batch) {
5435 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5436 if(cn.nodeType == 1){
5443 if (l == 0 || n.nodeIndex == l){
5446 } else if ((n.nodeIndex + l) % f == 0){
5454 "only-child" : function(c){
5455 var r = [], ri = -1;;
5456 for(var i = 0, ci; ci = c[i]; i++){
5457 if(!prev(ci) && !next(ci)){
5464 "empty" : function(c){
5465 var r = [], ri = -1;
5466 for(var i = 0, ci; ci = c[i]; i++){
5467 var cns = ci.childNodes, j = 0, cn, empty = true;
5470 if(cn.nodeType == 1 || cn.nodeType == 3){
5482 "contains" : function(c, v){
5483 var r = [], ri = -1;
5484 for(var i = 0, ci; ci = c[i]; i++){
5485 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5492 "nodeValue" : function(c, v){
5493 var r = [], ri = -1;
5494 for(var i = 0, ci; ci = c[i]; i++){
5495 if(ci.firstChild && ci.firstChild.nodeValue == v){
5502 "checked" : function(c){
5503 var r = [], ri = -1;
5504 for(var i = 0, ci; ci = c[i]; i++){
5505 if(ci.checked == true){
5512 "not" : function(c, ss){
5513 return Roo.DomQuery.filter(c, ss, true);
5516 "odd" : function(c){
5517 return this["nth-child"](c, "odd");
5520 "even" : function(c){
5521 return this["nth-child"](c, "even");
5524 "nth" : function(c, a){
5525 return c[a-1] || [];
5528 "first" : function(c){
5532 "last" : function(c){
5533 return c[c.length-1] || [];
5536 "has" : function(c, ss){
5537 var s = Roo.DomQuery.select;
5538 var r = [], ri = -1;
5539 for(var i = 0, ci; ci = c[i]; i++){
5540 if(s(ss, ci).length > 0){
5547 "next" : function(c, ss){
5548 var is = Roo.DomQuery.is;
5549 var r = [], ri = -1;
5550 for(var i = 0, ci; ci = c[i]; i++){
5559 "prev" : function(c, ss){
5560 var is = Roo.DomQuery.is;
5561 var r = [], ri = -1;
5562 for(var i = 0, ci; ci = c[i]; i++){
5575 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5576 * @param {String} path The selector/xpath query
5577 * @param {Node} root (optional) The start of the query (defaults to document).
5582 Roo.query = Roo.DomQuery.select;
5585 * Ext JS Library 1.1.1
5586 * Copyright(c) 2006-2007, Ext JS, LLC.
5588 * Originally Released Under LGPL - original licence link has changed is not relivant.
5591 * <script type="text/javascript">
5595 * @class Roo.util.Observable
5596 * Base class that provides a common interface for publishing events. Subclasses are expected to
5597 * to have a property "events" with all the events defined.<br>
5600 Employee = function(name){
5607 Roo.extend(Employee, Roo.util.Observable);
5609 * @param {Object} config properties to use (incuding events / listeners)
5612 Roo.util.Observable = function(cfg){
5615 this.addEvents(cfg.events || {});
5617 delete cfg.events; // make sure
5620 Roo.apply(this, cfg);
5623 this.on(this.listeners);
5624 delete this.listeners;
5627 Roo.util.Observable.prototype = {
5629 * @cfg {Object} listeners list of events and functions to call for this object,
5633 'click' : function(e) {
5643 * Fires the specified event with the passed parameters (minus the event name).
5644 * @param {String} eventName
5645 * @param {Object...} args Variable number of parameters are passed to handlers
5646 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5648 fireEvent : function(){
5649 var ce = this.events[arguments[0].toLowerCase()];
5650 if(typeof ce == "object"){
5651 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5658 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5661 * Appends an event handler to this component
5662 * @param {String} eventName The type of event to listen for
5663 * @param {Function} handler The method the event invokes
5664 * @param {Object} scope (optional) The scope in which to execute the handler
5665 * function. The handler function's "this" context.
5666 * @param {Object} options (optional) An object containing handler configuration
5667 * properties. This may contain any of the following properties:<ul>
5668 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5669 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5670 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5671 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5672 * by the specified number of milliseconds. If the event fires again within that time, the original
5673 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5676 * <b>Combining Options</b><br>
5677 * Using the options argument, it is possible to combine different types of listeners:<br>
5679 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5681 el.on('click', this.onClick, this, {
5688 * <b>Attaching multiple handlers in 1 call</b><br>
5689 * The method also allows for a single argument to be passed which is a config object containing properties
5690 * which specify multiple handlers.
5699 fn: this.onMouseOver,
5703 fn: this.onMouseOut,
5709 * Or a shorthand syntax which passes the same scope object to all handlers:
5712 'click': this.onClick,
5713 'mouseover': this.onMouseOver,
5714 'mouseout': this.onMouseOut,
5719 addListener : function(eventName, fn, scope, o){
5720 if(typeof eventName == "object"){
5723 if(this.filterOptRe.test(e)){
5726 if(typeof o[e] == "function"){
5728 this.addListener(e, o[e], o.scope, o);
5730 // individual options
5731 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5736 o = (!o || typeof o == "boolean") ? {} : o;
5737 eventName = eventName.toLowerCase();
5738 var ce = this.events[eventName] || true;
5739 if(typeof ce == "boolean"){
5740 ce = new Roo.util.Event(this, eventName);
5741 this.events[eventName] = ce;
5743 ce.addListener(fn, scope, o);
5747 * Removes a listener
5748 * @param {String} eventName The type of event to listen for
5749 * @param {Function} handler The handler to remove
5750 * @param {Object} scope (optional) The scope (this object) for the handler
5752 removeListener : function(eventName, fn, scope){
5753 var ce = this.events[eventName.toLowerCase()];
5754 if(typeof ce == "object"){
5755 ce.removeListener(fn, scope);
5760 * Removes all listeners for this object
5762 purgeListeners : function(){
5763 for(var evt in this.events){
5764 if(typeof this.events[evt] == "object"){
5765 this.events[evt].clearListeners();
5770 relayEvents : function(o, events){
5771 var createHandler = function(ename){
5773 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5776 for(var i = 0, len = events.length; i < len; i++){
5777 var ename = events[i];
5778 if(!this.events[ename]){ this.events[ename] = true; };
5779 o.on(ename, createHandler(ename), this);
5784 * Used to define events on this Observable
5785 * @param {Object} object The object with the events defined
5787 addEvents : function(o){
5791 Roo.applyIf(this.events, o);
5795 * Checks to see if this object has any listeners for a specified event
5796 * @param {String} eventName The name of the event to check for
5797 * @return {Boolean} True if the event is being listened for, else false
5799 hasListener : function(eventName){
5800 var e = this.events[eventName];
5801 return typeof e == "object" && e.listeners.length > 0;
5805 * Appends an event handler to this element (shorthand for addListener)
5806 * @param {String} eventName The type of event to listen for
5807 * @param {Function} handler The method the event invokes
5808 * @param {Object} scope (optional) The scope in which to execute the handler
5809 * function. The handler function's "this" context.
5810 * @param {Object} options (optional)
5813 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5815 * Removes a listener (shorthand for removeListener)
5816 * @param {String} eventName The type of event to listen for
5817 * @param {Function} handler The handler to remove
5818 * @param {Object} scope (optional) The scope (this object) for the handler
5821 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5824 * Starts capture on the specified Observable. All events will be passed
5825 * to the supplied function with the event name + standard signature of the event
5826 * <b>before</b> the event is fired. If the supplied function returns false,
5827 * the event will not fire.
5828 * @param {Observable} o The Observable to capture
5829 * @param {Function} fn The function to call
5830 * @param {Object} scope (optional) The scope (this object) for the fn
5833 Roo.util.Observable.capture = function(o, fn, scope){
5834 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5838 * Removes <b>all</b> added captures from the Observable.
5839 * @param {Observable} o The Observable to release
5842 Roo.util.Observable.releaseCapture = function(o){
5843 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5848 var createBuffered = function(h, o, scope){
5849 var task = new Roo.util.DelayedTask();
5851 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5855 var createSingle = function(h, e, fn, scope){
5857 e.removeListener(fn, scope);
5858 return h.apply(scope, arguments);
5862 var createDelayed = function(h, o, scope){
5864 var args = Array.prototype.slice.call(arguments, 0);
5865 setTimeout(function(){
5866 h.apply(scope, args);
5871 Roo.util.Event = function(obj, name){
5874 this.listeners = [];
5877 Roo.util.Event.prototype = {
5878 addListener : function(fn, scope, options){
5879 var o = options || {};
5880 scope = scope || this.obj;
5881 if(!this.isListening(fn, scope)){
5882 var l = {fn: fn, scope: scope, options: o};
5885 h = createDelayed(h, o, scope);
5888 h = createSingle(h, this, fn, scope);
5891 h = createBuffered(h, o, scope);
5894 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5895 this.listeners.push(l);
5897 this.listeners = this.listeners.slice(0);
5898 this.listeners.push(l);
5903 findListener : function(fn, scope){
5904 scope = scope || this.obj;
5905 var ls = this.listeners;
5906 for(var i = 0, len = ls.length; i < len; i++){
5908 if(l.fn == fn && l.scope == scope){
5915 isListening : function(fn, scope){
5916 return this.findListener(fn, scope) != -1;
5919 removeListener : function(fn, scope){
5921 if((index = this.findListener(fn, scope)) != -1){
5923 this.listeners.splice(index, 1);
5925 this.listeners = this.listeners.slice(0);
5926 this.listeners.splice(index, 1);
5933 clearListeners : function(){
5934 this.listeners = [];
5938 var ls = this.listeners, scope, len = ls.length;
5941 var args = Array.prototype.slice.call(arguments, 0);
5942 for(var i = 0; i < len; i++){
5944 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5945 this.firing = false;
5949 this.firing = false;
5956 * Ext JS Library 1.1.1
5957 * Copyright(c) 2006-2007, Ext JS, LLC.
5959 * Originally Released Under LGPL - original licence link has changed is not relivant.
5962 * <script type="text/javascript">
5966 * @class Roo.EventManager
5967 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5968 * several useful events directly.
5969 * See {@link Roo.EventObject} for more details on normalized event objects.
5972 Roo.EventManager = function(){
5973 var docReadyEvent, docReadyProcId, docReadyState = false;
5974 var resizeEvent, resizeTask, textEvent, textSize;
5975 var E = Roo.lib.Event;
5976 var D = Roo.lib.Dom;
5979 var fireDocReady = function(){
5981 docReadyState = true;
5984 clearInterval(docReadyProcId);
5986 if(Roo.isGecko || Roo.isOpera) {
5987 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5990 var defer = document.getElementById("ie-deferred-loader");
5992 defer.onreadystatechange = null;
5993 defer.parentNode.removeChild(defer);
5997 docReadyEvent.fire();
5998 docReadyEvent.clearListeners();
6003 var initDocReady = function(){
6004 docReadyEvent = new Roo.util.Event();
6005 if(Roo.isGecko || Roo.isOpera) {
6006 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6008 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6009 var defer = document.getElementById("ie-deferred-loader");
6010 defer.onreadystatechange = function(){
6011 if(this.readyState == "complete"){
6015 }else if(Roo.isSafari){
6016 docReadyProcId = setInterval(function(){
6017 var rs = document.readyState;
6018 if(rs == "complete") {
6023 // no matter what, make sure it fires on load
6024 E.on(window, "load", fireDocReady);
6027 var createBuffered = function(h, o){
6028 var task = new Roo.util.DelayedTask(h);
6030 // create new event object impl so new events don't wipe out properties
6031 e = new Roo.EventObjectImpl(e);
6032 task.delay(o.buffer, h, null, [e]);
6036 var createSingle = function(h, el, ename, fn){
6038 Roo.EventManager.removeListener(el, ename, fn);
6043 var createDelayed = function(h, o){
6045 // create new event object impl so new events don't wipe out properties
6046 e = new Roo.EventObjectImpl(e);
6047 setTimeout(function(){
6053 var listen = function(element, ename, opt, fn, scope){
6054 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6055 fn = fn || o.fn; scope = scope || o.scope;
6056 var el = Roo.getDom(element);
6058 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6060 var h = function(e){
6061 e = Roo.EventObject.setEvent(e);
6064 t = e.getTarget(o.delegate, el);
6071 if(o.stopEvent === true){
6074 if(o.preventDefault === true){
6077 if(o.stopPropagation === true){
6078 e.stopPropagation();
6081 if(o.normalized === false){
6085 fn.call(scope || el, e, t, o);
6088 h = createDelayed(h, o);
6091 h = createSingle(h, el, ename, fn);
6094 h = createBuffered(h, o);
6096 fn._handlers = fn._handlers || [];
6097 fn._handlers.push([Roo.id(el), ename, h]);
6100 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6101 el.addEventListener("DOMMouseScroll", h, false);
6102 E.on(window, 'unload', function(){
6103 el.removeEventListener("DOMMouseScroll", h, false);
6106 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6107 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6112 var stopListening = function(el, ename, fn){
6113 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6115 for(var i = 0, len = hds.length; i < len; i++){
6117 if(h[0] == id && h[1] == ename){
6124 E.un(el, ename, hd);
6125 el = Roo.getDom(el);
6126 if(ename == "mousewheel" && el.addEventListener){
6127 el.removeEventListener("DOMMouseScroll", hd, false);
6129 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6130 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6134 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6141 * @scope Roo.EventManager
6146 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6147 * object with a Roo.EventObject
6148 * @param {Function} fn The method the event invokes
6149 * @param {Object} scope An object that becomes the scope of the handler
6150 * @param {boolean} override If true, the obj passed in becomes
6151 * the execution scope of the listener
6152 * @return {Function} The wrapped function
6155 wrap : function(fn, scope, override){
6157 Roo.EventObject.setEvent(e);
6158 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6163 * Appends an event handler to an element (shorthand for addListener)
6164 * @param {String/HTMLElement} element The html element or id to assign the
6165 * @param {String} eventName The type of event to listen for
6166 * @param {Function} handler The method the event invokes
6167 * @param {Object} scope (optional) The scope in which to execute the handler
6168 * function. The handler function's "this" context.
6169 * @param {Object} options (optional) An object containing handler configuration
6170 * properties. This may contain any of the following properties:<ul>
6171 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6172 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6173 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6174 * <li>preventDefault {Boolean} True to prevent the default action</li>
6175 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6176 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6177 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6178 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6179 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6180 * by the specified number of milliseconds. If the event fires again within that time, the original
6181 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6184 * <b>Combining Options</b><br>
6185 * Using the options argument, it is possible to combine different types of listeners:<br>
6187 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6189 el.on('click', this.onClick, this, {
6196 * <b>Attaching multiple handlers in 1 call</b><br>
6197 * The method also allows for a single argument to be passed which is a config object containing properties
6198 * which specify multiple handlers.
6208 fn: this.onMouseOver
6217 * Or a shorthand syntax:<br>
6220 'click' : this.onClick,
6221 'mouseover' : this.onMouseOver,
6222 'mouseout' : this.onMouseOut
6226 addListener : function(element, eventName, fn, scope, options){
6227 if(typeof eventName == "object"){
6233 if(typeof o[e] == "function"){
6235 listen(element, e, o, o[e], o.scope);
6237 // individual options
6238 listen(element, e, o[e]);
6243 return listen(element, eventName, options, fn, scope);
6247 * Removes an event handler
6249 * @param {String/HTMLElement} element The id or html element to remove the
6251 * @param {String} eventName The type of event
6252 * @param {Function} fn
6253 * @return {Boolean} True if a listener was actually removed
6255 removeListener : function(element, eventName, fn){
6256 return stopListening(element, eventName, fn);
6260 * Fires when the document is ready (before onload and before images are loaded). Can be
6261 * accessed shorthanded Roo.onReady().
6262 * @param {Function} fn The method the event invokes
6263 * @param {Object} scope An object that becomes the scope of the handler
6264 * @param {boolean} options
6266 onDocumentReady : function(fn, scope, options){
6267 if(docReadyState){ // if it already fired
6268 docReadyEvent.addListener(fn, scope, options);
6269 docReadyEvent.fire();
6270 docReadyEvent.clearListeners();
6276 docReadyEvent.addListener(fn, scope, options);
6280 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6281 * @param {Function} fn The method the event invokes
6282 * @param {Object} scope An object that becomes the scope of the handler
6283 * @param {boolean} options
6285 onWindowResize : function(fn, scope, options){
6287 resizeEvent = new Roo.util.Event();
6288 resizeTask = new Roo.util.DelayedTask(function(){
6289 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6291 E.on(window, "resize", function(){
6293 resizeTask.delay(50);
6295 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6299 resizeEvent.addListener(fn, scope, options);
6303 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6304 * @param {Function} fn The method the event invokes
6305 * @param {Object} scope An object that becomes the scope of the handler
6306 * @param {boolean} options
6308 onTextResize : function(fn, scope, options){
6310 textEvent = new Roo.util.Event();
6311 var textEl = new Roo.Element(document.createElement('div'));
6312 textEl.dom.className = 'x-text-resize';
6313 textEl.dom.innerHTML = 'X';
6314 textEl.appendTo(document.body);
6315 textSize = textEl.dom.offsetHeight;
6316 setInterval(function(){
6317 if(textEl.dom.offsetHeight != textSize){
6318 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6320 }, this.textResizeInterval);
6322 textEvent.addListener(fn, scope, options);
6326 * Removes the passed window resize listener.
6327 * @param {Function} fn The method the event invokes
6328 * @param {Object} scope The scope of handler
6330 removeResizeListener : function(fn, scope){
6332 resizeEvent.removeListener(fn, scope);
6337 fireResize : function(){
6339 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6343 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6347 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6349 textResizeInterval : 50
6354 * @scopeAlias pub=Roo.EventManager
6358 * Appends an event handler to an element (shorthand for addListener)
6359 * @param {String/HTMLElement} element The html element or id to assign the
6360 * @param {String} eventName The type of event to listen for
6361 * @param {Function} handler The method the event invokes
6362 * @param {Object} scope (optional) The scope in which to execute the handler
6363 * function. The handler function's "this" context.
6364 * @param {Object} options (optional) An object containing handler configuration
6365 * properties. This may contain any of the following properties:<ul>
6366 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6367 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6368 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6369 * <li>preventDefault {Boolean} True to prevent the default action</li>
6370 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6371 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6372 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6373 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6374 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6375 * by the specified number of milliseconds. If the event fires again within that time, the original
6376 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6379 * <b>Combining Options</b><br>
6380 * Using the options argument, it is possible to combine different types of listeners:<br>
6382 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6384 el.on('click', this.onClick, this, {
6391 * <b>Attaching multiple handlers in 1 call</b><br>
6392 * The method also allows for a single argument to be passed which is a config object containing properties
6393 * which specify multiple handlers.
6403 fn: this.onMouseOver
6412 * Or a shorthand syntax:<br>
6415 'click' : this.onClick,
6416 'mouseover' : this.onMouseOver,
6417 'mouseout' : this.onMouseOut
6421 pub.on = pub.addListener;
6422 pub.un = pub.removeListener;
6424 pub.stoppedMouseDownEvent = new Roo.util.Event();
6428 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6429 * @param {Function} fn The method the event invokes
6430 * @param {Object} scope An object that becomes the scope of the handler
6431 * @param {boolean} override If true, the obj passed in becomes
6432 * the execution scope of the listener
6436 Roo.onReady = Roo.EventManager.onDocumentReady;
6438 Roo.onReady(function(){
6439 var bd = Roo.get(document.body);
6444 : Roo.isGecko ? "roo-gecko"
6445 : Roo.isOpera ? "roo-opera"
6446 : Roo.isSafari ? "roo-safari" : ""];
6449 cls.push("roo-mac");
6452 cls.push("roo-linux");
6454 if(Roo.isBorderBox){
6455 cls.push('roo-border-box');
6457 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6458 var p = bd.dom.parentNode;
6460 p.className += ' roo-strict';
6463 bd.addClass(cls.join(' '));
6467 * @class Roo.EventObject
6468 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6469 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6472 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6474 var target = e.getTarget();
6477 var myDiv = Roo.get("myDiv");
6478 myDiv.on("click", handleClick);
6480 Roo.EventManager.on("myDiv", 'click', handleClick);
6481 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6485 Roo.EventObject = function(){
6487 var E = Roo.lib.Event;
6489 // safari keypress events for special keys return bad keycodes
6492 63235 : 39, // right
6495 63276 : 33, // page up
6496 63277 : 34, // page down
6497 63272 : 46, // delete
6502 // normalize button clicks
6503 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6504 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6506 Roo.EventObjectImpl = function(e){
6508 this.setEvent(e.browserEvent || e);
6511 Roo.EventObjectImpl.prototype = {
6513 * Used to fix doc tools.
6514 * @scope Roo.EventObject.prototype
6520 /** The normal browser event */
6521 browserEvent : null,
6522 /** The button pressed in a mouse event */
6524 /** True if the shift key was down during the event */
6526 /** True if the control key was down during the event */
6528 /** True if the alt key was down during the event */
6587 setEvent : function(e){
6588 if(e == this || (e && e.browserEvent)){ // already wrapped
6591 this.browserEvent = e;
6593 // normalize buttons
6594 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6595 if(e.type == 'click' && this.button == -1){
6599 this.shiftKey = e.shiftKey;
6600 // mac metaKey behaves like ctrlKey
6601 this.ctrlKey = e.ctrlKey || e.metaKey;
6602 this.altKey = e.altKey;
6603 // in getKey these will be normalized for the mac
6604 this.keyCode = e.keyCode;
6605 // keyup warnings on firefox.
6606 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6607 // cache the target for the delayed and or buffered events
6608 this.target = E.getTarget(e);
6610 this.xy = E.getXY(e);
6613 this.shiftKey = false;
6614 this.ctrlKey = false;
6615 this.altKey = false;
6625 * Stop the event (preventDefault and stopPropagation)
6627 stopEvent : function(){
6628 if(this.browserEvent){
6629 if(this.browserEvent.type == 'mousedown'){
6630 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6632 E.stopEvent(this.browserEvent);
6637 * Prevents the browsers default handling of the event.
6639 preventDefault : function(){
6640 if(this.browserEvent){
6641 E.preventDefault(this.browserEvent);
6646 isNavKeyPress : function(){
6647 var k = this.keyCode;
6648 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6649 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6652 isSpecialKey : function(){
6653 var k = this.keyCode;
6654 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6655 (k == 16) || (k == 17) ||
6656 (k >= 18 && k <= 20) ||
6657 (k >= 33 && k <= 35) ||
6658 (k >= 36 && k <= 39) ||
6659 (k >= 44 && k <= 45);
6662 * Cancels bubbling of the event.
6664 stopPropagation : function(){
6665 if(this.browserEvent){
6666 if(this.type == 'mousedown'){
6667 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6669 E.stopPropagation(this.browserEvent);
6674 * Gets the key code for the event.
6677 getCharCode : function(){
6678 return this.charCode || this.keyCode;
6682 * Returns a normalized keyCode for the event.
6683 * @return {Number} The key code
6685 getKey : function(){
6686 var k = this.keyCode || this.charCode;
6687 return Roo.isSafari ? (safariKeys[k] || k) : k;
6691 * Gets the x coordinate of the event.
6694 getPageX : function(){
6699 * Gets the y coordinate of the event.
6702 getPageY : function(){
6707 * Gets the time of the event.
6710 getTime : function(){
6711 if(this.browserEvent){
6712 return E.getTime(this.browserEvent);
6718 * Gets the page coordinates of the event.
6719 * @return {Array} The xy values like [x, y]
6726 * Gets the target for the event.
6727 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6728 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6729 search as a number or element (defaults to 10 || document.body)
6730 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6731 * @return {HTMLelement}
6733 getTarget : function(selector, maxDepth, returnEl){
6734 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6737 * Gets the related target.
6738 * @return {HTMLElement}
6740 getRelatedTarget : function(){
6741 if(this.browserEvent){
6742 return E.getRelatedTarget(this.browserEvent);
6748 * Normalizes mouse wheel delta across browsers
6749 * @return {Number} The delta
6751 getWheelDelta : function(){
6752 var e = this.browserEvent;
6754 if(e.wheelDelta){ /* IE/Opera. */
6755 delta = e.wheelDelta/120;
6756 }else if(e.detail){ /* Mozilla case. */
6757 delta = -e.detail/3;
6763 * Returns true if the control, meta, shift or alt key was pressed during this event.
6766 hasModifier : function(){
6767 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6771 * Returns true if the target of this event equals el or is a child of el
6772 * @param {String/HTMLElement/Element} el
6773 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6776 within : function(el, related){
6777 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6778 return t && Roo.fly(el).contains(t);
6781 getPoint : function(){
6782 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6786 return new Roo.EventObjectImpl();
6791 * Ext JS Library 1.1.1
6792 * Copyright(c) 2006-2007, Ext JS, LLC.
6794 * Originally Released Under LGPL - original licence link has changed is not relivant.
6797 * <script type="text/javascript">
6801 // was in Composite Element!??!?!
6804 var D = Roo.lib.Dom;
6805 var E = Roo.lib.Event;
6806 var A = Roo.lib.Anim;
6808 // local style camelizing for speed
6810 var camelRe = /(-[a-z])/gi;
6811 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6812 var view = document.defaultView;
6815 * @class Roo.Element
6816 * Represents an Element in the DOM.<br><br>
6819 var el = Roo.get("my-div");
6822 var el = getEl("my-div");
6824 // or with a DOM element
6825 var el = Roo.get(myDivElement);
6827 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6828 * each call instead of constructing a new one.<br><br>
6829 * <b>Animations</b><br />
6830 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6831 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6833 Option Default Description
6834 --------- -------- ---------------------------------------------
6835 duration .35 The duration of the animation in seconds
6836 easing easeOut The YUI easing method
6837 callback none A function to execute when the anim completes
6838 scope this The scope (this) of the callback function
6840 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6841 * manipulate the animation. Here's an example:
6843 var el = Roo.get("my-div");
6848 // default animation
6849 el.setWidth(100, true);
6851 // animation with some options set
6858 // using the "anim" property to get the Anim object
6864 el.setWidth(100, opt);
6866 if(opt.anim.isAnimated()){
6870 * <b> Composite (Collections of) Elements</b><br />
6871 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6872 * @constructor Create a new Element directly.
6873 * @param {String/HTMLElement} element
6874 * @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).
6876 Roo.Element = function(element, forceNew){
6877 var dom = typeof element == "string" ?
6878 document.getElementById(element) : element;
6879 if(!dom){ // invalid id/element
6883 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6884 return Roo.Element.cache[id];
6894 * The DOM element ID
6897 this.id = id || Roo.id(dom);
6900 var El = Roo.Element;
6904 * The element's default display mode (defaults to "")
6907 originalDisplay : "",
6911 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6916 * Sets the element's visibility mode. When setVisible() is called it
6917 * will use this to determine whether to set the visibility or the display property.
6918 * @param visMode Element.VISIBILITY or Element.DISPLAY
6919 * @return {Roo.Element} this
6921 setVisibilityMode : function(visMode){
6922 this.visibilityMode = visMode;
6926 * Convenience method for setVisibilityMode(Element.DISPLAY)
6927 * @param {String} display (optional) What to set display to when visible
6928 * @return {Roo.Element} this
6930 enableDisplayMode : function(display){
6931 this.setVisibilityMode(El.DISPLAY);
6932 if(typeof display != "undefined") this.originalDisplay = display;
6937 * 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)
6938 * @param {String} selector The simple selector to test
6939 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6940 search as a number or element (defaults to 10 || document.body)
6941 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6942 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6944 findParent : function(simpleSelector, maxDepth, returnEl){
6945 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6946 maxDepth = maxDepth || 50;
6947 if(typeof maxDepth != "number"){
6948 stopEl = Roo.getDom(maxDepth);
6951 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6952 if(dq.is(p, simpleSelector)){
6953 return returnEl ? Roo.get(p) : p;
6963 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6964 * @param {String} selector The simple selector to test
6965 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6966 search as a number or element (defaults to 10 || document.body)
6967 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6968 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6970 findParentNode : function(simpleSelector, maxDepth, returnEl){
6971 var p = Roo.fly(this.dom.parentNode, '_internal');
6972 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6976 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6977 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6978 * @param {String} selector The simple selector to test
6979 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6980 search as a number or element (defaults to 10 || document.body)
6981 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6983 up : function(simpleSelector, maxDepth){
6984 return this.findParentNode(simpleSelector, maxDepth, true);
6990 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6991 * @param {String} selector The simple selector to test
6992 * @return {Boolean} True if this element matches the selector, else false
6994 is : function(simpleSelector){
6995 return Roo.DomQuery.is(this.dom, simpleSelector);
6999 * Perform animation on this element.
7000 * @param {Object} args The YUI animation control args
7001 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7002 * @param {Function} onComplete (optional) Function to call when animation completes
7003 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7004 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7005 * @return {Roo.Element} this
7007 animate : function(args, duration, onComplete, easing, animType){
7008 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7013 * @private Internal animation call
7015 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7016 animType = animType || 'run';
7018 var anim = Roo.lib.Anim[animType](
7020 (opt.duration || defaultDur) || .35,
7021 (opt.easing || defaultEase) || 'easeOut',
7023 Roo.callback(cb, this);
7024 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7032 // private legacy anim prep
7033 preanim : function(a, i){
7034 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7038 * Removes worthless text nodes
7039 * @param {Boolean} forceReclean (optional) By default the element
7040 * keeps track if it has been cleaned already so
7041 * you can call this over and over. However, if you update the element and
7042 * need to force a reclean, you can pass true.
7044 clean : function(forceReclean){
7045 if(this.isCleaned && forceReclean !== true){
7049 var d = this.dom, n = d.firstChild, ni = -1;
7051 var nx = n.nextSibling;
7052 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7059 this.isCleaned = true;
7064 calcOffsetsTo : function(el){
7067 var restorePos = false;
7068 if(el.getStyle('position') == 'static'){
7069 el.position('relative');
7074 while(op && op != d && op.tagName != 'HTML'){
7077 op = op.offsetParent;
7080 el.position('static');
7086 * Scrolls this element into view within the passed container.
7087 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7088 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7089 * @return {Roo.Element} this
7091 scrollIntoView : function(container, hscroll){
7092 var c = Roo.getDom(container) || document.body;
7095 var o = this.calcOffsetsTo(c),
7098 b = t+el.offsetHeight,
7099 r = l+el.offsetWidth;
7101 var ch = c.clientHeight;
7102 var ct = parseInt(c.scrollTop, 10);
7103 var cl = parseInt(c.scrollLeft, 10);
7105 var cr = cl + c.clientWidth;
7113 if(hscroll !== false){
7117 c.scrollLeft = r-c.clientWidth;
7124 scrollChildIntoView : function(child, hscroll){
7125 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7129 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7130 * the new height may not be available immediately.
7131 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7132 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7133 * @param {Function} onComplete (optional) Function to call when animation completes
7134 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7135 * @return {Roo.Element} this
7137 autoHeight : function(animate, duration, onComplete, easing){
7138 var oldHeight = this.getHeight();
7140 this.setHeight(1); // force clipping
7141 setTimeout(function(){
7142 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7144 this.setHeight(height);
7146 if(typeof onComplete == "function"){
7150 this.setHeight(oldHeight); // restore original height
7151 this.setHeight(height, animate, duration, function(){
7153 if(typeof onComplete == "function") onComplete();
7154 }.createDelegate(this), easing);
7156 }.createDelegate(this), 0);
7161 * Returns true if this element is an ancestor of the passed element
7162 * @param {HTMLElement/String} el The element to check
7163 * @return {Boolean} True if this element is an ancestor of el, else false
7165 contains : function(el){
7166 if(!el){return false;}
7167 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7171 * Checks whether the element is currently visible using both visibility and display properties.
7172 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7173 * @return {Boolean} True if the element is currently visible, else false
7175 isVisible : function(deep) {
7176 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7177 if(deep !== true || !vis){
7180 var p = this.dom.parentNode;
7181 while(p && p.tagName.toLowerCase() != "body"){
7182 if(!Roo.fly(p, '_isVisible').isVisible()){
7191 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7192 * @param {String} selector The CSS selector
7193 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7194 * @return {CompositeElement/CompositeElementLite} The composite element
7196 select : function(selector, unique){
7197 return El.select(selector, unique, this.dom);
7201 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7202 * @param {String} selector The CSS selector
7203 * @return {Array} An array of the matched nodes
7205 query : function(selector, unique){
7206 return Roo.DomQuery.select(selector, this.dom);
7210 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7211 * @param {String} selector The CSS selector
7212 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7213 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7215 child : function(selector, returnDom){
7216 var n = Roo.DomQuery.selectNode(selector, this.dom);
7217 return returnDom ? n : Roo.get(n);
7221 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7222 * @param {String} selector The CSS selector
7223 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7224 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7226 down : function(selector, returnDom){
7227 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7228 return returnDom ? n : Roo.get(n);
7232 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7233 * @param {String} group The group the DD object is member of
7234 * @param {Object} config The DD config object
7235 * @param {Object} overrides An object containing methods to override/implement on the DD object
7236 * @return {Roo.dd.DD} The DD object
7238 initDD : function(group, config, overrides){
7239 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7240 return Roo.apply(dd, overrides);
7244 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7245 * @param {String} group The group the DDProxy object is member of
7246 * @param {Object} config The DDProxy config object
7247 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7248 * @return {Roo.dd.DDProxy} The DDProxy object
7250 initDDProxy : function(group, config, overrides){
7251 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7252 return Roo.apply(dd, overrides);
7256 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7257 * @param {String} group The group the DDTarget object is member of
7258 * @param {Object} config The DDTarget config object
7259 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7260 * @return {Roo.dd.DDTarget} The DDTarget object
7262 initDDTarget : function(group, config, overrides){
7263 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7264 return Roo.apply(dd, overrides);
7268 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7269 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7270 * @param {Boolean} visible Whether the element is visible
7271 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7272 * @return {Roo.Element} this
7274 setVisible : function(visible, animate){
7276 if(this.visibilityMode == El.DISPLAY){
7277 this.setDisplayed(visible);
7280 this.dom.style.visibility = visible ? "visible" : "hidden";
7283 // closure for composites
7285 var visMode = this.visibilityMode;
7287 this.setOpacity(.01);
7288 this.setVisible(true);
7290 this.anim({opacity: { to: (visible?1:0) }},
7291 this.preanim(arguments, 1),
7292 null, .35, 'easeIn', function(){
7294 if(visMode == El.DISPLAY){
7295 dom.style.display = "none";
7297 dom.style.visibility = "hidden";
7299 Roo.get(dom).setOpacity(1);
7307 * Returns true if display is not "none"
7310 isDisplayed : function() {
7311 return this.getStyle("display") != "none";
7315 * Toggles the element's visibility or display, depending on visibility mode.
7316 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7317 * @return {Roo.Element} this
7319 toggle : function(animate){
7320 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7325 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7326 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7327 * @return {Roo.Element} this
7329 setDisplayed : function(value) {
7330 if(typeof value == "boolean"){
7331 value = value ? this.originalDisplay : "none";
7333 this.setStyle("display", value);
7338 * Tries to focus the element. Any exceptions are caught and ignored.
7339 * @return {Roo.Element} this
7341 focus : function() {
7349 * Tries to blur the element. Any exceptions are caught and ignored.
7350 * @return {Roo.Element} this
7360 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7361 * @param {String/Array} className The CSS class to add, or an array of classes
7362 * @return {Roo.Element} this
7364 addClass : function(className){
7365 if(className instanceof Array){
7366 for(var i = 0, len = className.length; i < len; i++) {
7367 this.addClass(className[i]);
7370 if(className && !this.hasClass(className)){
7371 this.dom.className = this.dom.className + " " + className;
7378 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7379 * @param {String/Array} className The CSS class to add, or an array of classes
7380 * @return {Roo.Element} this
7382 radioClass : function(className){
7383 var siblings = this.dom.parentNode.childNodes;
7384 for(var i = 0; i < siblings.length; i++) {
7385 var s = siblings[i];
7386 if(s.nodeType == 1){
7387 Roo.get(s).removeClass(className);
7390 this.addClass(className);
7395 * Removes one or more CSS classes from the element.
7396 * @param {String/Array} className The CSS class to remove, or an array of classes
7397 * @return {Roo.Element} this
7399 removeClass : function(className){
7400 if(!className || !this.dom.className){
7403 if(className instanceof Array){
7404 for(var i = 0, len = className.length; i < len; i++) {
7405 this.removeClass(className[i]);
7408 if(this.hasClass(className)){
7409 var re = this.classReCache[className];
7411 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7412 this.classReCache[className] = re;
7414 this.dom.className =
7415 this.dom.className.replace(re, " ");
7425 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7426 * @param {String} className The CSS class to toggle
7427 * @return {Roo.Element} this
7429 toggleClass : function(className){
7430 if(this.hasClass(className)){
7431 this.removeClass(className);
7433 this.addClass(className);
7439 * Checks if the specified CSS class exists on this element's DOM node.
7440 * @param {String} className The CSS class to check for
7441 * @return {Boolean} True if the class exists, else false
7443 hasClass : function(className){
7444 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7448 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7449 * @param {String} oldClassName The CSS class to replace
7450 * @param {String} newClassName The replacement CSS class
7451 * @return {Roo.Element} this
7453 replaceClass : function(oldClassName, newClassName){
7454 this.removeClass(oldClassName);
7455 this.addClass(newClassName);
7460 * Returns an object with properties matching the styles requested.
7461 * For example, el.getStyles('color', 'font-size', 'width') might return
7462 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7463 * @param {String} style1 A style name
7464 * @param {String} style2 A style name
7465 * @param {String} etc.
7466 * @return {Object} The style object
7468 getStyles : function(){
7469 var a = arguments, len = a.length, r = {};
7470 for(var i = 0; i < len; i++){
7471 r[a[i]] = this.getStyle(a[i]);
7477 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7478 * @param {String} property The style property whose value is returned.
7479 * @return {String} The current value of the style property for this element.
7481 getStyle : function(){
7482 return view && view.getComputedStyle ?
7484 var el = this.dom, v, cs, camel;
7485 if(prop == 'float'){
7488 if(el.style && (v = el.style[prop])){
7491 if(cs = view.getComputedStyle(el, "")){
7492 if(!(camel = propCache[prop])){
7493 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7500 var el = this.dom, v, cs, camel;
7501 if(prop == 'opacity'){
7502 if(typeof el.style.filter == 'string'){
7503 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7505 var fv = parseFloat(m[1]);
7507 return fv ? fv / 100 : 0;
7512 }else if(prop == 'float'){
7513 prop = "styleFloat";
7515 if(!(camel = propCache[prop])){
7516 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7518 if(v = el.style[camel]){
7521 if(cs = el.currentStyle){
7529 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7530 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7531 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7532 * @return {Roo.Element} this
7534 setStyle : function(prop, value){
7535 if(typeof prop == "string"){
7537 if (prop == 'float') {
7538 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7543 if(!(camel = propCache[prop])){
7544 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7547 if(camel == 'opacity') {
7548 this.setOpacity(value);
7550 this.dom.style[camel] = value;
7553 for(var style in prop){
7554 if(typeof prop[style] != "function"){
7555 this.setStyle(style, prop[style]);
7563 * More flexible version of {@link #setStyle} for setting style properties.
7564 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7565 * a function which returns such a specification.
7566 * @return {Roo.Element} this
7568 applyStyles : function(style){
7569 Roo.DomHelper.applyStyles(this.dom, style);
7574 * 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).
7575 * @return {Number} The X position of the element
7578 return D.getX(this.dom);
7582 * 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).
7583 * @return {Number} The Y position of the element
7586 return D.getY(this.dom);
7590 * 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).
7591 * @return {Array} The XY position of the element
7594 return D.getXY(this.dom);
7598 * 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).
7599 * @param {Number} The X position of the element
7600 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7601 * @return {Roo.Element} this
7603 setX : function(x, animate){
7605 D.setX(this.dom, x);
7607 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7613 * 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).
7614 * @param {Number} The Y position of the element
7615 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7616 * @return {Roo.Element} this
7618 setY : function(y, animate){
7620 D.setY(this.dom, y);
7622 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7628 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7629 * @param {String} left The left CSS property value
7630 * @return {Roo.Element} this
7632 setLeft : function(left){
7633 this.setStyle("left", this.addUnits(left));
7638 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7639 * @param {String} top The top CSS property value
7640 * @return {Roo.Element} this
7642 setTop : function(top){
7643 this.setStyle("top", this.addUnits(top));
7648 * Sets the element's CSS right style.
7649 * @param {String} right The right CSS property value
7650 * @return {Roo.Element} this
7652 setRight : function(right){
7653 this.setStyle("right", this.addUnits(right));
7658 * Sets the element's CSS bottom style.
7659 * @param {String} bottom The bottom CSS property value
7660 * @return {Roo.Element} this
7662 setBottom : function(bottom){
7663 this.setStyle("bottom", this.addUnits(bottom));
7668 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7669 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7670 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7671 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7672 * @return {Roo.Element} this
7674 setXY : function(pos, animate){
7676 D.setXY(this.dom, pos);
7678 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7684 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7685 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7686 * @param {Number} x X value for new position (coordinates are page-based)
7687 * @param {Number} y Y value for new position (coordinates are page-based)
7688 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7689 * @return {Roo.Element} this
7691 setLocation : function(x, y, animate){
7692 this.setXY([x, y], this.preanim(arguments, 2));
7697 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7698 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7699 * @param {Number} x X value for new position (coordinates are page-based)
7700 * @param {Number} y Y value for new position (coordinates are page-based)
7701 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7702 * @return {Roo.Element} this
7704 moveTo : function(x, y, animate){
7705 this.setXY([x, y], this.preanim(arguments, 2));
7710 * Returns the region of the given element.
7711 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7712 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7714 getRegion : function(){
7715 return D.getRegion(this.dom);
7719 * Returns the offset height of the element
7720 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7721 * @return {Number} The element's height
7723 getHeight : function(contentHeight){
7724 var h = this.dom.offsetHeight || 0;
7725 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7729 * Returns the offset width of the element
7730 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7731 * @return {Number} The element's width
7733 getWidth : function(contentWidth){
7734 var w = this.dom.offsetWidth || 0;
7735 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7739 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7740 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7741 * if a height has not been set using CSS.
7744 getComputedHeight : function(){
7745 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7747 h = parseInt(this.getStyle('height'), 10) || 0;
7748 if(!this.isBorderBox()){
7749 h += this.getFrameWidth('tb');
7756 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7757 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7758 * if a width has not been set using CSS.
7761 getComputedWidth : function(){
7762 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7764 w = parseInt(this.getStyle('width'), 10) || 0;
7765 if(!this.isBorderBox()){
7766 w += this.getFrameWidth('lr');
7773 * Returns the size of the element.
7774 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7775 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7777 getSize : function(contentSize){
7778 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7782 * Returns the width and height of the viewport.
7783 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7785 getViewSize : function(){
7786 var d = this.dom, doc = document, aw = 0, ah = 0;
7787 if(d == doc || d == doc.body){
7788 return {width : D.getViewWidth(), height: D.getViewHeight()};
7791 width : d.clientWidth,
7792 height: d.clientHeight
7798 * Returns the value of the "value" attribute
7799 * @param {Boolean} asNumber true to parse the value as a number
7800 * @return {String/Number}
7802 getValue : function(asNumber){
7803 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7807 adjustWidth : function(width){
7808 if(typeof width == "number"){
7809 if(this.autoBoxAdjust && !this.isBorderBox()){
7810 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7820 adjustHeight : function(height){
7821 if(typeof height == "number"){
7822 if(this.autoBoxAdjust && !this.isBorderBox()){
7823 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7833 * Set the width of the element
7834 * @param {Number} width The new width
7835 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7836 * @return {Roo.Element} this
7838 setWidth : function(width, animate){
7839 width = this.adjustWidth(width);
7841 this.dom.style.width = this.addUnits(width);
7843 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7849 * Set the height of the element
7850 * @param {Number} height The new height
7851 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7852 * @return {Roo.Element} this
7854 setHeight : function(height, animate){
7855 height = this.adjustHeight(height);
7857 this.dom.style.height = this.addUnits(height);
7859 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7865 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7866 * @param {Number} width The new width
7867 * @param {Number} height The new height
7868 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7869 * @return {Roo.Element} this
7871 setSize : function(width, height, animate){
7872 if(typeof width == "object"){ // in case of object from getSize()
7873 height = width.height; width = width.width;
7875 width = this.adjustWidth(width); height = this.adjustHeight(height);
7877 this.dom.style.width = this.addUnits(width);
7878 this.dom.style.height = this.addUnits(height);
7880 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7886 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7887 * @param {Number} x X value for new position (coordinates are page-based)
7888 * @param {Number} y Y value for new position (coordinates are page-based)
7889 * @param {Number} width The new width
7890 * @param {Number} height The new height
7891 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7892 * @return {Roo.Element} this
7894 setBounds : function(x, y, width, height, animate){
7896 this.setSize(width, height);
7897 this.setLocation(x, y);
7899 width = this.adjustWidth(width); height = this.adjustHeight(height);
7900 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7901 this.preanim(arguments, 4), 'motion');
7907 * 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.
7908 * @param {Roo.lib.Region} region The region to fill
7909 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7910 * @return {Roo.Element} this
7912 setRegion : function(region, animate){
7913 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7918 * Appends an event handler
7920 * @param {String} eventName The type of event to append
7921 * @param {Function} fn The method the event invokes
7922 * @param {Object} scope (optional) The scope (this object) of the fn
7923 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7925 addListener : function(eventName, fn, scope, options){
7927 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7932 * Removes an event handler from this element
7933 * @param {String} eventName the type of event to remove
7934 * @param {Function} fn the method the event invokes
7935 * @return {Roo.Element} this
7937 removeListener : function(eventName, fn){
7938 Roo.EventManager.removeListener(this.dom, eventName, fn);
7943 * Removes all previous added listeners from this element
7944 * @return {Roo.Element} this
7946 removeAllListeners : function(){
7947 E.purgeElement(this.dom);
7951 relayEvent : function(eventName, observable){
7952 this.on(eventName, function(e){
7953 observable.fireEvent(eventName, e);
7958 * Set the opacity of the element
7959 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7960 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7961 * @return {Roo.Element} this
7963 setOpacity : function(opacity, animate){
7965 var s = this.dom.style;
7968 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7969 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7971 s.opacity = opacity;
7974 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7980 * Gets the left X coordinate
7981 * @param {Boolean} local True to get the local css position instead of page coordinate
7984 getLeft : function(local){
7988 return parseInt(this.getStyle("left"), 10) || 0;
7993 * Gets the right X coordinate of the element (element X position + element width)
7994 * @param {Boolean} local True to get the local css position instead of page coordinate
7997 getRight : function(local){
7999 return this.getX() + this.getWidth();
8001 return (this.getLeft(true) + this.getWidth()) || 0;
8006 * Gets the top Y coordinate
8007 * @param {Boolean} local True to get the local css position instead of page coordinate
8010 getTop : function(local) {
8014 return parseInt(this.getStyle("top"), 10) || 0;
8019 * Gets the bottom Y coordinate of the element (element Y position + element height)
8020 * @param {Boolean} local True to get the local css position instead of page coordinate
8023 getBottom : function(local){
8025 return this.getY() + this.getHeight();
8027 return (this.getTop(true) + this.getHeight()) || 0;
8032 * Initializes positioning on this element. If a desired position is not passed, it will make the
8033 * the element positioned relative IF it is not already positioned.
8034 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8035 * @param {Number} zIndex (optional) The zIndex to apply
8036 * @param {Number} x (optional) Set the page X position
8037 * @param {Number} y (optional) Set the page Y position
8039 position : function(pos, zIndex, x, y){
8041 if(this.getStyle('position') == 'static'){
8042 this.setStyle('position', 'relative');
8045 this.setStyle("position", pos);
8048 this.setStyle("z-index", zIndex);
8050 if(x !== undefined && y !== undefined){
8052 }else if(x !== undefined){
8054 }else if(y !== undefined){
8060 * Clear positioning back to the default when the document was loaded
8061 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8062 * @return {Roo.Element} this
8064 clearPositioning : function(value){
8072 "position" : "static"
8078 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8079 * snapshot before performing an update and then restoring the element.
8082 getPositioning : function(){
8083 var l = this.getStyle("left");
8084 var t = this.getStyle("top");
8086 "position" : this.getStyle("position"),
8088 "right" : l ? "" : this.getStyle("right"),
8090 "bottom" : t ? "" : this.getStyle("bottom"),
8091 "z-index" : this.getStyle("z-index")
8096 * Gets the width of the border(s) for the specified side(s)
8097 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8098 * passing lr would get the border (l)eft width + the border (r)ight width.
8099 * @return {Number} The width of the sides passed added together
8101 getBorderWidth : function(side){
8102 return this.addStyles(side, El.borders);
8106 * Gets the width of the padding(s) for the specified side(s)
8107 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8108 * passing lr would get the padding (l)eft + the padding (r)ight.
8109 * @return {Number} The padding of the sides passed added together
8111 getPadding : function(side){
8112 return this.addStyles(side, El.paddings);
8116 * Set positioning with an object returned by getPositioning().
8117 * @param {Object} posCfg
8118 * @return {Roo.Element} this
8120 setPositioning : function(pc){
8121 this.applyStyles(pc);
8122 if(pc.right == "auto"){
8123 this.dom.style.right = "";
8125 if(pc.bottom == "auto"){
8126 this.dom.style.bottom = "";
8132 fixDisplay : function(){
8133 if(this.getStyle("display") == "none"){
8134 this.setStyle("visibility", "hidden");
8135 this.setStyle("display", this.originalDisplay); // first try reverting to default
8136 if(this.getStyle("display") == "none"){ // if that fails, default to block
8137 this.setStyle("display", "block");
8143 * Quick set left and top adding default units
8144 * @param {String} left The left CSS property value
8145 * @param {String} top The top CSS property value
8146 * @return {Roo.Element} this
8148 setLeftTop : function(left, top){
8149 this.dom.style.left = this.addUnits(left);
8150 this.dom.style.top = this.addUnits(top);
8155 * Move this element relative to its current position.
8156 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8157 * @param {Number} distance How far to move the element in pixels
8158 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8159 * @return {Roo.Element} this
8161 move : function(direction, distance, animate){
8162 var xy = this.getXY();
8163 direction = direction.toLowerCase();
8167 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8171 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8176 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8181 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8188 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8189 * @return {Roo.Element} this
8192 if(!this.isClipped){
8193 this.isClipped = true;
8194 this.originalClip = {
8195 "o": this.getStyle("overflow"),
8196 "x": this.getStyle("overflow-x"),
8197 "y": this.getStyle("overflow-y")
8199 this.setStyle("overflow", "hidden");
8200 this.setStyle("overflow-x", "hidden");
8201 this.setStyle("overflow-y", "hidden");
8207 * Return clipping (overflow) to original clipping before clip() was called
8208 * @return {Roo.Element} this
8210 unclip : function(){
8212 this.isClipped = false;
8213 var o = this.originalClip;
8214 if(o.o){this.setStyle("overflow", o.o);}
8215 if(o.x){this.setStyle("overflow-x", o.x);}
8216 if(o.y){this.setStyle("overflow-y", o.y);}
8223 * Gets the x,y coordinates specified by the anchor position on the element.
8224 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8225 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8226 * {width: (target width), height: (target height)} (defaults to the element's current size)
8227 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8228 * @return {Array} [x, y] An array containing the element's x and y coordinates
8230 getAnchorXY : function(anchor, local, s){
8231 //Passing a different size is useful for pre-calculating anchors,
8232 //especially for anchored animations that change the el size.
8234 var w, h, vp = false;
8237 if(d == document.body || d == document){
8239 w = D.getViewWidth(); h = D.getViewHeight();
8241 w = this.getWidth(); h = this.getHeight();
8244 w = s.width; h = s.height;
8246 var x = 0, y = 0, r = Math.round;
8247 switch((anchor || "tl").toLowerCase()){
8289 var sc = this.getScroll();
8290 return [x + sc.left, y + sc.top];
8292 //Add the element's offset xy
8293 var o = this.getXY();
8294 return [x+o[0], y+o[1]];
8298 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8299 * supported position values.
8300 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8301 * @param {String} position The position to align to.
8302 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8303 * @return {Array} [x, y]
8305 getAlignToXY : function(el, p, o){
8309 throw "Element.alignTo with an element that doesn't exist";
8311 var c = false; //constrain to viewport
8312 var p1 = "", p2 = "";
8319 }else if(p.indexOf("-") == -1){
8322 p = p.toLowerCase();
8323 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8325 throw "Element.alignTo with an invalid alignment " + p;
8327 p1 = m[1]; p2 = m[2]; c = !!m[3];
8329 //Subtract the aligned el's internal xy from the target's offset xy
8330 //plus custom offset to get the aligned el's new offset xy
8331 var a1 = this.getAnchorXY(p1, true);
8332 var a2 = el.getAnchorXY(p2, false);
8333 var x = a2[0] - a1[0] + o[0];
8334 var y = a2[1] - a1[1] + o[1];
8336 //constrain the aligned el to viewport if necessary
8337 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8338 // 5px of margin for ie
8339 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8341 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8342 //perpendicular to the vp border, allow the aligned el to slide on that border,
8343 //otherwise swap the aligned el to the opposite border of the target.
8344 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8345 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8346 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8347 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8350 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8351 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8353 if((x+w) > dw + scrollX){
8354 x = swapX ? r.left-w : dw+scrollX-w;
8357 x = swapX ? r.right : scrollX;
8359 if((y+h) > dh + scrollY){
8360 y = swapY ? r.top-h : dh+scrollY-h;
8363 y = swapY ? r.bottom : scrollY;
8370 getConstrainToXY : function(){
8371 var os = {top:0, left:0, bottom:0, right: 0};
8373 return function(el, local, offsets, proposedXY){
8375 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8377 var vw, vh, vx = 0, vy = 0;
8378 if(el.dom == document.body || el.dom == document){
8379 vw = Roo.lib.Dom.getViewWidth();
8380 vh = Roo.lib.Dom.getViewHeight();
8382 vw = el.dom.clientWidth;
8383 vh = el.dom.clientHeight;
8385 var vxy = el.getXY();
8391 var s = el.getScroll();
8393 vx += offsets.left + s.left;
8394 vy += offsets.top + s.top;
8396 vw -= offsets.right;
8397 vh -= offsets.bottom;
8402 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8403 var x = xy[0], y = xy[1];
8404 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8406 // only move it if it needs it
8409 // first validate right/bottom
8418 // then make sure top/left isn't negative
8427 return moved ? [x, y] : false;
8432 adjustForConstraints : function(xy, parent, offsets){
8433 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8437 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8438 * document it aligns it to the viewport.
8439 * The position parameter is optional, and can be specified in any one of the following formats:
8441 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8442 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8443 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8444 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8445 * <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
8446 * element's anchor point, and the second value is used as the target's anchor point.</li>
8448 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8449 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8450 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8451 * that specified in order to enforce the viewport constraints.
8452 * Following are all of the supported anchor positions:
8455 ----- -----------------------------
8456 tl The top left corner (default)
8457 t The center of the top edge
8458 tr The top right corner
8459 l The center of the left edge
8460 c In the center of the element
8461 r The center of the right edge
8462 bl The bottom left corner
8463 b The center of the bottom edge
8464 br The bottom right corner
8468 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8469 el.alignTo("other-el");
8471 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8472 el.alignTo("other-el", "tr?");
8474 // align the bottom right corner of el with the center left edge of other-el
8475 el.alignTo("other-el", "br-l?");
8477 // align the center of el with the bottom left corner of other-el and
8478 // adjust the x position by -6 pixels (and the y position by 0)
8479 el.alignTo("other-el", "c-bl", [-6, 0]);
8481 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8482 * @param {String} position The position to align to.
8483 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8484 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8485 * @return {Roo.Element} this
8487 alignTo : function(element, position, offsets, animate){
8488 var xy = this.getAlignToXY(element, position, offsets);
8489 this.setXY(xy, this.preanim(arguments, 3));
8494 * Anchors an element to another element and realigns it when the window is resized.
8495 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8496 * @param {String} position The position to align to.
8497 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8498 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8499 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8500 * is a number, it is used as the buffer delay (defaults to 50ms).
8501 * @param {Function} callback The function to call after the animation finishes
8502 * @return {Roo.Element} this
8504 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8505 var action = function(){
8506 this.alignTo(el, alignment, offsets, animate);
8507 Roo.callback(callback, this);
8509 Roo.EventManager.onWindowResize(action, this);
8510 var tm = typeof monitorScroll;
8511 if(tm != 'undefined'){
8512 Roo.EventManager.on(window, 'scroll', action, this,
8513 {buffer: tm == 'number' ? monitorScroll : 50});
8515 action.call(this); // align immediately
8519 * Clears any opacity settings from this element. Required in some cases for IE.
8520 * @return {Roo.Element} this
8522 clearOpacity : function(){
8523 if (window.ActiveXObject) {
8524 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8525 this.dom.style.filter = "";
8528 this.dom.style.opacity = "";
8529 this.dom.style["-moz-opacity"] = "";
8530 this.dom.style["-khtml-opacity"] = "";
8536 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8537 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8538 * @return {Roo.Element} this
8540 hide : function(animate){
8541 this.setVisible(false, this.preanim(arguments, 0));
8546 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8547 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8548 * @return {Roo.Element} this
8550 show : function(animate){
8551 this.setVisible(true, this.preanim(arguments, 0));
8556 * @private Test if size has a unit, otherwise appends the default
8558 addUnits : function(size){
8559 return Roo.Element.addUnits(size, this.defaultUnit);
8563 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8564 * @return {Roo.Element} this
8566 beginMeasure : function(){
8568 if(el.offsetWidth || el.offsetHeight){
8569 return this; // offsets work already
8572 var p = this.dom, b = document.body; // start with this element
8573 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8574 var pe = Roo.get(p);
8575 if(pe.getStyle('display') == 'none'){
8576 changed.push({el: p, visibility: pe.getStyle("visibility")});
8577 p.style.visibility = "hidden";
8578 p.style.display = "block";
8582 this._measureChanged = changed;
8588 * Restores displays to before beginMeasure was called
8589 * @return {Roo.Element} this
8591 endMeasure : function(){
8592 var changed = this._measureChanged;
8594 for(var i = 0, len = changed.length; i < len; i++) {
8596 r.el.style.visibility = r.visibility;
8597 r.el.style.display = "none";
8599 this._measureChanged = null;
8605 * Update the innerHTML of this element, optionally searching for and processing scripts
8606 * @param {String} html The new HTML
8607 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8608 * @param {Function} callback For async script loading you can be noticed when the update completes
8609 * @return {Roo.Element} this
8611 update : function(html, loadScripts, callback){
8612 if(typeof html == "undefined"){
8615 if(loadScripts !== true){
8616 this.dom.innerHTML = html;
8617 if(typeof callback == "function"){
8625 html += '<span id="' + id + '"></span>';
8627 E.onAvailable(id, function(){
8628 var hd = document.getElementsByTagName("head")[0];
8629 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8630 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8631 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8634 while(match = re.exec(html)){
8635 var attrs = match[1];
8636 var srcMatch = attrs ? attrs.match(srcRe) : false;
8637 if(srcMatch && srcMatch[2]){
8638 var s = document.createElement("script");
8639 s.src = srcMatch[2];
8640 var typeMatch = attrs.match(typeRe);
8641 if(typeMatch && typeMatch[2]){
8642 s.type = typeMatch[2];
8645 }else if(match[2] && match[2].length > 0){
8646 if(window.execScript) {
8647 window.execScript(match[2]);
8655 window.eval(match[2]);
8659 var el = document.getElementById(id);
8660 if(el){el.parentNode.removeChild(el);}
8661 if(typeof callback == "function"){
8665 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8670 * Direct access to the UpdateManager update() method (takes the same parameters).
8671 * @param {String/Function} url The url for this request or a function to call to get the url
8672 * @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}
8673 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8674 * @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.
8675 * @return {Roo.Element} this
8678 var um = this.getUpdateManager();
8679 um.update.apply(um, arguments);
8684 * Gets this element's UpdateManager
8685 * @return {Roo.UpdateManager} The UpdateManager
8687 getUpdateManager : function(){
8688 if(!this.updateManager){
8689 this.updateManager = new Roo.UpdateManager(this);
8691 return this.updateManager;
8695 * Disables text selection for this element (normalized across browsers)
8696 * @return {Roo.Element} this
8698 unselectable : function(){
8699 this.dom.unselectable = "on";
8700 this.swallowEvent("selectstart", true);
8701 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8702 this.addClass("x-unselectable");
8707 * Calculates the x, y to center this element on the screen
8708 * @return {Array} The x, y values [x, y]
8710 getCenterXY : function(){
8711 return this.getAlignToXY(document, 'c-c');
8715 * Centers the Element in either the viewport, or another Element.
8716 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8718 center : function(centerIn){
8719 this.alignTo(centerIn || document, 'c-c');
8724 * Tests various css rules/browsers to determine if this element uses a border box
8727 isBorderBox : function(){
8728 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8732 * Return a box {x, y, width, height} that can be used to set another elements
8733 * size/location to match this element.
8734 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8735 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8736 * @return {Object} box An object in the format {x, y, width, height}
8738 getBox : function(contentBox, local){
8743 var left = parseInt(this.getStyle("left"), 10) || 0;
8744 var top = parseInt(this.getStyle("top"), 10) || 0;
8747 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8749 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8751 var l = this.getBorderWidth("l")+this.getPadding("l");
8752 var r = this.getBorderWidth("r")+this.getPadding("r");
8753 var t = this.getBorderWidth("t")+this.getPadding("t");
8754 var b = this.getBorderWidth("b")+this.getPadding("b");
8755 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)};
8757 bx.right = bx.x + bx.width;
8758 bx.bottom = bx.y + bx.height;
8763 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8764 for more information about the sides.
8765 * @param {String} sides
8768 getFrameWidth : function(sides, onlyContentBox){
8769 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8773 * 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.
8774 * @param {Object} box The box to fill {x, y, width, height}
8775 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8776 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8777 * @return {Roo.Element} this
8779 setBox : function(box, adjust, animate){
8780 var w = box.width, h = box.height;
8781 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8782 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8783 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8785 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8790 * Forces the browser to repaint this element
8791 * @return {Roo.Element} this
8793 repaint : function(){
8795 this.addClass("x-repaint");
8796 setTimeout(function(){
8797 Roo.get(dom).removeClass("x-repaint");
8803 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8804 * then it returns the calculated width of the sides (see getPadding)
8805 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8806 * @return {Object/Number}
8808 getMargins : function(side){
8811 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8812 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8813 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8814 right: parseInt(this.getStyle("margin-right"), 10) || 0
8817 return this.addStyles(side, El.margins);
8822 addStyles : function(sides, styles){
8824 for(var i = 0, len = sides.length; i < len; i++){
8825 v = this.getStyle(styles[sides.charAt(i)]);
8827 w = parseInt(v, 10);
8835 * Creates a proxy element of this element
8836 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8837 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8838 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8839 * @return {Roo.Element} The new proxy element
8841 createProxy : function(config, renderTo, matchBox){
8843 renderTo = Roo.getDom(renderTo);
8845 renderTo = document.body;
8847 config = typeof config == "object" ?
8848 config : {tag : "div", cls: config};
8849 var proxy = Roo.DomHelper.append(renderTo, config, true);
8851 proxy.setBox(this.getBox());
8857 * Puts a mask over this element to disable user interaction. Requires core.css.
8858 * This method can only be applied to elements which accept child nodes.
8859 * @param {String} msg (optional) A message to display in the mask
8860 * @param {String} msgCls (optional) A css class to apply to the msg element
8861 * @return {Element} The mask element
8863 mask : function(msg, msgCls)
8865 if(this.getStyle("position") == "static"){
8866 this.setStyle("position", "relative");
8869 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8871 this.addClass("x-masked");
8872 this._mask.setDisplayed(true);
8873 var p = this.getPositioning();
8874 if(typeof msg == 'string'){
8876 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8878 var mm = this._maskMsg;
8879 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8880 mm.dom.firstChild.innerHTML = msg;
8881 mm.setDisplayed(true);
8883 mm.setStyle('z-index', parseInt(p['z-index']) + 102);
8885 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8886 this._mask.setHeight(this.getHeight());
8888 this._mask.setStyle('z-index', parseInt(p['z-index']) + 100);
8894 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8895 * it is cached for reuse.
8897 unmask : function(removeEl){
8899 if(removeEl === true){
8900 this._mask.remove();
8903 this._maskMsg.remove();
8904 delete this._maskMsg;
8907 this._mask.setDisplayed(false);
8909 this._maskMsg.setDisplayed(false);
8913 this.removeClass("x-masked");
8917 * Returns true if this element is masked
8920 isMasked : function(){
8921 return this._mask && this._mask.isVisible();
8925 * Creates an iframe shim for this element to keep selects and other windowed objects from
8927 * @return {Roo.Element} The new shim element
8929 createShim : function(){
8930 var el = document.createElement('iframe');
8931 el.frameBorder = 'no';
8932 el.className = 'roo-shim';
8933 if(Roo.isIE && Roo.isSecure){
8934 el.src = Roo.SSL_SECURE_URL;
8936 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8937 shim.autoBoxAdjust = false;
8942 * Removes this element from the DOM and deletes it from the cache
8944 remove : function(){
8945 if(this.dom.parentNode){
8946 this.dom.parentNode.removeChild(this.dom);
8948 delete El.cache[this.dom.id];
8952 * Sets up event handlers to add and remove a css class when the mouse is over this element
8953 * @param {String} className
8954 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8955 * mouseout events for children elements
8956 * @return {Roo.Element} this
8958 addClassOnOver : function(className, preventFlicker){
8959 this.on("mouseover", function(){
8960 Roo.fly(this, '_internal').addClass(className);
8962 var removeFn = function(e){
8963 if(preventFlicker !== true || !e.within(this, true)){
8964 Roo.fly(this, '_internal').removeClass(className);
8967 this.on("mouseout", removeFn, this.dom);
8972 * Sets up event handlers to add and remove a css class when this element has the focus
8973 * @param {String} className
8974 * @return {Roo.Element} this
8976 addClassOnFocus : function(className){
8977 this.on("focus", function(){
8978 Roo.fly(this, '_internal').addClass(className);
8980 this.on("blur", function(){
8981 Roo.fly(this, '_internal').removeClass(className);
8986 * 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)
8987 * @param {String} className
8988 * @return {Roo.Element} this
8990 addClassOnClick : function(className){
8992 this.on("mousedown", function(){
8993 Roo.fly(dom, '_internal').addClass(className);
8994 var d = Roo.get(document);
8995 var fn = function(){
8996 Roo.fly(dom, '_internal').removeClass(className);
8997 d.removeListener("mouseup", fn);
8999 d.on("mouseup", fn);
9005 * Stops the specified event from bubbling and optionally prevents the default action
9006 * @param {String} eventName
9007 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9008 * @return {Roo.Element} this
9010 swallowEvent : function(eventName, preventDefault){
9011 var fn = function(e){
9012 e.stopPropagation();
9017 if(eventName instanceof Array){
9018 for(var i = 0, len = eventName.length; i < len; i++){
9019 this.on(eventName[i], fn);
9023 this.on(eventName, fn);
9030 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9033 * Sizes this element to its parent element's dimensions performing
9034 * neccessary box adjustments.
9035 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9036 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9037 * @return {Roo.Element} this
9039 fitToParent : function(monitorResize, targetParent) {
9040 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9041 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9042 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9045 var p = Roo.get(targetParent || this.dom.parentNode);
9046 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9047 if (monitorResize === true) {
9048 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9049 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9055 * Gets the next sibling, skipping text nodes
9056 * @return {HTMLElement} The next sibling or null
9058 getNextSibling : function(){
9059 var n = this.dom.nextSibling;
9060 while(n && n.nodeType != 1){
9067 * Gets the previous sibling, skipping text nodes
9068 * @return {HTMLElement} The previous sibling or null
9070 getPrevSibling : function(){
9071 var n = this.dom.previousSibling;
9072 while(n && n.nodeType != 1){
9073 n = n.previousSibling;
9080 * Appends the passed element(s) to this element
9081 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9082 * @return {Roo.Element} this
9084 appendChild: function(el){
9091 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9092 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9093 * automatically generated with the specified attributes.
9094 * @param {HTMLElement} insertBefore (optional) a child element of this element
9095 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9096 * @return {Roo.Element} The new child element
9098 createChild: function(config, insertBefore, returnDom){
9099 config = config || {tag:'div'};
9101 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9103 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9107 * Appends this element to the passed element
9108 * @param {String/HTMLElement/Element} el The new parent element
9109 * @return {Roo.Element} this
9111 appendTo: function(el){
9112 el = Roo.getDom(el);
9113 el.appendChild(this.dom);
9118 * Inserts this element before the passed element in the DOM
9119 * @param {String/HTMLElement/Element} el The element to insert before
9120 * @return {Roo.Element} this
9122 insertBefore: function(el){
9123 el = Roo.getDom(el);
9124 el.parentNode.insertBefore(this.dom, el);
9129 * Inserts this element after the passed element in the DOM
9130 * @param {String/HTMLElement/Element} el The element to insert after
9131 * @return {Roo.Element} this
9133 insertAfter: function(el){
9134 el = Roo.getDom(el);
9135 el.parentNode.insertBefore(this.dom, el.nextSibling);
9140 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9141 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9142 * @return {Roo.Element} The new child
9144 insertFirst: function(el, returnDom){
9146 if(typeof el == 'object' && !el.nodeType){ // dh config
9147 return this.createChild(el, this.dom.firstChild, returnDom);
9149 el = Roo.getDom(el);
9150 this.dom.insertBefore(el, this.dom.firstChild);
9151 return !returnDom ? Roo.get(el) : el;
9156 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9157 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9158 * @param {String} where (optional) 'before' or 'after' defaults to before
9159 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9160 * @return {Roo.Element} the inserted Element
9162 insertSibling: function(el, where, returnDom){
9163 where = where ? where.toLowerCase() : 'before';
9165 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9167 if(typeof el == 'object' && !el.nodeType){ // dh config
9168 if(where == 'after' && !this.dom.nextSibling){
9169 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9171 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9175 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9176 where == 'before' ? this.dom : this.dom.nextSibling);
9185 * Creates and wraps this element with another element
9186 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9187 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9188 * @return {HTMLElement/Element} The newly created wrapper element
9190 wrap: function(config, returnDom){
9192 config = {tag: "div"};
9194 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9195 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9200 * Replaces the passed element with this element
9201 * @param {String/HTMLElement/Element} el The element to replace
9202 * @return {Roo.Element} this
9204 replace: function(el){
9206 this.insertBefore(el);
9212 * Inserts an html fragment into this element
9213 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9214 * @param {String} html The HTML fragment
9215 * @param {Boolean} returnEl True to return an Roo.Element
9216 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9218 insertHtml : function(where, html, returnEl){
9219 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9220 return returnEl ? Roo.get(el) : el;
9224 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9225 * @param {Object} o The object with the attributes
9226 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9227 * @return {Roo.Element} this
9229 set : function(o, useSet){
9231 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9233 if(attr == "style" || typeof o[attr] == "function") continue;
9235 el.className = o["cls"];
9237 if(useSet) el.setAttribute(attr, o[attr]);
9238 else el[attr] = o[attr];
9242 Roo.DomHelper.applyStyles(el, o.style);
9248 * Convenience method for constructing a KeyMap
9249 * @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:
9250 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9251 * @param {Function} fn The function to call
9252 * @param {Object} scope (optional) The scope of the function
9253 * @return {Roo.KeyMap} The KeyMap created
9255 addKeyListener : function(key, fn, scope){
9257 if(typeof key != "object" || key instanceof Array){
9273 return new Roo.KeyMap(this, config);
9277 * Creates a KeyMap for this element
9278 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9279 * @return {Roo.KeyMap} The KeyMap created
9281 addKeyMap : function(config){
9282 return new Roo.KeyMap(this, config);
9286 * Returns true if this element is scrollable.
9289 isScrollable : function(){
9291 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9295 * 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().
9296 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9297 * @param {Number} value The new scroll value
9298 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9299 * @return {Element} this
9302 scrollTo : function(side, value, animate){
9303 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9305 this.dom[prop] = value;
9307 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9308 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9314 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9315 * within this element's scrollable range.
9316 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9317 * @param {Number} distance How far to scroll the element in pixels
9318 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9319 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9320 * was scrolled as far as it could go.
9322 scroll : function(direction, distance, animate){
9323 if(!this.isScrollable()){
9327 var l = el.scrollLeft, t = el.scrollTop;
9328 var w = el.scrollWidth, h = el.scrollHeight;
9329 var cw = el.clientWidth, ch = el.clientHeight;
9330 direction = direction.toLowerCase();
9331 var scrolled = false;
9332 var a = this.preanim(arguments, 2);
9337 var v = Math.min(l + distance, w-cw);
9338 this.scrollTo("left", v, a);
9345 var v = Math.max(l - distance, 0);
9346 this.scrollTo("left", v, a);
9354 var v = Math.max(t - distance, 0);
9355 this.scrollTo("top", v, a);
9363 var v = Math.min(t + distance, h-ch);
9364 this.scrollTo("top", v, a);
9373 * Translates the passed page coordinates into left/top css values for this element
9374 * @param {Number/Array} x The page x or an array containing [x, y]
9375 * @param {Number} y The page y
9376 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9378 translatePoints : function(x, y){
9379 if(typeof x == 'object' || x instanceof Array){
9382 var p = this.getStyle('position');
9383 var o = this.getXY();
9385 var l = parseInt(this.getStyle('left'), 10);
9386 var t = parseInt(this.getStyle('top'), 10);
9389 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9392 t = (p == "relative") ? 0 : this.dom.offsetTop;
9395 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9399 * Returns the current scroll position of the element.
9400 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9402 getScroll : function(){
9403 var d = this.dom, doc = document;
9404 if(d == doc || d == doc.body){
9405 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9406 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9407 return {left: l, top: t};
9409 return {left: d.scrollLeft, top: d.scrollTop};
9414 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9415 * are convert to standard 6 digit hex color.
9416 * @param {String} attr The css attribute
9417 * @param {String} defaultValue The default value to use when a valid color isn't found
9418 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9421 getColor : function(attr, defaultValue, prefix){
9422 var v = this.getStyle(attr);
9423 if(!v || v == "transparent" || v == "inherit") {
9424 return defaultValue;
9426 var color = typeof prefix == "undefined" ? "#" : prefix;
9427 if(v.substr(0, 4) == "rgb("){
9428 var rvs = v.slice(4, v.length -1).split(",");
9429 for(var i = 0; i < 3; i++){
9430 var h = parseInt(rvs[i]).toString(16);
9437 if(v.substr(0, 1) == "#"){
9439 for(var i = 1; i < 4; i++){
9440 var c = v.charAt(i);
9443 }else if(v.length == 7){
9444 color += v.substr(1);
9448 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9452 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9453 * gradient background, rounded corners and a 4-way shadow.
9454 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9455 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9456 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9457 * @return {Roo.Element} this
9459 boxWrap : function(cls){
9460 cls = cls || 'x-box';
9461 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9462 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9467 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9468 * @param {String} namespace The namespace in which to look for the attribute
9469 * @param {String} name The attribute name
9470 * @return {String} The attribute value
9472 getAttributeNS : Roo.isIE ? function(ns, name){
9474 var type = typeof d[ns+":"+name];
9475 if(type != 'undefined' && type != 'unknown'){
9476 return d[ns+":"+name];
9479 } : function(ns, name){
9481 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9485 var ep = El.prototype;
9488 * Appends an event handler (Shorthand for addListener)
9489 * @param {String} eventName The type of event to append
9490 * @param {Function} fn The method the event invokes
9491 * @param {Object} scope (optional) The scope (this object) of the fn
9492 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9495 ep.on = ep.addListener;
9497 ep.mon = ep.addListener;
9500 * Removes an event handler from this element (shorthand for removeListener)
9501 * @param {String} eventName the type of event to remove
9502 * @param {Function} fn the method the event invokes
9503 * @return {Roo.Element} this
9506 ep.un = ep.removeListener;
9509 * true to automatically adjust width and height settings for box-model issues (default to true)
9511 ep.autoBoxAdjust = true;
9514 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9517 El.addUnits = function(v, defaultUnit){
9518 if(v === "" || v == "auto"){
9521 if(v === undefined){
9524 if(typeof v == "number" || !El.unitPattern.test(v)){
9525 return v + (defaultUnit || 'px');
9530 // special markup used throughout Roo when box wrapping elements
9531 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>';
9533 * Visibility mode constant - Use visibility to hide element
9539 * Visibility mode constant - Use display to hide element
9545 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9546 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9547 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9559 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9560 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9561 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9562 * @return {Element} The Element object
9565 El.get = function(el){
9567 if(!el){ return null; }
9568 if(typeof el == "string"){ // element id
9569 if(!(elm = document.getElementById(el))){
9572 if(ex = El.cache[el]){
9575 ex = El.cache[el] = new El(elm);
9578 }else if(el.tagName){ // dom element
9582 if(ex = El.cache[id]){
9585 ex = El.cache[id] = new El(el);
9588 }else if(el instanceof El){
9590 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9591 // catch case where it hasn't been appended
9592 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9595 }else if(el.isComposite){
9597 }else if(el instanceof Array){
9598 return El.select(el);
9599 }else if(el == document){
9600 // create a bogus element object representing the document object
9602 var f = function(){};
9603 f.prototype = El.prototype;
9605 docEl.dom = document;
9613 El.uncache = function(el){
9614 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9616 delete El.cache[a[i].id || a[i]];
9622 // Garbage collection - uncache elements/purge listeners on orphaned elements
9623 // so we don't hold a reference and cause the browser to retain them
9624 El.garbageCollect = function(){
9625 if(!Roo.enableGarbageCollector){
9626 clearInterval(El.collectorThread);
9629 for(var eid in El.cache){
9630 var el = El.cache[eid], d = el.dom;
9631 // -------------------------------------------------------
9632 // Determining what is garbage:
9633 // -------------------------------------------------------
9635 // dom node is null, definitely garbage
9636 // -------------------------------------------------------
9638 // no parentNode == direct orphan, definitely garbage
9639 // -------------------------------------------------------
9640 // !d.offsetParent && !document.getElementById(eid)
9641 // display none elements have no offsetParent so we will
9642 // also try to look it up by it's id. However, check
9643 // offsetParent first so we don't do unneeded lookups.
9644 // This enables collection of elements that are not orphans
9645 // directly, but somewhere up the line they have an orphan
9647 // -------------------------------------------------------
9648 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9649 delete El.cache[eid];
9650 if(d && Roo.enableListenerCollection){
9656 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9660 El.Flyweight = function(dom){
9663 El.Flyweight.prototype = El.prototype;
9665 El._flyweights = {};
9667 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9668 * the dom node can be overwritten by other code.
9669 * @param {String/HTMLElement} el The dom node or id
9670 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9671 * prevent conflicts (e.g. internally Roo uses "_internal")
9673 * @return {Element} The shared Element object
9675 El.fly = function(el, named){
9676 named = named || '_global';
9677 el = Roo.getDom(el);
9681 if(!El._flyweights[named]){
9682 El._flyweights[named] = new El.Flyweight();
9684 El._flyweights[named].dom = el;
9685 return El._flyweights[named];
9689 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9690 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9691 * Shorthand of {@link Roo.Element#get}
9692 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9693 * @return {Element} The Element object
9699 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9700 * the dom node can be overwritten by other code.
9701 * Shorthand of {@link Roo.Element#fly}
9702 * @param {String/HTMLElement} el The dom node or id
9703 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9704 * prevent conflicts (e.g. internally Roo uses "_internal")
9706 * @return {Element} The shared Element object
9712 // speedy lookup for elements never to box adjust
9713 var noBoxAdjust = Roo.isStrict ? {
9716 input:1, select:1, textarea:1
9718 if(Roo.isIE || Roo.isGecko){
9719 noBoxAdjust['button'] = 1;
9723 Roo.EventManager.on(window, 'unload', function(){
9725 delete El._flyweights;
9733 Roo.Element.selectorFunction = Roo.DomQuery.select;
9736 Roo.Element.select = function(selector, unique, root){
9738 if(typeof selector == "string"){
9739 els = Roo.Element.selectorFunction(selector, root);
9740 }else if(selector.length !== undefined){
9743 throw "Invalid selector";
9745 if(unique === true){
9746 return new Roo.CompositeElement(els);
9748 return new Roo.CompositeElementLite(els);
9752 * Selects elements based on the passed CSS selector to enable working on them as 1.
9753 * @param {String/Array} selector The CSS selector or an array of elements
9754 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9755 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9756 * @return {CompositeElementLite/CompositeElement}
9760 Roo.select = Roo.Element.select;
9777 * Ext JS Library 1.1.1
9778 * Copyright(c) 2006-2007, Ext JS, LLC.
9780 * Originally Released Under LGPL - original licence link has changed is not relivant.
9783 * <script type="text/javascript">
9788 //Notifies Element that fx methods are available
9789 Roo.enableFx = true;
9793 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9794 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9795 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9796 * Element effects to work.</p><br/>
9798 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9799 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9800 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9801 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9802 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9803 * expected results and should be done with care.</p><br/>
9805 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9806 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9809 ----- -----------------------------
9810 tl The top left corner
9811 t The center of the top edge
9812 tr The top right corner
9813 l The center of the left edge
9814 r The center of the right edge
9815 bl The bottom left corner
9816 b The center of the bottom edge
9817 br The bottom right corner
9819 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9820 * below are common options that can be passed to any Fx method.</b>
9821 * @cfg {Function} callback A function called when the effect is finished
9822 * @cfg {Object} scope The scope of the effect function
9823 * @cfg {String} easing A valid Easing value for the effect
9824 * @cfg {String} afterCls A css class to apply after the effect
9825 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9826 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9827 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9828 * effects that end with the element being visually hidden, ignored otherwise)
9829 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9830 * a function which returns such a specification that will be applied to the Element after the effect finishes
9831 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9832 * @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
9833 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9837 * Slides the element into view. An anchor point can be optionally passed to set the point of
9838 * origin for the slide effect. This function automatically handles wrapping the element with
9839 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9842 // default: slide the element in from the top
9845 // custom: slide the element in from the right with a 2-second duration
9846 el.slideIn('r', { duration: 2 });
9848 // common config options shown with default values
9854 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9855 * @param {Object} options (optional) Object literal with any of the Fx config options
9856 * @return {Roo.Element} The Element
9858 slideIn : function(anchor, o){
9859 var el = this.getFxEl();
9862 el.queueFx(o, function(){
9864 anchor = anchor || "t";
9866 // fix display to visibility
9869 // restore values after effect
9870 var r = this.getFxRestore();
9871 var b = this.getBox();
9872 // fixed size for slide
9876 var wrap = this.fxWrap(r.pos, o, "hidden");
9878 var st = this.dom.style;
9879 st.visibility = "visible";
9880 st.position = "absolute";
9882 // clear out temp styles after slide and unwrap
9883 var after = function(){
9884 el.fxUnwrap(wrap, r.pos, o);
9886 st.height = r.height;
9889 // time to calc the positions
9890 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9892 switch(anchor.toLowerCase()){
9894 wrap.setSize(b.width, 0);
9895 st.left = st.bottom = "0";
9899 wrap.setSize(0, b.height);
9900 st.right = st.top = "0";
9904 wrap.setSize(0, b.height);
9906 st.left = st.top = "0";
9907 a = {width: bw, points: pt};
9910 wrap.setSize(b.width, 0);
9911 wrap.setY(b.bottom);
9912 st.left = st.top = "0";
9913 a = {height: bh, points: pt};
9917 st.right = st.bottom = "0";
9918 a = {width: bw, height: bh};
9922 wrap.setY(b.y+b.height);
9923 st.right = st.top = "0";
9924 a = {width: bw, height: bh, points: pt};
9928 wrap.setXY([b.right, b.bottom]);
9929 st.left = st.top = "0";
9930 a = {width: bw, height: bh, points: pt};
9934 wrap.setX(b.x+b.width);
9935 st.left = st.bottom = "0";
9936 a = {width: bw, height: bh, points: pt};
9939 this.dom.style.visibility = "visible";
9942 arguments.callee.anim = wrap.fxanim(a,
9952 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9953 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9954 * 'hidden') but block elements will still take up space in the document. The element must be removed
9955 * from the DOM using the 'remove' config option if desired. This function automatically handles
9956 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9959 // default: slide the element out to the top
9962 // custom: slide the element out to the right with a 2-second duration
9963 el.slideOut('r', { duration: 2 });
9965 // common config options shown with default values
9973 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9974 * @param {Object} options (optional) Object literal with any of the Fx config options
9975 * @return {Roo.Element} The Element
9977 slideOut : function(anchor, o){
9978 var el = this.getFxEl();
9981 el.queueFx(o, function(){
9983 anchor = anchor || "t";
9985 // restore values after effect
9986 var r = this.getFxRestore();
9988 var b = this.getBox();
9989 // fixed size for slide
9993 var wrap = this.fxWrap(r.pos, o, "visible");
9995 var st = this.dom.style;
9996 st.visibility = "visible";
9997 st.position = "absolute";
10001 var after = function(){
10003 el.setDisplayed(false);
10008 el.fxUnwrap(wrap, r.pos, o);
10010 st.width = r.width;
10011 st.height = r.height;
10016 var a, zero = {to: 0};
10017 switch(anchor.toLowerCase()){
10019 st.left = st.bottom = "0";
10020 a = {height: zero};
10023 st.right = st.top = "0";
10027 st.left = st.top = "0";
10028 a = {width: zero, points: {to:[b.right, b.y]}};
10031 st.left = st.top = "0";
10032 a = {height: zero, points: {to:[b.x, b.bottom]}};
10035 st.right = st.bottom = "0";
10036 a = {width: zero, height: zero};
10039 st.right = st.top = "0";
10040 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10043 st.left = st.top = "0";
10044 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10047 st.left = st.bottom = "0";
10048 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10052 arguments.callee.anim = wrap.fxanim(a,
10062 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10063 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10064 * The element must be removed from the DOM using the 'remove' config option if desired.
10070 // common config options shown with default values
10078 * @param {Object} options (optional) Object literal with any of the Fx config options
10079 * @return {Roo.Element} The Element
10081 puff : function(o){
10082 var el = this.getFxEl();
10085 el.queueFx(o, function(){
10086 this.clearOpacity();
10089 // restore values after effect
10090 var r = this.getFxRestore();
10091 var st = this.dom.style;
10093 var after = function(){
10095 el.setDisplayed(false);
10102 el.setPositioning(r.pos);
10103 st.width = r.width;
10104 st.height = r.height;
10109 var width = this.getWidth();
10110 var height = this.getHeight();
10112 arguments.callee.anim = this.fxanim({
10113 width : {to: this.adjustWidth(width * 2)},
10114 height : {to: this.adjustHeight(height * 2)},
10115 points : {by: [-(width * .5), -(height * .5)]},
10117 fontSize: {to:200, unit: "%"}
10128 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10129 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10130 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10136 // all config options shown with default values
10144 * @param {Object} options (optional) Object literal with any of the Fx config options
10145 * @return {Roo.Element} The Element
10147 switchOff : function(o){
10148 var el = this.getFxEl();
10151 el.queueFx(o, function(){
10152 this.clearOpacity();
10155 // restore values after effect
10156 var r = this.getFxRestore();
10157 var st = this.dom.style;
10159 var after = function(){
10161 el.setDisplayed(false);
10167 el.setPositioning(r.pos);
10168 st.width = r.width;
10169 st.height = r.height;
10174 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10175 this.clearOpacity();
10179 points:{by:[0, this.getHeight() * .5]}
10180 }, o, 'motion', 0.3, 'easeIn', after);
10181 }).defer(100, this);
10188 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10189 * changed using the "attr" config option) and then fading back to the original color. If no original
10190 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10193 // default: highlight background to yellow
10196 // custom: highlight foreground text to blue for 2 seconds
10197 el.highlight("0000ff", { attr: 'color', duration: 2 });
10199 // common config options shown with default values
10200 el.highlight("ffff9c", {
10201 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10202 endColor: (current color) or "ffffff",
10207 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10208 * @param {Object} options (optional) Object literal with any of the Fx config options
10209 * @return {Roo.Element} The Element
10211 highlight : function(color, o){
10212 var el = this.getFxEl();
10215 el.queueFx(o, function(){
10216 color = color || "ffff9c";
10217 attr = o.attr || "backgroundColor";
10219 this.clearOpacity();
10222 var origColor = this.getColor(attr);
10223 var restoreColor = this.dom.style[attr];
10224 endColor = (o.endColor || origColor) || "ffffff";
10226 var after = function(){
10227 el.dom.style[attr] = restoreColor;
10232 a[attr] = {from: color, to: endColor};
10233 arguments.callee.anim = this.fxanim(a,
10243 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10246 // default: a single light blue ripple
10249 // custom: 3 red ripples lasting 3 seconds total
10250 el.frame("ff0000", 3, { duration: 3 });
10252 // common config options shown with default values
10253 el.frame("C3DAF9", 1, {
10254 duration: 1 //duration of entire animation (not each individual ripple)
10255 // Note: Easing is not configurable and will be ignored if included
10258 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10259 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10260 * @param {Object} options (optional) Object literal with any of the Fx config options
10261 * @return {Roo.Element} The Element
10263 frame : function(color, count, o){
10264 var el = this.getFxEl();
10267 el.queueFx(o, function(){
10268 color = color || "#C3DAF9";
10269 if(color.length == 6){
10270 color = "#" + color;
10272 count = count || 1;
10273 duration = o.duration || 1;
10276 var b = this.getBox();
10277 var animFn = function(){
10278 var proxy = this.createProxy({
10281 visbility:"hidden",
10282 position:"absolute",
10283 "z-index":"35000", // yee haw
10284 border:"0px solid " + color
10287 var scale = Roo.isBorderBox ? 2 : 1;
10289 top:{from:b.y, to:b.y - 20},
10290 left:{from:b.x, to:b.x - 20},
10291 borderWidth:{from:0, to:10},
10292 opacity:{from:1, to:0},
10293 height:{from:b.height, to:(b.height + (20*scale))},
10294 width:{from:b.width, to:(b.width + (20*scale))}
10295 }, duration, function(){
10299 animFn.defer((duration/2)*1000, this);
10310 * Creates a pause before any subsequent queued effects begin. If there are
10311 * no effects queued after the pause it will have no effect.
10316 * @param {Number} seconds The length of time to pause (in seconds)
10317 * @return {Roo.Element} The Element
10319 pause : function(seconds){
10320 var el = this.getFxEl();
10323 el.queueFx(o, function(){
10324 setTimeout(function(){
10326 }, seconds * 1000);
10332 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10333 * using the "endOpacity" config option.
10336 // default: fade in from opacity 0 to 100%
10339 // custom: fade in from opacity 0 to 75% over 2 seconds
10340 el.fadeIn({ endOpacity: .75, duration: 2});
10342 // common config options shown with default values
10344 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10349 * @param {Object} options (optional) Object literal with any of the Fx config options
10350 * @return {Roo.Element} The Element
10352 fadeIn : function(o){
10353 var el = this.getFxEl();
10355 el.queueFx(o, function(){
10356 this.setOpacity(0);
10358 this.dom.style.visibility = 'visible';
10359 var to = o.endOpacity || 1;
10360 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10361 o, null, .5, "easeOut", function(){
10363 this.clearOpacity();
10372 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10373 * using the "endOpacity" config option.
10376 // default: fade out from the element's current opacity to 0
10379 // custom: fade out from the element's current opacity to 25% over 2 seconds
10380 el.fadeOut({ endOpacity: .25, duration: 2});
10382 // common config options shown with default values
10384 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10391 * @param {Object} options (optional) Object literal with any of the Fx config options
10392 * @return {Roo.Element} The Element
10394 fadeOut : function(o){
10395 var el = this.getFxEl();
10397 el.queueFx(o, function(){
10398 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10399 o, null, .5, "easeOut", function(){
10400 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10401 this.dom.style.display = "none";
10403 this.dom.style.visibility = "hidden";
10405 this.clearOpacity();
10413 * Animates the transition of an element's dimensions from a starting height/width
10414 * to an ending height/width.
10417 // change height and width to 100x100 pixels
10418 el.scale(100, 100);
10420 // common config options shown with default values. The height and width will default to
10421 // the element's existing values if passed as null.
10424 [element's height], {
10429 * @param {Number} width The new width (pass undefined to keep the original width)
10430 * @param {Number} height The new height (pass undefined to keep the original height)
10431 * @param {Object} options (optional) Object literal with any of the Fx config options
10432 * @return {Roo.Element} The Element
10434 scale : function(w, h, o){
10435 this.shift(Roo.apply({}, o, {
10443 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10444 * Any of these properties not specified in the config object will not be changed. This effect
10445 * requires that at least one new dimension, position or opacity setting must be passed in on
10446 * the config object in order for the function to have any effect.
10449 // slide the element horizontally to x position 200 while changing the height and opacity
10450 el.shift({ x: 200, height: 50, opacity: .8 });
10452 // common config options shown with default values.
10454 width: [element's width],
10455 height: [element's height],
10456 x: [element's x position],
10457 y: [element's y position],
10458 opacity: [element's opacity],
10463 * @param {Object} options Object literal with any of the Fx config options
10464 * @return {Roo.Element} The Element
10466 shift : function(o){
10467 var el = this.getFxEl();
10469 el.queueFx(o, function(){
10470 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10471 if(w !== undefined){
10472 a.width = {to: this.adjustWidth(w)};
10474 if(h !== undefined){
10475 a.height = {to: this.adjustHeight(h)};
10477 if(x !== undefined || y !== undefined){
10479 x !== undefined ? x : this.getX(),
10480 y !== undefined ? y : this.getY()
10483 if(op !== undefined){
10484 a.opacity = {to: op};
10486 if(o.xy !== undefined){
10487 a.points = {to: o.xy};
10489 arguments.callee.anim = this.fxanim(a,
10490 o, 'motion', .35, "easeOut", function(){
10498 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10499 * ending point of the effect.
10502 // default: slide the element downward while fading out
10505 // custom: slide the element out to the right with a 2-second duration
10506 el.ghost('r', { duration: 2 });
10508 // common config options shown with default values
10516 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10517 * @param {Object} options (optional) Object literal with any of the Fx config options
10518 * @return {Roo.Element} The Element
10520 ghost : function(anchor, o){
10521 var el = this.getFxEl();
10524 el.queueFx(o, function(){
10525 anchor = anchor || "b";
10527 // restore values after effect
10528 var r = this.getFxRestore();
10529 var w = this.getWidth(),
10530 h = this.getHeight();
10532 var st = this.dom.style;
10534 var after = function(){
10536 el.setDisplayed(false);
10542 el.setPositioning(r.pos);
10543 st.width = r.width;
10544 st.height = r.height;
10549 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10550 switch(anchor.toLowerCase()){
10577 arguments.callee.anim = this.fxanim(a,
10587 * Ensures that all effects queued after syncFx is called on the element are
10588 * run concurrently. This is the opposite of {@link #sequenceFx}.
10589 * @return {Roo.Element} The Element
10591 syncFx : function(){
10592 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10601 * Ensures that all effects queued after sequenceFx is called on the element are
10602 * run in sequence. This is the opposite of {@link #syncFx}.
10603 * @return {Roo.Element} The Element
10605 sequenceFx : function(){
10606 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10608 concurrent : false,
10615 nextFx : function(){
10616 var ef = this.fxQueue[0];
10623 * Returns true if the element has any effects actively running or queued, else returns false.
10624 * @return {Boolean} True if element has active effects, else false
10626 hasActiveFx : function(){
10627 return this.fxQueue && this.fxQueue[0];
10631 * Stops any running effects and clears the element's internal effects queue if it contains
10632 * any additional effects that haven't started yet.
10633 * @return {Roo.Element} The Element
10635 stopFx : function(){
10636 if(this.hasActiveFx()){
10637 var cur = this.fxQueue[0];
10638 if(cur && cur.anim && cur.anim.isAnimated()){
10639 this.fxQueue = [cur]; // clear out others
10640 cur.anim.stop(true);
10647 beforeFx : function(o){
10648 if(this.hasActiveFx() && !o.concurrent){
10659 * Returns true if the element is currently blocking so that no other effect can be queued
10660 * until this effect is finished, else returns false if blocking is not set. This is commonly
10661 * used to ensure that an effect initiated by a user action runs to completion prior to the
10662 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10663 * @return {Boolean} True if blocking, else false
10665 hasFxBlock : function(){
10666 var q = this.fxQueue;
10667 return q && q[0] && q[0].block;
10671 queueFx : function(o, fn){
10675 if(!this.hasFxBlock()){
10676 Roo.applyIf(o, this.fxDefaults);
10678 var run = this.beforeFx(o);
10679 fn.block = o.block;
10680 this.fxQueue.push(fn);
10692 fxWrap : function(pos, o, vis){
10694 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10697 wrapXY = this.getXY();
10699 var div = document.createElement("div");
10700 div.style.visibility = vis;
10701 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10702 wrap.setPositioning(pos);
10703 if(wrap.getStyle("position") == "static"){
10704 wrap.position("relative");
10706 this.clearPositioning('auto');
10708 wrap.dom.appendChild(this.dom);
10710 wrap.setXY(wrapXY);
10717 fxUnwrap : function(wrap, pos, o){
10718 this.clearPositioning();
10719 this.setPositioning(pos);
10721 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10727 getFxRestore : function(){
10728 var st = this.dom.style;
10729 return {pos: this.getPositioning(), width: st.width, height : st.height};
10733 afterFx : function(o){
10735 this.applyStyles(o.afterStyle);
10738 this.addClass(o.afterCls);
10740 if(o.remove === true){
10743 Roo.callback(o.callback, o.scope, [this]);
10745 this.fxQueue.shift();
10751 getFxEl : function(){ // support for composite element fx
10752 return Roo.get(this.dom);
10756 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10757 animType = animType || 'run';
10759 var anim = Roo.lib.Anim[animType](
10761 (opt.duration || defaultDur) || .35,
10762 (opt.easing || defaultEase) || 'easeOut',
10764 Roo.callback(cb, this);
10773 // backwords compat
10774 Roo.Fx.resize = Roo.Fx.scale;
10776 //When included, Roo.Fx is automatically applied to Element so that all basic
10777 //effects are available directly via the Element API
10778 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10780 * Ext JS Library 1.1.1
10781 * Copyright(c) 2006-2007, Ext JS, LLC.
10783 * Originally Released Under LGPL - original licence link has changed is not relivant.
10786 * <script type="text/javascript">
10791 * @class Roo.CompositeElement
10792 * Standard composite class. Creates a Roo.Element for every element in the collection.
10794 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10795 * actions will be performed on all the elements in this collection.</b>
10797 * All methods return <i>this</i> and can be chained.
10799 var els = Roo.select("#some-el div.some-class", true);
10800 // or select directly from an existing element
10801 var el = Roo.get('some-el');
10802 el.select('div.some-class', true);
10804 els.setWidth(100); // all elements become 100 width
10805 els.hide(true); // all elements fade out and hide
10807 els.setWidth(100).hide(true);
10810 Roo.CompositeElement = function(els){
10811 this.elements = [];
10812 this.addElements(els);
10814 Roo.CompositeElement.prototype = {
10816 addElements : function(els){
10817 if(!els) return this;
10818 if(typeof els == "string"){
10819 els = Roo.Element.selectorFunction(els);
10821 var yels = this.elements;
10822 var index = yels.length-1;
10823 for(var i = 0, len = els.length; i < len; i++) {
10824 yels[++index] = Roo.get(els[i]);
10830 * Clears this composite and adds the elements returned by the passed selector.
10831 * @param {String/Array} els A string CSS selector, an array of elements or an element
10832 * @return {CompositeElement} this
10834 fill : function(els){
10835 this.elements = [];
10841 * Filters this composite to only elements that match the passed selector.
10842 * @param {String} selector A string CSS selector
10843 * @return {CompositeElement} this
10845 filter : function(selector){
10847 this.each(function(el){
10848 if(el.is(selector)){
10849 els[els.length] = el.dom;
10856 invoke : function(fn, args){
10857 var els = this.elements;
10858 for(var i = 0, len = els.length; i < len; i++) {
10859 Roo.Element.prototype[fn].apply(els[i], args);
10864 * Adds elements to this composite.
10865 * @param {String/Array} els A string CSS selector, an array of elements or an element
10866 * @return {CompositeElement} this
10868 add : function(els){
10869 if(typeof els == "string"){
10870 this.addElements(Roo.Element.selectorFunction(els));
10871 }else if(els.length !== undefined){
10872 this.addElements(els);
10874 this.addElements([els]);
10879 * Calls the passed function passing (el, this, index) for each element in this composite.
10880 * @param {Function} fn The function to call
10881 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10882 * @return {CompositeElement} this
10884 each : function(fn, scope){
10885 var els = this.elements;
10886 for(var i = 0, len = els.length; i < len; i++){
10887 if(fn.call(scope || els[i], els[i], this, i) === false) {
10895 * Returns the Element object at the specified index
10896 * @param {Number} index
10897 * @return {Roo.Element}
10899 item : function(index){
10900 return this.elements[index] || null;
10904 * Returns the first Element
10905 * @return {Roo.Element}
10907 first : function(){
10908 return this.item(0);
10912 * Returns the last Element
10913 * @return {Roo.Element}
10916 return this.item(this.elements.length-1);
10920 * Returns the number of elements in this composite
10923 getCount : function(){
10924 return this.elements.length;
10928 * Returns true if this composite contains the passed element
10931 contains : function(el){
10932 return this.indexOf(el) !== -1;
10936 * Returns true if this composite contains the passed element
10939 indexOf : function(el){
10940 return this.elements.indexOf(Roo.get(el));
10945 * Removes the specified element(s).
10946 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10947 * or an array of any of those.
10948 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10949 * @return {CompositeElement} this
10951 removeElement : function(el, removeDom){
10952 if(el instanceof Array){
10953 for(var i = 0, len = el.length; i < len; i++){
10954 this.removeElement(el[i]);
10958 var index = typeof el == 'number' ? el : this.indexOf(el);
10961 var d = this.elements[index];
10965 d.parentNode.removeChild(d);
10968 this.elements.splice(index, 1);
10974 * Replaces the specified element with the passed element.
10975 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10977 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10978 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10979 * @return {CompositeElement} this
10981 replaceElement : function(el, replacement, domReplace){
10982 var index = typeof el == 'number' ? el : this.indexOf(el);
10985 this.elements[index].replaceWith(replacement);
10987 this.elements.splice(index, 1, Roo.get(replacement))
10994 * Removes all elements.
10996 clear : function(){
10997 this.elements = [];
11001 Roo.CompositeElement.createCall = function(proto, fnName){
11002 if(!proto[fnName]){
11003 proto[fnName] = function(){
11004 return this.invoke(fnName, arguments);
11008 for(var fnName in Roo.Element.prototype){
11009 if(typeof Roo.Element.prototype[fnName] == "function"){
11010 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11016 * Ext JS Library 1.1.1
11017 * Copyright(c) 2006-2007, Ext JS, LLC.
11019 * Originally Released Under LGPL - original licence link has changed is not relivant.
11022 * <script type="text/javascript">
11026 * @class Roo.CompositeElementLite
11027 * @extends Roo.CompositeElement
11028 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11030 var els = Roo.select("#some-el div.some-class");
11031 // or select directly from an existing element
11032 var el = Roo.get('some-el');
11033 el.select('div.some-class');
11035 els.setWidth(100); // all elements become 100 width
11036 els.hide(true); // all elements fade out and hide
11038 els.setWidth(100).hide(true);
11039 </code></pre><br><br>
11040 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11041 * actions will be performed on all the elements in this collection.</b>
11043 Roo.CompositeElementLite = function(els){
11044 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11045 this.el = new Roo.Element.Flyweight();
11047 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11048 addElements : function(els){
11050 if(els instanceof Array){
11051 this.elements = this.elements.concat(els);
11053 var yels = this.elements;
11054 var index = yels.length-1;
11055 for(var i = 0, len = els.length; i < len; i++) {
11056 yels[++index] = els[i];
11062 invoke : function(fn, args){
11063 var els = this.elements;
11065 for(var i = 0, len = els.length; i < len; i++) {
11067 Roo.Element.prototype[fn].apply(el, args);
11072 * Returns a flyweight Element of the dom element object at the specified index
11073 * @param {Number} index
11074 * @return {Roo.Element}
11076 item : function(index){
11077 if(!this.elements[index]){
11080 this.el.dom = this.elements[index];
11084 // fixes scope with flyweight
11085 addListener : function(eventName, handler, scope, opt){
11086 var els = this.elements;
11087 for(var i = 0, len = els.length; i < len; i++) {
11088 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11094 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11095 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11096 * a reference to the dom node, use el.dom.</b>
11097 * @param {Function} fn The function to call
11098 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11099 * @return {CompositeElement} this
11101 each : function(fn, scope){
11102 var els = this.elements;
11104 for(var i = 0, len = els.length; i < len; i++){
11106 if(fn.call(scope || el, el, this, i) === false){
11113 indexOf : function(el){
11114 return this.elements.indexOf(Roo.getDom(el));
11117 replaceElement : function(el, replacement, domReplace){
11118 var index = typeof el == 'number' ? el : this.indexOf(el);
11120 replacement = Roo.getDom(replacement);
11122 var d = this.elements[index];
11123 d.parentNode.insertBefore(replacement, d);
11124 d.parentNode.removeChild(d);
11126 this.elements.splice(index, 1, replacement);
11131 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11135 * Ext JS Library 1.1.1
11136 * Copyright(c) 2006-2007, Ext JS, LLC.
11138 * Originally Released Under LGPL - original licence link has changed is not relivant.
11141 * <script type="text/javascript">
11147 * @class Roo.data.Connection
11148 * @extends Roo.util.Observable
11149 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11150 * either to a configured URL, or to a URL specified at request time.<br><br>
11152 * Requests made by this class are asynchronous, and will return immediately. No data from
11153 * the server will be available to the statement immediately following the {@link #request} call.
11154 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11156 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11157 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11158 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11159 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11160 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11161 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11162 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11163 * standard DOM methods.
11165 * @param {Object} config a configuration object.
11167 Roo.data.Connection = function(config){
11168 Roo.apply(this, config);
11171 * @event beforerequest
11172 * Fires before a network request is made to retrieve a data object.
11173 * @param {Connection} conn This Connection object.
11174 * @param {Object} options The options config object passed to the {@link #request} method.
11176 "beforerequest" : true,
11178 * @event requestcomplete
11179 * Fires if the request was successfully completed.
11180 * @param {Connection} conn This Connection object.
11181 * @param {Object} response The XHR object containing the response data.
11182 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11183 * @param {Object} options The options config object passed to the {@link #request} method.
11185 "requestcomplete" : true,
11187 * @event requestexception
11188 * Fires if an error HTTP status was returned from the server.
11189 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11190 * @param {Connection} conn This Connection object.
11191 * @param {Object} response The XHR object containing the response data.
11192 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11193 * @param {Object} options The options config object passed to the {@link #request} method.
11195 "requestexception" : true
11197 Roo.data.Connection.superclass.constructor.call(this);
11200 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11202 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11205 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11206 * extra parameters to each request made by this object. (defaults to undefined)
11209 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11210 * to each request made by this object. (defaults to undefined)
11213 * @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)
11216 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11220 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11226 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11229 disableCaching: true,
11232 * Sends an HTTP request to a remote server.
11233 * @param {Object} options An object which may contain the following properties:<ul>
11234 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11235 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11236 * request, a url encoded string or a function to call to get either.</li>
11237 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11238 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11239 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11240 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11241 * <li>options {Object} The parameter to the request call.</li>
11242 * <li>success {Boolean} True if the request succeeded.</li>
11243 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11245 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11246 * The callback is passed the following parameters:<ul>
11247 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11248 * <li>options {Object} The parameter to the request call.</li>
11250 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11251 * The callback is passed the following parameters:<ul>
11252 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11253 * <li>options {Object} The parameter to the request call.</li>
11255 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11256 * for the callback function. Defaults to the browser window.</li>
11257 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11258 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11259 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11260 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11261 * params for the post data. Any params will be appended to the URL.</li>
11262 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11264 * @return {Number} transactionId
11266 request : function(o){
11267 if(this.fireEvent("beforerequest", this, o) !== false){
11270 if(typeof p == "function"){
11271 p = p.call(o.scope||window, o);
11273 if(typeof p == "object"){
11274 p = Roo.urlEncode(o.params);
11276 if(this.extraParams){
11277 var extras = Roo.urlEncode(this.extraParams);
11278 p = p ? (p + '&' + extras) : extras;
11281 var url = o.url || this.url;
11282 if(typeof url == 'function'){
11283 url = url.call(o.scope||window, o);
11287 var form = Roo.getDom(o.form);
11288 url = url || form.action;
11290 var enctype = form.getAttribute("enctype");
11291 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11292 return this.doFormUpload(o, p, url);
11294 var f = Roo.lib.Ajax.serializeForm(form);
11295 p = p ? (p + '&' + f) : f;
11298 var hs = o.headers;
11299 if(this.defaultHeaders){
11300 hs = Roo.apply(hs || {}, this.defaultHeaders);
11307 success: this.handleResponse,
11308 failure: this.handleFailure,
11310 argument: {options: o},
11311 timeout : this.timeout
11314 var method = o.method||this.method||(p ? "POST" : "GET");
11316 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11317 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11320 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11324 }else if(this.autoAbort !== false){
11328 if((method == 'GET' && p) || o.xmlData){
11329 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11332 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11333 return this.transId;
11335 Roo.callback(o.callback, o.scope, [o, null, null]);
11341 * Determine whether this object has a request outstanding.
11342 * @param {Number} transactionId (Optional) defaults to the last transaction
11343 * @return {Boolean} True if there is an outstanding request.
11345 isLoading : function(transId){
11347 return Roo.lib.Ajax.isCallInProgress(transId);
11349 return this.transId ? true : false;
11354 * Aborts any outstanding request.
11355 * @param {Number} transactionId (Optional) defaults to the last transaction
11357 abort : function(transId){
11358 if(transId || this.isLoading()){
11359 Roo.lib.Ajax.abort(transId || this.transId);
11364 handleResponse : function(response){
11365 this.transId = false;
11366 var options = response.argument.options;
11367 response.argument = options ? options.argument : null;
11368 this.fireEvent("requestcomplete", this, response, options);
11369 Roo.callback(options.success, options.scope, [response, options]);
11370 Roo.callback(options.callback, options.scope, [options, true, response]);
11374 handleFailure : function(response, e){
11375 this.transId = false;
11376 var options = response.argument.options;
11377 response.argument = options ? options.argument : null;
11378 this.fireEvent("requestexception", this, response, options, e);
11379 Roo.callback(options.failure, options.scope, [response, options]);
11380 Roo.callback(options.callback, options.scope, [options, false, response]);
11384 doFormUpload : function(o, ps, url){
11386 var frame = document.createElement('iframe');
11389 frame.className = 'x-hidden';
11391 frame.src = Roo.SSL_SECURE_URL;
11393 document.body.appendChild(frame);
11396 document.frames[id].name = id;
11399 var form = Roo.getDom(o.form);
11401 form.method = 'POST';
11402 form.enctype = form.encoding = 'multipart/form-data';
11408 if(ps){ // add dynamic params
11410 ps = Roo.urlDecode(ps, false);
11412 if(ps.hasOwnProperty(k)){
11413 hd = document.createElement('input');
11414 hd.type = 'hidden';
11417 form.appendChild(hd);
11424 var r = { // bogus response object
11429 r.argument = o ? o.argument : null;
11434 doc = frame.contentWindow.document;
11436 doc = (frame.contentDocument || window.frames[id].document);
11438 if(doc && doc.body){
11439 r.responseText = doc.body.innerHTML;
11441 if(doc && doc.XMLDocument){
11442 r.responseXML = doc.XMLDocument;
11444 r.responseXML = doc;
11451 Roo.EventManager.removeListener(frame, 'load', cb, this);
11453 this.fireEvent("requestcomplete", this, r, o);
11454 Roo.callback(o.success, o.scope, [r, o]);
11455 Roo.callback(o.callback, o.scope, [o, true, r]);
11457 setTimeout(function(){document.body.removeChild(frame);}, 100);
11460 Roo.EventManager.on(frame, 'load', cb, this);
11463 if(hiddens){ // remove dynamic params
11464 for(var i = 0, len = hiddens.length; i < len; i++){
11465 form.removeChild(hiddens[i]);
11473 * @extends Roo.data.Connection
11474 * Global Ajax request class.
11478 Roo.Ajax = new Roo.data.Connection({
11481 * @cfg {String} url @hide
11484 * @cfg {Object} extraParams @hide
11487 * @cfg {Object} defaultHeaders @hide
11490 * @cfg {String} method (Optional) @hide
11493 * @cfg {Number} timeout (Optional) @hide
11496 * @cfg {Boolean} autoAbort (Optional) @hide
11500 * @cfg {Boolean} disableCaching (Optional) @hide
11504 * @property disableCaching
11505 * True to add a unique cache-buster param to GET requests. (defaults to true)
11510 * The default URL to be used for requests to the server. (defaults to undefined)
11514 * @property extraParams
11515 * An object containing properties which are used as
11516 * extra parameters to each request made by this object. (defaults to undefined)
11520 * @property defaultHeaders
11521 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11526 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11530 * @property timeout
11531 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11536 * @property autoAbort
11537 * Whether a new request should abort any pending requests. (defaults to false)
11543 * Serialize the passed form into a url encoded string
11544 * @param {String/HTMLElement} form
11547 serializeForm : function(form){
11548 return Roo.lib.Ajax.serializeForm(form);
11552 * Ext JS Library 1.1.1
11553 * Copyright(c) 2006-2007, Ext JS, LLC.
11555 * Originally Released Under LGPL - original licence link has changed is not relivant.
11558 * <script type="text/javascript">
11562 * Global Ajax request class.
11565 * @extends Roo.data.Connection
11568 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11569 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11570 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11571 * @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)
11572 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11573 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11574 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11576 Roo.Ajax = new Roo.data.Connection({
11585 * 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;
19037 if(!this.editing && this.store){
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 = {};
19281 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
19283 Roo.data.Store.superclass.constructor.call(this);
19285 if(this.inlineData){
19286 this.loadData(this.inlineData);
19287 delete this.inlineData;
19290 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19292 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19293 * without a remote query - used by combo/forms at present.
19297 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19300 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19303 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19304 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19307 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19308 * on any HTTP request
19311 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19314 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
19318 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19319 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19321 remoteSort : false,
19324 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19325 * loaded or when a record is removed. (defaults to false).
19327 pruneModifiedRecords : false,
19330 lastOptions : null,
19333 * Add Records to the Store and fires the add event.
19334 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19336 add : function(records){
19337 records = [].concat(records);
19338 for(var i = 0, len = records.length; i < len; i++){
19339 records[i].join(this);
19341 var index = this.data.length;
19342 this.data.addAll(records);
19343 this.fireEvent("add", this, records, index);
19347 * Remove a Record from the Store and fires the remove event.
19348 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19350 remove : function(record){
19351 var index = this.data.indexOf(record);
19352 this.data.removeAt(index);
19353 if(this.pruneModifiedRecords){
19354 this.modified.remove(record);
19356 this.fireEvent("remove", this, record, index);
19360 * Remove all Records from the Store and fires the clear event.
19362 removeAll : function(){
19364 if(this.pruneModifiedRecords){
19365 this.modified = [];
19367 this.fireEvent("clear", this);
19371 * Inserts Records to the Store at the given index and fires the add event.
19372 * @param {Number} index The start index at which to insert the passed Records.
19373 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19375 insert : function(index, records){
19376 records = [].concat(records);
19377 for(var i = 0, len = records.length; i < len; i++){
19378 this.data.insert(index, records[i]);
19379 records[i].join(this);
19381 this.fireEvent("add", this, records, index);
19385 * Get the index within the cache of the passed Record.
19386 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19387 * @return {Number} The index of the passed Record. Returns -1 if not found.
19389 indexOf : function(record){
19390 return this.data.indexOf(record);
19394 * Get the index within the cache of the Record with the passed id.
19395 * @param {String} id The id of the Record to find.
19396 * @return {Number} The index of the Record. Returns -1 if not found.
19398 indexOfId : function(id){
19399 return this.data.indexOfKey(id);
19403 * Get the Record with the specified id.
19404 * @param {String} id The id of the Record to find.
19405 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19407 getById : function(id){
19408 return this.data.key(id);
19412 * Get the Record at the specified index.
19413 * @param {Number} index The index of the Record to find.
19414 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19416 getAt : function(index){
19417 return this.data.itemAt(index);
19421 * Returns a range of Records between specified indices.
19422 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19423 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19424 * @return {Roo.data.Record[]} An array of Records
19426 getRange : function(start, end){
19427 return this.data.getRange(start, end);
19431 storeOptions : function(o){
19432 o = Roo.apply({}, o);
19435 this.lastOptions = o;
19439 * Loads the Record cache from the configured Proxy using the configured Reader.
19441 * If using remote paging, then the first load call must specify the <em>start</em>
19442 * and <em>limit</em> properties in the options.params property to establish the initial
19443 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19445 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19446 * and this call will return before the new data has been loaded. Perform any post-processing
19447 * in a callback function, or in a "load" event handler.</strong>
19449 * @param {Object} options An object containing properties which control loading options:<ul>
19450 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19451 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19452 * passed the following arguments:<ul>
19453 * <li>r : Roo.data.Record[]</li>
19454 * <li>options: Options object from the load call</li>
19455 * <li>success: Boolean success indicator</li></ul></li>
19456 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19457 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19460 load : function(options){
19461 options = options || {};
19462 if(this.fireEvent("beforeload", this, options) !== false){
19463 this.storeOptions(options);
19464 var p = Roo.apply(options.params || {}, this.baseParams);
19465 // if meta was not loaded from remote source.. try requesting it.
19466 if (!this.reader.metaFromRemote) {
19467 p._requestMeta = 1;
19469 if(this.sortInfo && this.remoteSort){
19470 var pn = this.paramNames;
19471 p[pn["sort"]] = this.sortInfo.field;
19472 p[pn["dir"]] = this.sortInfo.direction;
19474 if (this.multiSort) {
19475 var pn = this.paramNames;
19476 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
19479 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19484 * Reloads the Record cache from the configured Proxy using the configured Reader and
19485 * the options from the last load operation performed.
19486 * @param {Object} options (optional) An object containing properties which may override the options
19487 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19488 * the most recently used options are reused).
19490 reload : function(options){
19491 this.load(Roo.applyIf(options||{}, this.lastOptions));
19495 // Called as a callback by the Reader during a load operation.
19496 loadRecords : function(o, options, success){
19497 if(!o || success === false){
19498 if(success !== false){
19499 this.fireEvent("load", this, [], options);
19501 if(options.callback){
19502 options.callback.call(options.scope || this, [], options, false);
19506 // if data returned failure - throw an exception.
19507 if (o.success === false) {
19508 // show a message if no listener is registered.
19509 if (!this.hasListener('loadexception') && typeof(this.reader.jsonData.errorMsg) != 'undefined') {
19510 Roo.MessageBox.alert("Error loading",this.reader.jsonData.errorMsg);
19512 // loadmask wil be hooked into this..
19513 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19516 var r = o.records, t = o.totalRecords || r.length;
19517 if(!options || options.add !== true){
19518 if(this.pruneModifiedRecords){
19519 this.modified = [];
19521 for(var i = 0, len = r.length; i < len; i++){
19525 this.data = this.snapshot;
19526 delete this.snapshot;
19529 this.data.addAll(r);
19530 this.totalLength = t;
19532 this.fireEvent("datachanged", this);
19534 this.totalLength = Math.max(t, this.data.length+r.length);
19537 this.fireEvent("load", this, r, options);
19538 if(options.callback){
19539 options.callback.call(options.scope || this, r, options, true);
19545 * Loads data from a passed data block. A Reader which understands the format of the data
19546 * must have been configured in the constructor.
19547 * @param {Object} data The data block from which to read the Records. The format of the data expected
19548 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19549 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19551 loadData : function(o, append){
19552 var r = this.reader.readRecords(o);
19553 this.loadRecords(r, {add: append}, true);
19557 * Gets the number of cached records.
19559 * <em>If using paging, this may not be the total size of the dataset. If the data object
19560 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19561 * the data set size</em>
19563 getCount : function(){
19564 return this.data.length || 0;
19568 * Gets the total number of records in the dataset as returned by the server.
19570 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19571 * the dataset size</em>
19573 getTotalCount : function(){
19574 return this.totalLength || 0;
19578 * Returns the sort state of the Store as an object with two properties:
19580 field {String} The name of the field by which the Records are sorted
19581 direction {String} The sort order, "ASC" or "DESC"
19584 getSortState : function(){
19585 return this.sortInfo;
19589 applySort : function(){
19590 if(this.sortInfo && !this.remoteSort){
19591 var s = this.sortInfo, f = s.field;
19592 var st = this.fields.get(f).sortType;
19593 var fn = function(r1, r2){
19594 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19595 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19597 this.data.sort(s.direction, fn);
19598 if(this.snapshot && this.snapshot != this.data){
19599 this.snapshot.sort(s.direction, fn);
19605 * Sets the default sort column and order to be used by the next load operation.
19606 * @param {String} fieldName The name of the field to sort by.
19607 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19609 setDefaultSort : function(field, dir){
19610 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19614 * Sort the Records.
19615 * If remote sorting is used, the sort is performed on the server, and the cache is
19616 * reloaded. If local sorting is used, the cache is sorted internally.
19617 * @param {String} fieldName The name of the field to sort by.
19618 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19620 sort : function(fieldName, dir){
19621 var f = this.fields.get(fieldName);
19623 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
19625 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
19626 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19631 this.sortToggle[f.name] = dir;
19632 this.sortInfo = {field: f.name, direction: dir};
19633 if(!this.remoteSort){
19635 this.fireEvent("datachanged", this);
19637 this.load(this.lastOptions);
19642 * Calls the specified function for each of the Records in the cache.
19643 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19644 * Returning <em>false</em> aborts and exits the iteration.
19645 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19647 each : function(fn, scope){
19648 this.data.each(fn, scope);
19652 * Gets all records modified since the last commit. Modified records are persisted across load operations
19653 * (e.g., during paging).
19654 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19656 getModifiedRecords : function(){
19657 return this.modified;
19661 createFilterFn : function(property, value, anyMatch){
19662 if(!value.exec){ // not a regex
19663 value = String(value);
19664 if(value.length == 0){
19667 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19669 return function(r){
19670 return value.test(r.data[property]);
19675 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19676 * @param {String} property A field on your records
19677 * @param {Number} start The record index to start at (defaults to 0)
19678 * @param {Number} end The last record index to include (defaults to length - 1)
19679 * @return {Number} The sum
19681 sum : function(property, start, end){
19682 var rs = this.data.items, v = 0;
19683 start = start || 0;
19684 end = (end || end === 0) ? end : rs.length-1;
19686 for(var i = start; i <= end; i++){
19687 v += (rs[i].data[property] || 0);
19693 * Filter the records by a specified property.
19694 * @param {String} field A field on your records
19695 * @param {String/RegExp} value Either a string that the field
19696 * should start with or a RegExp to test against the field
19697 * @param {Boolean} anyMatch True to match any part not just the beginning
19699 filter : function(property, value, anyMatch){
19700 var fn = this.createFilterFn(property, value, anyMatch);
19701 return fn ? this.filterBy(fn) : this.clearFilter();
19705 * Filter by a function. The specified function will be called with each
19706 * record in this data source. If the function returns true the record is included,
19707 * otherwise it is filtered.
19708 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19709 * @param {Object} scope (optional) The scope of the function (defaults to this)
19711 filterBy : function(fn, scope){
19712 this.snapshot = this.snapshot || this.data;
19713 this.data = this.queryBy(fn, scope||this);
19714 this.fireEvent("datachanged", this);
19718 * Query the records by a specified property.
19719 * @param {String} field A field on your records
19720 * @param {String/RegExp} value Either a string that the field
19721 * should start with or a RegExp to test against the field
19722 * @param {Boolean} anyMatch True to match any part not just the beginning
19723 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19725 query : function(property, value, anyMatch){
19726 var fn = this.createFilterFn(property, value, anyMatch);
19727 return fn ? this.queryBy(fn) : this.data.clone();
19731 * Query by a function. The specified function will be called with each
19732 * record in this data source. If the function returns true the record is included
19734 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19735 * @param {Object} scope (optional) The scope of the function (defaults to this)
19736 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19738 queryBy : function(fn, scope){
19739 var data = this.snapshot || this.data;
19740 return data.filterBy(fn, scope||this);
19744 * Collects unique values for a particular dataIndex from this store.
19745 * @param {String} dataIndex The property to collect
19746 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19747 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19748 * @return {Array} An array of the unique values
19750 collect : function(dataIndex, allowNull, bypassFilter){
19751 var d = (bypassFilter === true && this.snapshot) ?
19752 this.snapshot.items : this.data.items;
19753 var v, sv, r = [], l = {};
19754 for(var i = 0, len = d.length; i < len; i++){
19755 v = d[i].data[dataIndex];
19757 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19766 * Revert to a view of the Record cache with no filtering applied.
19767 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19769 clearFilter : function(suppressEvent){
19770 if(this.snapshot && this.snapshot != this.data){
19771 this.data = this.snapshot;
19772 delete this.snapshot;
19773 if(suppressEvent !== true){
19774 this.fireEvent("datachanged", this);
19780 afterEdit : function(record){
19781 if(this.modified.indexOf(record) == -1){
19782 this.modified.push(record);
19784 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19788 afterReject : function(record){
19789 this.modified.remove(record);
19790 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19794 afterCommit : function(record){
19795 this.modified.remove(record);
19796 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19800 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19801 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19803 commitChanges : function(){
19804 var m = this.modified.slice(0);
19805 this.modified = [];
19806 for(var i = 0, len = m.length; i < len; i++){
19812 * Cancel outstanding changes on all changed records.
19814 rejectChanges : function(){
19815 var m = this.modified.slice(0);
19816 this.modified = [];
19817 for(var i = 0, len = m.length; i < len; i++){
19822 onMetaChange : function(meta, rtype, o){
19823 this.recordType = rtype;
19824 this.fields = rtype.prototype.fields;
19825 delete this.snapshot;
19826 this.sortInfo = meta.sortInfo || this.sortInfo;
19827 this.modified = [];
19828 this.fireEvent('metachange', this, this.reader.meta);
19832 * Ext JS Library 1.1.1
19833 * Copyright(c) 2006-2007, Ext JS, LLC.
19835 * Originally Released Under LGPL - original licence link has changed is not relivant.
19838 * <script type="text/javascript">
19842 * @class Roo.data.SimpleStore
19843 * @extends Roo.data.Store
19844 * Small helper class to make creating Stores from Array data easier.
19845 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19846 * @cfg {Array} fields An array of field definition objects, or field name strings.
19847 * @cfg {Array} data The multi-dimensional array of data
19849 * @param {Object} config
19851 Roo.data.SimpleStore = function(config){
19852 Roo.data.SimpleStore.superclass.constructor.call(this, {
19854 reader: new Roo.data.ArrayReader({
19857 Roo.data.Record.create(config.fields)
19859 proxy : new Roo.data.MemoryProxy(config.data)
19863 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19865 * Ext JS Library 1.1.1
19866 * Copyright(c) 2006-2007, Ext JS, LLC.
19868 * Originally Released Under LGPL - original licence link has changed is not relivant.
19871 * <script type="text/javascript">
19876 * @extends Roo.data.Store
19877 * @class Roo.data.JsonStore
19878 * Small helper class to make creating Stores for JSON data easier. <br/>
19880 var store = new Roo.data.JsonStore({
19881 url: 'get-images.php',
19883 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19886 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19887 * JsonReader and HttpProxy (unless inline data is provided).</b>
19888 * @cfg {Array} fields An array of field definition objects, or field name strings.
19890 * @param {Object} config
19892 Roo.data.JsonStore = function(c){
19893 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19894 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19895 reader: new Roo.data.JsonReader(c, c.fields)
19898 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19900 * Ext JS Library 1.1.1
19901 * Copyright(c) 2006-2007, Ext JS, LLC.
19903 * Originally Released Under LGPL - original licence link has changed is not relivant.
19906 * <script type="text/javascript">
19910 Roo.data.Field = function(config){
19911 if(typeof config == "string"){
19912 config = {name: config};
19914 Roo.apply(this, config);
19917 this.type = "auto";
19920 var st = Roo.data.SortTypes;
19921 // named sortTypes are supported, here we look them up
19922 if(typeof this.sortType == "string"){
19923 this.sortType = st[this.sortType];
19926 // set default sortType for strings and dates
19927 if(!this.sortType){
19930 this.sortType = st.asUCString;
19933 this.sortType = st.asDate;
19936 this.sortType = st.none;
19941 var stripRe = /[\$,%]/g;
19943 // prebuilt conversion function for this field, instead of
19944 // switching every time we're reading a value
19946 var cv, dateFormat = this.dateFormat;
19951 cv = function(v){ return v; };
19954 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19958 return v !== undefined && v !== null && v !== '' ?
19959 parseInt(String(v).replace(stripRe, ""), 10) : '';
19964 return v !== undefined && v !== null && v !== '' ?
19965 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19970 cv = function(v){ return v === true || v === "true" || v == 1; };
19977 if(v instanceof Date){
19981 if(dateFormat == "timestamp"){
19982 return new Date(v*1000);
19984 return Date.parseDate(v, dateFormat);
19986 var parsed = Date.parse(v);
19987 return parsed ? new Date(parsed) : null;
19996 Roo.data.Field.prototype = {
20004 * Ext JS Library 1.1.1
20005 * Copyright(c) 2006-2007, Ext JS, LLC.
20007 * Originally Released Under LGPL - original licence link has changed is not relivant.
20010 * <script type="text/javascript">
20013 // Base class for reading structured data from a data source. This class is intended to be
20014 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20017 * @class Roo.data.DataReader
20018 * Base class for reading structured data from a data source. This class is intended to be
20019 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20022 Roo.data.DataReader = function(meta, recordType){
20026 this.recordType = recordType instanceof Array ?
20027 Roo.data.Record.create(recordType) : recordType;
20030 Roo.data.DataReader.prototype = {
20032 * Create an empty record
20033 * @param {Object} data (optional) - overlay some values
20034 * @return {Roo.data.Record} record created.
20036 newRow : function(d) {
20038 this.recordType.prototype.fields.each(function(c) {
20040 case 'int' : da[c.name] = 0; break;
20041 case 'date' : da[c.name] = new Date(); break;
20042 case 'float' : da[c.name] = 0.0; break;
20043 case 'boolean' : da[c.name] = false; break;
20044 default : da[c.name] = ""; break;
20048 return new this.recordType(Roo.apply(da, d));
20053 * Ext JS Library 1.1.1
20054 * Copyright(c) 2006-2007, Ext JS, LLC.
20056 * Originally Released Under LGPL - original licence link has changed is not relivant.
20059 * <script type="text/javascript">
20063 * @class Roo.data.DataProxy
20064 * @extends Roo.data.Observable
20065 * This class is an abstract base class for implementations which provide retrieval of
20066 * unformatted data objects.<br>
20068 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20069 * (of the appropriate type which knows how to parse the data object) to provide a block of
20070 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20072 * Custom implementations must implement the load method as described in
20073 * {@link Roo.data.HttpProxy#load}.
20075 Roo.data.DataProxy = function(){
20078 * @event beforeload
20079 * Fires before a network request is made to retrieve a data object.
20080 * @param {Object} This DataProxy object.
20081 * @param {Object} params The params parameter to the load function.
20086 * Fires before the load method's callback is called.
20087 * @param {Object} This DataProxy object.
20088 * @param {Object} o The data object.
20089 * @param {Object} arg The callback argument object passed to the load function.
20093 * @event loadexception
20094 * Fires if an Exception occurs during data retrieval.
20095 * @param {Object} This DataProxy object.
20096 * @param {Object} o The data object.
20097 * @param {Object} arg The callback argument object passed to the load function.
20098 * @param {Object} e The Exception.
20100 loadexception : true
20102 Roo.data.DataProxy.superclass.constructor.call(this);
20105 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20108 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20112 * Ext JS Library 1.1.1
20113 * Copyright(c) 2006-2007, Ext JS, LLC.
20115 * Originally Released Under LGPL - original licence link has changed is not relivant.
20118 * <script type="text/javascript">
20121 * @class Roo.data.MemoryProxy
20122 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20123 * to the Reader when its load method is called.
20125 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20127 Roo.data.MemoryProxy = function(data){
20131 Roo.data.MemoryProxy.superclass.constructor.call(this);
20135 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20137 * Load data from the requested source (in this case an in-memory
20138 * data object passed to the constructor), read the data object into
20139 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20140 * process that block using the passed callback.
20141 * @param {Object} params This parameter is not used by the MemoryProxy class.
20142 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20143 * object into a block of Roo.data.Records.
20144 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20145 * The function must be passed <ul>
20146 * <li>The Record block object</li>
20147 * <li>The "arg" argument from the load function</li>
20148 * <li>A boolean success indicator</li>
20150 * @param {Object} scope The scope in which to call the callback
20151 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20153 load : function(params, reader, callback, scope, arg){
20154 params = params || {};
20157 result = reader.readRecords(this.data);
20159 this.fireEvent("loadexception", this, arg, null, e);
20160 callback.call(scope, null, arg, false);
20163 callback.call(scope, result, arg, true);
20167 update : function(params, records){
20172 * Ext JS Library 1.1.1
20173 * Copyright(c) 2006-2007, Ext JS, LLC.
20175 * Originally Released Under LGPL - original licence link has changed is not relivant.
20178 * <script type="text/javascript">
20181 * @class Roo.data.HttpProxy
20182 * @extends Roo.data.DataProxy
20183 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20184 * configured to reference a certain URL.<br><br>
20186 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20187 * from which the running page was served.<br><br>
20189 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20191 * Be aware that to enable the browser to parse an XML document, the server must set
20192 * the Content-Type header in the HTTP response to "text/xml".
20194 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20195 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20196 * will be used to make the request.
20198 Roo.data.HttpProxy = function(conn){
20199 Roo.data.HttpProxy.superclass.constructor.call(this);
20200 // is conn a conn config or a real conn?
20202 this.useAjax = !conn || !conn.events;
20206 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20207 // thse are take from connection...
20210 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20213 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20214 * extra parameters to each request made by this object. (defaults to undefined)
20217 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20218 * to each request made by this object. (defaults to undefined)
20221 * @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)
20224 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20227 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20233 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20237 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20238 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20239 * a finer-grained basis than the DataProxy events.
20241 getConnection : function(){
20242 return this.useAjax ? Roo.Ajax : this.conn;
20246 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20247 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20248 * process that block using the passed callback.
20249 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20250 * for the request to the remote server.
20251 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20252 * object into a block of Roo.data.Records.
20253 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20254 * The function must be passed <ul>
20255 * <li>The Record block object</li>
20256 * <li>The "arg" argument from the load function</li>
20257 * <li>A boolean success indicator</li>
20259 * @param {Object} scope The scope in which to call the callback
20260 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20262 load : function(params, reader, callback, scope, arg){
20263 if(this.fireEvent("beforeload", this, params) !== false){
20265 params : params || {},
20267 callback : callback,
20272 callback : this.loadResponse,
20276 Roo.applyIf(o, this.conn);
20277 if(this.activeRequest){
20278 Roo.Ajax.abort(this.activeRequest);
20280 this.activeRequest = Roo.Ajax.request(o);
20282 this.conn.request(o);
20285 callback.call(scope||this, null, arg, false);
20290 loadResponse : function(o, success, response){
20291 delete this.activeRequest;
20293 this.fireEvent("loadexception", this, o, response);
20294 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20299 result = o.reader.read(response);
20301 this.fireEvent("loadexception", this, o, response, e);
20302 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20306 this.fireEvent("load", this, o, o.request.arg);
20307 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20311 update : function(dataSet){
20316 updateResponse : function(dataSet){
20321 * Ext JS Library 1.1.1
20322 * Copyright(c) 2006-2007, Ext JS, LLC.
20324 * Originally Released Under LGPL - original licence link has changed is not relivant.
20327 * <script type="text/javascript">
20331 * @class Roo.data.ScriptTagProxy
20332 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20333 * other than the originating domain of the running page.<br><br>
20335 * <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
20336 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20338 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20339 * source code that is used as the source inside a <script> tag.<br><br>
20341 * In order for the browser to process the returned data, the server must wrap the data object
20342 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20343 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20344 * depending on whether the callback name was passed:
20347 boolean scriptTag = false;
20348 String cb = request.getParameter("callback");
20351 response.setContentType("text/javascript");
20353 response.setContentType("application/x-json");
20355 Writer out = response.getWriter();
20357 out.write(cb + "(");
20359 out.print(dataBlock.toJsonString());
20366 * @param {Object} config A configuration object.
20368 Roo.data.ScriptTagProxy = function(config){
20369 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20370 Roo.apply(this, config);
20371 this.head = document.getElementsByTagName("head")[0];
20374 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20376 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20378 * @cfg {String} url The URL from which to request the data object.
20381 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20385 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20386 * the server the name of the callback function set up by the load call to process the returned data object.
20387 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20388 * javascript output which calls this named function passing the data object as its only parameter.
20390 callbackParam : "callback",
20392 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20393 * name to the request.
20398 * Load data from the configured URL, read the data object into
20399 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20400 * process that block using the passed callback.
20401 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20402 * for the request to the remote server.
20403 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20404 * object into a block of Roo.data.Records.
20405 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20406 * The function must be passed <ul>
20407 * <li>The Record block object</li>
20408 * <li>The "arg" argument from the load function</li>
20409 * <li>A boolean success indicator</li>
20411 * @param {Object} scope The scope in which to call the callback
20412 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20414 load : function(params, reader, callback, scope, arg){
20415 if(this.fireEvent("beforeload", this, params) !== false){
20417 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20419 var url = this.url;
20420 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20422 url += "&_dc=" + (new Date().getTime());
20424 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20427 cb : "stcCallback"+transId,
20428 scriptId : "stcScript"+transId,
20432 callback : callback,
20438 window[trans.cb] = function(o){
20439 conn.handleResponse(o, trans);
20442 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20444 if(this.autoAbort !== false){
20448 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20450 var script = document.createElement("script");
20451 script.setAttribute("src", url);
20452 script.setAttribute("type", "text/javascript");
20453 script.setAttribute("id", trans.scriptId);
20454 this.head.appendChild(script);
20456 this.trans = trans;
20458 callback.call(scope||this, null, arg, false);
20463 isLoading : function(){
20464 return this.trans ? true : false;
20468 * Abort the current server request.
20470 abort : function(){
20471 if(this.isLoading()){
20472 this.destroyTrans(this.trans);
20477 destroyTrans : function(trans, isLoaded){
20478 this.head.removeChild(document.getElementById(trans.scriptId));
20479 clearTimeout(trans.timeoutId);
20481 window[trans.cb] = undefined;
20483 delete window[trans.cb];
20486 // if hasn't been loaded, wait for load to remove it to prevent script error
20487 window[trans.cb] = function(){
20488 window[trans.cb] = undefined;
20490 delete window[trans.cb];
20497 handleResponse : function(o, trans){
20498 this.trans = false;
20499 this.destroyTrans(trans, true);
20502 result = trans.reader.readRecords(o);
20504 this.fireEvent("loadexception", this, o, trans.arg, e);
20505 trans.callback.call(trans.scope||window, null, trans.arg, false);
20508 this.fireEvent("load", this, o, trans.arg);
20509 trans.callback.call(trans.scope||window, result, trans.arg, true);
20513 handleFailure : function(trans){
20514 this.trans = false;
20515 this.destroyTrans(trans, false);
20516 this.fireEvent("loadexception", this, null, trans.arg);
20517 trans.callback.call(trans.scope||window, null, trans.arg, false);
20521 * Ext JS Library 1.1.1
20522 * Copyright(c) 2006-2007, Ext JS, LLC.
20524 * Originally Released Under LGPL - original licence link has changed is not relivant.
20527 * <script type="text/javascript">
20531 * @class Roo.data.JsonReader
20532 * @extends Roo.data.DataReader
20533 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20534 * based on mappings in a provided Roo.data.Record constructor.
20536 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
20537 * in the reply previously.
20542 var RecordDef = Roo.data.Record.create([
20543 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20544 {name: 'occupation'} // This field will use "occupation" as the mapping.
20546 var myReader = new Roo.data.JsonReader({
20547 totalProperty: "results", // The property which contains the total dataset size (optional)
20548 root: "rows", // The property which contains an Array of row objects
20549 id: "id" // The property within each row object that provides an ID for the record (optional)
20553 * This would consume a JSON file like this:
20555 { 'results': 2, 'rows': [
20556 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20557 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20560 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20561 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20562 * paged from the remote server.
20563 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20564 * @cfg {String} root name of the property which contains the Array of row objects.
20565 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20567 * Create a new JsonReader
20568 * @param {Object} meta Metadata configuration options
20569 * @param {Object} recordType Either an Array of field definition objects,
20570 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20572 Roo.data.JsonReader = function(meta, recordType){
20575 // set some defaults:
20576 Roo.applyIf(meta, {
20577 totalProperty: 'total',
20578 successProperty : 'success',
20583 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20585 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20588 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
20589 * Used by Store query builder to append _requestMeta to params.
20592 metaFromRemote : false,
20594 * This method is only used by a DataProxy which has retrieved data from a remote server.
20595 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20596 * @return {Object} data A data block which is used by an Roo.data.Store object as
20597 * a cache of Roo.data.Records.
20599 read : function(response){
20600 var json = response.responseText;
20602 var o = /* eval:var:o */ eval("("+json+")");
20604 throw {message: "JsonReader.read: Json object not found"};
20610 this.metaFromRemote = true;
20611 this.meta = o.metaData;
20612 this.recordType = Roo.data.Record.create(o.metaData.fields);
20613 this.onMetaChange(this.meta, this.recordType, o);
20615 return this.readRecords(o);
20618 // private function a store will implement
20619 onMetaChange : function(meta, recordType, o){
20626 simpleAccess: function(obj, subsc) {
20633 getJsonAccessor: function(){
20635 return function(expr) {
20637 return(re.test(expr))
20638 ? new Function("obj", "return obj." + expr)
20643 return Roo.emptyFn;
20648 * Create a data block containing Roo.data.Records from an XML document.
20649 * @param {Object} o An object which contains an Array of row objects in the property specified
20650 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20651 * which contains the total size of the dataset.
20652 * @return {Object} data A data block which is used by an Roo.data.Store object as
20653 * a cache of Roo.data.Records.
20655 readRecords : function(o){
20657 * After any data loads, the raw JSON data is available for further custom processing.
20661 var s = this.meta, Record = this.recordType,
20662 f = Record.prototype.fields, fi = f.items, fl = f.length;
20664 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20666 if(s.totalProperty) {
20667 this.getTotal = this.getJsonAccessor(s.totalProperty);
20669 if(s.successProperty) {
20670 this.getSuccess = this.getJsonAccessor(s.successProperty);
20672 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20674 var g = this.getJsonAccessor(s.id);
20675 this.getId = function(rec) {
20677 return (r === undefined || r === "") ? null : r;
20680 this.getId = function(){return null;};
20683 for(var jj = 0; jj < fl; jj++){
20685 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20686 this.ef[jj] = this.getJsonAccessor(map);
20690 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20691 if(s.totalProperty){
20692 var vt = parseInt(this.getTotal(o), 10);
20697 if(s.successProperty){
20698 var vs = this.getSuccess(o);
20699 if(vs === false || vs === 'false'){
20704 for(var i = 0; i < c; i++){
20707 var id = this.getId(n);
20708 for(var j = 0; j < fl; j++){
20710 var v = this.ef[j](n);
20712 Roo.log('missing convert for ' + f.name);
20716 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20718 var record = new Record(values, id);
20720 records[i] = record;
20725 totalRecords : totalRecords
20730 * Ext JS Library 1.1.1
20731 * Copyright(c) 2006-2007, Ext JS, LLC.
20733 * Originally Released Under LGPL - original licence link has changed is not relivant.
20736 * <script type="text/javascript">
20740 * @class Roo.data.XmlReader
20741 * @extends Roo.data.DataReader
20742 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20743 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20745 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20746 * header in the HTTP response must be set to "text/xml".</em>
20750 var RecordDef = Roo.data.Record.create([
20751 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20752 {name: 'occupation'} // This field will use "occupation" as the mapping.
20754 var myReader = new Roo.data.XmlReader({
20755 totalRecords: "results", // The element which contains the total dataset size (optional)
20756 record: "row", // The repeated element which contains row information
20757 id: "id" // The element within the row that provides an ID for the record (optional)
20761 * This would consume an XML file like this:
20765 <results>2</results>
20768 <name>Bill</name>
20769 <occupation>Gardener</occupation>
20773 <name>Ben</name>
20774 <occupation>Horticulturalist</occupation>
20778 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20779 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20780 * paged from the remote server.
20781 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20782 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20783 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20784 * a record identifier value.
20786 * Create a new XmlReader
20787 * @param {Object} meta Metadata configuration options
20788 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20789 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20790 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20792 Roo.data.XmlReader = function(meta, recordType){
20794 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20796 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20798 * This method is only used by a DataProxy which has retrieved data from a remote server.
20799 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20800 * to contain a method called 'responseXML' that returns an XML document object.
20801 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20802 * a cache of Roo.data.Records.
20804 read : function(response){
20805 var doc = response.responseXML;
20807 throw {message: "XmlReader.read: XML Document not available"};
20809 return this.readRecords(doc);
20813 * Create a data block containing Roo.data.Records from an XML document.
20814 * @param {Object} doc A parsed XML document.
20815 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20816 * a cache of Roo.data.Records.
20818 readRecords : function(doc){
20820 * After any data loads/reads, the raw XML Document is available for further custom processing.
20821 * @type XMLDocument
20823 this.xmlData = doc;
20824 var root = doc.documentElement || doc;
20825 var q = Roo.DomQuery;
20826 var recordType = this.recordType, fields = recordType.prototype.fields;
20827 var sid = this.meta.id;
20828 var totalRecords = 0, success = true;
20829 if(this.meta.totalRecords){
20830 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20833 if(this.meta.success){
20834 var sv = q.selectValue(this.meta.success, root, true);
20835 success = sv !== false && sv !== 'false';
20838 var ns = q.select(this.meta.record, root);
20839 for(var i = 0, len = ns.length; i < len; i++) {
20842 var id = sid ? q.selectValue(sid, n) : undefined;
20843 for(var j = 0, jlen = fields.length; j < jlen; j++){
20844 var f = fields.items[j];
20845 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20847 values[f.name] = v;
20849 var record = new recordType(values, id);
20851 records[records.length] = record;
20857 totalRecords : totalRecords || records.length
20862 * Ext JS Library 1.1.1
20863 * Copyright(c) 2006-2007, Ext JS, LLC.
20865 * Originally Released Under LGPL - original licence link has changed is not relivant.
20868 * <script type="text/javascript">
20872 * @class Roo.data.ArrayReader
20873 * @extends Roo.data.DataReader
20874 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20875 * Each element of that Array represents a row of data fields. The
20876 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20877 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20881 var RecordDef = Roo.data.Record.create([
20882 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20883 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20885 var myReader = new Roo.data.ArrayReader({
20886 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20890 * This would consume an Array like this:
20892 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20894 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20896 * Create a new JsonReader
20897 * @param {Object} meta Metadata configuration options.
20898 * @param {Object} recordType Either an Array of field definition objects
20899 * as specified to {@link Roo.data.Record#create},
20900 * or an {@link Roo.data.Record} object
20901 * created using {@link Roo.data.Record#create}.
20903 Roo.data.ArrayReader = function(meta, recordType){
20904 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20907 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20909 * Create a data block containing Roo.data.Records from an XML document.
20910 * @param {Object} o An Array of row objects which represents the dataset.
20911 * @return {Object} data A data block which is used by an Roo.data.Store object as
20912 * a cache of Roo.data.Records.
20914 readRecords : function(o){
20915 var sid = this.meta ? this.meta.id : null;
20916 var recordType = this.recordType, fields = recordType.prototype.fields;
20919 for(var i = 0; i < root.length; i++){
20922 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20923 for(var j = 0, jlen = fields.length; j < jlen; j++){
20924 var f = fields.items[j];
20925 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20926 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20928 values[f.name] = v;
20930 var record = new recordType(values, id);
20932 records[records.length] = record;
20936 totalRecords : records.length
20941 * Ext JS Library 1.1.1
20942 * Copyright(c) 2006-2007, Ext JS, LLC.
20944 * Originally Released Under LGPL - original licence link has changed is not relivant.
20947 * <script type="text/javascript">
20952 * @class Roo.data.Tree
20953 * @extends Roo.util.Observable
20954 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20955 * in the tree have most standard DOM functionality.
20957 * @param {Node} root (optional) The root node
20959 Roo.data.Tree = function(root){
20960 this.nodeHash = {};
20962 * The root node for this tree
20967 this.setRootNode(root);
20972 * Fires when a new child node is appended to a node in this tree.
20973 * @param {Tree} tree The owner tree
20974 * @param {Node} parent The parent node
20975 * @param {Node} node The newly appended node
20976 * @param {Number} index The index of the newly appended node
20981 * Fires when a child node is removed from a node in this tree.
20982 * @param {Tree} tree The owner tree
20983 * @param {Node} parent The parent node
20984 * @param {Node} node The child node removed
20989 * Fires when a node is moved to a new location in the tree
20990 * @param {Tree} tree The owner tree
20991 * @param {Node} node The node moved
20992 * @param {Node} oldParent The old parent of this node
20993 * @param {Node} newParent The new parent of this node
20994 * @param {Number} index The index it was moved to
20999 * Fires when a new child node is inserted in a node in this tree.
21000 * @param {Tree} tree The owner tree
21001 * @param {Node} parent The parent node
21002 * @param {Node} node The child node inserted
21003 * @param {Node} refNode The child node the node was inserted before
21007 * @event beforeappend
21008 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21009 * @param {Tree} tree The owner tree
21010 * @param {Node} parent The parent node
21011 * @param {Node} node The child node to be appended
21013 "beforeappend" : true,
21015 * @event beforeremove
21016 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21017 * @param {Tree} tree The owner tree
21018 * @param {Node} parent The parent node
21019 * @param {Node} node The child node to be removed
21021 "beforeremove" : true,
21023 * @event beforemove
21024 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21025 * @param {Tree} tree The owner tree
21026 * @param {Node} node The node being moved
21027 * @param {Node} oldParent The parent of the node
21028 * @param {Node} newParent The new parent the node is moving to
21029 * @param {Number} index The index it is being moved to
21031 "beforemove" : true,
21033 * @event beforeinsert
21034 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21035 * @param {Tree} tree The owner tree
21036 * @param {Node} parent The parent node
21037 * @param {Node} node The child node to be inserted
21038 * @param {Node} refNode The child node the node is being inserted before
21040 "beforeinsert" : true
21043 Roo.data.Tree.superclass.constructor.call(this);
21046 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21047 pathSeparator: "/",
21049 proxyNodeEvent : function(){
21050 return this.fireEvent.apply(this, arguments);
21054 * Returns the root node for this tree.
21057 getRootNode : function(){
21062 * Sets the root node for this tree.
21063 * @param {Node} node
21066 setRootNode : function(node){
21068 node.ownerTree = this;
21069 node.isRoot = true;
21070 this.registerNode(node);
21075 * Gets a node in this tree by its id.
21076 * @param {String} id
21079 getNodeById : function(id){
21080 return this.nodeHash[id];
21083 registerNode : function(node){
21084 this.nodeHash[node.id] = node;
21087 unregisterNode : function(node){
21088 delete this.nodeHash[node.id];
21091 toString : function(){
21092 return "[Tree"+(this.id?" "+this.id:"")+"]";
21097 * @class Roo.data.Node
21098 * @extends Roo.util.Observable
21099 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21100 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21102 * @param {Object} attributes The attributes/config for the node
21104 Roo.data.Node = function(attributes){
21106 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21109 this.attributes = attributes || {};
21110 this.leaf = this.attributes.leaf;
21112 * The node id. @type String
21114 this.id = this.attributes.id;
21116 this.id = Roo.id(null, "ynode-");
21117 this.attributes.id = this.id;
21120 * All child nodes of this node. @type Array
21122 this.childNodes = [];
21123 if(!this.childNodes.indexOf){ // indexOf is a must
21124 this.childNodes.indexOf = function(o){
21125 for(var i = 0, len = this.length; i < len; i++){
21134 * The parent node for this node. @type Node
21136 this.parentNode = null;
21138 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21140 this.firstChild = null;
21142 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21144 this.lastChild = null;
21146 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21148 this.previousSibling = null;
21150 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21152 this.nextSibling = null;
21157 * Fires when a new child node is appended
21158 * @param {Tree} tree The owner tree
21159 * @param {Node} this This node
21160 * @param {Node} node The newly appended node
21161 * @param {Number} index The index of the newly appended node
21166 * Fires when a child node is removed
21167 * @param {Tree} tree The owner tree
21168 * @param {Node} this This node
21169 * @param {Node} node The removed node
21174 * Fires when this node is moved to a new location in the tree
21175 * @param {Tree} tree The owner tree
21176 * @param {Node} this This node
21177 * @param {Node} oldParent The old parent of this node
21178 * @param {Node} newParent The new parent of this node
21179 * @param {Number} index The index it was moved to
21184 * Fires when a new child node is inserted.
21185 * @param {Tree} tree The owner tree
21186 * @param {Node} this This node
21187 * @param {Node} node The child node inserted
21188 * @param {Node} refNode The child node the node was inserted before
21192 * @event beforeappend
21193 * Fires before a new child is appended, return false to cancel the append.
21194 * @param {Tree} tree The owner tree
21195 * @param {Node} this This node
21196 * @param {Node} node The child node to be appended
21198 "beforeappend" : true,
21200 * @event beforeremove
21201 * Fires before a child is removed, return false to cancel the remove.
21202 * @param {Tree} tree The owner tree
21203 * @param {Node} this This node
21204 * @param {Node} node The child node to be removed
21206 "beforeremove" : true,
21208 * @event beforemove
21209 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21210 * @param {Tree} tree The owner tree
21211 * @param {Node} this This node
21212 * @param {Node} oldParent The parent of this node
21213 * @param {Node} newParent The new parent this node is moving to
21214 * @param {Number} index The index it is being moved to
21216 "beforemove" : true,
21218 * @event beforeinsert
21219 * Fires before a new child is inserted, return false to cancel the insert.
21220 * @param {Tree} tree The owner tree
21221 * @param {Node} this This node
21222 * @param {Node} node The child node to be inserted
21223 * @param {Node} refNode The child node the node is being inserted before
21225 "beforeinsert" : true
21227 this.listeners = this.attributes.listeners;
21228 Roo.data.Node.superclass.constructor.call(this);
21231 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21232 fireEvent : function(evtName){
21233 // first do standard event for this node
21234 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21237 // then bubble it up to the tree if the event wasn't cancelled
21238 var ot = this.getOwnerTree();
21240 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21248 * Returns true if this node is a leaf
21249 * @return {Boolean}
21251 isLeaf : function(){
21252 return this.leaf === true;
21256 setFirstChild : function(node){
21257 this.firstChild = node;
21261 setLastChild : function(node){
21262 this.lastChild = node;
21267 * Returns true if this node is the last child of its parent
21268 * @return {Boolean}
21270 isLast : function(){
21271 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21275 * Returns true if this node is the first child of its parent
21276 * @return {Boolean}
21278 isFirst : function(){
21279 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21282 hasChildNodes : function(){
21283 return !this.isLeaf() && this.childNodes.length > 0;
21287 * Insert node(s) as the last child node of this node.
21288 * @param {Node/Array} node The node or Array of nodes to append
21289 * @return {Node} The appended node if single append, or null if an array was passed
21291 appendChild : function(node){
21293 if(node instanceof Array){
21295 }else if(arguments.length > 1){
21298 // if passed an array or multiple args do them one by one
21300 for(var i = 0, len = multi.length; i < len; i++) {
21301 this.appendChild(multi[i]);
21304 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21307 var index = this.childNodes.length;
21308 var oldParent = node.parentNode;
21309 // it's a move, make sure we move it cleanly
21311 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21314 oldParent.removeChild(node);
21316 index = this.childNodes.length;
21318 this.setFirstChild(node);
21320 this.childNodes.push(node);
21321 node.parentNode = this;
21322 var ps = this.childNodes[index-1];
21324 node.previousSibling = ps;
21325 ps.nextSibling = node;
21327 node.previousSibling = null;
21329 node.nextSibling = null;
21330 this.setLastChild(node);
21331 node.setOwnerTree(this.getOwnerTree());
21332 this.fireEvent("append", this.ownerTree, this, node, index);
21334 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21341 * Removes a child node from this node.
21342 * @param {Node} node The node to remove
21343 * @return {Node} The removed node
21345 removeChild : function(node){
21346 var index = this.childNodes.indexOf(node);
21350 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21354 // remove it from childNodes collection
21355 this.childNodes.splice(index, 1);
21358 if(node.previousSibling){
21359 node.previousSibling.nextSibling = node.nextSibling;
21361 if(node.nextSibling){
21362 node.nextSibling.previousSibling = node.previousSibling;
21365 // update child refs
21366 if(this.firstChild == node){
21367 this.setFirstChild(node.nextSibling);
21369 if(this.lastChild == node){
21370 this.setLastChild(node.previousSibling);
21373 node.setOwnerTree(null);
21374 // clear any references from the node
21375 node.parentNode = null;
21376 node.previousSibling = null;
21377 node.nextSibling = null;
21378 this.fireEvent("remove", this.ownerTree, this, node);
21383 * Inserts the first node before the second node in this nodes childNodes collection.
21384 * @param {Node} node The node to insert
21385 * @param {Node} refNode The node to insert before (if null the node is appended)
21386 * @return {Node} The inserted node
21388 insertBefore : function(node, refNode){
21389 if(!refNode){ // like standard Dom, refNode can be null for append
21390 return this.appendChild(node);
21393 if(node == refNode){
21397 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21400 var index = this.childNodes.indexOf(refNode);
21401 var oldParent = node.parentNode;
21402 var refIndex = index;
21404 // when moving internally, indexes will change after remove
21405 if(oldParent == this && this.childNodes.indexOf(node) < index){
21409 // it's a move, make sure we move it cleanly
21411 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21414 oldParent.removeChild(node);
21417 this.setFirstChild(node);
21419 this.childNodes.splice(refIndex, 0, node);
21420 node.parentNode = this;
21421 var ps = this.childNodes[refIndex-1];
21423 node.previousSibling = ps;
21424 ps.nextSibling = node;
21426 node.previousSibling = null;
21428 node.nextSibling = refNode;
21429 refNode.previousSibling = node;
21430 node.setOwnerTree(this.getOwnerTree());
21431 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21433 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21439 * Returns the child node at the specified index.
21440 * @param {Number} index
21443 item : function(index){
21444 return this.childNodes[index];
21448 * Replaces one child node in this node with another.
21449 * @param {Node} newChild The replacement node
21450 * @param {Node} oldChild The node to replace
21451 * @return {Node} The replaced node
21453 replaceChild : function(newChild, oldChild){
21454 this.insertBefore(newChild, oldChild);
21455 this.removeChild(oldChild);
21460 * Returns the index of a child node
21461 * @param {Node} node
21462 * @return {Number} The index of the node or -1 if it was not found
21464 indexOf : function(child){
21465 return this.childNodes.indexOf(child);
21469 * Returns the tree this node is in.
21472 getOwnerTree : function(){
21473 // if it doesn't have one, look for one
21474 if(!this.ownerTree){
21478 this.ownerTree = p.ownerTree;
21484 return this.ownerTree;
21488 * Returns depth of this node (the root node has a depth of 0)
21491 getDepth : function(){
21494 while(p.parentNode){
21502 setOwnerTree : function(tree){
21503 // if it's move, we need to update everyone
21504 if(tree != this.ownerTree){
21505 if(this.ownerTree){
21506 this.ownerTree.unregisterNode(this);
21508 this.ownerTree = tree;
21509 var cs = this.childNodes;
21510 for(var i = 0, len = cs.length; i < len; i++) {
21511 cs[i].setOwnerTree(tree);
21514 tree.registerNode(this);
21520 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21521 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21522 * @return {String} The path
21524 getPath : function(attr){
21525 attr = attr || "id";
21526 var p = this.parentNode;
21527 var b = [this.attributes[attr]];
21529 b.unshift(p.attributes[attr]);
21532 var sep = this.getOwnerTree().pathSeparator;
21533 return sep + b.join(sep);
21537 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21538 * function call will be the scope provided or the current node. The arguments to the function
21539 * will be the args provided or the current node. If the function returns false at any point,
21540 * the bubble is stopped.
21541 * @param {Function} fn The function to call
21542 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21543 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21545 bubble : function(fn, scope, args){
21548 if(fn.call(scope || p, args || p) === false){
21556 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21557 * function call will be the scope provided or the current node. The arguments to the function
21558 * will be the args provided or the current node. If the function returns false at any point,
21559 * the cascade is stopped on that branch.
21560 * @param {Function} fn The function to call
21561 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21562 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21564 cascade : function(fn, scope, args){
21565 if(fn.call(scope || this, args || this) !== false){
21566 var cs = this.childNodes;
21567 for(var i = 0, len = cs.length; i < len; i++) {
21568 cs[i].cascade(fn, scope, args);
21574 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21575 * function call will be the scope provided or the current node. The arguments to the function
21576 * will be the args provided or the current node. If the function returns false at any point,
21577 * the iteration stops.
21578 * @param {Function} fn The function to call
21579 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21580 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21582 eachChild : function(fn, scope, args){
21583 var cs = this.childNodes;
21584 for(var i = 0, len = cs.length; i < len; i++) {
21585 if(fn.call(scope || this, args || cs[i]) === false){
21592 * Finds the first child that has the attribute with the specified value.
21593 * @param {String} attribute The attribute name
21594 * @param {Mixed} value The value to search for
21595 * @return {Node} The found child or null if none was found
21597 findChild : function(attribute, value){
21598 var cs = this.childNodes;
21599 for(var i = 0, len = cs.length; i < len; i++) {
21600 if(cs[i].attributes[attribute] == value){
21608 * Finds the first child by a custom function. The child matches if the function passed
21610 * @param {Function} fn
21611 * @param {Object} scope (optional)
21612 * @return {Node} The found child or null if none was found
21614 findChildBy : function(fn, scope){
21615 var cs = this.childNodes;
21616 for(var i = 0, len = cs.length; i < len; i++) {
21617 if(fn.call(scope||cs[i], cs[i]) === true){
21625 * Sorts this nodes children using the supplied sort function
21626 * @param {Function} fn
21627 * @param {Object} scope (optional)
21629 sort : function(fn, scope){
21630 var cs = this.childNodes;
21631 var len = cs.length;
21633 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21635 for(var i = 0; i < len; i++){
21637 n.previousSibling = cs[i-1];
21638 n.nextSibling = cs[i+1];
21640 this.setFirstChild(n);
21643 this.setLastChild(n);
21650 * Returns true if this node is an ancestor (at any point) of the passed node.
21651 * @param {Node} node
21652 * @return {Boolean}
21654 contains : function(node){
21655 return node.isAncestor(this);
21659 * Returns true if the passed node is an ancestor (at any point) of this node.
21660 * @param {Node} node
21661 * @return {Boolean}
21663 isAncestor : function(node){
21664 var p = this.parentNode;
21674 toString : function(){
21675 return "[Node"+(this.id?" "+this.id:"")+"]";
21679 * Ext JS Library 1.1.1
21680 * Copyright(c) 2006-2007, Ext JS, LLC.
21682 * Originally Released Under LGPL - original licence link has changed is not relivant.
21685 * <script type="text/javascript">
21690 * @class Roo.ComponentMgr
21691 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21694 Roo.ComponentMgr = function(){
21695 var all = new Roo.util.MixedCollection();
21699 * Registers a component.
21700 * @param {Roo.Component} c The component
21702 register : function(c){
21707 * Unregisters a component.
21708 * @param {Roo.Component} c The component
21710 unregister : function(c){
21715 * Returns a component by id
21716 * @param {String} id The component id
21718 get : function(id){
21719 return all.get(id);
21723 * Registers a function that will be called when a specified component is added to ComponentMgr
21724 * @param {String} id The component id
21725 * @param {Funtction} fn The callback function
21726 * @param {Object} scope The scope of the callback
21728 onAvailable : function(id, fn, scope){
21729 all.on("add", function(index, o){
21731 fn.call(scope || o, o);
21732 all.un("add", fn, scope);
21739 * Ext JS Library 1.1.1
21740 * Copyright(c) 2006-2007, Ext JS, LLC.
21742 * Originally Released Under LGPL - original licence link has changed is not relivant.
21745 * <script type="text/javascript">
21749 * @class Roo.Component
21750 * @extends Roo.util.Observable
21751 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21752 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21753 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21754 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21755 * All visual components (widgets) that require rendering into a layout should subclass Component.
21757 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21758 * 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
21759 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21761 Roo.Component = function(config){
21762 config = config || {};
21763 if(config.tagName || config.dom || typeof config == "string"){ // element object
21764 config = {el: config, id: config.id || config};
21766 this.initialConfig = config;
21768 Roo.apply(this, config);
21772 * Fires after the component is disabled.
21773 * @param {Roo.Component} this
21778 * Fires after the component is enabled.
21779 * @param {Roo.Component} this
21783 * @event beforeshow
21784 * Fires before the component is shown. Return false to stop the show.
21785 * @param {Roo.Component} this
21790 * Fires after the component is shown.
21791 * @param {Roo.Component} this
21795 * @event beforehide
21796 * Fires before the component is hidden. Return false to stop the hide.
21797 * @param {Roo.Component} this
21802 * Fires after the component is hidden.
21803 * @param {Roo.Component} this
21807 * @event beforerender
21808 * Fires before the component is rendered. Return false to stop the render.
21809 * @param {Roo.Component} this
21811 beforerender : true,
21814 * Fires after the component is rendered.
21815 * @param {Roo.Component} this
21819 * @event beforedestroy
21820 * Fires before the component is destroyed. Return false to stop the destroy.
21821 * @param {Roo.Component} this
21823 beforedestroy : true,
21826 * Fires after the component is destroyed.
21827 * @param {Roo.Component} this
21832 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21834 Roo.ComponentMgr.register(this);
21835 Roo.Component.superclass.constructor.call(this);
21836 this.initComponent();
21837 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21838 this.render(this.renderTo);
21839 delete this.renderTo;
21844 Roo.Component.AUTO_ID = 1000;
21846 Roo.extend(Roo.Component, Roo.util.Observable, {
21848 * @scope Roo.Component.prototype
21850 * true if this component is hidden. Read-only.
21855 * true if this component is disabled. Read-only.
21860 * true if this component has been rendered. Read-only.
21864 /** @cfg {String} disableClass
21865 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21867 disabledClass : "x-item-disabled",
21868 /** @cfg {Boolean} allowDomMove
21869 * Whether the component can move the Dom node when rendering (defaults to true).
21871 allowDomMove : true,
21872 /** @cfg {String} hideMode
21873 * How this component should hidden. Supported values are
21874 * "visibility" (css visibility), "offsets" (negative offset position) and
21875 * "display" (css display) - defaults to "display".
21877 hideMode: 'display',
21880 ctype : "Roo.Component",
21883 * @cfg {String} actionMode
21884 * which property holds the element that used for hide() / show() / disable() / enable()
21890 getActionEl : function(){
21891 return this[this.actionMode];
21894 initComponent : Roo.emptyFn,
21896 * If this is a lazy rendering component, render it to its container element.
21897 * @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.
21899 render : function(container, position){
21900 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21901 if(!container && this.el){
21902 this.el = Roo.get(this.el);
21903 container = this.el.dom.parentNode;
21904 this.allowDomMove = false;
21906 this.container = Roo.get(container);
21907 this.rendered = true;
21908 if(position !== undefined){
21909 if(typeof position == 'number'){
21910 position = this.container.dom.childNodes[position];
21912 position = Roo.getDom(position);
21915 this.onRender(this.container, position || null);
21917 this.el.addClass(this.cls);
21921 this.el.applyStyles(this.style);
21924 this.fireEvent("render", this);
21925 this.afterRender(this.container);
21937 // default function is not really useful
21938 onRender : function(ct, position){
21940 this.el = Roo.get(this.el);
21941 if(this.allowDomMove !== false){
21942 ct.dom.insertBefore(this.el.dom, position);
21948 getAutoCreate : function(){
21949 var cfg = typeof this.autoCreate == "object" ?
21950 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21951 if(this.id && !cfg.id){
21958 afterRender : Roo.emptyFn,
21961 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21962 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21964 destroy : function(){
21965 if(this.fireEvent("beforedestroy", this) !== false){
21966 this.purgeListeners();
21967 this.beforeDestroy();
21969 this.el.removeAllListeners();
21971 if(this.actionMode == "container"){
21972 this.container.remove();
21976 Roo.ComponentMgr.unregister(this);
21977 this.fireEvent("destroy", this);
21982 beforeDestroy : function(){
21987 onDestroy : function(){
21992 * Returns the underlying {@link Roo.Element}.
21993 * @return {Roo.Element} The element
21995 getEl : function(){
22000 * Returns the id of this component.
22003 getId : function(){
22008 * Try to focus this component.
22009 * @param {Boolean} selectText True to also select the text in this component (if applicable)
22010 * @return {Roo.Component} this
22012 focus : function(selectText){
22015 if(selectText === true){
22016 this.el.dom.select();
22031 * Disable this component.
22032 * @return {Roo.Component} this
22034 disable : function(){
22038 this.disabled = true;
22039 this.fireEvent("disable", this);
22044 onDisable : function(){
22045 this.getActionEl().addClass(this.disabledClass);
22046 this.el.dom.disabled = true;
22050 * Enable this component.
22051 * @return {Roo.Component} this
22053 enable : function(){
22057 this.disabled = false;
22058 this.fireEvent("enable", this);
22063 onEnable : function(){
22064 this.getActionEl().removeClass(this.disabledClass);
22065 this.el.dom.disabled = false;
22069 * Convenience function for setting disabled/enabled by boolean.
22070 * @param {Boolean} disabled
22072 setDisabled : function(disabled){
22073 this[disabled ? "disable" : "enable"]();
22077 * Show this component.
22078 * @return {Roo.Component} this
22081 if(this.fireEvent("beforeshow", this) !== false){
22082 this.hidden = false;
22086 this.fireEvent("show", this);
22092 onShow : function(){
22093 var ae = this.getActionEl();
22094 if(this.hideMode == 'visibility'){
22095 ae.dom.style.visibility = "visible";
22096 }else if(this.hideMode == 'offsets'){
22097 ae.removeClass('x-hidden');
22099 ae.dom.style.display = "";
22104 * Hide this component.
22105 * @return {Roo.Component} this
22108 if(this.fireEvent("beforehide", this) !== false){
22109 this.hidden = true;
22113 this.fireEvent("hide", this);
22119 onHide : function(){
22120 var ae = this.getActionEl();
22121 if(this.hideMode == 'visibility'){
22122 ae.dom.style.visibility = "hidden";
22123 }else if(this.hideMode == 'offsets'){
22124 ae.addClass('x-hidden');
22126 ae.dom.style.display = "none";
22131 * Convenience function to hide or show this component by boolean.
22132 * @param {Boolean} visible True to show, false to hide
22133 * @return {Roo.Component} this
22135 setVisible: function(visible){
22145 * Returns true if this component is visible.
22147 isVisible : function(){
22148 return this.getActionEl().isVisible();
22151 cloneConfig : function(overrides){
22152 overrides = overrides || {};
22153 var id = overrides.id || Roo.id();
22154 var cfg = Roo.applyIf(overrides, this.initialConfig);
22155 cfg.id = id; // prevent dup id
22156 return new this.constructor(cfg);
22160 * Ext JS Library 1.1.1
22161 * Copyright(c) 2006-2007, Ext JS, LLC.
22163 * Originally Released Under LGPL - original licence link has changed is not relivant.
22166 * <script type="text/javascript">
22171 * @extends Roo.Element
22172 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22173 * automatic maintaining of shadow/shim positions.
22174 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22175 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22176 * you can pass a string with a CSS class name. False turns off the shadow.
22177 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22178 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22179 * @cfg {String} cls CSS class to add to the element
22180 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22181 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22183 * @param {Object} config An object with config options.
22184 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22187 Roo.Layer = function(config, existingEl){
22188 config = config || {};
22189 var dh = Roo.DomHelper;
22190 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22192 this.dom = Roo.getDom(existingEl);
22195 var o = config.dh || {tag: "div", cls: "x-layer"};
22196 this.dom = dh.append(pel, o);
22199 this.addClass(config.cls);
22201 this.constrain = config.constrain !== false;
22202 this.visibilityMode = Roo.Element.VISIBILITY;
22204 this.id = this.dom.id = config.id;
22206 this.id = Roo.id(this.dom);
22208 this.zindex = config.zindex || this.getZIndex();
22209 this.position("absolute", this.zindex);
22211 this.shadowOffset = config.shadowOffset || 4;
22212 this.shadow = new Roo.Shadow({
22213 offset : this.shadowOffset,
22214 mode : config.shadow
22217 this.shadowOffset = 0;
22219 this.useShim = config.shim !== false && Roo.useShims;
22220 this.useDisplay = config.useDisplay;
22224 var supr = Roo.Element.prototype;
22226 // shims are shared among layer to keep from having 100 iframes
22229 Roo.extend(Roo.Layer, Roo.Element, {
22231 getZIndex : function(){
22232 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22235 getShim : function(){
22242 var shim = shims.shift();
22244 shim = this.createShim();
22245 shim.enableDisplayMode('block');
22246 shim.dom.style.display = 'none';
22247 shim.dom.style.visibility = 'visible';
22249 var pn = this.dom.parentNode;
22250 if(shim.dom.parentNode != pn){
22251 pn.insertBefore(shim.dom, this.dom);
22253 shim.setStyle('z-index', this.getZIndex()-2);
22258 hideShim : function(){
22260 this.shim.setDisplayed(false);
22261 shims.push(this.shim);
22266 disableShadow : function(){
22268 this.shadowDisabled = true;
22269 this.shadow.hide();
22270 this.lastShadowOffset = this.shadowOffset;
22271 this.shadowOffset = 0;
22275 enableShadow : function(show){
22277 this.shadowDisabled = false;
22278 this.shadowOffset = this.lastShadowOffset;
22279 delete this.lastShadowOffset;
22287 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22288 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22289 sync : function(doShow){
22290 var sw = this.shadow;
22291 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22292 var sh = this.getShim();
22294 var w = this.getWidth(),
22295 h = this.getHeight();
22297 var l = this.getLeft(true),
22298 t = this.getTop(true);
22300 if(sw && !this.shadowDisabled){
22301 if(doShow && !sw.isVisible()){
22304 sw.realign(l, t, w, h);
22310 // fit the shim behind the shadow, so it is shimmed too
22311 var a = sw.adjusts, s = sh.dom.style;
22312 s.left = (Math.min(l, l+a.l))+"px";
22313 s.top = (Math.min(t, t+a.t))+"px";
22314 s.width = (w+a.w)+"px";
22315 s.height = (h+a.h)+"px";
22322 sh.setLeftTop(l, t);
22329 destroy : function(){
22332 this.shadow.hide();
22334 this.removeAllListeners();
22335 var pn = this.dom.parentNode;
22337 pn.removeChild(this.dom);
22339 Roo.Element.uncache(this.id);
22342 remove : function(){
22347 beginUpdate : function(){
22348 this.updating = true;
22352 endUpdate : function(){
22353 this.updating = false;
22358 hideUnders : function(negOffset){
22360 this.shadow.hide();
22366 constrainXY : function(){
22367 if(this.constrain){
22368 var vw = Roo.lib.Dom.getViewWidth(),
22369 vh = Roo.lib.Dom.getViewHeight();
22370 var s = Roo.get(document).getScroll();
22372 var xy = this.getXY();
22373 var x = xy[0], y = xy[1];
22374 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22375 // only move it if it needs it
22377 // first validate right/bottom
22378 if((x + w) > vw+s.left){
22379 x = vw - w - this.shadowOffset;
22382 if((y + h) > vh+s.top){
22383 y = vh - h - this.shadowOffset;
22386 // then make sure top/left isn't negative
22397 var ay = this.avoidY;
22398 if(y <= ay && (y+h) >= ay){
22404 supr.setXY.call(this, xy);
22410 isVisible : function(){
22411 return this.visible;
22415 showAction : function(){
22416 this.visible = true; // track visibility to prevent getStyle calls
22417 if(this.useDisplay === true){
22418 this.setDisplayed("");
22419 }else if(this.lastXY){
22420 supr.setXY.call(this, this.lastXY);
22421 }else if(this.lastLT){
22422 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22427 hideAction : function(){
22428 this.visible = false;
22429 if(this.useDisplay === true){
22430 this.setDisplayed(false);
22432 this.setLeftTop(-10000,-10000);
22436 // overridden Element method
22437 setVisible : function(v, a, d, c, e){
22442 var cb = function(){
22447 }.createDelegate(this);
22448 supr.setVisible.call(this, true, true, d, cb, e);
22451 this.hideUnders(true);
22460 }.createDelegate(this);
22462 supr.setVisible.call(this, v, a, d, cb, e);
22471 storeXY : function(xy){
22472 delete this.lastLT;
22476 storeLeftTop : function(left, top){
22477 delete this.lastXY;
22478 this.lastLT = [left, top];
22482 beforeFx : function(){
22483 this.beforeAction();
22484 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22488 afterFx : function(){
22489 Roo.Layer.superclass.afterFx.apply(this, arguments);
22490 this.sync(this.isVisible());
22494 beforeAction : function(){
22495 if(!this.updating && this.shadow){
22496 this.shadow.hide();
22500 // overridden Element method
22501 setLeft : function(left){
22502 this.storeLeftTop(left, this.getTop(true));
22503 supr.setLeft.apply(this, arguments);
22507 setTop : function(top){
22508 this.storeLeftTop(this.getLeft(true), top);
22509 supr.setTop.apply(this, arguments);
22513 setLeftTop : function(left, top){
22514 this.storeLeftTop(left, top);
22515 supr.setLeftTop.apply(this, arguments);
22519 setXY : function(xy, a, d, c, e){
22521 this.beforeAction();
22523 var cb = this.createCB(c);
22524 supr.setXY.call(this, xy, a, d, cb, e);
22531 createCB : function(c){
22542 // overridden Element method
22543 setX : function(x, a, d, c, e){
22544 this.setXY([x, this.getY()], a, d, c, e);
22547 // overridden Element method
22548 setY : function(y, a, d, c, e){
22549 this.setXY([this.getX(), y], a, d, c, e);
22552 // overridden Element method
22553 setSize : function(w, h, a, d, c, e){
22554 this.beforeAction();
22555 var cb = this.createCB(c);
22556 supr.setSize.call(this, w, h, a, d, cb, e);
22562 // overridden Element method
22563 setWidth : function(w, a, d, c, e){
22564 this.beforeAction();
22565 var cb = this.createCB(c);
22566 supr.setWidth.call(this, w, a, d, cb, e);
22572 // overridden Element method
22573 setHeight : function(h, a, d, c, e){
22574 this.beforeAction();
22575 var cb = this.createCB(c);
22576 supr.setHeight.call(this, h, a, d, cb, e);
22582 // overridden Element method
22583 setBounds : function(x, y, w, h, a, d, c, e){
22584 this.beforeAction();
22585 var cb = this.createCB(c);
22587 this.storeXY([x, y]);
22588 supr.setXY.call(this, [x, y]);
22589 supr.setSize.call(this, w, h, a, d, cb, e);
22592 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22598 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22599 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22600 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22601 * @param {Number} zindex The new z-index to set
22602 * @return {this} The Layer
22604 setZIndex : function(zindex){
22605 this.zindex = zindex;
22606 this.setStyle("z-index", zindex + 2);
22608 this.shadow.setZIndex(zindex + 1);
22611 this.shim.setStyle("z-index", zindex);
22617 * Ext JS Library 1.1.1
22618 * Copyright(c) 2006-2007, Ext JS, LLC.
22620 * Originally Released Under LGPL - original licence link has changed is not relivant.
22623 * <script type="text/javascript">
22628 * @class Roo.Shadow
22629 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22630 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22631 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22633 * Create a new Shadow
22634 * @param {Object} config The config object
22636 Roo.Shadow = function(config){
22637 Roo.apply(this, config);
22638 if(typeof this.mode != "string"){
22639 this.mode = this.defaultMode;
22641 var o = this.offset, a = {h: 0};
22642 var rad = Math.floor(this.offset/2);
22643 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22649 a.l -= this.offset + rad;
22650 a.t -= this.offset + rad;
22661 a.l -= (this.offset - rad);
22662 a.t -= this.offset + rad;
22664 a.w -= (this.offset - rad)*2;
22675 a.l -= (this.offset - rad);
22676 a.t -= (this.offset - rad);
22678 a.w -= (this.offset + rad + 1);
22679 a.h -= (this.offset + rad);
22688 Roo.Shadow.prototype = {
22690 * @cfg {String} mode
22691 * The shadow display mode. Supports the following options:<br />
22692 * sides: Shadow displays on both sides and bottom only<br />
22693 * frame: Shadow displays equally on all four sides<br />
22694 * drop: Traditional bottom-right drop shadow (default)
22697 * @cfg {String} offset
22698 * The number of pixels to offset the shadow from the element (defaults to 4)
22703 defaultMode: "drop",
22706 * Displays the shadow under the target element
22707 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22709 show : function(target){
22710 target = Roo.get(target);
22712 this.el = Roo.Shadow.Pool.pull();
22713 if(this.el.dom.nextSibling != target.dom){
22714 this.el.insertBefore(target);
22717 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22719 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22722 target.getLeft(true),
22723 target.getTop(true),
22727 this.el.dom.style.display = "block";
22731 * Returns true if the shadow is visible, else false
22733 isVisible : function(){
22734 return this.el ? true : false;
22738 * Direct alignment when values are already available. Show must be called at least once before
22739 * calling this method to ensure it is initialized.
22740 * @param {Number} left The target element left position
22741 * @param {Number} top The target element top position
22742 * @param {Number} width The target element width
22743 * @param {Number} height The target element height
22745 realign : function(l, t, w, h){
22749 var a = this.adjusts, d = this.el.dom, s = d.style;
22751 s.left = (l+a.l)+"px";
22752 s.top = (t+a.t)+"px";
22753 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22755 if(s.width != sws || s.height != shs){
22759 var cn = d.childNodes;
22760 var sww = Math.max(0, (sw-12))+"px";
22761 cn[0].childNodes[1].style.width = sww;
22762 cn[1].childNodes[1].style.width = sww;
22763 cn[2].childNodes[1].style.width = sww;
22764 cn[1].style.height = Math.max(0, (sh-12))+"px";
22770 * Hides this shadow
22774 this.el.dom.style.display = "none";
22775 Roo.Shadow.Pool.push(this.el);
22781 * Adjust the z-index of this shadow
22782 * @param {Number} zindex The new z-index
22784 setZIndex : function(z){
22787 this.el.setStyle("z-index", z);
22792 // Private utility class that manages the internal Shadow cache
22793 Roo.Shadow.Pool = function(){
22795 var markup = Roo.isIE ?
22796 '<div class="x-ie-shadow"></div>' :
22797 '<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>';
22800 var sh = p.shift();
22802 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22803 sh.autoBoxAdjust = false;
22808 push : function(sh){
22814 * Ext JS Library 1.1.1
22815 * Copyright(c) 2006-2007, Ext JS, LLC.
22817 * Originally Released Under LGPL - original licence link has changed is not relivant.
22820 * <script type="text/javascript">
22824 * @class Roo.BoxComponent
22825 * @extends Roo.Component
22826 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22827 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22828 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22829 * layout containers.
22831 * @param {Roo.Element/String/Object} config The configuration options.
22833 Roo.BoxComponent = function(config){
22834 Roo.Component.call(this, config);
22838 * Fires after the component is resized.
22839 * @param {Roo.Component} this
22840 * @param {Number} adjWidth The box-adjusted width that was set
22841 * @param {Number} adjHeight The box-adjusted height that was set
22842 * @param {Number} rawWidth The width that was originally specified
22843 * @param {Number} rawHeight The height that was originally specified
22848 * Fires after the component is moved.
22849 * @param {Roo.Component} this
22850 * @param {Number} x The new x position
22851 * @param {Number} y The new y position
22857 Roo.extend(Roo.BoxComponent, Roo.Component, {
22858 // private, set in afterRender to signify that the component has been rendered
22860 // private, used to defer height settings to subclasses
22861 deferHeight: false,
22862 /** @cfg {Number} width
22863 * width (optional) size of component
22865 /** @cfg {Number} height
22866 * height (optional) size of component
22870 * Sets the width and height of the component. This method fires the resize event. This method can accept
22871 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22872 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22873 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22874 * @return {Roo.BoxComponent} this
22876 setSize : function(w, h){
22877 // support for standard size objects
22878 if(typeof w == 'object'){
22883 if(!this.boxReady){
22889 // prevent recalcs when not needed
22890 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22893 this.lastSize = {width: w, height: h};
22895 var adj = this.adjustSize(w, h);
22896 var aw = adj.width, ah = adj.height;
22897 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22898 var rz = this.getResizeEl();
22899 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22900 rz.setSize(aw, ah);
22901 }else if(!this.deferHeight && ah !== undefined){
22903 }else if(aw !== undefined){
22906 this.onResize(aw, ah, w, h);
22907 this.fireEvent('resize', this, aw, ah, w, h);
22913 * Gets the current size of the component's underlying element.
22914 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22916 getSize : function(){
22917 return this.el.getSize();
22921 * Gets the current XY position of the component's underlying element.
22922 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22923 * @return {Array} The XY position of the element (e.g., [100, 200])
22925 getPosition : function(local){
22926 if(local === true){
22927 return [this.el.getLeft(true), this.el.getTop(true)];
22929 return this.xy || this.el.getXY();
22933 * Gets the current box measurements of the component's underlying element.
22934 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22935 * @returns {Object} box An object in the format {x, y, width, height}
22937 getBox : function(local){
22938 var s = this.el.getSize();
22940 s.x = this.el.getLeft(true);
22941 s.y = this.el.getTop(true);
22943 var xy = this.xy || this.el.getXY();
22951 * Sets the current box measurements of the component's underlying element.
22952 * @param {Object} box An object in the format {x, y, width, height}
22953 * @returns {Roo.BoxComponent} this
22955 updateBox : function(box){
22956 this.setSize(box.width, box.height);
22957 this.setPagePosition(box.x, box.y);
22962 getResizeEl : function(){
22963 return this.resizeEl || this.el;
22967 getPositionEl : function(){
22968 return this.positionEl || this.el;
22972 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22973 * This method fires the move event.
22974 * @param {Number} left The new left
22975 * @param {Number} top The new top
22976 * @returns {Roo.BoxComponent} this
22978 setPosition : function(x, y){
22981 if(!this.boxReady){
22984 var adj = this.adjustPosition(x, y);
22985 var ax = adj.x, ay = adj.y;
22987 var el = this.getPositionEl();
22988 if(ax !== undefined || ay !== undefined){
22989 if(ax !== undefined && ay !== undefined){
22990 el.setLeftTop(ax, ay);
22991 }else if(ax !== undefined){
22993 }else if(ay !== undefined){
22996 this.onPosition(ax, ay);
22997 this.fireEvent('move', this, ax, ay);
23003 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
23004 * This method fires the move event.
23005 * @param {Number} x The new x position
23006 * @param {Number} y The new y position
23007 * @returns {Roo.BoxComponent} this
23009 setPagePosition : function(x, y){
23012 if(!this.boxReady){
23015 if(x === undefined || y === undefined){ // cannot translate undefined points
23018 var p = this.el.translatePoints(x, y);
23019 this.setPosition(p.left, p.top);
23024 onRender : function(ct, position){
23025 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23027 this.resizeEl = Roo.get(this.resizeEl);
23029 if(this.positionEl){
23030 this.positionEl = Roo.get(this.positionEl);
23035 afterRender : function(){
23036 Roo.BoxComponent.superclass.afterRender.call(this);
23037 this.boxReady = true;
23038 this.setSize(this.width, this.height);
23039 if(this.x || this.y){
23040 this.setPosition(this.x, this.y);
23042 if(this.pageX || this.pageY){
23043 this.setPagePosition(this.pageX, this.pageY);
23048 * Force the component's size to recalculate based on the underlying element's current height and width.
23049 * @returns {Roo.BoxComponent} this
23051 syncSize : function(){
23052 delete this.lastSize;
23053 this.setSize(this.el.getWidth(), this.el.getHeight());
23058 * Called after the component is resized, this method is empty by default but can be implemented by any
23059 * subclass that needs to perform custom logic after a resize occurs.
23060 * @param {Number} adjWidth The box-adjusted width that was set
23061 * @param {Number} adjHeight The box-adjusted height that was set
23062 * @param {Number} rawWidth The width that was originally specified
23063 * @param {Number} rawHeight The height that was originally specified
23065 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23070 * Called after the component is moved, this method is empty by default but can be implemented by any
23071 * subclass that needs to perform custom logic after a move occurs.
23072 * @param {Number} x The new x position
23073 * @param {Number} y The new y position
23075 onPosition : function(x, y){
23080 adjustSize : function(w, h){
23081 if(this.autoWidth){
23084 if(this.autoHeight){
23087 return {width : w, height: h};
23091 adjustPosition : function(x, y){
23092 return {x : x, y: y};
23096 * Ext JS Library 1.1.1
23097 * Copyright(c) 2006-2007, Ext JS, LLC.
23099 * Originally Released Under LGPL - original licence link has changed is not relivant.
23102 * <script type="text/javascript">
23107 * @class Roo.SplitBar
23108 * @extends Roo.util.Observable
23109 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23113 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23114 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23115 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23116 split.minSize = 100;
23117 split.maxSize = 600;
23118 split.animate = true;
23119 split.on('moved', splitterMoved);
23122 * Create a new SplitBar
23123 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23124 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23125 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23126 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23127 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23128 position of the SplitBar).
23130 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23133 this.el = Roo.get(dragElement, true);
23134 this.el.dom.unselectable = "on";
23136 this.resizingEl = Roo.get(resizingElement, true);
23140 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23141 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23144 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23147 * The minimum size of the resizing element. (Defaults to 0)
23153 * The maximum size of the resizing element. (Defaults to 2000)
23156 this.maxSize = 2000;
23159 * Whether to animate the transition to the new size
23162 this.animate = false;
23165 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23168 this.useShim = false;
23173 if(!existingProxy){
23175 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23177 this.proxy = Roo.get(existingProxy).dom;
23180 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23183 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23186 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23189 this.dragSpecs = {};
23192 * @private The adapter to use to positon and resize elements
23194 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23195 this.adapter.init(this);
23197 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23199 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23200 this.el.addClass("x-splitbar-h");
23203 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23204 this.el.addClass("x-splitbar-v");
23210 * Fires when the splitter is moved (alias for {@link #event-moved})
23211 * @param {Roo.SplitBar} this
23212 * @param {Number} newSize the new width or height
23217 * Fires when the splitter is moved
23218 * @param {Roo.SplitBar} this
23219 * @param {Number} newSize the new width or height
23223 * @event beforeresize
23224 * Fires before the splitter is dragged
23225 * @param {Roo.SplitBar} this
23227 "beforeresize" : true,
23229 "beforeapply" : true
23232 Roo.util.Observable.call(this);
23235 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23236 onStartProxyDrag : function(x, y){
23237 this.fireEvent("beforeresize", this);
23239 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23241 o.enableDisplayMode("block");
23242 // all splitbars share the same overlay
23243 Roo.SplitBar.prototype.overlay = o;
23245 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23246 this.overlay.show();
23247 Roo.get(this.proxy).setDisplayed("block");
23248 var size = this.adapter.getElementSize(this);
23249 this.activeMinSize = this.getMinimumSize();;
23250 this.activeMaxSize = this.getMaximumSize();;
23251 var c1 = size - this.activeMinSize;
23252 var c2 = Math.max(this.activeMaxSize - size, 0);
23253 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23254 this.dd.resetConstraints();
23255 this.dd.setXConstraint(
23256 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23257 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23259 this.dd.setYConstraint(0, 0);
23261 this.dd.resetConstraints();
23262 this.dd.setXConstraint(0, 0);
23263 this.dd.setYConstraint(
23264 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23265 this.placement == Roo.SplitBar.TOP ? c2 : c1
23268 this.dragSpecs.startSize = size;
23269 this.dragSpecs.startPoint = [x, y];
23270 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23274 * @private Called after the drag operation by the DDProxy
23276 onEndProxyDrag : function(e){
23277 Roo.get(this.proxy).setDisplayed(false);
23278 var endPoint = Roo.lib.Event.getXY(e);
23280 this.overlay.hide();
23283 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23284 newSize = this.dragSpecs.startSize +
23285 (this.placement == Roo.SplitBar.LEFT ?
23286 endPoint[0] - this.dragSpecs.startPoint[0] :
23287 this.dragSpecs.startPoint[0] - endPoint[0]
23290 newSize = this.dragSpecs.startSize +
23291 (this.placement == Roo.SplitBar.TOP ?
23292 endPoint[1] - this.dragSpecs.startPoint[1] :
23293 this.dragSpecs.startPoint[1] - endPoint[1]
23296 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23297 if(newSize != this.dragSpecs.startSize){
23298 if(this.fireEvent('beforeapply', this, newSize) !== false){
23299 this.adapter.setElementSize(this, newSize);
23300 this.fireEvent("moved", this, newSize);
23301 this.fireEvent("resize", this, newSize);
23307 * Get the adapter this SplitBar uses
23308 * @return The adapter object
23310 getAdapter : function(){
23311 return this.adapter;
23315 * Set the adapter this SplitBar uses
23316 * @param {Object} adapter A SplitBar adapter object
23318 setAdapter : function(adapter){
23319 this.adapter = adapter;
23320 this.adapter.init(this);
23324 * Gets the minimum size for the resizing element
23325 * @return {Number} The minimum size
23327 getMinimumSize : function(){
23328 return this.minSize;
23332 * Sets the minimum size for the resizing element
23333 * @param {Number} minSize The minimum size
23335 setMinimumSize : function(minSize){
23336 this.minSize = minSize;
23340 * Gets the maximum size for the resizing element
23341 * @return {Number} The maximum size
23343 getMaximumSize : function(){
23344 return this.maxSize;
23348 * Sets the maximum size for the resizing element
23349 * @param {Number} maxSize The maximum size
23351 setMaximumSize : function(maxSize){
23352 this.maxSize = maxSize;
23356 * Sets the initialize size for the resizing element
23357 * @param {Number} size The initial size
23359 setCurrentSize : function(size){
23360 var oldAnimate = this.animate;
23361 this.animate = false;
23362 this.adapter.setElementSize(this, size);
23363 this.animate = oldAnimate;
23367 * Destroy this splitbar.
23368 * @param {Boolean} removeEl True to remove the element
23370 destroy : function(removeEl){
23372 this.shim.remove();
23375 this.proxy.parentNode.removeChild(this.proxy);
23383 * @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.
23385 Roo.SplitBar.createProxy = function(dir){
23386 var proxy = new Roo.Element(document.createElement("div"));
23387 proxy.unselectable();
23388 var cls = 'x-splitbar-proxy';
23389 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23390 document.body.appendChild(proxy.dom);
23395 * @class Roo.SplitBar.BasicLayoutAdapter
23396 * Default Adapter. It assumes the splitter and resizing element are not positioned
23397 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23399 Roo.SplitBar.BasicLayoutAdapter = function(){
23402 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23403 // do nothing for now
23404 init : function(s){
23408 * Called before drag operations to get the current size of the resizing element.
23409 * @param {Roo.SplitBar} s The SplitBar using this adapter
23411 getElementSize : function(s){
23412 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23413 return s.resizingEl.getWidth();
23415 return s.resizingEl.getHeight();
23420 * Called after drag operations to set the size of the resizing element.
23421 * @param {Roo.SplitBar} s The SplitBar using this adapter
23422 * @param {Number} newSize The new size to set
23423 * @param {Function} onComplete A function to be invoked when resizing is complete
23425 setElementSize : function(s, newSize, onComplete){
23426 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23428 s.resizingEl.setWidth(newSize);
23430 onComplete(s, newSize);
23433 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23438 s.resizingEl.setHeight(newSize);
23440 onComplete(s, newSize);
23443 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23450 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23451 * @extends Roo.SplitBar.BasicLayoutAdapter
23452 * Adapter that moves the splitter element to align with the resized sizing element.
23453 * Used with an absolute positioned SplitBar.
23454 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23455 * document.body, make sure you assign an id to the body element.
23457 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23458 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23459 this.container = Roo.get(container);
23462 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23463 init : function(s){
23464 this.basic.init(s);
23467 getElementSize : function(s){
23468 return this.basic.getElementSize(s);
23471 setElementSize : function(s, newSize, onComplete){
23472 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23475 moveSplitter : function(s){
23476 var yes = Roo.SplitBar;
23477 switch(s.placement){
23479 s.el.setX(s.resizingEl.getRight());
23482 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23485 s.el.setY(s.resizingEl.getBottom());
23488 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23495 * Orientation constant - Create a vertical SplitBar
23499 Roo.SplitBar.VERTICAL = 1;
23502 * Orientation constant - Create a horizontal SplitBar
23506 Roo.SplitBar.HORIZONTAL = 2;
23509 * Placement constant - The resizing element is to the left of the splitter element
23513 Roo.SplitBar.LEFT = 1;
23516 * Placement constant - The resizing element is to the right of the splitter element
23520 Roo.SplitBar.RIGHT = 2;
23523 * Placement constant - The resizing element is positioned above the splitter element
23527 Roo.SplitBar.TOP = 3;
23530 * Placement constant - The resizing element is positioned under splitter element
23534 Roo.SplitBar.BOTTOM = 4;
23537 * Ext JS Library 1.1.1
23538 * Copyright(c) 2006-2007, Ext JS, LLC.
23540 * Originally Released Under LGPL - original licence link has changed is not relivant.
23543 * <script type="text/javascript">
23548 * @extends Roo.util.Observable
23549 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23550 * This class also supports single and multi selection modes. <br>
23551 * Create a data model bound view:
23553 var store = new Roo.data.Store(...);
23555 var view = new Roo.View({
23557 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
23559 singleSelect: true,
23560 selectedClass: "ydataview-selected",
23564 // listen for node click?
23565 view.on("click", function(vw, index, node, e){
23566 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23570 dataModel.load("foobar.xml");
23572 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23574 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23575 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23577 * Note: old style constructor is still suported (container, template, config)
23580 * Create a new View
23581 * @param {Object} config The config object
23584 Roo.View = function(config, depreciated_tpl, depreciated_config){
23586 if (typeof(depreciated_tpl) == 'undefined') {
23587 // new way.. - universal constructor.
23588 Roo.apply(this, config);
23589 this.el = Roo.get(this.el);
23592 this.el = Roo.get(config);
23593 this.tpl = depreciated_tpl;
23594 Roo.apply(this, depreciated_config);
23598 if(typeof(this.tpl) == "string"){
23599 this.tpl = new Roo.Template(this.tpl);
23601 // support xtype ctors..
23602 this.tpl = new Roo.factory(this.tpl, Roo);
23606 this.tpl.compile();
23613 * @event beforeclick
23614 * Fires before a click is processed. Returns false to cancel the default action.
23615 * @param {Roo.View} this
23616 * @param {Number} index The index of the target node
23617 * @param {HTMLElement} node The target node
23618 * @param {Roo.EventObject} e The raw event object
23620 "beforeclick" : true,
23623 * Fires when a template node is clicked.
23624 * @param {Roo.View} this
23625 * @param {Number} index The index of the target node
23626 * @param {HTMLElement} node The target node
23627 * @param {Roo.EventObject} e The raw event object
23632 * Fires when a template node is double clicked.
23633 * @param {Roo.View} this
23634 * @param {Number} index The index of the target node
23635 * @param {HTMLElement} node The target node
23636 * @param {Roo.EventObject} e The raw event object
23640 * @event contextmenu
23641 * Fires when a template node is right clicked.
23642 * @param {Roo.View} this
23643 * @param {Number} index The index of the target node
23644 * @param {HTMLElement} node The target node
23645 * @param {Roo.EventObject} e The raw event object
23647 "contextmenu" : true,
23649 * @event selectionchange
23650 * Fires when the selected nodes change.
23651 * @param {Roo.View} this
23652 * @param {Array} selections Array of the selected nodes
23654 "selectionchange" : true,
23657 * @event beforeselect
23658 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23659 * @param {Roo.View} this
23660 * @param {HTMLElement} node The node to be selected
23661 * @param {Array} selections Array of currently selected nodes
23663 "beforeselect" : true,
23665 * @event preparedata
23666 * Fires on every row to render, to allow you to change the data.
23667 * @param {Roo.View} this
23668 * @param {Object} data to be rendered (change this)
23670 "preparedata" : true
23674 "click": this.onClick,
23675 "dblclick": this.onDblClick,
23676 "contextmenu": this.onContextMenu,
23680 this.selections = [];
23682 this.cmp = new Roo.CompositeElementLite([]);
23684 this.store = Roo.factory(this.store, Roo.data);
23685 this.setStore(this.store, true);
23687 Roo.View.superclass.constructor.call(this);
23690 Roo.extend(Roo.View, Roo.util.Observable, {
23693 * @cfg {Roo.data.Store} store Data store to load data from.
23698 * @cfg {String|Roo.Element} el The container element.
23703 * @cfg {String|Roo.Template} tpl The template used by this View
23708 * @cfg {String} selectedClass The css class to add to selected nodes
23710 selectedClass : "x-view-selected",
23712 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23716 * @cfg {Boolean} multiSelect Allow multiple selection
23718 multiSelect : false,
23720 * @cfg {Boolean} singleSelect Allow single selection
23722 singleSelect: false,
23725 * @cfg {Boolean} toggleSelect - selecting
23727 toggleSelect : false,
23730 * Returns the element this view is bound to.
23731 * @return {Roo.Element}
23733 getEl : function(){
23738 * Refreshes the view.
23740 refresh : function(){
23742 this.clearSelections();
23743 this.el.update("");
23745 var records = this.store.getRange();
23746 if(records.length < 1){
23747 this.el.update(this.emptyText);
23750 for(var i = 0, len = records.length; i < len; i++){
23751 var data = this.prepareData(records[i].data, i, records[i]);
23752 this.fireEvent("preparedata", this, data, i, records[i]);
23753 html[html.length] = t.apply(data);
23755 this.el.update(html.join(""));
23756 this.nodes = this.el.dom.childNodes;
23757 this.updateIndexes(0);
23761 * Function to override to reformat the data that is sent to
23762 * the template for each node.
23763 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23764 * a JSON object for an UpdateManager bound view).
23766 prepareData : function(data){
23770 onUpdate : function(ds, record){
23771 this.clearSelections();
23772 var index = this.store.indexOf(record);
23773 var n = this.nodes[index];
23774 this.tpl.insertBefore(n, this.prepareData(record.data));
23775 n.parentNode.removeChild(n);
23776 this.updateIndexes(index, index);
23779 onAdd : function(ds, records, index){
23780 this.clearSelections();
23781 if(this.nodes.length == 0){
23785 var n = this.nodes[index];
23786 for(var i = 0, len = records.length; i < len; i++){
23787 var d = this.prepareData(records[i].data);
23789 this.tpl.insertBefore(n, d);
23791 this.tpl.append(this.el, d);
23794 this.updateIndexes(index);
23797 onRemove : function(ds, record, index){
23798 this.clearSelections();
23799 this.el.dom.removeChild(this.nodes[index]);
23800 this.updateIndexes(index);
23804 * Refresh an individual node.
23805 * @param {Number} index
23807 refreshNode : function(index){
23808 this.onUpdate(this.store, this.store.getAt(index));
23811 updateIndexes : function(startIndex, endIndex){
23812 var ns = this.nodes;
23813 startIndex = startIndex || 0;
23814 endIndex = endIndex || ns.length - 1;
23815 for(var i = startIndex; i <= endIndex; i++){
23816 ns[i].nodeIndex = i;
23821 * Changes the data store this view uses and refresh the view.
23822 * @param {Store} store
23824 setStore : function(store, initial){
23825 if(!initial && this.store){
23826 this.store.un("datachanged", this.refresh);
23827 this.store.un("add", this.onAdd);
23828 this.store.un("remove", this.onRemove);
23829 this.store.un("update", this.onUpdate);
23830 this.store.un("clear", this.refresh);
23834 store.on("datachanged", this.refresh, this);
23835 store.on("add", this.onAdd, this);
23836 store.on("remove", this.onRemove, this);
23837 store.on("update", this.onUpdate, this);
23838 store.on("clear", this.refresh, this);
23847 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23848 * @param {HTMLElement} node
23849 * @return {HTMLElement} The template node
23851 findItemFromChild : function(node){
23852 var el = this.el.dom;
23853 if(!node || node.parentNode == el){
23856 var p = node.parentNode;
23857 while(p && p != el){
23858 if(p.parentNode == el){
23867 onClick : function(e){
23868 var item = this.findItemFromChild(e.getTarget());
23870 var index = this.indexOf(item);
23871 if(this.onItemClick(item, index, e) !== false){
23872 this.fireEvent("click", this, index, item, e);
23875 this.clearSelections();
23880 onContextMenu : function(e){
23881 var item = this.findItemFromChild(e.getTarget());
23883 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23888 onDblClick : function(e){
23889 var item = this.findItemFromChild(e.getTarget());
23891 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23895 onItemClick : function(item, index, e)
23897 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23900 if (this.toggleSelect) {
23901 var m = this.isSelected(item) ? 'unselect' : 'select';
23904 _t[m](item, true, false);
23907 if(this.multiSelect || this.singleSelect){
23908 if(this.multiSelect && e.shiftKey && this.lastSelection){
23909 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23911 this.select(item, this.multiSelect && e.ctrlKey);
23912 this.lastSelection = item;
23914 e.preventDefault();
23920 * Get the number of selected nodes.
23923 getSelectionCount : function(){
23924 return this.selections.length;
23928 * Get the currently selected nodes.
23929 * @return {Array} An array of HTMLElements
23931 getSelectedNodes : function(){
23932 return this.selections;
23936 * Get the indexes of the selected nodes.
23939 getSelectedIndexes : function(){
23940 var indexes = [], s = this.selections;
23941 for(var i = 0, len = s.length; i < len; i++){
23942 indexes.push(s[i].nodeIndex);
23948 * Clear all selections
23949 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23951 clearSelections : function(suppressEvent){
23952 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23953 this.cmp.elements = this.selections;
23954 this.cmp.removeClass(this.selectedClass);
23955 this.selections = [];
23956 if(!suppressEvent){
23957 this.fireEvent("selectionchange", this, this.selections);
23963 * Returns true if the passed node is selected
23964 * @param {HTMLElement/Number} node The node or node index
23965 * @return {Boolean}
23967 isSelected : function(node){
23968 var s = this.selections;
23972 node = this.getNode(node);
23973 return s.indexOf(node) !== -1;
23978 * @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
23979 * @param {Boolean} keepExisting (optional) true to keep existing selections
23980 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23982 select : function(nodeInfo, keepExisting, suppressEvent){
23983 if(nodeInfo instanceof Array){
23985 this.clearSelections(true);
23987 for(var i = 0, len = nodeInfo.length; i < len; i++){
23988 this.select(nodeInfo[i], true, true);
23992 var node = this.getNode(nodeInfo);
23993 if(!node || this.isSelected(node)){
23994 return; // already selected.
23997 this.clearSelections(true);
23999 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
24000 Roo.fly(node).addClass(this.selectedClass);
24001 this.selections.push(node);
24002 if(!suppressEvent){
24003 this.fireEvent("selectionchange", this, this.selections);
24011 * @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
24012 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
24013 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24015 unselect : function(nodeInfo, keepExisting, suppressEvent)
24017 if(nodeInfo instanceof Array){
24018 Roo.each(this.selections, function(s) {
24019 this.unselect(s, nodeInfo);
24023 var node = this.getNode(nodeInfo);
24024 if(!node || !this.isSelected(node)){
24025 Roo.log("not selected");
24026 return; // not selected.
24030 Roo.each(this.selections, function(s) {
24032 Roo.fly(node).removeClass(this.selectedClass);
24039 this.selections= ns;
24040 this.fireEvent("selectionchange", this, this.selections);
24044 * Gets a template node.
24045 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24046 * @return {HTMLElement} The node or null if it wasn't found
24048 getNode : function(nodeInfo){
24049 if(typeof nodeInfo == "string"){
24050 return document.getElementById(nodeInfo);
24051 }else if(typeof nodeInfo == "number"){
24052 return this.nodes[nodeInfo];
24058 * Gets a range template nodes.
24059 * @param {Number} startIndex
24060 * @param {Number} endIndex
24061 * @return {Array} An array of nodes
24063 getNodes : function(start, end){
24064 var ns = this.nodes;
24065 start = start || 0;
24066 end = typeof end == "undefined" ? ns.length - 1 : end;
24069 for(var i = start; i <= end; i++){
24073 for(var i = start; i >= end; i--){
24081 * Finds the index of the passed node
24082 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24083 * @return {Number} The index of the node or -1
24085 indexOf : function(node){
24086 node = this.getNode(node);
24087 if(typeof node.nodeIndex == "number"){
24088 return node.nodeIndex;
24090 var ns = this.nodes;
24091 for(var i = 0, len = ns.length; i < len; i++){
24101 * Ext JS Library 1.1.1
24102 * Copyright(c) 2006-2007, Ext JS, LLC.
24104 * Originally Released Under LGPL - original licence link has changed is not relivant.
24107 * <script type="text/javascript">
24111 * @class Roo.JsonView
24112 * @extends Roo.View
24113 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24115 var view = new Roo.JsonView({
24116 container: "my-element",
24117 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24122 // listen for node click?
24123 view.on("click", function(vw, index, node, e){
24124 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24127 // direct load of JSON data
24128 view.load("foobar.php");
24130 // Example from my blog list
24131 var tpl = new Roo.Template(
24132 '<div class="entry">' +
24133 '<a class="entry-title" href="{link}">{title}</a>' +
24134 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24135 "</div><hr />"
24138 var moreView = new Roo.JsonView({
24139 container : "entry-list",
24143 moreView.on("beforerender", this.sortEntries, this);
24145 url: "/blog/get-posts.php",
24146 params: "allposts=true",
24147 text: "Loading Blog Entries..."
24151 * Note: old code is supported with arguments : (container, template, config)
24155 * Create a new JsonView
24157 * @param {Object} config The config object
24160 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24163 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24165 var um = this.el.getUpdateManager();
24166 um.setRenderer(this);
24167 um.on("update", this.onLoad, this);
24168 um.on("failure", this.onLoadException, this);
24171 * @event beforerender
24172 * Fires before rendering of the downloaded JSON data.
24173 * @param {Roo.JsonView} this
24174 * @param {Object} data The JSON data loaded
24178 * Fires when data is loaded.
24179 * @param {Roo.JsonView} this
24180 * @param {Object} data The JSON data loaded
24181 * @param {Object} response The raw Connect response object
24184 * @event loadexception
24185 * Fires when loading fails.
24186 * @param {Roo.JsonView} this
24187 * @param {Object} response The raw Connect response object
24190 'beforerender' : true,
24192 'loadexception' : true
24195 Roo.extend(Roo.JsonView, Roo.View, {
24197 * @type {String} The root property in the loaded JSON object that contains the data
24202 * Refreshes the view.
24204 refresh : function(){
24205 this.clearSelections();
24206 this.el.update("");
24208 var o = this.jsonData;
24209 if(o && o.length > 0){
24210 for(var i = 0, len = o.length; i < len; i++){
24211 var data = this.prepareData(o[i], i, o);
24212 html[html.length] = this.tpl.apply(data);
24215 html.push(this.emptyText);
24217 this.el.update(html.join(""));
24218 this.nodes = this.el.dom.childNodes;
24219 this.updateIndexes(0);
24223 * 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.
24224 * @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:
24227 url: "your-url.php",
24228 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24229 callback: yourFunction,
24230 scope: yourObject, //(optional scope)
24233 text: "Loading...",
24238 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24239 * 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.
24240 * @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}
24241 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24242 * @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.
24245 var um = this.el.getUpdateManager();
24246 um.update.apply(um, arguments);
24249 render : function(el, response){
24250 this.clearSelections();
24251 this.el.update("");
24254 o = Roo.util.JSON.decode(response.responseText);
24257 o = o[this.jsonRoot];
24262 * The current JSON data or null
24265 this.beforeRender();
24270 * Get the number of records in the current JSON dataset
24273 getCount : function(){
24274 return this.jsonData ? this.jsonData.length : 0;
24278 * Returns the JSON object for the specified node(s)
24279 * @param {HTMLElement/Array} node The node or an array of nodes
24280 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24281 * you get the JSON object for the node
24283 getNodeData : function(node){
24284 if(node instanceof Array){
24286 for(var i = 0, len = node.length; i < len; i++){
24287 data.push(this.getNodeData(node[i]));
24291 return this.jsonData[this.indexOf(node)] || null;
24294 beforeRender : function(){
24295 this.snapshot = this.jsonData;
24297 this.sort.apply(this, this.sortInfo);
24299 this.fireEvent("beforerender", this, this.jsonData);
24302 onLoad : function(el, o){
24303 this.fireEvent("load", this, this.jsonData, o);
24306 onLoadException : function(el, o){
24307 this.fireEvent("loadexception", this, o);
24311 * Filter the data by a specific property.
24312 * @param {String} property A property on your JSON objects
24313 * @param {String/RegExp} value Either string that the property values
24314 * should start with, or a RegExp to test against the property
24316 filter : function(property, value){
24319 var ss = this.snapshot;
24320 if(typeof value == "string"){
24321 var vlen = value.length;
24323 this.clearFilter();
24326 value = value.toLowerCase();
24327 for(var i = 0, len = ss.length; i < len; i++){
24329 if(o[property].substr(0, vlen).toLowerCase() == value){
24333 } else if(value.exec){ // regex?
24334 for(var i = 0, len = ss.length; i < len; i++){
24336 if(value.test(o[property])){
24343 this.jsonData = data;
24349 * Filter by a function. The passed function will be called with each
24350 * object in the current dataset. If the function returns true the value is kept,
24351 * otherwise it is filtered.
24352 * @param {Function} fn
24353 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24355 filterBy : function(fn, scope){
24358 var ss = this.snapshot;
24359 for(var i = 0, len = ss.length; i < len; i++){
24361 if(fn.call(scope || this, o)){
24365 this.jsonData = data;
24371 * Clears the current filter.
24373 clearFilter : function(){
24374 if(this.snapshot && this.jsonData != this.snapshot){
24375 this.jsonData = this.snapshot;
24382 * Sorts the data for this view and refreshes it.
24383 * @param {String} property A property on your JSON objects to sort on
24384 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24385 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24387 sort : function(property, dir, sortType){
24388 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24391 var dsc = dir && dir.toLowerCase() == "desc";
24392 var f = function(o1, o2){
24393 var v1 = sortType ? sortType(o1[p]) : o1[p];
24394 var v2 = sortType ? sortType(o2[p]) : o2[p];
24397 return dsc ? +1 : -1;
24398 } else if(v1 > v2){
24399 return dsc ? -1 : +1;
24404 this.jsonData.sort(f);
24406 if(this.jsonData != this.snapshot){
24407 this.snapshot.sort(f);
24413 * Ext JS Library 1.1.1
24414 * Copyright(c) 2006-2007, Ext JS, LLC.
24416 * Originally Released Under LGPL - original licence link has changed is not relivant.
24419 * <script type="text/javascript">
24424 * @class Roo.ColorPalette
24425 * @extends Roo.Component
24426 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24427 * Here's an example of typical usage:
24429 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24430 cp.render('my-div');
24432 cp.on('select', function(palette, selColor){
24433 // do something with selColor
24437 * Create a new ColorPalette
24438 * @param {Object} config The config object
24440 Roo.ColorPalette = function(config){
24441 Roo.ColorPalette.superclass.constructor.call(this, config);
24445 * Fires when a color is selected
24446 * @param {ColorPalette} this
24447 * @param {String} color The 6-digit color hex code (without the # symbol)
24453 this.on("select", this.handler, this.scope, true);
24456 Roo.extend(Roo.ColorPalette, Roo.Component, {
24458 * @cfg {String} itemCls
24459 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24461 itemCls : "x-color-palette",
24463 * @cfg {String} value
24464 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24465 * the hex codes are case-sensitive.
24468 clickEvent:'click',
24470 ctype: "Roo.ColorPalette",
24473 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24475 allowReselect : false,
24478 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24479 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24480 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24481 * of colors with the width setting until the box is symmetrical.</p>
24482 * <p>You can override individual colors if needed:</p>
24484 var cp = new Roo.ColorPalette();
24485 cp.colors[0] = "FF0000"; // change the first box to red
24488 Or you can provide a custom array of your own for complete control:
24490 var cp = new Roo.ColorPalette();
24491 cp.colors = ["000000", "993300", "333300"];
24496 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24497 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24498 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24499 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24500 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24504 onRender : function(container, position){
24505 var t = new Roo.MasterTemplate(
24506 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24508 var c = this.colors;
24509 for(var i = 0, len = c.length; i < len; i++){
24512 var el = document.createElement("div");
24513 el.className = this.itemCls;
24515 container.dom.insertBefore(el, position);
24516 this.el = Roo.get(el);
24517 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24518 if(this.clickEvent != 'click'){
24519 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24524 afterRender : function(){
24525 Roo.ColorPalette.superclass.afterRender.call(this);
24527 var s = this.value;
24534 handleClick : function(e, t){
24535 e.preventDefault();
24536 if(!this.disabled){
24537 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24538 this.select(c.toUpperCase());
24543 * Selects the specified color in the palette (fires the select event)
24544 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24546 select : function(color){
24547 color = color.replace("#", "");
24548 if(color != this.value || this.allowReselect){
24551 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24553 el.child("a.color-"+color).addClass("x-color-palette-sel");
24554 this.value = color;
24555 this.fireEvent("select", this, color);
24560 * Ext JS Library 1.1.1
24561 * Copyright(c) 2006-2007, Ext JS, LLC.
24563 * Originally Released Under LGPL - original licence link has changed is not relivant.
24566 * <script type="text/javascript">
24570 * @class Roo.DatePicker
24571 * @extends Roo.Component
24572 * Simple date picker class.
24574 * Create a new DatePicker
24575 * @param {Object} config The config object
24577 Roo.DatePicker = function(config){
24578 Roo.DatePicker.superclass.constructor.call(this, config);
24580 this.value = config && config.value ?
24581 config.value.clearTime() : new Date().clearTime();
24586 * Fires when a date is selected
24587 * @param {DatePicker} this
24588 * @param {Date} date The selected date
24592 * @event monthchange
24593 * Fires when the displayed month changes
24594 * @param {DatePicker} this
24595 * @param {Date} date The selected month
24597 'monthchange': true
24601 this.on("select", this.handler, this.scope || this);
24603 // build the disabledDatesRE
24604 if(!this.disabledDatesRE && this.disabledDates){
24605 var dd = this.disabledDates;
24607 for(var i = 0; i < dd.length; i++){
24609 if(i != dd.length-1) re += "|";
24611 this.disabledDatesRE = new RegExp(re + ")");
24615 Roo.extend(Roo.DatePicker, Roo.Component, {
24617 * @cfg {String} todayText
24618 * The text to display on the button that selects the current date (defaults to "Today")
24620 todayText : "Today",
24622 * @cfg {String} okText
24623 * The text to display on the ok button
24625 okText : " OK ", //   to give the user extra clicking room
24627 * @cfg {String} cancelText
24628 * The text to display on the cancel button
24630 cancelText : "Cancel",
24632 * @cfg {String} todayTip
24633 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24635 todayTip : "{0} (Spacebar)",
24637 * @cfg {Date} minDate
24638 * Minimum allowable date (JavaScript date object, defaults to null)
24642 * @cfg {Date} maxDate
24643 * Maximum allowable date (JavaScript date object, defaults to null)
24647 * @cfg {String} minText
24648 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24650 minText : "This date is before the minimum date",
24652 * @cfg {String} maxText
24653 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24655 maxText : "This date is after the maximum date",
24657 * @cfg {String} format
24658 * The default date format string which can be overriden for localization support. The format must be
24659 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24663 * @cfg {Array} disabledDays
24664 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24666 disabledDays : null,
24668 * @cfg {String} disabledDaysText
24669 * The tooltip to display when the date falls on a disabled day (defaults to "")
24671 disabledDaysText : "",
24673 * @cfg {RegExp} disabledDatesRE
24674 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24676 disabledDatesRE : null,
24678 * @cfg {String} disabledDatesText
24679 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24681 disabledDatesText : "",
24683 * @cfg {Boolean} constrainToViewport
24684 * True to constrain the date picker to the viewport (defaults to true)
24686 constrainToViewport : true,
24688 * @cfg {Array} monthNames
24689 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24691 monthNames : Date.monthNames,
24693 * @cfg {Array} dayNames
24694 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24696 dayNames : Date.dayNames,
24698 * @cfg {String} nextText
24699 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24701 nextText: 'Next Month (Control+Right)',
24703 * @cfg {String} prevText
24704 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24706 prevText: 'Previous Month (Control+Left)',
24708 * @cfg {String} monthYearText
24709 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24711 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24713 * @cfg {Number} startDay
24714 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24718 * @cfg {Bool} showClear
24719 * Show a clear button (usefull for date form elements that can be blank.)
24725 * Sets the value of the date field
24726 * @param {Date} value The date to set
24728 setValue : function(value){
24729 var old = this.value;
24730 this.value = value.clearTime(true);
24732 this.update(this.value);
24737 * Gets the current selected value of the date field
24738 * @return {Date} The selected date
24740 getValue : function(){
24745 focus : function(){
24747 this.update(this.activeDate);
24752 onRender : function(container, position){
24754 '<table cellspacing="0">',
24755 '<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>',
24756 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24757 var dn = this.dayNames;
24758 for(var i = 0; i < 7; i++){
24759 var d = this.startDay+i;
24763 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24765 m[m.length] = "</tr></thead><tbody><tr>";
24766 for(var i = 0; i < 42; i++) {
24767 if(i % 7 == 0 && i != 0){
24768 m[m.length] = "</tr><tr>";
24770 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24772 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24773 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24775 var el = document.createElement("div");
24776 el.className = "x-date-picker";
24777 el.innerHTML = m.join("");
24779 container.dom.insertBefore(el, position);
24781 this.el = Roo.get(el);
24782 this.eventEl = Roo.get(el.firstChild);
24784 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24785 handler: this.showPrevMonth,
24787 preventDefault:true,
24791 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24792 handler: this.showNextMonth,
24794 preventDefault:true,
24798 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24800 this.monthPicker = this.el.down('div.x-date-mp');
24801 this.monthPicker.enableDisplayMode('block');
24803 var kn = new Roo.KeyNav(this.eventEl, {
24804 "left" : function(e){
24806 this.showPrevMonth() :
24807 this.update(this.activeDate.add("d", -1));
24810 "right" : function(e){
24812 this.showNextMonth() :
24813 this.update(this.activeDate.add("d", 1));
24816 "up" : function(e){
24818 this.showNextYear() :
24819 this.update(this.activeDate.add("d", -7));
24822 "down" : function(e){
24824 this.showPrevYear() :
24825 this.update(this.activeDate.add("d", 7));
24828 "pageUp" : function(e){
24829 this.showNextMonth();
24832 "pageDown" : function(e){
24833 this.showPrevMonth();
24836 "enter" : function(e){
24837 e.stopPropagation();
24844 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24846 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24848 this.el.unselectable();
24850 this.cells = this.el.select("table.x-date-inner tbody td");
24851 this.textNodes = this.el.query("table.x-date-inner tbody span");
24853 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24855 tooltip: this.monthYearText
24858 this.mbtn.on('click', this.showMonthPicker, this);
24859 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24862 var today = (new Date()).dateFormat(this.format);
24864 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24865 if (this.showClear) {
24866 baseTb.add( new Roo.Toolbar.Fill());
24869 text: String.format(this.todayText, today),
24870 tooltip: String.format(this.todayTip, today),
24871 handler: this.selectToday,
24875 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24878 if (this.showClear) {
24880 baseTb.add( new Roo.Toolbar.Fill());
24883 cls: 'x-btn-icon x-btn-clear',
24884 handler: function() {
24886 this.fireEvent("select", this, '');
24896 this.update(this.value);
24899 createMonthPicker : function(){
24900 if(!this.monthPicker.dom.firstChild){
24901 var buf = ['<table border="0" cellspacing="0">'];
24902 for(var i = 0; i < 6; i++){
24904 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24905 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24907 '<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>' :
24908 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24912 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24914 '</button><button type="button" class="x-date-mp-cancel">',
24916 '</button></td></tr>',
24919 this.monthPicker.update(buf.join(''));
24920 this.monthPicker.on('click', this.onMonthClick, this);
24921 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24923 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24924 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24926 this.mpMonths.each(function(m, a, i){
24929 m.dom.xmonth = 5 + Math.round(i * .5);
24931 m.dom.xmonth = Math.round((i-1) * .5);
24937 showMonthPicker : function(){
24938 this.createMonthPicker();
24939 var size = this.el.getSize();
24940 this.monthPicker.setSize(size);
24941 this.monthPicker.child('table').setSize(size);
24943 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24944 this.updateMPMonth(this.mpSelMonth);
24945 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24946 this.updateMPYear(this.mpSelYear);
24948 this.monthPicker.slideIn('t', {duration:.2});
24951 updateMPYear : function(y){
24953 var ys = this.mpYears.elements;
24954 for(var i = 1; i <= 10; i++){
24955 var td = ys[i-1], y2;
24957 y2 = y + Math.round(i * .5);
24958 td.firstChild.innerHTML = y2;
24961 y2 = y - (5-Math.round(i * .5));
24962 td.firstChild.innerHTML = y2;
24965 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24969 updateMPMonth : function(sm){
24970 this.mpMonths.each(function(m, a, i){
24971 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24975 selectMPMonth: function(m){
24979 onMonthClick : function(e, t){
24981 var el = new Roo.Element(t), pn;
24982 if(el.is('button.x-date-mp-cancel')){
24983 this.hideMonthPicker();
24985 else if(el.is('button.x-date-mp-ok')){
24986 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24987 this.hideMonthPicker();
24989 else if(pn = el.up('td.x-date-mp-month', 2)){
24990 this.mpMonths.removeClass('x-date-mp-sel');
24991 pn.addClass('x-date-mp-sel');
24992 this.mpSelMonth = pn.dom.xmonth;
24994 else if(pn = el.up('td.x-date-mp-year', 2)){
24995 this.mpYears.removeClass('x-date-mp-sel');
24996 pn.addClass('x-date-mp-sel');
24997 this.mpSelYear = pn.dom.xyear;
24999 else if(el.is('a.x-date-mp-prev')){
25000 this.updateMPYear(this.mpyear-10);
25002 else if(el.is('a.x-date-mp-next')){
25003 this.updateMPYear(this.mpyear+10);
25007 onMonthDblClick : function(e, t){
25009 var el = new Roo.Element(t), pn;
25010 if(pn = el.up('td.x-date-mp-month', 2)){
25011 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
25012 this.hideMonthPicker();
25014 else if(pn = el.up('td.x-date-mp-year', 2)){
25015 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25016 this.hideMonthPicker();
25020 hideMonthPicker : function(disableAnim){
25021 if(this.monthPicker){
25022 if(disableAnim === true){
25023 this.monthPicker.hide();
25025 this.monthPicker.slideOut('t', {duration:.2});
25031 showPrevMonth : function(e){
25032 this.update(this.activeDate.add("mo", -1));
25036 showNextMonth : function(e){
25037 this.update(this.activeDate.add("mo", 1));
25041 showPrevYear : function(){
25042 this.update(this.activeDate.add("y", -1));
25046 showNextYear : function(){
25047 this.update(this.activeDate.add("y", 1));
25051 handleMouseWheel : function(e){
25052 var delta = e.getWheelDelta();
25054 this.showPrevMonth();
25056 } else if(delta < 0){
25057 this.showNextMonth();
25063 handleDateClick : function(e, t){
25065 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25066 this.setValue(new Date(t.dateValue));
25067 this.fireEvent("select", this, this.value);
25072 selectToday : function(){
25073 this.setValue(new Date().clearTime());
25074 this.fireEvent("select", this, this.value);
25078 update : function(date)
25080 var vd = this.activeDate;
25081 this.activeDate = date;
25083 var t = date.getTime();
25084 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25085 this.cells.removeClass("x-date-selected");
25086 this.cells.each(function(c){
25087 if(c.dom.firstChild.dateValue == t){
25088 c.addClass("x-date-selected");
25089 setTimeout(function(){
25090 try{c.dom.firstChild.focus();}catch(e){}
25099 var days = date.getDaysInMonth();
25100 var firstOfMonth = date.getFirstDateOfMonth();
25101 var startingPos = firstOfMonth.getDay()-this.startDay;
25103 if(startingPos <= this.startDay){
25107 var pm = date.add("mo", -1);
25108 var prevStart = pm.getDaysInMonth()-startingPos;
25110 var cells = this.cells.elements;
25111 var textEls = this.textNodes;
25112 days += startingPos;
25114 // convert everything to numbers so it's fast
25115 var day = 86400000;
25116 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25117 var today = new Date().clearTime().getTime();
25118 var sel = date.clearTime().getTime();
25119 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25120 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25121 var ddMatch = this.disabledDatesRE;
25122 var ddText = this.disabledDatesText;
25123 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25124 var ddaysText = this.disabledDaysText;
25125 var format = this.format;
25127 var setCellClass = function(cal, cell){
25129 var t = d.getTime();
25130 cell.firstChild.dateValue = t;
25132 cell.className += " x-date-today";
25133 cell.title = cal.todayText;
25136 cell.className += " x-date-selected";
25137 setTimeout(function(){
25138 try{cell.firstChild.focus();}catch(e){}
25143 cell.className = " x-date-disabled";
25144 cell.title = cal.minText;
25148 cell.className = " x-date-disabled";
25149 cell.title = cal.maxText;
25153 if(ddays.indexOf(d.getDay()) != -1){
25154 cell.title = ddaysText;
25155 cell.className = " x-date-disabled";
25158 if(ddMatch && format){
25159 var fvalue = d.dateFormat(format);
25160 if(ddMatch.test(fvalue)){
25161 cell.title = ddText.replace("%0", fvalue);
25162 cell.className = " x-date-disabled";
25168 for(; i < startingPos; i++) {
25169 textEls[i].innerHTML = (++prevStart);
25170 d.setDate(d.getDate()+1);
25171 cells[i].className = "x-date-prevday";
25172 setCellClass(this, cells[i]);
25174 for(; i < days; i++){
25175 intDay = i - startingPos + 1;
25176 textEls[i].innerHTML = (intDay);
25177 d.setDate(d.getDate()+1);
25178 cells[i].className = "x-date-active";
25179 setCellClass(this, cells[i]);
25182 for(; i < 42; i++) {
25183 textEls[i].innerHTML = (++extraDays);
25184 d.setDate(d.getDate()+1);
25185 cells[i].className = "x-date-nextday";
25186 setCellClass(this, cells[i]);
25189 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25190 this.fireEvent('monthchange', this, date);
25192 if(!this.internalRender){
25193 var main = this.el.dom.firstChild;
25194 var w = main.offsetWidth;
25195 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25196 Roo.fly(main).setWidth(w);
25197 this.internalRender = true;
25198 // opera does not respect the auto grow header center column
25199 // then, after it gets a width opera refuses to recalculate
25200 // without a second pass
25201 if(Roo.isOpera && !this.secondPass){
25202 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25203 this.secondPass = true;
25204 this.update.defer(10, this, [date]);
25212 * Ext JS Library 1.1.1
25213 * Copyright(c) 2006-2007, Ext JS, LLC.
25215 * Originally Released Under LGPL - original licence link has changed is not relivant.
25218 * <script type="text/javascript">
25221 * @class Roo.TabPanel
25222 * @extends Roo.util.Observable
25223 * A lightweight tab container.
25227 // basic tabs 1, built from existing content
25228 var tabs = new Roo.TabPanel("tabs1");
25229 tabs.addTab("script", "View Script");
25230 tabs.addTab("markup", "View Markup");
25231 tabs.activate("script");
25233 // more advanced tabs, built from javascript
25234 var jtabs = new Roo.TabPanel("jtabs");
25235 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25237 // set up the UpdateManager
25238 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25239 var updater = tab2.getUpdateManager();
25240 updater.setDefaultUrl("ajax1.htm");
25241 tab2.on('activate', updater.refresh, updater, true);
25243 // Use setUrl for Ajax loading
25244 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25245 tab3.setUrl("ajax2.htm", null, true);
25248 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25251 jtabs.activate("jtabs-1");
25254 * Create a new TabPanel.
25255 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25256 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25258 Roo.TabPanel = function(container, config){
25260 * The container element for this TabPanel.
25261 * @type Roo.Element
25263 this.el = Roo.get(container, true);
25265 if(typeof config == "boolean"){
25266 this.tabPosition = config ? "bottom" : "top";
25268 Roo.apply(this, config);
25271 if(this.tabPosition == "bottom"){
25272 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25273 this.el.addClass("x-tabs-bottom");
25275 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25276 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25277 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25279 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25281 if(this.tabPosition != "bottom"){
25282 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
25283 * @type Roo.Element
25285 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25286 this.el.addClass("x-tabs-top");
25290 this.bodyEl.setStyle("position", "relative");
25292 this.active = null;
25293 this.activateDelegate = this.activate.createDelegate(this);
25298 * Fires when the active tab changes
25299 * @param {Roo.TabPanel} this
25300 * @param {Roo.TabPanelItem} activePanel The new active tab
25304 * @event beforetabchange
25305 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25306 * @param {Roo.TabPanel} this
25307 * @param {Object} e Set cancel to true on this object to cancel the tab change
25308 * @param {Roo.TabPanelItem} tab The tab being changed to
25310 "beforetabchange" : true
25313 Roo.EventManager.onWindowResize(this.onResize, this);
25314 this.cpad = this.el.getPadding("lr");
25315 this.hiddenCount = 0;
25318 // toolbar on the tabbar support...
25319 if (this.toolbar) {
25320 var tcfg = this.toolbar;
25321 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
25322 this.toolbar = new Roo.Toolbar(tcfg);
25323 if (Roo.isSafari) {
25324 var tbl = tcfg.container.child('table', true);
25325 tbl.setAttribute('width', '100%');
25332 Roo.TabPanel.superclass.constructor.call(this);
25335 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25337 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25339 tabPosition : "top",
25341 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25343 currentTabWidth : 0,
25345 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25349 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25353 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25355 preferredTabWidth : 175,
25357 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25359 resizeTabs : false,
25361 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25363 monitorResize : true,
25365 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
25370 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25371 * @param {String} id The id of the div to use <b>or create</b>
25372 * @param {String} text The text for the tab
25373 * @param {String} content (optional) Content to put in the TabPanelItem body
25374 * @param {Boolean} closable (optional) True to create a close icon on the tab
25375 * @return {Roo.TabPanelItem} The created TabPanelItem
25377 addTab : function(id, text, content, closable){
25378 var item = new Roo.TabPanelItem(this, id, text, closable);
25379 this.addTabItem(item);
25381 item.setContent(content);
25387 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25388 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25389 * @return {Roo.TabPanelItem}
25391 getTab : function(id){
25392 return this.items[id];
25396 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25397 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25399 hideTab : function(id){
25400 var t = this.items[id];
25403 this.hiddenCount++;
25404 this.autoSizeTabs();
25409 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25410 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25412 unhideTab : function(id){
25413 var t = this.items[id];
25415 t.setHidden(false);
25416 this.hiddenCount--;
25417 this.autoSizeTabs();
25422 * Adds an existing {@link Roo.TabPanelItem}.
25423 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25425 addTabItem : function(item){
25426 this.items[item.id] = item;
25427 this.items.push(item);
25428 if(this.resizeTabs){
25429 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25430 this.autoSizeTabs();
25437 * Removes a {@link Roo.TabPanelItem}.
25438 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25440 removeTab : function(id){
25441 var items = this.items;
25442 var tab = items[id];
25443 if(!tab) { return; }
25444 var index = items.indexOf(tab);
25445 if(this.active == tab && items.length > 1){
25446 var newTab = this.getNextAvailable(index);
25451 this.stripEl.dom.removeChild(tab.pnode.dom);
25452 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25453 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25455 items.splice(index, 1);
25456 delete this.items[tab.id];
25457 tab.fireEvent("close", tab);
25458 tab.purgeListeners();
25459 this.autoSizeTabs();
25462 getNextAvailable : function(start){
25463 var items = this.items;
25465 // look for a next tab that will slide over to
25466 // replace the one being removed
25467 while(index < items.length){
25468 var item = items[++index];
25469 if(item && !item.isHidden()){
25473 // if one isn't found select the previous tab (on the left)
25476 var item = items[--index];
25477 if(item && !item.isHidden()){
25485 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25486 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25488 disableTab : function(id){
25489 var tab = this.items[id];
25490 if(tab && this.active != tab){
25496 * Enables a {@link Roo.TabPanelItem} that is disabled.
25497 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25499 enableTab : function(id){
25500 var tab = this.items[id];
25505 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25506 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25507 * @return {Roo.TabPanelItem} The TabPanelItem.
25509 activate : function(id){
25510 var tab = this.items[id];
25514 if(tab == this.active || tab.disabled){
25518 this.fireEvent("beforetabchange", this, e, tab);
25519 if(e.cancel !== true && !tab.disabled){
25521 this.active.hide();
25523 this.active = this.items[id];
25524 this.active.show();
25525 this.fireEvent("tabchange", this, this.active);
25531 * Gets the active {@link Roo.TabPanelItem}.
25532 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25534 getActiveTab : function(){
25535 return this.active;
25539 * Updates the tab body element to fit the height of the container element
25540 * for overflow scrolling
25541 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25543 syncHeight : function(targetHeight){
25544 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25545 var bm = this.bodyEl.getMargins();
25546 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25547 this.bodyEl.setHeight(newHeight);
25551 onResize : function(){
25552 if(this.monitorResize){
25553 this.autoSizeTabs();
25558 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25560 beginUpdate : function(){
25561 this.updating = true;
25565 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25567 endUpdate : function(){
25568 this.updating = false;
25569 this.autoSizeTabs();
25573 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25575 autoSizeTabs : function(){
25576 var count = this.items.length;
25577 var vcount = count - this.hiddenCount;
25578 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25579 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25580 var availWidth = Math.floor(w / vcount);
25581 var b = this.stripBody;
25582 if(b.getWidth() > w){
25583 var tabs = this.items;
25584 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25585 if(availWidth < this.minTabWidth){
25586 /*if(!this.sleft){ // incomplete scrolling code
25587 this.createScrollButtons();
25590 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25593 if(this.currentTabWidth < this.preferredTabWidth){
25594 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25600 * Returns the number of tabs in this TabPanel.
25603 getCount : function(){
25604 return this.items.length;
25608 * Resizes all the tabs to the passed width
25609 * @param {Number} The new width
25611 setTabWidth : function(width){
25612 this.currentTabWidth = width;
25613 for(var i = 0, len = this.items.length; i < len; i++) {
25614 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25619 * Destroys this TabPanel
25620 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25622 destroy : function(removeEl){
25623 Roo.EventManager.removeResizeListener(this.onResize, this);
25624 for(var i = 0, len = this.items.length; i < len; i++){
25625 this.items[i].purgeListeners();
25627 if(removeEl === true){
25628 this.el.update("");
25635 * @class Roo.TabPanelItem
25636 * @extends Roo.util.Observable
25637 * Represents an individual item (tab plus body) in a TabPanel.
25638 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25639 * @param {String} id The id of this TabPanelItem
25640 * @param {String} text The text for the tab of this TabPanelItem
25641 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25643 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25645 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25646 * @type Roo.TabPanel
25648 this.tabPanel = tabPanel;
25650 * The id for this TabPanelItem
25655 this.disabled = false;
25659 this.loaded = false;
25660 this.closable = closable;
25663 * The body element for this TabPanelItem.
25664 * @type Roo.Element
25666 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25667 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25668 this.bodyEl.setStyle("display", "block");
25669 this.bodyEl.setStyle("zoom", "1");
25672 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25674 this.el = Roo.get(els.el, true);
25675 this.inner = Roo.get(els.inner, true);
25676 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25677 this.pnode = Roo.get(els.el.parentNode, true);
25678 this.el.on("mousedown", this.onTabMouseDown, this);
25679 this.el.on("click", this.onTabClick, this);
25682 var c = Roo.get(els.close, true);
25683 c.dom.title = this.closeText;
25684 c.addClassOnOver("close-over");
25685 c.on("click", this.closeClick, this);
25691 * Fires when this tab becomes the active tab.
25692 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25693 * @param {Roo.TabPanelItem} this
25697 * @event beforeclose
25698 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25699 * @param {Roo.TabPanelItem} this
25700 * @param {Object} e Set cancel to true on this object to cancel the close.
25702 "beforeclose": true,
25705 * Fires when this tab is closed.
25706 * @param {Roo.TabPanelItem} this
25710 * @event deactivate
25711 * Fires when this tab is no longer the active tab.
25712 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25713 * @param {Roo.TabPanelItem} this
25715 "deactivate" : true
25717 this.hidden = false;
25719 Roo.TabPanelItem.superclass.constructor.call(this);
25722 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25723 purgeListeners : function(){
25724 Roo.util.Observable.prototype.purgeListeners.call(this);
25725 this.el.removeAllListeners();
25728 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25731 this.pnode.addClass("on");
25734 this.tabPanel.stripWrap.repaint();
25736 this.fireEvent("activate", this.tabPanel, this);
25740 * Returns true if this tab is the active tab.
25741 * @return {Boolean}
25743 isActive : function(){
25744 return this.tabPanel.getActiveTab() == this;
25748 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25751 this.pnode.removeClass("on");
25753 this.fireEvent("deactivate", this.tabPanel, this);
25756 hideAction : function(){
25757 this.bodyEl.hide();
25758 this.bodyEl.setStyle("position", "absolute");
25759 this.bodyEl.setLeft("-20000px");
25760 this.bodyEl.setTop("-20000px");
25763 showAction : function(){
25764 this.bodyEl.setStyle("position", "relative");
25765 this.bodyEl.setTop("");
25766 this.bodyEl.setLeft("");
25767 this.bodyEl.show();
25771 * Set the tooltip for the tab.
25772 * @param {String} tooltip The tab's tooltip
25774 setTooltip : function(text){
25775 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25776 this.textEl.dom.qtip = text;
25777 this.textEl.dom.removeAttribute('title');
25779 this.textEl.dom.title = text;
25783 onTabClick : function(e){
25784 e.preventDefault();
25785 this.tabPanel.activate(this.id);
25788 onTabMouseDown : function(e){
25789 e.preventDefault();
25790 this.tabPanel.activate(this.id);
25793 getWidth : function(){
25794 return this.inner.getWidth();
25797 setWidth : function(width){
25798 var iwidth = width - this.pnode.getPadding("lr");
25799 this.inner.setWidth(iwidth);
25800 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25801 this.pnode.setWidth(width);
25805 * Show or hide the tab
25806 * @param {Boolean} hidden True to hide or false to show.
25808 setHidden : function(hidden){
25809 this.hidden = hidden;
25810 this.pnode.setStyle("display", hidden ? "none" : "");
25814 * Returns true if this tab is "hidden"
25815 * @return {Boolean}
25817 isHidden : function(){
25818 return this.hidden;
25822 * Returns the text for this tab
25825 getText : function(){
25829 autoSize : function(){
25830 //this.el.beginMeasure();
25831 this.textEl.setWidth(1);
25832 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25833 //this.el.endMeasure();
25837 * Sets the text for the tab (Note: this also sets the tooltip text)
25838 * @param {String} text The tab's text and tooltip
25840 setText : function(text){
25842 this.textEl.update(text);
25843 this.setTooltip(text);
25844 if(!this.tabPanel.resizeTabs){
25849 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25851 activate : function(){
25852 this.tabPanel.activate(this.id);
25856 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25858 disable : function(){
25859 if(this.tabPanel.active != this){
25860 this.disabled = true;
25861 this.pnode.addClass("disabled");
25866 * Enables this TabPanelItem if it was previously disabled.
25868 enable : function(){
25869 this.disabled = false;
25870 this.pnode.removeClass("disabled");
25874 * Sets the content for this TabPanelItem.
25875 * @param {String} content The content
25876 * @param {Boolean} loadScripts true to look for and load scripts
25878 setContent : function(content, loadScripts){
25879 this.bodyEl.update(content, loadScripts);
25883 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25884 * @return {Roo.UpdateManager} The UpdateManager
25886 getUpdateManager : function(){
25887 return this.bodyEl.getUpdateManager();
25891 * Set a URL to be used to load the content for this TabPanelItem.
25892 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25893 * @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)
25894 * @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)
25895 * @return {Roo.UpdateManager} The UpdateManager
25897 setUrl : function(url, params, loadOnce){
25898 if(this.refreshDelegate){
25899 this.un('activate', this.refreshDelegate);
25901 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25902 this.on("activate", this.refreshDelegate);
25903 return this.bodyEl.getUpdateManager();
25907 _handleRefresh : function(url, params, loadOnce){
25908 if(!loadOnce || !this.loaded){
25909 var updater = this.bodyEl.getUpdateManager();
25910 updater.update(url, params, this._setLoaded.createDelegate(this));
25915 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25916 * Will fail silently if the setUrl method has not been called.
25917 * This does not activate the panel, just updates its content.
25919 refresh : function(){
25920 if(this.refreshDelegate){
25921 this.loaded = false;
25922 this.refreshDelegate();
25927 _setLoaded : function(){
25928 this.loaded = true;
25932 closeClick : function(e){
25935 this.fireEvent("beforeclose", this, o);
25936 if(o.cancel !== true){
25937 this.tabPanel.removeTab(this.id);
25941 * The text displayed in the tooltip for the close icon.
25944 closeText : "Close this tab"
25948 Roo.TabPanel.prototype.createStrip = function(container){
25949 var strip = document.createElement("div");
25950 strip.className = "x-tabs-wrap";
25951 container.appendChild(strip);
25955 Roo.TabPanel.prototype.createStripList = function(strip){
25956 // div wrapper for retard IE
25957 // returns the "tr" element.
25958 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
25959 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
25960 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
25961 return strip.firstChild.firstChild.firstChild.firstChild;
25964 Roo.TabPanel.prototype.createBody = function(container){
25965 var body = document.createElement("div");
25966 Roo.id(body, "tab-body");
25967 Roo.fly(body).addClass("x-tabs-body");
25968 container.appendChild(body);
25972 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25973 var body = Roo.getDom(id);
25975 body = document.createElement("div");
25978 Roo.fly(body).addClass("x-tabs-item-body");
25979 bodyEl.insertBefore(body, bodyEl.firstChild);
25983 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25984 var td = document.createElement("td");
25985 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
25986 //stripEl.appendChild(td);
25988 td.className = "x-tabs-closable";
25989 if(!this.closeTpl){
25990 this.closeTpl = new Roo.Template(
25991 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25992 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25993 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25996 var el = this.closeTpl.overwrite(td, {"text": text});
25997 var close = el.getElementsByTagName("div")[0];
25998 var inner = el.getElementsByTagName("em")[0];
25999 return {"el": el, "close": close, "inner": inner};
26002 this.tabTpl = new Roo.Template(
26003 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26004 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
26007 var el = this.tabTpl.overwrite(td, {"text": text});
26008 var inner = el.getElementsByTagName("em")[0];
26009 return {"el": el, "inner": inner};
26013 * Ext JS Library 1.1.1
26014 * Copyright(c) 2006-2007, Ext JS, LLC.
26016 * Originally Released Under LGPL - original licence link has changed is not relivant.
26019 * <script type="text/javascript">
26023 * @class Roo.Button
26024 * @extends Roo.util.Observable
26025 * Simple Button class
26026 * @cfg {String} text The button text
26027 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
26028 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
26029 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
26030 * @cfg {Object} scope The scope of the handler
26031 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
26032 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
26033 * @cfg {Boolean} hidden True to start hidden (defaults to false)
26034 * @cfg {Boolean} disabled True to start disabled (defaults to false)
26035 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
26036 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
26037 applies if enableToggle = true)
26038 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
26039 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
26040 an {@link Roo.util.ClickRepeater} config object (defaults to false).
26042 * Create a new button
26043 * @param {Object} config The config object
26045 Roo.Button = function(renderTo, config)
26049 renderTo = config.renderTo || false;
26052 Roo.apply(this, config);
26056 * Fires when this button is clicked
26057 * @param {Button} this
26058 * @param {EventObject} e The click event
26063 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26064 * @param {Button} this
26065 * @param {Boolean} pressed
26070 * Fires when the mouse hovers over the button
26071 * @param {Button} this
26072 * @param {Event} e The event object
26074 'mouseover' : true,
26077 * Fires when the mouse exits the button
26078 * @param {Button} this
26079 * @param {Event} e The event object
26084 * Fires when the button is rendered
26085 * @param {Button} this
26090 this.menu = Roo.menu.MenuMgr.get(this.menu);
26092 // register listeners first!! - so render can be captured..
26093 Roo.util.Observable.call(this);
26095 this.render(renderTo);
26101 Roo.extend(Roo.Button, Roo.util.Observable, {
26107 * Read-only. True if this button is hidden
26112 * Read-only. True if this button is disabled
26117 * Read-only. True if this button is pressed (only if enableToggle = true)
26123 * @cfg {Number} tabIndex
26124 * The DOM tabIndex for this button (defaults to undefined)
26126 tabIndex : undefined,
26129 * @cfg {Boolean} enableToggle
26130 * True to enable pressed/not pressed toggling (defaults to false)
26132 enableToggle: false,
26134 * @cfg {Mixed} menu
26135 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26139 * @cfg {String} menuAlign
26140 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26142 menuAlign : "tl-bl?",
26145 * @cfg {String} iconCls
26146 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26148 iconCls : undefined,
26150 * @cfg {String} type
26151 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26156 menuClassTarget: 'tr',
26159 * @cfg {String} clickEvent
26160 * The type of event to map to the button's event handler (defaults to 'click')
26162 clickEvent : 'click',
26165 * @cfg {Boolean} handleMouseEvents
26166 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26168 handleMouseEvents : true,
26171 * @cfg {String} tooltipType
26172 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26174 tooltipType : 'qtip',
26177 * @cfg {String} cls
26178 * A CSS class to apply to the button's main element.
26182 * @cfg {Roo.Template} template (Optional)
26183 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26184 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26185 * require code modifications if required elements (e.g. a button) aren't present.
26189 render : function(renderTo){
26191 if(this.hideParent){
26192 this.parentEl = Roo.get(renderTo);
26194 if(!this.dhconfig){
26195 if(!this.template){
26196 if(!Roo.Button.buttonTemplate){
26197 // hideous table template
26198 Roo.Button.buttonTemplate = new Roo.Template(
26199 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26200 '<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>',
26201 "</tr></tbody></table>");
26203 this.template = Roo.Button.buttonTemplate;
26205 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26206 var btnEl = btn.child("button:first");
26207 btnEl.on('focus', this.onFocus, this);
26208 btnEl.on('blur', this.onBlur, this);
26210 btn.addClass(this.cls);
26213 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26216 btnEl.addClass(this.iconCls);
26218 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26221 if(this.tabIndex !== undefined){
26222 btnEl.dom.tabIndex = this.tabIndex;
26225 if(typeof this.tooltip == 'object'){
26226 Roo.QuickTips.tips(Roo.apply({
26230 btnEl.dom[this.tooltipType] = this.tooltip;
26234 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26238 this.el.dom.id = this.el.id = this.id;
26241 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26242 this.menu.on("show", this.onMenuShow, this);
26243 this.menu.on("hide", this.onMenuHide, this);
26245 btn.addClass("x-btn");
26246 if(Roo.isIE && !Roo.isIE7){
26247 this.autoWidth.defer(1, this);
26251 if(this.handleMouseEvents){
26252 btn.on("mouseover", this.onMouseOver, this);
26253 btn.on("mouseout", this.onMouseOut, this);
26254 btn.on("mousedown", this.onMouseDown, this);
26256 btn.on(this.clickEvent, this.onClick, this);
26257 //btn.on("mouseup", this.onMouseUp, this);
26264 Roo.ButtonToggleMgr.register(this);
26266 this.el.addClass("x-btn-pressed");
26269 var repeater = new Roo.util.ClickRepeater(btn,
26270 typeof this.repeat == "object" ? this.repeat : {}
26272 repeater.on("click", this.onClick, this);
26275 this.fireEvent('render', this);
26279 * Returns the button's underlying element
26280 * @return {Roo.Element} The element
26282 getEl : function(){
26287 * Destroys this Button and removes any listeners.
26289 destroy : function(){
26290 Roo.ButtonToggleMgr.unregister(this);
26291 this.el.removeAllListeners();
26292 this.purgeListeners();
26297 autoWidth : function(){
26299 this.el.setWidth("auto");
26300 if(Roo.isIE7 && Roo.isStrict){
26301 var ib = this.el.child('button');
26302 if(ib && ib.getWidth() > 20){
26304 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26309 this.el.beginMeasure();
26311 if(this.el.getWidth() < this.minWidth){
26312 this.el.setWidth(this.minWidth);
26315 this.el.endMeasure();
26322 * Assigns this button's click handler
26323 * @param {Function} handler The function to call when the button is clicked
26324 * @param {Object} scope (optional) Scope for the function passed in
26326 setHandler : function(handler, scope){
26327 this.handler = handler;
26328 this.scope = scope;
26332 * Sets this button's text
26333 * @param {String} text The button text
26335 setText : function(text){
26338 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26344 * Gets the text for this button
26345 * @return {String} The button text
26347 getText : function(){
26355 this.hidden = false;
26357 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26365 this.hidden = true;
26367 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26372 * Convenience function for boolean show/hide
26373 * @param {Boolean} visible True to show, false to hide
26375 setVisible: function(visible){
26384 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26385 * @param {Boolean} state (optional) Force a particular state
26387 toggle : function(state){
26388 state = state === undefined ? !this.pressed : state;
26389 if(state != this.pressed){
26391 this.el.addClass("x-btn-pressed");
26392 this.pressed = true;
26393 this.fireEvent("toggle", this, true);
26395 this.el.removeClass("x-btn-pressed");
26396 this.pressed = false;
26397 this.fireEvent("toggle", this, false);
26399 if(this.toggleHandler){
26400 this.toggleHandler.call(this.scope || this, this, state);
26408 focus : function(){
26409 this.el.child('button:first').focus();
26413 * Disable this button
26415 disable : function(){
26417 this.el.addClass("x-btn-disabled");
26419 this.disabled = true;
26423 * Enable this button
26425 enable : function(){
26427 this.el.removeClass("x-btn-disabled");
26429 this.disabled = false;
26433 * Convenience function for boolean enable/disable
26434 * @param {Boolean} enabled True to enable, false to disable
26436 setDisabled : function(v){
26437 this[v !== true ? "enable" : "disable"]();
26441 onClick : function(e){
26443 e.preventDefault();
26448 if(!this.disabled){
26449 if(this.enableToggle){
26452 if(this.menu && !this.menu.isVisible()){
26453 this.menu.show(this.el, this.menuAlign);
26455 this.fireEvent("click", this, e);
26457 this.el.removeClass("x-btn-over");
26458 this.handler.call(this.scope || this, this, e);
26463 onMouseOver : function(e){
26464 if(!this.disabled){
26465 this.el.addClass("x-btn-over");
26466 this.fireEvent('mouseover', this, e);
26470 onMouseOut : function(e){
26471 if(!e.within(this.el, true)){
26472 this.el.removeClass("x-btn-over");
26473 this.fireEvent('mouseout', this, e);
26477 onFocus : function(e){
26478 if(!this.disabled){
26479 this.el.addClass("x-btn-focus");
26483 onBlur : function(e){
26484 this.el.removeClass("x-btn-focus");
26487 onMouseDown : function(e){
26488 if(!this.disabled && e.button == 0){
26489 this.el.addClass("x-btn-click");
26490 Roo.get(document).on('mouseup', this.onMouseUp, this);
26494 onMouseUp : function(e){
26496 this.el.removeClass("x-btn-click");
26497 Roo.get(document).un('mouseup', this.onMouseUp, this);
26501 onMenuShow : function(e){
26502 this.el.addClass("x-btn-menu-active");
26505 onMenuHide : function(e){
26506 this.el.removeClass("x-btn-menu-active");
26510 // Private utility class used by Button
26511 Roo.ButtonToggleMgr = function(){
26514 function toggleGroup(btn, state){
26516 var g = groups[btn.toggleGroup];
26517 for(var i = 0, l = g.length; i < l; i++){
26519 g[i].toggle(false);
26526 register : function(btn){
26527 if(!btn.toggleGroup){
26530 var g = groups[btn.toggleGroup];
26532 g = groups[btn.toggleGroup] = [];
26535 btn.on("toggle", toggleGroup);
26538 unregister : function(btn){
26539 if(!btn.toggleGroup){
26542 var g = groups[btn.toggleGroup];
26545 btn.un("toggle", toggleGroup);
26551 * Ext JS Library 1.1.1
26552 * Copyright(c) 2006-2007, Ext JS, LLC.
26554 * Originally Released Under LGPL - original licence link has changed is not relivant.
26557 * <script type="text/javascript">
26561 * @class Roo.SplitButton
26562 * @extends Roo.Button
26563 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26564 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26565 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26566 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26567 * @cfg {String} arrowTooltip The title attribute of the arrow
26569 * Create a new menu button
26570 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26571 * @param {Object} config The config object
26573 Roo.SplitButton = function(renderTo, config){
26574 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26576 * @event arrowclick
26577 * Fires when this button's arrow is clicked
26578 * @param {SplitButton} this
26579 * @param {EventObject} e The click event
26581 this.addEvents({"arrowclick":true});
26584 Roo.extend(Roo.SplitButton, Roo.Button, {
26585 render : function(renderTo){
26586 // this is one sweet looking template!
26587 var tpl = new Roo.Template(
26588 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26589 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26590 '<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>',
26591 "</tbody></table></td><td>",
26592 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26593 '<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>',
26594 "</tbody></table></td></tr></table>"
26596 var btn = tpl.append(renderTo, [this.text, this.type], true);
26597 var btnEl = btn.child("button");
26599 btn.addClass(this.cls);
26602 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26605 btnEl.addClass(this.iconCls);
26607 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26611 if(this.handleMouseEvents){
26612 btn.on("mouseover", this.onMouseOver, this);
26613 btn.on("mouseout", this.onMouseOut, this);
26614 btn.on("mousedown", this.onMouseDown, this);
26615 btn.on("mouseup", this.onMouseUp, this);
26617 btn.on(this.clickEvent, this.onClick, this);
26619 if(typeof this.tooltip == 'object'){
26620 Roo.QuickTips.tips(Roo.apply({
26624 btnEl.dom[this.tooltipType] = this.tooltip;
26627 if(this.arrowTooltip){
26628 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26637 this.el.addClass("x-btn-pressed");
26639 if(Roo.isIE && !Roo.isIE7){
26640 this.autoWidth.defer(1, this);
26645 this.menu.on("show", this.onMenuShow, this);
26646 this.menu.on("hide", this.onMenuHide, this);
26648 this.fireEvent('render', this);
26652 autoWidth : function(){
26654 var tbl = this.el.child("table:first");
26655 var tbl2 = this.el.child("table:last");
26656 this.el.setWidth("auto");
26657 tbl.setWidth("auto");
26658 if(Roo.isIE7 && Roo.isStrict){
26659 var ib = this.el.child('button:first');
26660 if(ib && ib.getWidth() > 20){
26662 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26667 this.el.beginMeasure();
26669 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26670 tbl.setWidth(this.minWidth-tbl2.getWidth());
26673 this.el.endMeasure();
26676 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26680 * Sets this button's click handler
26681 * @param {Function} handler The function to call when the button is clicked
26682 * @param {Object} scope (optional) Scope for the function passed above
26684 setHandler : function(handler, scope){
26685 this.handler = handler;
26686 this.scope = scope;
26690 * Sets this button's arrow click handler
26691 * @param {Function} handler The function to call when the arrow is clicked
26692 * @param {Object} scope (optional) Scope for the function passed above
26694 setArrowHandler : function(handler, scope){
26695 this.arrowHandler = handler;
26696 this.scope = scope;
26702 focus : function(){
26704 this.el.child("button:first").focus();
26709 onClick : function(e){
26710 e.preventDefault();
26711 if(!this.disabled){
26712 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26713 if(this.menu && !this.menu.isVisible()){
26714 this.menu.show(this.el, this.menuAlign);
26716 this.fireEvent("arrowclick", this, e);
26717 if(this.arrowHandler){
26718 this.arrowHandler.call(this.scope || this, this, e);
26721 this.fireEvent("click", this, e);
26723 this.handler.call(this.scope || this, this, e);
26729 onMouseDown : function(e){
26730 if(!this.disabled){
26731 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26735 onMouseUp : function(e){
26736 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26741 // backwards compat
26742 Roo.MenuButton = Roo.SplitButton;/*
26744 * Ext JS Library 1.1.1
26745 * Copyright(c) 2006-2007, Ext JS, LLC.
26747 * Originally Released Under LGPL - original licence link has changed is not relivant.
26750 * <script type="text/javascript">
26754 * @class Roo.Toolbar
26755 * Basic Toolbar class.
26757 * Creates a new Toolbar
26758 * @param {Object} container The config object
26760 Roo.Toolbar = function(container, buttons, config)
26762 /// old consturctor format still supported..
26763 if(container instanceof Array){ // omit the container for later rendering
26764 buttons = container;
26768 if (typeof(container) == 'object' && container.xtype) {
26769 config = container;
26770 container = config.container;
26771 buttons = config.buttons || []; // not really - use items!!
26774 if (config && config.items) {
26775 xitems = config.items;
26776 delete config.items;
26778 Roo.apply(this, config);
26779 this.buttons = buttons;
26782 this.render(container);
26784 this.xitems = xitems;
26785 Roo.each(xitems, function(b) {
26791 Roo.Toolbar.prototype = {
26793 * @cfg {Array} items
26794 * array of button configs or elements to add (will be converted to a MixedCollection)
26798 * @cfg {String/HTMLElement/Element} container
26799 * The id or element that will contain the toolbar
26802 render : function(ct){
26803 this.el = Roo.get(ct);
26805 this.el.addClass(this.cls);
26807 // using a table allows for vertical alignment
26808 // 100% width is needed by Safari...
26809 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26810 this.tr = this.el.child("tr", true);
26812 this.items = new Roo.util.MixedCollection(false, function(o){
26813 return o.id || ("item" + (++autoId));
26816 this.add.apply(this, this.buttons);
26817 delete this.buttons;
26822 * Adds element(s) to the toolbar -- this function takes a variable number of
26823 * arguments of mixed type and adds them to the toolbar.
26824 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26826 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26827 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26828 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26829 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26830 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26831 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26832 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26833 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26834 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26836 * @param {Mixed} arg2
26837 * @param {Mixed} etc.
26840 var a = arguments, l = a.length;
26841 for(var i = 0; i < l; i++){
26846 _add : function(el) {
26849 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26852 if (el.applyTo){ // some kind of form field
26853 return this.addField(el);
26855 if (el.render){ // some kind of Toolbar.Item
26856 return this.addItem(el);
26858 if (typeof el == "string"){ // string
26859 if(el == "separator" || el == "-"){
26860 return this.addSeparator();
26863 return this.addSpacer();
26866 return this.addFill();
26868 return this.addText(el);
26871 if(el.tagName){ // element
26872 return this.addElement(el);
26874 if(typeof el == "object"){ // must be button config?
26875 return this.addButton(el);
26877 // and now what?!?!
26883 * Add an Xtype element
26884 * @param {Object} xtype Xtype Object
26885 * @return {Object} created Object
26887 addxtype : function(e){
26888 return this.add(e);
26892 * Returns the Element for this toolbar.
26893 * @return {Roo.Element}
26895 getEl : function(){
26901 * @return {Roo.Toolbar.Item} The separator item
26903 addSeparator : function(){
26904 return this.addItem(new Roo.Toolbar.Separator());
26908 * Adds a spacer element
26909 * @return {Roo.Toolbar.Spacer} The spacer item
26911 addSpacer : function(){
26912 return this.addItem(new Roo.Toolbar.Spacer());
26916 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26917 * @return {Roo.Toolbar.Fill} The fill item
26919 addFill : function(){
26920 return this.addItem(new Roo.Toolbar.Fill());
26924 * Adds any standard HTML element to the toolbar
26925 * @param {String/HTMLElement/Element} el The element or id of the element to add
26926 * @return {Roo.Toolbar.Item} The element's item
26928 addElement : function(el){
26929 return this.addItem(new Roo.Toolbar.Item(el));
26932 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26933 * @type Roo.util.MixedCollection
26938 * Adds any Toolbar.Item or subclass
26939 * @param {Roo.Toolbar.Item} item
26940 * @return {Roo.Toolbar.Item} The item
26942 addItem : function(item){
26943 var td = this.nextBlock();
26945 this.items.add(item);
26950 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26951 * @param {Object/Array} config A button config or array of configs
26952 * @return {Roo.Toolbar.Button/Array}
26954 addButton : function(config){
26955 if(config instanceof Array){
26957 for(var i = 0, len = config.length; i < len; i++) {
26958 buttons.push(this.addButton(config[i]));
26963 if(!(config instanceof Roo.Toolbar.Button)){
26965 new Roo.Toolbar.SplitButton(config) :
26966 new Roo.Toolbar.Button(config);
26968 var td = this.nextBlock();
26975 * Adds text to the toolbar
26976 * @param {String} text The text to add
26977 * @return {Roo.Toolbar.Item} The element's item
26979 addText : function(text){
26980 return this.addItem(new Roo.Toolbar.TextItem(text));
26984 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26985 * @param {Number} index The index where the item is to be inserted
26986 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26987 * @return {Roo.Toolbar.Button/Item}
26989 insertButton : function(index, item){
26990 if(item instanceof Array){
26992 for(var i = 0, len = item.length; i < len; i++) {
26993 buttons.push(this.insertButton(index + i, item[i]));
26997 if (!(item instanceof Roo.Toolbar.Button)){
26998 item = new Roo.Toolbar.Button(item);
27000 var td = document.createElement("td");
27001 this.tr.insertBefore(td, this.tr.childNodes[index]);
27003 this.items.insert(index, item);
27008 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
27009 * @param {Object} config
27010 * @return {Roo.Toolbar.Item} The element's item
27012 addDom : function(config, returnEl){
27013 var td = this.nextBlock();
27014 Roo.DomHelper.overwrite(td, config);
27015 var ti = new Roo.Toolbar.Item(td.firstChild);
27017 this.items.add(ti);
27022 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
27023 * @type Roo.util.MixedCollection
27028 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
27029 * Note: the field should not have been rendered yet. For a field that has already been
27030 * rendered, use {@link #addElement}.
27031 * @param {Roo.form.Field} field
27032 * @return {Roo.ToolbarItem}
27036 addField : function(field) {
27037 if (!this.fields) {
27039 this.fields = new Roo.util.MixedCollection(false, function(o){
27040 return o.id || ("item" + (++autoId));
27045 var td = this.nextBlock();
27047 var ti = new Roo.Toolbar.Item(td.firstChild);
27049 this.items.add(ti);
27050 this.fields.add(field);
27061 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
27062 this.el.child('div').hide();
27070 this.el.child('div').show();
27074 nextBlock : function(){
27075 var td = document.createElement("td");
27076 this.tr.appendChild(td);
27081 destroy : function(){
27082 if(this.items){ // rendered?
27083 Roo.destroy.apply(Roo, this.items.items);
27085 if(this.fields){ // rendered?
27086 Roo.destroy.apply(Roo, this.fields.items);
27088 Roo.Element.uncache(this.el, this.tr);
27093 * @class Roo.Toolbar.Item
27094 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27096 * Creates a new Item
27097 * @param {HTMLElement} el
27099 Roo.Toolbar.Item = function(el){
27100 this.el = Roo.getDom(el);
27101 this.id = Roo.id(this.el);
27102 this.hidden = false;
27105 Roo.Toolbar.Item.prototype = {
27108 * Get this item's HTML Element
27109 * @return {HTMLElement}
27111 getEl : function(){
27116 render : function(td){
27118 td.appendChild(this.el);
27122 * Removes and destroys this item.
27124 destroy : function(){
27125 this.td.parentNode.removeChild(this.td);
27132 this.hidden = false;
27133 this.td.style.display = "";
27140 this.hidden = true;
27141 this.td.style.display = "none";
27145 * Convenience function for boolean show/hide.
27146 * @param {Boolean} visible true to show/false to hide
27148 setVisible: function(visible){
27157 * Try to focus this item.
27159 focus : function(){
27160 Roo.fly(this.el).focus();
27164 * Disables this item.
27166 disable : function(){
27167 Roo.fly(this.td).addClass("x-item-disabled");
27168 this.disabled = true;
27169 this.el.disabled = true;
27173 * Enables this item.
27175 enable : function(){
27176 Roo.fly(this.td).removeClass("x-item-disabled");
27177 this.disabled = false;
27178 this.el.disabled = false;
27184 * @class Roo.Toolbar.Separator
27185 * @extends Roo.Toolbar.Item
27186 * A simple toolbar separator class
27188 * Creates a new Separator
27190 Roo.Toolbar.Separator = function(){
27191 var s = document.createElement("span");
27192 s.className = "ytb-sep";
27193 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27195 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27196 enable:Roo.emptyFn,
27197 disable:Roo.emptyFn,
27202 * @class Roo.Toolbar.Spacer
27203 * @extends Roo.Toolbar.Item
27204 * A simple element that adds extra horizontal space to a toolbar.
27206 * Creates a new Spacer
27208 Roo.Toolbar.Spacer = function(){
27209 var s = document.createElement("div");
27210 s.className = "ytb-spacer";
27211 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27213 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27214 enable:Roo.emptyFn,
27215 disable:Roo.emptyFn,
27220 * @class Roo.Toolbar.Fill
27221 * @extends Roo.Toolbar.Spacer
27222 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27224 * Creates a new Spacer
27226 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27228 render : function(td){
27229 td.style.width = '100%';
27230 Roo.Toolbar.Fill.superclass.render.call(this, td);
27235 * @class Roo.Toolbar.TextItem
27236 * @extends Roo.Toolbar.Item
27237 * A simple class that renders text directly into a toolbar.
27239 * Creates a new TextItem
27240 * @param {String} text
27242 Roo.Toolbar.TextItem = function(text){
27243 if (typeof(text) == 'object') {
27246 var s = document.createElement("span");
27247 s.className = "ytb-text";
27248 s.innerHTML = text;
27249 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27251 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27252 enable:Roo.emptyFn,
27253 disable:Roo.emptyFn,
27258 * @class Roo.Toolbar.Button
27259 * @extends Roo.Button
27260 * A button that renders into a toolbar.
27262 * Creates a new Button
27263 * @param {Object} config A standard {@link Roo.Button} config object
27265 Roo.Toolbar.Button = function(config){
27266 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27268 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27269 render : function(td){
27271 Roo.Toolbar.Button.superclass.render.call(this, td);
27275 * Removes and destroys this button
27277 destroy : function(){
27278 Roo.Toolbar.Button.superclass.destroy.call(this);
27279 this.td.parentNode.removeChild(this.td);
27283 * Shows this button
27286 this.hidden = false;
27287 this.td.style.display = "";
27291 * Hides this button
27294 this.hidden = true;
27295 this.td.style.display = "none";
27299 * Disables this item
27301 disable : function(){
27302 Roo.fly(this.td).addClass("x-item-disabled");
27303 this.disabled = true;
27307 * Enables this item
27309 enable : function(){
27310 Roo.fly(this.td).removeClass("x-item-disabled");
27311 this.disabled = false;
27314 // backwards compat
27315 Roo.ToolbarButton = Roo.Toolbar.Button;
27318 * @class Roo.Toolbar.SplitButton
27319 * @extends Roo.SplitButton
27320 * A menu button that renders into a toolbar.
27322 * Creates a new SplitButton
27323 * @param {Object} config A standard {@link Roo.SplitButton} config object
27325 Roo.Toolbar.SplitButton = function(config){
27326 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27328 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27329 render : function(td){
27331 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27335 * Removes and destroys this button
27337 destroy : function(){
27338 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27339 this.td.parentNode.removeChild(this.td);
27343 * Shows this button
27346 this.hidden = false;
27347 this.td.style.display = "";
27351 * Hides this button
27354 this.hidden = true;
27355 this.td.style.display = "none";
27359 // backwards compat
27360 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27362 * Ext JS Library 1.1.1
27363 * Copyright(c) 2006-2007, Ext JS, LLC.
27365 * Originally Released Under LGPL - original licence link has changed is not relivant.
27368 * <script type="text/javascript">
27372 * @class Roo.PagingToolbar
27373 * @extends Roo.Toolbar
27374 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27376 * Create a new PagingToolbar
27377 * @param {Object} config The config object
27379 Roo.PagingToolbar = function(el, ds, config)
27381 // old args format still supported... - xtype is prefered..
27382 if (typeof(el) == 'object' && el.xtype) {
27383 // created from xtype...
27385 ds = el.dataSource;
27386 el = config.container;
27389 if (config.items) {
27390 items = config.items;
27394 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27397 this.renderButtons(this.el);
27400 // supprot items array.
27402 Roo.each(items, function(e) {
27403 this.add(Roo.factory(e));
27408 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27410 * @cfg {Roo.data.Store} dataSource
27411 * The underlying data store providing the paged data
27414 * @cfg {String/HTMLElement/Element} container
27415 * container The id or element that will contain the toolbar
27418 * @cfg {Boolean} displayInfo
27419 * True to display the displayMsg (defaults to false)
27422 * @cfg {Number} pageSize
27423 * The number of records to display per page (defaults to 20)
27427 * @cfg {String} displayMsg
27428 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27430 displayMsg : 'Displaying {0} - {1} of {2}',
27432 * @cfg {String} emptyMsg
27433 * The message to display when no records are found (defaults to "No data to display")
27435 emptyMsg : 'No data to display',
27437 * Customizable piece of the default paging text (defaults to "Page")
27440 beforePageText : "Page",
27442 * Customizable piece of the default paging text (defaults to "of %0")
27445 afterPageText : "of {0}",
27447 * Customizable piece of the default paging text (defaults to "First Page")
27450 firstText : "First Page",
27452 * Customizable piece of the default paging text (defaults to "Previous Page")
27455 prevText : "Previous Page",
27457 * Customizable piece of the default paging text (defaults to "Next Page")
27460 nextText : "Next Page",
27462 * Customizable piece of the default paging text (defaults to "Last Page")
27465 lastText : "Last Page",
27467 * Customizable piece of the default paging text (defaults to "Refresh")
27470 refreshText : "Refresh",
27473 renderButtons : function(el){
27474 Roo.PagingToolbar.superclass.render.call(this, el);
27475 this.first = this.addButton({
27476 tooltip: this.firstText,
27477 cls: "x-btn-icon x-grid-page-first",
27479 handler: this.onClick.createDelegate(this, ["first"])
27481 this.prev = this.addButton({
27482 tooltip: this.prevText,
27483 cls: "x-btn-icon x-grid-page-prev",
27485 handler: this.onClick.createDelegate(this, ["prev"])
27487 //this.addSeparator();
27488 this.add(this.beforePageText);
27489 this.field = Roo.get(this.addDom({
27494 cls: "x-grid-page-number"
27496 this.field.on("keydown", this.onPagingKeydown, this);
27497 this.field.on("focus", function(){this.dom.select();});
27498 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27499 this.field.setHeight(18);
27500 //this.addSeparator();
27501 this.next = this.addButton({
27502 tooltip: this.nextText,
27503 cls: "x-btn-icon x-grid-page-next",
27505 handler: this.onClick.createDelegate(this, ["next"])
27507 this.last = this.addButton({
27508 tooltip: this.lastText,
27509 cls: "x-btn-icon x-grid-page-last",
27511 handler: this.onClick.createDelegate(this, ["last"])
27513 //this.addSeparator();
27514 this.loading = this.addButton({
27515 tooltip: this.refreshText,
27516 cls: "x-btn-icon x-grid-loading",
27517 handler: this.onClick.createDelegate(this, ["refresh"])
27520 if(this.displayInfo){
27521 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27526 updateInfo : function(){
27527 if(this.displayEl){
27528 var count = this.ds.getCount();
27529 var msg = count == 0 ?
27533 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27535 this.displayEl.update(msg);
27540 onLoad : function(ds, r, o){
27541 this.cursor = o.params ? o.params.start : 0;
27542 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27544 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27545 this.field.dom.value = ap;
27546 this.first.setDisabled(ap == 1);
27547 this.prev.setDisabled(ap == 1);
27548 this.next.setDisabled(ap == ps);
27549 this.last.setDisabled(ap == ps);
27550 this.loading.enable();
27555 getPageData : function(){
27556 var total = this.ds.getTotalCount();
27559 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27560 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27565 onLoadError : function(){
27566 this.loading.enable();
27570 onPagingKeydown : function(e){
27571 var k = e.getKey();
27572 var d = this.getPageData();
27574 var v = this.field.dom.value, pageNum;
27575 if(!v || isNaN(pageNum = parseInt(v, 10))){
27576 this.field.dom.value = d.activePage;
27579 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27580 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27583 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))
27585 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27586 this.field.dom.value = pageNum;
27587 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27590 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27592 var v = this.field.dom.value, pageNum;
27593 var increment = (e.shiftKey) ? 10 : 1;
27594 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27596 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27597 this.field.dom.value = d.activePage;
27600 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27602 this.field.dom.value = parseInt(v, 10) + increment;
27603 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27604 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27611 beforeLoad : function(){
27613 this.loading.disable();
27618 onClick : function(which){
27622 ds.load({params:{start: 0, limit: this.pageSize}});
27625 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27628 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27631 var total = ds.getTotalCount();
27632 var extra = total % this.pageSize;
27633 var lastStart = extra ? (total - extra) : total-this.pageSize;
27634 ds.load({params:{start: lastStart, limit: this.pageSize}});
27637 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27643 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27644 * @param {Roo.data.Store} store The data store to unbind
27646 unbind : function(ds){
27647 ds.un("beforeload", this.beforeLoad, this);
27648 ds.un("load", this.onLoad, this);
27649 ds.un("loadexception", this.onLoadError, this);
27650 ds.un("remove", this.updateInfo, this);
27651 ds.un("add", this.updateInfo, this);
27652 this.ds = undefined;
27656 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27657 * @param {Roo.data.Store} store The data store to bind
27659 bind : function(ds){
27660 ds.on("beforeload", this.beforeLoad, this);
27661 ds.on("load", this.onLoad, this);
27662 ds.on("loadexception", this.onLoadError, this);
27663 ds.on("remove", this.updateInfo, this);
27664 ds.on("add", this.updateInfo, this);
27669 * Ext JS Library 1.1.1
27670 * Copyright(c) 2006-2007, Ext JS, LLC.
27672 * Originally Released Under LGPL - original licence link has changed is not relivant.
27675 * <script type="text/javascript">
27679 * @class Roo.Resizable
27680 * @extends Roo.util.Observable
27681 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27682 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27683 * 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
27684 * the element will be wrapped for you automatically.</p>
27685 * <p>Here is the list of valid resize handles:</p>
27688 ------ -------------------
27697 'hd' horizontal drag
27700 * <p>Here's an example showing the creation of a typical Resizable:</p>
27702 var resizer = new Roo.Resizable("element-id", {
27710 resizer.on("resize", myHandler);
27712 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27713 * resizer.east.setDisplayed(false);</p>
27714 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27715 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27716 * resize operation's new size (defaults to [0, 0])
27717 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27718 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27719 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27720 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27721 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27722 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27723 * @cfg {Number} width The width of the element in pixels (defaults to null)
27724 * @cfg {Number} height The height of the element in pixels (defaults to null)
27725 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27726 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27727 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27728 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27729 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27730 * in favor of the handles config option (defaults to false)
27731 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27732 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27733 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27734 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27735 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27736 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27737 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27738 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27739 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27740 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27741 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27743 * Create a new resizable component
27744 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27745 * @param {Object} config configuration options
27747 Roo.Resizable = function(el, config)
27749 this.el = Roo.get(el);
27751 if(config && config.wrap){
27752 config.resizeChild = this.el;
27753 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27754 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27755 this.el.setStyle("overflow", "hidden");
27756 this.el.setPositioning(config.resizeChild.getPositioning());
27757 config.resizeChild.clearPositioning();
27758 if(!config.width || !config.height){
27759 var csize = config.resizeChild.getSize();
27760 this.el.setSize(csize.width, csize.height);
27762 if(config.pinned && !config.adjustments){
27763 config.adjustments = "auto";
27767 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27768 this.proxy.unselectable();
27769 this.proxy.enableDisplayMode('block');
27771 Roo.apply(this, config);
27774 this.disableTrackOver = true;
27775 this.el.addClass("x-resizable-pinned");
27777 // if the element isn't positioned, make it relative
27778 var position = this.el.getStyle("position");
27779 if(position != "absolute" && position != "fixed"){
27780 this.el.setStyle("position", "relative");
27782 if(!this.handles){ // no handles passed, must be legacy style
27783 this.handles = 's,e,se';
27784 if(this.multiDirectional){
27785 this.handles += ',n,w';
27788 if(this.handles == "all"){
27789 this.handles = "n s e w ne nw se sw";
27791 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27792 var ps = Roo.Resizable.positions;
27793 for(var i = 0, len = hs.length; i < len; i++){
27794 if(hs[i] && ps[hs[i]]){
27795 var pos = ps[hs[i]];
27796 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27800 this.corner = this.southeast;
27802 // updateBox = the box can move..
27803 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27804 this.updateBox = true;
27807 this.activeHandle = null;
27809 if(this.resizeChild){
27810 if(typeof this.resizeChild == "boolean"){
27811 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27813 this.resizeChild = Roo.get(this.resizeChild, true);
27817 if(this.adjustments == "auto"){
27818 var rc = this.resizeChild;
27819 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27820 if(rc && (hw || hn)){
27821 rc.position("relative");
27822 rc.setLeft(hw ? hw.el.getWidth() : 0);
27823 rc.setTop(hn ? hn.el.getHeight() : 0);
27825 this.adjustments = [
27826 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27827 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27831 if(this.draggable){
27832 this.dd = this.dynamic ?
27833 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27834 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27840 * @event beforeresize
27841 * Fired before resize is allowed. Set enabled to false to cancel resize.
27842 * @param {Roo.Resizable} this
27843 * @param {Roo.EventObject} e The mousedown event
27845 "beforeresize" : true,
27848 * Fired after a resize.
27849 * @param {Roo.Resizable} this
27850 * @param {Number} width The new width
27851 * @param {Number} height The new height
27852 * @param {Roo.EventObject} e The mouseup event
27857 if(this.width !== null && this.height !== null){
27858 this.resizeTo(this.width, this.height);
27860 this.updateChildSize();
27863 this.el.dom.style.zoom = 1;
27865 Roo.Resizable.superclass.constructor.call(this);
27868 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27869 resizeChild : false,
27870 adjustments : [0, 0],
27880 multiDirectional : false,
27881 disableTrackOver : false,
27882 easing : 'easeOutStrong',
27883 widthIncrement : 0,
27884 heightIncrement : 0,
27888 preserveRatio : false,
27889 transparent: false,
27895 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27897 constrainTo: undefined,
27899 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27901 resizeRegion: undefined,
27905 * Perform a manual resize
27906 * @param {Number} width
27907 * @param {Number} height
27909 resizeTo : function(width, height){
27910 this.el.setSize(width, height);
27911 this.updateChildSize();
27912 this.fireEvent("resize", this, width, height, null);
27916 startSizing : function(e, handle){
27917 this.fireEvent("beforeresize", this, e);
27918 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27921 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27922 this.overlay.unselectable();
27923 this.overlay.enableDisplayMode("block");
27924 this.overlay.on("mousemove", this.onMouseMove, this);
27925 this.overlay.on("mouseup", this.onMouseUp, this);
27927 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27929 this.resizing = true;
27930 this.startBox = this.el.getBox();
27931 this.startPoint = e.getXY();
27932 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27933 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27935 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27936 this.overlay.show();
27938 if(this.constrainTo) {
27939 var ct = Roo.get(this.constrainTo);
27940 this.resizeRegion = ct.getRegion().adjust(
27941 ct.getFrameWidth('t'),
27942 ct.getFrameWidth('l'),
27943 -ct.getFrameWidth('b'),
27944 -ct.getFrameWidth('r')
27948 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27950 this.proxy.setBox(this.startBox);
27952 this.proxy.setStyle('visibility', 'visible');
27958 onMouseDown : function(handle, e){
27961 this.activeHandle = handle;
27962 this.startSizing(e, handle);
27967 onMouseUp : function(e){
27968 var size = this.resizeElement();
27969 this.resizing = false;
27971 this.overlay.hide();
27973 this.fireEvent("resize", this, size.width, size.height, e);
27977 updateChildSize : function(){
27978 if(this.resizeChild){
27980 var child = this.resizeChild;
27981 var adj = this.adjustments;
27982 if(el.dom.offsetWidth){
27983 var b = el.getSize(true);
27984 child.setSize(b.width+adj[0], b.height+adj[1]);
27986 // Second call here for IE
27987 // The first call enables instant resizing and
27988 // the second call corrects scroll bars if they
27991 setTimeout(function(){
27992 if(el.dom.offsetWidth){
27993 var b = el.getSize(true);
27994 child.setSize(b.width+adj[0], b.height+adj[1]);
28002 snap : function(value, inc, min){
28003 if(!inc || !value) return value;
28004 var newValue = value;
28005 var m = value % inc;
28008 newValue = value + (inc-m);
28010 newValue = value - m;
28013 return Math.max(min, newValue);
28017 resizeElement : function(){
28018 var box = this.proxy.getBox();
28019 if(this.updateBox){
28020 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
28022 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
28024 this.updateChildSize();
28032 constrain : function(v, diff, m, mx){
28035 }else if(v - diff > mx){
28042 onMouseMove : function(e){
28044 try{// try catch so if something goes wrong the user doesn't get hung
28046 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
28050 //var curXY = this.startPoint;
28051 var curSize = this.curSize || this.startBox;
28052 var x = this.startBox.x, y = this.startBox.y;
28053 var ox = x, oy = y;
28054 var w = curSize.width, h = curSize.height;
28055 var ow = w, oh = h;
28056 var mw = this.minWidth, mh = this.minHeight;
28057 var mxw = this.maxWidth, mxh = this.maxHeight;
28058 var wi = this.widthIncrement;
28059 var hi = this.heightIncrement;
28061 var eventXY = e.getXY();
28062 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
28063 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28065 var pos = this.activeHandle.position;
28070 w = Math.min(Math.max(mw, w), mxw);
28075 h = Math.min(Math.max(mh, h), mxh);
28080 w = Math.min(Math.max(mw, w), mxw);
28081 h = Math.min(Math.max(mh, h), mxh);
28084 diffY = this.constrain(h, diffY, mh, mxh);
28091 var adiffX = Math.abs(diffX);
28092 var sub = (adiffX % wi); // how much
28093 if (sub > (wi/2)) { // far enough to snap
28094 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28096 // remove difference..
28097 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28101 x = Math.max(this.minX, x);
28104 diffX = this.constrain(w, diffX, mw, mxw);
28110 w = Math.min(Math.max(mw, w), mxw);
28111 diffY = this.constrain(h, diffY, mh, mxh);
28116 diffX = this.constrain(w, diffX, mw, mxw);
28117 diffY = this.constrain(h, diffY, mh, mxh);
28124 diffX = this.constrain(w, diffX, mw, mxw);
28126 h = Math.min(Math.max(mh, h), mxh);
28132 var sw = this.snap(w, wi, mw);
28133 var sh = this.snap(h, hi, mh);
28134 if(sw != w || sh != h){
28157 if(this.preserveRatio){
28162 h = Math.min(Math.max(mh, h), mxh);
28167 w = Math.min(Math.max(mw, w), mxw);
28172 w = Math.min(Math.max(mw, w), mxw);
28178 w = Math.min(Math.max(mw, w), mxw);
28184 h = Math.min(Math.max(mh, h), mxh);
28192 h = Math.min(Math.max(mh, h), mxh);
28202 h = Math.min(Math.max(mh, h), mxh);
28210 if (pos == 'hdrag') {
28213 this.proxy.setBounds(x, y, w, h);
28215 this.resizeElement();
28222 handleOver : function(){
28224 this.el.addClass("x-resizable-over");
28229 handleOut : function(){
28230 if(!this.resizing){
28231 this.el.removeClass("x-resizable-over");
28236 * Returns the element this component is bound to.
28237 * @return {Roo.Element}
28239 getEl : function(){
28244 * Returns the resizeChild element (or null).
28245 * @return {Roo.Element}
28247 getResizeChild : function(){
28248 return this.resizeChild;
28252 * Destroys this resizable. If the element was wrapped and
28253 * removeEl is not true then the element remains.
28254 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28256 destroy : function(removeEl){
28257 this.proxy.remove();
28259 this.overlay.removeAllListeners();
28260 this.overlay.remove();
28262 var ps = Roo.Resizable.positions;
28264 if(typeof ps[k] != "function" && this[ps[k]]){
28265 var h = this[ps[k]];
28266 h.el.removeAllListeners();
28271 this.el.update("");
28278 // hash to map config positions to true positions
28279 Roo.Resizable.positions = {
28280 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28285 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28287 // only initialize the template if resizable is used
28288 var tpl = Roo.DomHelper.createTemplate(
28289 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28292 Roo.Resizable.Handle.prototype.tpl = tpl;
28294 this.position = pos;
28296 // show north drag fro topdra
28297 var handlepos = pos == 'hdrag' ? 'north' : pos;
28299 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28300 if (pos == 'hdrag') {
28301 this.el.setStyle('cursor', 'pointer');
28303 this.el.unselectable();
28305 this.el.setOpacity(0);
28307 this.el.on("mousedown", this.onMouseDown, this);
28308 if(!disableTrackOver){
28309 this.el.on("mouseover", this.onMouseOver, this);
28310 this.el.on("mouseout", this.onMouseOut, this);
28315 Roo.Resizable.Handle.prototype = {
28316 afterResize : function(rz){
28320 onMouseDown : function(e){
28321 this.rz.onMouseDown(this, e);
28324 onMouseOver : function(e){
28325 this.rz.handleOver(this, e);
28328 onMouseOut : function(e){
28329 this.rz.handleOut(this, e);
28333 * Ext JS Library 1.1.1
28334 * Copyright(c) 2006-2007, Ext JS, LLC.
28336 * Originally Released Under LGPL - original licence link has changed is not relivant.
28339 * <script type="text/javascript">
28343 * @class Roo.Editor
28344 * @extends Roo.Component
28345 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28347 * Create a new Editor
28348 * @param {Roo.form.Field} field The Field object (or descendant)
28349 * @param {Object} config The config object
28351 Roo.Editor = function(field, config){
28352 Roo.Editor.superclass.constructor.call(this, config);
28353 this.field = field;
28356 * @event beforestartedit
28357 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28358 * false from the handler of this event.
28359 * @param {Editor} this
28360 * @param {Roo.Element} boundEl The underlying element bound to this editor
28361 * @param {Mixed} value The field value being set
28363 "beforestartedit" : true,
28366 * Fires when this editor is displayed
28367 * @param {Roo.Element} boundEl The underlying element bound to this editor
28368 * @param {Mixed} value The starting field value
28370 "startedit" : true,
28372 * @event beforecomplete
28373 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28374 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28375 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28376 * event will not fire since no edit actually occurred.
28377 * @param {Editor} this
28378 * @param {Mixed} value The current field value
28379 * @param {Mixed} startValue The original field value
28381 "beforecomplete" : true,
28384 * Fires after editing is complete and any changed value has been written to the underlying field.
28385 * @param {Editor} this
28386 * @param {Mixed} value The current field value
28387 * @param {Mixed} startValue The original field value
28391 * @event specialkey
28392 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28393 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28394 * @param {Roo.form.Field} this
28395 * @param {Roo.EventObject} e The event object
28397 "specialkey" : true
28401 Roo.extend(Roo.Editor, Roo.Component, {
28403 * @cfg {Boolean/String} autosize
28404 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28405 * or "height" to adopt the height only (defaults to false)
28408 * @cfg {Boolean} revertInvalid
28409 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28410 * validation fails (defaults to true)
28413 * @cfg {Boolean} ignoreNoChange
28414 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28415 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28416 * will never be ignored.
28419 * @cfg {Boolean} hideEl
28420 * False to keep the bound element visible while the editor is displayed (defaults to true)
28423 * @cfg {Mixed} value
28424 * The data value of the underlying field (defaults to "")
28428 * @cfg {String} alignment
28429 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28433 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28434 * for bottom-right shadow (defaults to "frame")
28438 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28442 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28444 completeOnEnter : false,
28446 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28448 cancelOnEsc : false,
28450 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28455 onRender : function(ct, position){
28456 this.el = new Roo.Layer({
28457 shadow: this.shadow,
28463 constrain: this.constrain
28465 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28466 if(this.field.msgTarget != 'title'){
28467 this.field.msgTarget = 'qtip';
28469 this.field.render(this.el);
28471 this.field.el.dom.setAttribute('autocomplete', 'off');
28473 this.field.on("specialkey", this.onSpecialKey, this);
28474 if(this.swallowKeys){
28475 this.field.el.swallowEvent(['keydown','keypress']);
28478 this.field.on("blur", this.onBlur, this);
28479 if(this.field.grow){
28480 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28484 onSpecialKey : function(field, e)
28486 //Roo.log('editor onSpecialKey');
28487 if(this.completeOnEnter && e.getKey() == e.ENTER){
28489 this.completeEdit();
28492 // do not fire special key otherwise it might hide close the editor...
28493 if(e.getKey() == e.ENTER){
28496 if(this.cancelOnEsc && e.getKey() == e.ESC){
28500 this.fireEvent('specialkey', field, e);
28505 * Starts the editing process and shows the editor.
28506 * @param {String/HTMLElement/Element} el The element to edit
28507 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28508 * to the innerHTML of el.
28510 startEdit : function(el, value){
28512 this.completeEdit();
28514 this.boundEl = Roo.get(el);
28515 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28516 if(!this.rendered){
28517 this.render(this.parentEl || document.body);
28519 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28522 this.startValue = v;
28523 this.field.setValue(v);
28525 var sz = this.boundEl.getSize();
28526 switch(this.autoSize){
28528 this.setSize(sz.width, "");
28531 this.setSize("", sz.height);
28534 this.setSize(sz.width, sz.height);
28537 this.el.alignTo(this.boundEl, this.alignment);
28538 this.editing = true;
28540 Roo.QuickTips.disable();
28546 * Sets the height and width of this editor.
28547 * @param {Number} width The new width
28548 * @param {Number} height The new height
28550 setSize : function(w, h){
28551 this.field.setSize(w, h);
28558 * Realigns the editor to the bound field based on the current alignment config value.
28560 realign : function(){
28561 this.el.alignTo(this.boundEl, this.alignment);
28565 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28566 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28568 completeEdit : function(remainVisible){
28572 var v = this.getValue();
28573 if(this.revertInvalid !== false && !this.field.isValid()){
28574 v = this.startValue;
28575 this.cancelEdit(true);
28577 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28578 this.editing = false;
28582 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28583 this.editing = false;
28584 if(this.updateEl && this.boundEl){
28585 this.boundEl.update(v);
28587 if(remainVisible !== true){
28590 this.fireEvent("complete", this, v, this.startValue);
28595 onShow : function(){
28597 if(this.hideEl !== false){
28598 this.boundEl.hide();
28601 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28602 this.fixIEFocus = true;
28603 this.deferredFocus.defer(50, this);
28605 this.field.focus();
28607 this.fireEvent("startedit", this.boundEl, this.startValue);
28610 deferredFocus : function(){
28612 this.field.focus();
28617 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28618 * reverted to the original starting value.
28619 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28620 * cancel (defaults to false)
28622 cancelEdit : function(remainVisible){
28624 this.setValue(this.startValue);
28625 if(remainVisible !== true){
28632 onBlur : function(){
28633 if(this.allowBlur !== true && this.editing){
28634 this.completeEdit();
28639 onHide : function(){
28641 this.completeEdit();
28645 if(this.field.collapse){
28646 this.field.collapse();
28649 if(this.hideEl !== false){
28650 this.boundEl.show();
28653 Roo.QuickTips.enable();
28658 * Sets the data value of the editor
28659 * @param {Mixed} value Any valid value supported by the underlying field
28661 setValue : function(v){
28662 this.field.setValue(v);
28666 * Gets the data value of the editor
28667 * @return {Mixed} The data value
28669 getValue : function(){
28670 return this.field.getValue();
28674 * Ext JS Library 1.1.1
28675 * Copyright(c) 2006-2007, Ext JS, LLC.
28677 * Originally Released Under LGPL - original licence link has changed is not relivant.
28680 * <script type="text/javascript">
28684 * @class Roo.BasicDialog
28685 * @extends Roo.util.Observable
28686 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28688 var dlg = new Roo.BasicDialog("my-dlg", {
28697 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28698 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28699 dlg.addButton('Cancel', dlg.hide, dlg);
28702 <b>A Dialog should always be a direct child of the body element.</b>
28703 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28704 * @cfg {String} title Default text to display in the title bar (defaults to null)
28705 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28706 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28707 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28708 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28709 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28710 * (defaults to null with no animation)
28711 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28712 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28713 * property for valid values (defaults to 'all')
28714 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28715 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28716 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28717 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28718 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28719 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28720 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28721 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28722 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28723 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28724 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28725 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28726 * draggable = true (defaults to false)
28727 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28728 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28729 * shadow (defaults to false)
28730 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28731 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28732 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28733 * @cfg {Array} buttons Array of buttons
28734 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28736 * Create a new BasicDialog.
28737 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28738 * @param {Object} config Configuration options
28740 Roo.BasicDialog = function(el, config){
28741 this.el = Roo.get(el);
28742 var dh = Roo.DomHelper;
28743 if(!this.el && config && config.autoCreate){
28744 if(typeof config.autoCreate == "object"){
28745 if(!config.autoCreate.id){
28746 config.autoCreate.id = el;
28748 this.el = dh.append(document.body,
28749 config.autoCreate, true);
28751 this.el = dh.append(document.body,
28752 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28756 el.setDisplayed(true);
28757 el.hide = this.hideAction;
28759 el.addClass("x-dlg");
28761 Roo.apply(this, config);
28763 this.proxy = el.createProxy("x-dlg-proxy");
28764 this.proxy.hide = this.hideAction;
28765 this.proxy.setOpacity(.5);
28769 el.setWidth(config.width);
28772 el.setHeight(config.height);
28774 this.size = el.getSize();
28775 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28776 this.xy = [config.x,config.y];
28778 this.xy = el.getCenterXY(true);
28780 /** The header element @type Roo.Element */
28781 this.header = el.child("> .x-dlg-hd");
28782 /** The body element @type Roo.Element */
28783 this.body = el.child("> .x-dlg-bd");
28784 /** The footer element @type Roo.Element */
28785 this.footer = el.child("> .x-dlg-ft");
28788 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28791 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28794 this.header.unselectable();
28796 this.header.update(this.title);
28798 // this element allows the dialog to be focused for keyboard event
28799 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28800 this.focusEl.swallowEvent("click", true);
28802 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28804 // wrap the body and footer for special rendering
28805 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28807 this.bwrap.dom.appendChild(this.footer.dom);
28810 this.bg = this.el.createChild({
28811 tag: "div", cls:"x-dlg-bg",
28812 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28814 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28817 if(this.autoScroll !== false && !this.autoTabs){
28818 this.body.setStyle("overflow", "auto");
28821 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28823 if(this.closable !== false){
28824 this.el.addClass("x-dlg-closable");
28825 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28826 this.close.on("click", this.closeClick, this);
28827 this.close.addClassOnOver("x-dlg-close-over");
28829 if(this.collapsible !== false){
28830 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28831 this.collapseBtn.on("click", this.collapseClick, this);
28832 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28833 this.header.on("dblclick", this.collapseClick, this);
28835 if(this.resizable !== false){
28836 this.el.addClass("x-dlg-resizable");
28837 this.resizer = new Roo.Resizable(el, {
28838 minWidth: this.minWidth || 80,
28839 minHeight:this.minHeight || 80,
28840 handles: this.resizeHandles || "all",
28843 this.resizer.on("beforeresize", this.beforeResize, this);
28844 this.resizer.on("resize", this.onResize, this);
28846 if(this.draggable !== false){
28847 el.addClass("x-dlg-draggable");
28848 if (!this.proxyDrag) {
28849 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28852 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28854 dd.setHandleElId(this.header.id);
28855 dd.endDrag = this.endMove.createDelegate(this);
28856 dd.startDrag = this.startMove.createDelegate(this);
28857 dd.onDrag = this.onDrag.createDelegate(this);
28862 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28863 this.mask.enableDisplayMode("block");
28865 this.el.addClass("x-dlg-modal");
28868 this.shadow = new Roo.Shadow({
28869 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28870 offset : this.shadowOffset
28873 this.shadowOffset = 0;
28875 if(Roo.useShims && this.shim !== false){
28876 this.shim = this.el.createShim();
28877 this.shim.hide = this.hideAction;
28885 if (this.buttons) {
28886 var bts= this.buttons;
28888 Roo.each(bts, function(b) {
28897 * Fires when a key is pressed
28898 * @param {Roo.BasicDialog} this
28899 * @param {Roo.EventObject} e
28904 * Fires when this dialog is moved by the user.
28905 * @param {Roo.BasicDialog} this
28906 * @param {Number} x The new page X
28907 * @param {Number} y The new page Y
28912 * Fires when this dialog is resized by the user.
28913 * @param {Roo.BasicDialog} this
28914 * @param {Number} width The new width
28915 * @param {Number} height The new height
28919 * @event beforehide
28920 * Fires before this dialog is hidden.
28921 * @param {Roo.BasicDialog} this
28923 "beforehide" : true,
28926 * Fires when this dialog is hidden.
28927 * @param {Roo.BasicDialog} this
28931 * @event beforeshow
28932 * Fires before this dialog is shown.
28933 * @param {Roo.BasicDialog} this
28935 "beforeshow" : true,
28938 * Fires when this dialog is shown.
28939 * @param {Roo.BasicDialog} this
28943 el.on("keydown", this.onKeyDown, this);
28944 el.on("mousedown", this.toFront, this);
28945 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28947 Roo.DialogManager.register(this);
28948 Roo.BasicDialog.superclass.constructor.call(this);
28951 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28952 shadowOffset: Roo.isIE ? 6 : 5,
28955 minButtonWidth: 75,
28956 defaultButton: null,
28957 buttonAlign: "right",
28962 * Sets the dialog title text
28963 * @param {String} text The title text to display
28964 * @return {Roo.BasicDialog} this
28966 setTitle : function(text){
28967 this.header.update(text);
28972 closeClick : function(){
28977 collapseClick : function(){
28978 this[this.collapsed ? "expand" : "collapse"]();
28982 * Collapses the dialog to its minimized state (only the title bar is visible).
28983 * Equivalent to the user clicking the collapse dialog button.
28985 collapse : function(){
28986 if(!this.collapsed){
28987 this.collapsed = true;
28988 this.el.addClass("x-dlg-collapsed");
28989 this.restoreHeight = this.el.getHeight();
28990 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28995 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28996 * clicking the expand dialog button.
28998 expand : function(){
28999 if(this.collapsed){
29000 this.collapsed = false;
29001 this.el.removeClass("x-dlg-collapsed");
29002 this.resizeTo(this.el.getWidth(), this.restoreHeight);
29007 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
29008 * @return {Roo.TabPanel} The tabs component
29010 initTabs : function(){
29011 var tabs = this.getTabs();
29012 while(tabs.getTab(0)){
29015 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
29017 tabs.addTab(Roo.id(dom), dom.title);
29025 beforeResize : function(){
29026 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
29030 onResize : function(){
29031 this.refreshSize();
29032 this.syncBodyHeight();
29033 this.adjustAssets();
29035 this.fireEvent("resize", this, this.size.width, this.size.height);
29039 onKeyDown : function(e){
29040 if(this.isVisible()){
29041 this.fireEvent("keydown", this, e);
29046 * Resizes the dialog.
29047 * @param {Number} width
29048 * @param {Number} height
29049 * @return {Roo.BasicDialog} this
29051 resizeTo : function(width, height){
29052 this.el.setSize(width, height);
29053 this.size = {width: width, height: height};
29054 this.syncBodyHeight();
29055 if(this.fixedcenter){
29058 if(this.isVisible()){
29059 this.constrainXY();
29060 this.adjustAssets();
29062 this.fireEvent("resize", this, width, height);
29068 * Resizes the dialog to fit the specified content size.
29069 * @param {Number} width
29070 * @param {Number} height
29071 * @return {Roo.BasicDialog} this
29073 setContentSize : function(w, h){
29074 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29075 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29076 //if(!this.el.isBorderBox()){
29077 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29078 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29081 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29082 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29084 this.resizeTo(w, h);
29089 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29090 * executed in response to a particular key being pressed while the dialog is active.
29091 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29092 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29093 * @param {Function} fn The function to call
29094 * @param {Object} scope (optional) The scope of the function
29095 * @return {Roo.BasicDialog} this
29097 addKeyListener : function(key, fn, scope){
29098 var keyCode, shift, ctrl, alt;
29099 if(typeof key == "object" && !(key instanceof Array)){
29100 keyCode = key["key"];
29101 shift = key["shift"];
29102 ctrl = key["ctrl"];
29107 var handler = function(dlg, e){
29108 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29109 var k = e.getKey();
29110 if(keyCode instanceof Array){
29111 for(var i = 0, len = keyCode.length; i < len; i++){
29112 if(keyCode[i] == k){
29113 fn.call(scope || window, dlg, k, e);
29119 fn.call(scope || window, dlg, k, e);
29124 this.on("keydown", handler);
29129 * Returns the TabPanel component (creates it if it doesn't exist).
29130 * Note: If you wish to simply check for the existence of tabs without creating them,
29131 * check for a null 'tabs' property.
29132 * @return {Roo.TabPanel} The tabs component
29134 getTabs : function(){
29136 this.el.addClass("x-dlg-auto-tabs");
29137 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29138 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29144 * Adds a button to the footer section of the dialog.
29145 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29146 * object or a valid Roo.DomHelper element config
29147 * @param {Function} handler The function called when the button is clicked
29148 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29149 * @return {Roo.Button} The new button
29151 addButton : function(config, handler, scope){
29152 var dh = Roo.DomHelper;
29154 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29156 if(!this.btnContainer){
29157 var tb = this.footer.createChild({
29159 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29160 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29162 this.btnContainer = tb.firstChild.firstChild.firstChild;
29167 minWidth: this.minButtonWidth,
29170 if(typeof config == "string"){
29171 bconfig.text = config;
29174 bconfig.dhconfig = config;
29176 Roo.apply(bconfig, config);
29180 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29181 bconfig.position = Math.max(0, bconfig.position);
29182 fc = this.btnContainer.childNodes[bconfig.position];
29185 var btn = new Roo.Button(
29187 this.btnContainer.insertBefore(document.createElement("td"),fc)
29188 : this.btnContainer.appendChild(document.createElement("td")),
29189 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29192 this.syncBodyHeight();
29195 * Array of all the buttons that have been added to this dialog via addButton
29200 this.buttons.push(btn);
29205 * Sets the default button to be focused when the dialog is displayed.
29206 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29207 * @return {Roo.BasicDialog} this
29209 setDefaultButton : function(btn){
29210 this.defaultButton = btn;
29215 getHeaderFooterHeight : function(safe){
29218 height += this.header.getHeight();
29221 var fm = this.footer.getMargins();
29222 height += (this.footer.getHeight()+fm.top+fm.bottom);
29224 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29225 height += this.centerBg.getPadding("tb");
29230 syncBodyHeight : function(){
29231 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29232 var height = this.size.height - this.getHeaderFooterHeight(false);
29233 bd.setHeight(height-bd.getMargins("tb"));
29234 var hh = this.header.getHeight();
29235 var h = this.size.height-hh;
29237 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29238 bw.setHeight(h-cb.getPadding("tb"));
29239 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29240 bd.setWidth(bw.getWidth(true));
29242 this.tabs.syncHeight();
29244 this.tabs.el.repaint();
29250 * Restores the previous state of the dialog if Roo.state is configured.
29251 * @return {Roo.BasicDialog} this
29253 restoreState : function(){
29254 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29255 if(box && box.width){
29256 this.xy = [box.x, box.y];
29257 this.resizeTo(box.width, box.height);
29263 beforeShow : function(){
29265 if(this.fixedcenter){
29266 this.xy = this.el.getCenterXY(true);
29269 Roo.get(document.body).addClass("x-body-masked");
29270 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29273 this.constrainXY();
29277 animShow : function(){
29278 var b = Roo.get(this.animateTarget).getBox();
29279 this.proxy.setSize(b.width, b.height);
29280 this.proxy.setLocation(b.x, b.y);
29282 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29283 true, .35, this.showEl.createDelegate(this));
29287 * Shows the dialog.
29288 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29289 * @return {Roo.BasicDialog} this
29291 show : function(animateTarget){
29292 if (this.fireEvent("beforeshow", this) === false){
29295 if(this.syncHeightBeforeShow){
29296 this.syncBodyHeight();
29297 }else if(this.firstShow){
29298 this.firstShow = false;
29299 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29301 this.animateTarget = animateTarget || this.animateTarget;
29302 if(!this.el.isVisible()){
29304 if(this.animateTarget && Roo.get(this.animateTarget)){
29314 showEl : function(){
29316 this.el.setXY(this.xy);
29318 this.adjustAssets(true);
29321 // IE peekaboo bug - fix found by Dave Fenwick
29325 this.fireEvent("show", this);
29329 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29330 * dialog itself will receive focus.
29332 focus : function(){
29333 if(this.defaultButton){
29334 this.defaultButton.focus();
29336 this.focusEl.focus();
29341 constrainXY : function(){
29342 if(this.constraintoviewport !== false){
29343 if(!this.viewSize){
29344 if(this.container){
29345 var s = this.container.getSize();
29346 this.viewSize = [s.width, s.height];
29348 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29351 var s = Roo.get(this.container||document).getScroll();
29353 var x = this.xy[0], y = this.xy[1];
29354 var w = this.size.width, h = this.size.height;
29355 var vw = this.viewSize[0], vh = this.viewSize[1];
29356 // only move it if it needs it
29358 // first validate right/bottom
29359 if(x + w > vw+s.left){
29363 if(y + h > vh+s.top){
29367 // then make sure top/left isn't negative
29379 if(this.isVisible()){
29380 this.el.setLocation(x, y);
29381 this.adjustAssets();
29388 onDrag : function(){
29389 if(!this.proxyDrag){
29390 this.xy = this.el.getXY();
29391 this.adjustAssets();
29396 adjustAssets : function(doShow){
29397 var x = this.xy[0], y = this.xy[1];
29398 var w = this.size.width, h = this.size.height;
29399 if(doShow === true){
29401 this.shadow.show(this.el);
29407 if(this.shadow && this.shadow.isVisible()){
29408 this.shadow.show(this.el);
29410 if(this.shim && this.shim.isVisible()){
29411 this.shim.setBounds(x, y, w, h);
29416 adjustViewport : function(w, h){
29418 w = Roo.lib.Dom.getViewWidth();
29419 h = Roo.lib.Dom.getViewHeight();
29422 this.viewSize = [w, h];
29423 if(this.modal && this.mask.isVisible()){
29424 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29425 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29427 if(this.isVisible()){
29428 this.constrainXY();
29433 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29434 * shadow, proxy, mask, etc.) Also removes all event listeners.
29435 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29437 destroy : function(removeEl){
29438 if(this.isVisible()){
29439 this.animateTarget = null;
29442 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29444 this.tabs.destroy(removeEl);
29457 for(var i = 0, len = this.buttons.length; i < len; i++){
29458 this.buttons[i].destroy();
29461 this.el.removeAllListeners();
29462 if(removeEl === true){
29463 this.el.update("");
29466 Roo.DialogManager.unregister(this);
29470 startMove : function(){
29471 if(this.proxyDrag){
29474 if(this.constraintoviewport !== false){
29475 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29480 endMove : function(){
29481 if(!this.proxyDrag){
29482 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29484 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29487 this.refreshSize();
29488 this.adjustAssets();
29490 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29494 * Brings this dialog to the front of any other visible dialogs
29495 * @return {Roo.BasicDialog} this
29497 toFront : function(){
29498 Roo.DialogManager.bringToFront(this);
29503 * Sends this dialog to the back (under) of any other visible dialogs
29504 * @return {Roo.BasicDialog} this
29506 toBack : function(){
29507 Roo.DialogManager.sendToBack(this);
29512 * Centers this dialog in the viewport
29513 * @return {Roo.BasicDialog} this
29515 center : function(){
29516 var xy = this.el.getCenterXY(true);
29517 this.moveTo(xy[0], xy[1]);
29522 * Moves the dialog's top-left corner to the specified point
29523 * @param {Number} x
29524 * @param {Number} y
29525 * @return {Roo.BasicDialog} this
29527 moveTo : function(x, y){
29529 if(this.isVisible()){
29530 this.el.setXY(this.xy);
29531 this.adjustAssets();
29537 * Aligns the dialog to the specified element
29538 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29539 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29540 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29541 * @return {Roo.BasicDialog} this
29543 alignTo : function(element, position, offsets){
29544 this.xy = this.el.getAlignToXY(element, position, offsets);
29545 if(this.isVisible()){
29546 this.el.setXY(this.xy);
29547 this.adjustAssets();
29553 * Anchors an element to another element and realigns it when the window is resized.
29554 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29555 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29556 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29557 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29558 * is a number, it is used as the buffer delay (defaults to 50ms).
29559 * @return {Roo.BasicDialog} this
29561 anchorTo : function(el, alignment, offsets, monitorScroll){
29562 var action = function(){
29563 this.alignTo(el, alignment, offsets);
29565 Roo.EventManager.onWindowResize(action, this);
29566 var tm = typeof monitorScroll;
29567 if(tm != 'undefined'){
29568 Roo.EventManager.on(window, 'scroll', action, this,
29569 {buffer: tm == 'number' ? monitorScroll : 50});
29576 * Returns true if the dialog is visible
29577 * @return {Boolean}
29579 isVisible : function(){
29580 return this.el.isVisible();
29584 animHide : function(callback){
29585 var b = Roo.get(this.animateTarget).getBox();
29587 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29589 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29590 this.hideEl.createDelegate(this, [callback]));
29594 * Hides the dialog.
29595 * @param {Function} callback (optional) Function to call when the dialog is hidden
29596 * @return {Roo.BasicDialog} this
29598 hide : function(callback){
29599 if (this.fireEvent("beforehide", this) === false){
29603 this.shadow.hide();
29608 // sometimes animateTarget seems to get set.. causing problems...
29609 // this just double checks..
29610 if(this.animateTarget && Roo.get(this.animateTarget)) {
29611 this.animHide(callback);
29614 this.hideEl(callback);
29620 hideEl : function(callback){
29624 Roo.get(document.body).removeClass("x-body-masked");
29626 this.fireEvent("hide", this);
29627 if(typeof callback == "function"){
29633 hideAction : function(){
29634 this.setLeft("-10000px");
29635 this.setTop("-10000px");
29636 this.setStyle("visibility", "hidden");
29640 refreshSize : function(){
29641 this.size = this.el.getSize();
29642 this.xy = this.el.getXY();
29643 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29647 // z-index is managed by the DialogManager and may be overwritten at any time
29648 setZIndex : function(index){
29650 this.mask.setStyle("z-index", index);
29653 this.shim.setStyle("z-index", ++index);
29656 this.shadow.setZIndex(++index);
29658 this.el.setStyle("z-index", ++index);
29660 this.proxy.setStyle("z-index", ++index);
29663 this.resizer.proxy.setStyle("z-index", ++index);
29666 this.lastZIndex = index;
29670 * Returns the element for this dialog
29671 * @return {Roo.Element} The underlying dialog Element
29673 getEl : function(){
29679 * @class Roo.DialogManager
29680 * Provides global access to BasicDialogs that have been created and
29681 * support for z-indexing (layering) multiple open dialogs.
29683 Roo.DialogManager = function(){
29685 var accessList = [];
29689 var sortDialogs = function(d1, d2){
29690 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29694 var orderDialogs = function(){
29695 accessList.sort(sortDialogs);
29696 var seed = Roo.DialogManager.zseed;
29697 for(var i = 0, len = accessList.length; i < len; i++){
29698 var dlg = accessList[i];
29700 dlg.setZIndex(seed + (i*10));
29707 * The starting z-index for BasicDialogs (defaults to 9000)
29708 * @type Number The z-index value
29713 register : function(dlg){
29714 list[dlg.id] = dlg;
29715 accessList.push(dlg);
29719 unregister : function(dlg){
29720 delete list[dlg.id];
29723 if(!accessList.indexOf){
29724 for( i = 0, len = accessList.length; i < len; i++){
29725 if(accessList[i] == dlg){
29726 accessList.splice(i, 1);
29731 i = accessList.indexOf(dlg);
29733 accessList.splice(i, 1);
29739 * Gets a registered dialog by id
29740 * @param {String/Object} id The id of the dialog or a dialog
29741 * @return {Roo.BasicDialog} this
29743 get : function(id){
29744 return typeof id == "object" ? id : list[id];
29748 * Brings the specified dialog to the front
29749 * @param {String/Object} dlg The id of the dialog or a dialog
29750 * @return {Roo.BasicDialog} this
29752 bringToFront : function(dlg){
29753 dlg = this.get(dlg);
29756 dlg._lastAccess = new Date().getTime();
29763 * Sends the specified dialog to the back
29764 * @param {String/Object} dlg The id of the dialog or a dialog
29765 * @return {Roo.BasicDialog} this
29767 sendToBack : function(dlg){
29768 dlg = this.get(dlg);
29769 dlg._lastAccess = -(new Date().getTime());
29775 * Hides all dialogs
29777 hideAll : function(){
29778 for(var id in list){
29779 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29788 * @class Roo.LayoutDialog
29789 * @extends Roo.BasicDialog
29790 * Dialog which provides adjustments for working with a layout in a Dialog.
29791 * Add your necessary layout config options to the dialog's config.<br>
29792 * Example usage (including a nested layout):
29795 dialog = new Roo.LayoutDialog("download-dlg", {
29804 // layout config merges with the dialog config
29806 tabPosition: "top",
29807 alwaysShowTabs: true
29810 dialog.addKeyListener(27, dialog.hide, dialog);
29811 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29812 dialog.addButton("Build It!", this.getDownload, this);
29814 // we can even add nested layouts
29815 var innerLayout = new Roo.BorderLayout("dl-inner", {
29825 innerLayout.beginUpdate();
29826 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29827 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29828 innerLayout.endUpdate(true);
29830 var layout = dialog.getLayout();
29831 layout.beginUpdate();
29832 layout.add("center", new Roo.ContentPanel("standard-panel",
29833 {title: "Download the Source", fitToFrame:true}));
29834 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29835 {title: "Build your own roo.js"}));
29836 layout.getRegion("center").showPanel(sp);
29837 layout.endUpdate();
29841 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29842 * @param {Object} config configuration options
29844 Roo.LayoutDialog = function(el, cfg){
29847 if (typeof(cfg) == 'undefined') {
29848 config = Roo.apply({}, el);
29849 // not sure why we use documentElement here.. - it should always be body.
29850 // IE7 borks horribly if we use documentElement.
29851 // webkit also does not like documentElement - it creates a body element...
29852 el = Roo.get( document.body || document.documentElement ).createChild();
29853 //config.autoCreate = true;
29857 config.autoTabs = false;
29858 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29859 this.body.setStyle({overflow:"hidden", position:"relative"});
29860 this.layout = new Roo.BorderLayout(this.body.dom, config);
29861 this.layout.monitorWindowResize = false;
29862 this.el.addClass("x-dlg-auto-layout");
29863 // fix case when center region overwrites center function
29864 this.center = Roo.BasicDialog.prototype.center;
29865 this.on("show", this.layout.layout, this.layout, true);
29866 if (config.items) {
29867 var xitems = config.items;
29868 delete config.items;
29869 Roo.each(xitems, this.addxtype, this);
29874 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29876 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29879 endUpdate : function(){
29880 this.layout.endUpdate();
29884 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29887 beginUpdate : function(){
29888 this.layout.beginUpdate();
29892 * Get the BorderLayout for this dialog
29893 * @return {Roo.BorderLayout}
29895 getLayout : function(){
29896 return this.layout;
29899 showEl : function(){
29900 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29902 this.layout.layout();
29907 // Use the syncHeightBeforeShow config option to control this automatically
29908 syncBodyHeight : function(){
29909 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29910 if(this.layout){this.layout.layout();}
29914 * Add an xtype element (actually adds to the layout.)
29915 * @return {Object} xdata xtype object data.
29918 addxtype : function(c) {
29919 return this.layout.addxtype(c);
29923 * Ext JS Library 1.1.1
29924 * Copyright(c) 2006-2007, Ext JS, LLC.
29926 * Originally Released Under LGPL - original licence link has changed is not relivant.
29929 * <script type="text/javascript">
29933 * @class Roo.MessageBox
29934 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29938 Roo.Msg.alert('Status', 'Changes saved successfully.');
29940 // Prompt for user data:
29941 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29943 // process text value...
29947 // Show a dialog using config options:
29949 title:'Save Changes?',
29950 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29951 buttons: Roo.Msg.YESNOCANCEL,
29958 Roo.MessageBox = function(){
29959 var dlg, opt, mask, waitTimer;
29960 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29961 var buttons, activeTextEl, bwidth;
29964 var handleButton = function(button){
29966 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29970 var handleHide = function(){
29971 if(opt && opt.cls){
29972 dlg.el.removeClass(opt.cls);
29975 Roo.TaskMgr.stop(waitTimer);
29981 var updateButtons = function(b){
29984 buttons["ok"].hide();
29985 buttons["cancel"].hide();
29986 buttons["yes"].hide();
29987 buttons["no"].hide();
29988 dlg.footer.dom.style.display = 'none';
29991 dlg.footer.dom.style.display = '';
29992 for(var k in buttons){
29993 if(typeof buttons[k] != "function"){
29996 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29997 width += buttons[k].el.getWidth()+15;
30007 var handleEsc = function(d, k, e){
30008 if(opt && opt.closable !== false){
30018 * Returns a reference to the underlying {@link Roo.BasicDialog} element
30019 * @return {Roo.BasicDialog} The BasicDialog element
30021 getDialog : function(){
30023 dlg = new Roo.BasicDialog("x-msg-box", {
30028 constraintoviewport:false,
30030 collapsible : false,
30033 width:400, height:100,
30034 buttonAlign:"center",
30035 closeClick : function(){
30036 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
30037 handleButton("no");
30039 handleButton("cancel");
30043 dlg.on("hide", handleHide);
30045 dlg.addKeyListener(27, handleEsc);
30047 var bt = this.buttonText;
30048 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
30049 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
30050 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
30051 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
30052 bodyEl = dlg.body.createChild({
30054 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>'
30056 msgEl = bodyEl.dom.firstChild;
30057 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
30058 textboxEl.enableDisplayMode();
30059 textboxEl.addKeyListener([10,13], function(){
30060 if(dlg.isVisible() && opt && opt.buttons){
30061 if(opt.buttons.ok){
30062 handleButton("ok");
30063 }else if(opt.buttons.yes){
30064 handleButton("yes");
30068 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
30069 textareaEl.enableDisplayMode();
30070 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
30071 progressEl.enableDisplayMode();
30072 var pf = progressEl.dom.firstChild;
30074 pp = Roo.get(pf.firstChild);
30075 pp.setHeight(pf.offsetHeight);
30083 * Updates the message box body text
30084 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30085 * the XHTML-compliant non-breaking space character '&#160;')
30086 * @return {Roo.MessageBox} This message box
30088 updateText : function(text){
30089 if(!dlg.isVisible() && !opt.width){
30090 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30092 msgEl.innerHTML = text || ' ';
30093 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
30094 Math.max(opt.minWidth || this.minWidth, bwidth));
30096 activeTextEl.setWidth(w);
30098 if(dlg.isVisible()){
30099 dlg.fixedcenter = false;
30101 // to big, make it scoll.
30102 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
30103 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
30104 bodyEl.dom.style.overflowY = 'auto';
30106 bodyEl.dom.style.height = '';
30107 bodyEl.dom.style.overflowY = '';
30110 dlg.setContentSize(w, bodyEl.getHeight());
30111 if(dlg.isVisible()){
30112 dlg.fixedcenter = true;
30118 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30119 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30120 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30121 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30122 * @return {Roo.MessageBox} This message box
30124 updateProgress : function(value, text){
30126 this.updateText(text);
30128 if (pp) { // weird bug on my firefox - for some reason this is not defined
30129 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30135 * Returns true if the message box is currently displayed
30136 * @return {Boolean} True if the message box is visible, else false
30138 isVisible : function(){
30139 return dlg && dlg.isVisible();
30143 * Hides the message box if it is displayed
30146 if(this.isVisible()){
30152 * Displays a new message box, or reinitializes an existing message box, based on the config options
30153 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30154 * The following config object properties are supported:
30156 Property Type Description
30157 ---------- --------------- ------------------------------------------------------------------------------------
30158 animEl String/Element An id or Element from which the message box should animate as it opens and
30159 closes (defaults to undefined)
30160 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30161 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30162 closable Boolean False to hide the top-right close button (defaults to true). Note that
30163 progress and wait dialogs will ignore this property and always hide the
30164 close button as they can only be closed programmatically.
30165 cls String A custom CSS class to apply to the message box element
30166 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30167 displayed (defaults to 75)
30168 fn Function A callback function to execute after closing the dialog. The arguments to the
30169 function will be btn (the name of the button that was clicked, if applicable,
30170 e.g. "ok"), and text (the value of the active text field, if applicable).
30171 Progress and wait dialogs will ignore this option since they do not respond to
30172 user actions and can only be closed programmatically, so any required function
30173 should be called by the same code after it closes the dialog.
30174 icon String A CSS class that provides a background image to be used as an icon for
30175 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30176 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30177 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30178 modal Boolean False to allow user interaction with the page while the message box is
30179 displayed (defaults to true)
30180 msg String A string that will replace the existing message box body text (defaults
30181 to the XHTML-compliant non-breaking space character ' ')
30182 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30183 progress Boolean True to display a progress bar (defaults to false)
30184 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30185 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30186 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30187 title String The title text
30188 value String The string value to set into the active textbox element if displayed
30189 wait Boolean True to display a progress bar (defaults to false)
30190 width Number The width of the dialog in pixels
30197 msg: 'Please enter your address:',
30199 buttons: Roo.MessageBox.OKCANCEL,
30202 animEl: 'addAddressBtn'
30205 * @param {Object} config Configuration options
30206 * @return {Roo.MessageBox} This message box
30208 show : function(options)
30211 // this causes nightmares if you show one dialog after another
30212 // especially on callbacks..
30214 if(this.isVisible()){
30217 Roo.log("Old Dialog Message:" + msgEl.innerHTML )
30218 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
30219 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
30222 var d = this.getDialog();
30224 d.setTitle(opt.title || " ");
30225 d.close.setDisplayed(opt.closable !== false);
30226 activeTextEl = textboxEl;
30227 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30232 textareaEl.setHeight(typeof opt.multiline == "number" ?
30233 opt.multiline : this.defaultTextHeight);
30234 activeTextEl = textareaEl;
30243 progressEl.setDisplayed(opt.progress === true);
30244 this.updateProgress(0);
30245 activeTextEl.dom.value = opt.value || "";
30247 dlg.setDefaultButton(activeTextEl);
30249 var bs = opt.buttons;
30252 db = buttons["ok"];
30253 }else if(bs && bs.yes){
30254 db = buttons["yes"];
30256 dlg.setDefaultButton(db);
30258 bwidth = updateButtons(opt.buttons);
30259 this.updateText(opt.msg);
30261 d.el.addClass(opt.cls);
30263 d.proxyDrag = opt.proxyDrag === true;
30264 d.modal = opt.modal !== false;
30265 d.mask = opt.modal !== false ? mask : false;
30266 if(!d.isVisible()){
30267 // force it to the end of the z-index stack so it gets a cursor in FF
30268 document.body.appendChild(dlg.el.dom);
30269 d.animateTarget = null;
30270 d.show(options.animEl);
30276 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30277 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30278 * and closing the message box when the process is complete.
30279 * @param {String} title The title bar text
30280 * @param {String} msg The message box body text
30281 * @return {Roo.MessageBox} This message box
30283 progress : function(title, msg){
30290 minWidth: this.minProgressWidth,
30297 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30298 * If a callback function is passed it will be called after the user clicks the button, and the
30299 * id of the button that was clicked will be passed as the only parameter to the callback
30300 * (could also be the top-right close button).
30301 * @param {String} title The title bar text
30302 * @param {String} msg The message box body text
30303 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30304 * @param {Object} scope (optional) The scope of the callback function
30305 * @return {Roo.MessageBox} This message box
30307 alert : function(title, msg, fn, scope){
30320 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30321 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30322 * You are responsible for closing the message box when the process is complete.
30323 * @param {String} msg The message box body text
30324 * @param {String} title (optional) The title bar text
30325 * @return {Roo.MessageBox} This message box
30327 wait : function(msg, title){
30338 waitTimer = Roo.TaskMgr.start({
30340 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30348 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30349 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30350 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30351 * @param {String} title The title bar text
30352 * @param {String} msg The message box body text
30353 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30354 * @param {Object} scope (optional) The scope of the callback function
30355 * @return {Roo.MessageBox} This message box
30357 confirm : function(title, msg, fn, scope){
30361 buttons: this.YESNO,
30370 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30371 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30372 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30373 * (could also be the top-right close button) and the text that was entered will be passed as the two
30374 * parameters to the callback.
30375 * @param {String} title The title bar text
30376 * @param {String} msg The message box body text
30377 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30378 * @param {Object} scope (optional) The scope of the callback function
30379 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30380 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30381 * @return {Roo.MessageBox} This message box
30383 prompt : function(title, msg, fn, scope, multiline){
30387 buttons: this.OKCANCEL,
30392 multiline: multiline,
30399 * Button config that displays a single OK button
30404 * Button config that displays Yes and No buttons
30407 YESNO : {yes:true, no:true},
30409 * Button config that displays OK and Cancel buttons
30412 OKCANCEL : {ok:true, cancel:true},
30414 * Button config that displays Yes, No and Cancel buttons
30417 YESNOCANCEL : {yes:true, no:true, cancel:true},
30420 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30423 defaultTextHeight : 75,
30425 * The maximum width in pixels of the message box (defaults to 600)
30430 * The minimum width in pixels of the message box (defaults to 100)
30435 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30436 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30439 minProgressWidth : 250,
30441 * An object containing the default button text strings that can be overriden for localized language support.
30442 * Supported properties are: ok, cancel, yes and no.
30443 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30456 * Shorthand for {@link Roo.MessageBox}
30458 Roo.Msg = Roo.MessageBox;/*
30460 * Ext JS Library 1.1.1
30461 * Copyright(c) 2006-2007, Ext JS, LLC.
30463 * Originally Released Under LGPL - original licence link has changed is not relivant.
30466 * <script type="text/javascript">
30469 * @class Roo.QuickTips
30470 * Provides attractive and customizable tooltips for any element.
30473 Roo.QuickTips = function(){
30474 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30475 var ce, bd, xy, dd;
30476 var visible = false, disabled = true, inited = false;
30477 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30479 var onOver = function(e){
30483 var t = e.getTarget();
30484 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30487 if(ce && t == ce.el){
30488 clearTimeout(hideProc);
30491 if(t && tagEls[t.id]){
30492 tagEls[t.id].el = t;
30493 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30496 var ttp, et = Roo.fly(t);
30497 var ns = cfg.namespace;
30498 if(tm.interceptTitles && t.title){
30501 t.removeAttribute("title");
30502 e.preventDefault();
30504 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30507 showProc = show.defer(tm.showDelay, tm, [{
30510 width: et.getAttributeNS(ns, cfg.width),
30511 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30512 title: et.getAttributeNS(ns, cfg.title),
30513 cls: et.getAttributeNS(ns, cfg.cls)
30518 var onOut = function(e){
30519 clearTimeout(showProc);
30520 var t = e.getTarget();
30521 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30522 hideProc = setTimeout(hide, tm.hideDelay);
30526 var onMove = function(e){
30532 if(tm.trackMouse && ce){
30537 var onDown = function(e){
30538 clearTimeout(showProc);
30539 clearTimeout(hideProc);
30541 if(tm.hideOnClick){
30544 tm.enable.defer(100, tm);
30549 var getPad = function(){
30550 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30553 var show = function(o){
30557 clearTimeout(dismissProc);
30559 if(removeCls){ // in case manually hidden
30560 el.removeClass(removeCls);
30564 el.addClass(ce.cls);
30565 removeCls = ce.cls;
30568 tipTitle.update(ce.title);
30571 tipTitle.update('');
30574 el.dom.style.width = tm.maxWidth+'px';
30575 //tipBody.dom.style.width = '';
30576 tipBodyText.update(o.text);
30577 var p = getPad(), w = ce.width;
30579 var td = tipBodyText.dom;
30580 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30581 if(aw > tm.maxWidth){
30583 }else if(aw < tm.minWidth){
30589 //tipBody.setWidth(w);
30590 el.setWidth(parseInt(w, 10) + p);
30591 if(ce.autoHide === false){
30592 close.setDisplayed(true);
30597 close.setDisplayed(false);
30603 el.avoidY = xy[1]-18;
30608 el.setStyle("visibility", "visible");
30609 el.fadeIn({callback: afterShow});
30615 var afterShow = function(){
30619 if(tm.autoDismiss && ce.autoHide !== false){
30620 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30625 var hide = function(noanim){
30626 clearTimeout(dismissProc);
30627 clearTimeout(hideProc);
30629 if(el.isVisible()){
30631 if(noanim !== true && tm.animate){
30632 el.fadeOut({callback: afterHide});
30639 var afterHide = function(){
30642 el.removeClass(removeCls);
30649 * @cfg {Number} minWidth
30650 * The minimum width of the quick tip (defaults to 40)
30654 * @cfg {Number} maxWidth
30655 * The maximum width of the quick tip (defaults to 300)
30659 * @cfg {Boolean} interceptTitles
30660 * True to automatically use the element's DOM title value if available (defaults to false)
30662 interceptTitles : false,
30664 * @cfg {Boolean} trackMouse
30665 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30667 trackMouse : false,
30669 * @cfg {Boolean} hideOnClick
30670 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30672 hideOnClick : true,
30674 * @cfg {Number} showDelay
30675 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30679 * @cfg {Number} hideDelay
30680 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30684 * @cfg {Boolean} autoHide
30685 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30686 * Used in conjunction with hideDelay.
30691 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30692 * (defaults to true). Used in conjunction with autoDismissDelay.
30694 autoDismiss : true,
30697 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30699 autoDismissDelay : 5000,
30701 * @cfg {Boolean} animate
30702 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30707 * @cfg {String} title
30708 * Title text to display (defaults to ''). This can be any valid HTML markup.
30712 * @cfg {String} text
30713 * Body text to display (defaults to ''). This can be any valid HTML markup.
30717 * @cfg {String} cls
30718 * A CSS class to apply to the base quick tip element (defaults to '').
30722 * @cfg {Number} width
30723 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30724 * minWidth or maxWidth.
30729 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30730 * or display QuickTips in a page.
30733 tm = Roo.QuickTips;
30734 cfg = tm.tagConfig;
30736 if(!Roo.isReady){ // allow calling of init() before onReady
30737 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30740 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30741 el.fxDefaults = {stopFx: true};
30742 // maximum custom styling
30743 //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>');
30744 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>');
30745 tipTitle = el.child('h3');
30746 tipTitle.enableDisplayMode("block");
30747 tipBody = el.child('div.x-tip-bd');
30748 tipBodyText = el.child('div.x-tip-bd-inner');
30749 //bdLeft = el.child('div.x-tip-bd-left');
30750 //bdRight = el.child('div.x-tip-bd-right');
30751 close = el.child('div.x-tip-close');
30752 close.enableDisplayMode("block");
30753 close.on("click", hide);
30754 var d = Roo.get(document);
30755 d.on("mousedown", onDown);
30756 d.on("mouseover", onOver);
30757 d.on("mouseout", onOut);
30758 d.on("mousemove", onMove);
30759 esc = d.addKeyListener(27, hide);
30762 dd = el.initDD("default", null, {
30763 onDrag : function(){
30767 dd.setHandleElId(tipTitle.id);
30776 * Configures a new quick tip instance and assigns it to a target element. The following config options
30779 Property Type Description
30780 ---------- --------------------- ------------------------------------------------------------------------
30781 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30783 * @param {Object} config The config object
30785 register : function(config){
30786 var cs = config instanceof Array ? config : arguments;
30787 for(var i = 0, len = cs.length; i < len; i++) {
30789 var target = c.target;
30791 if(target instanceof Array){
30792 for(var j = 0, jlen = target.length; j < jlen; j++){
30793 tagEls[target[j]] = c;
30796 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30803 * Removes this quick tip from its element and destroys it.
30804 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30806 unregister : function(el){
30807 delete tagEls[Roo.id(el)];
30811 * Enable this quick tip.
30813 enable : function(){
30814 if(inited && disabled){
30816 if(locks.length < 1){
30823 * Disable this quick tip.
30825 disable : function(){
30827 clearTimeout(showProc);
30828 clearTimeout(hideProc);
30829 clearTimeout(dismissProc);
30837 * Returns true if the quick tip is enabled, else false.
30839 isEnabled : function(){
30846 attribute : "qtip",
30856 // backwards compat
30857 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30859 * Ext JS Library 1.1.1
30860 * Copyright(c) 2006-2007, Ext JS, LLC.
30862 * Originally Released Under LGPL - original licence link has changed is not relivant.
30865 * <script type="text/javascript">
30870 * @class Roo.tree.TreePanel
30871 * @extends Roo.data.Tree
30873 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30874 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30875 * @cfg {Boolean} enableDD true to enable drag and drop
30876 * @cfg {Boolean} enableDrag true to enable just drag
30877 * @cfg {Boolean} enableDrop true to enable just drop
30878 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30879 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30880 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30881 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30882 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30883 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30884 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30885 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30886 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30887 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30888 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30889 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30890 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
30891 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30892 * @cfg {Function} renderer DEPRECATED - use TreeLoader:create event / 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>
30893 * @cfg {Function} rendererTip DEPRECATED - use TreeLoader:create event / 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>
30896 * @param {String/HTMLElement/Element} el The container element
30897 * @param {Object} config
30899 Roo.tree.TreePanel = function(el, config){
30901 var loader = false;
30903 root = config.root;
30904 delete config.root;
30906 if (config.loader) {
30907 loader = config.loader;
30908 delete config.loader;
30911 Roo.apply(this, config);
30912 Roo.tree.TreePanel.superclass.constructor.call(this);
30913 this.el = Roo.get(el);
30914 this.el.addClass('x-tree');
30915 //console.log(root);
30917 this.setRootNode( Roo.factory(root, Roo.tree));
30920 this.loader = Roo.factory(loader, Roo.tree);
30923 * Read-only. The id of the container element becomes this TreePanel's id.
30925 this.id = this.el.id;
30928 * @event beforeload
30929 * Fires before a node is loaded, return false to cancel
30930 * @param {Node} node The node being loaded
30932 "beforeload" : true,
30935 * Fires when a node is loaded
30936 * @param {Node} node The node that was loaded
30940 * @event textchange
30941 * Fires when the text for a node is changed
30942 * @param {Node} node The node
30943 * @param {String} text The new text
30944 * @param {String} oldText The old text
30946 "textchange" : true,
30948 * @event beforeexpand
30949 * Fires before a node is expanded, return false to cancel.
30950 * @param {Node} node The node
30951 * @param {Boolean} deep
30952 * @param {Boolean} anim
30954 "beforeexpand" : true,
30956 * @event beforecollapse
30957 * Fires before a node is collapsed, return false to cancel.
30958 * @param {Node} node The node
30959 * @param {Boolean} deep
30960 * @param {Boolean} anim
30962 "beforecollapse" : true,
30965 * Fires when a node is expanded
30966 * @param {Node} node The node
30970 * @event disabledchange
30971 * Fires when the disabled status of a node changes
30972 * @param {Node} node The node
30973 * @param {Boolean} disabled
30975 "disabledchange" : true,
30978 * Fires when a node is collapsed
30979 * @param {Node} node The node
30983 * @event beforeclick
30984 * Fires before click processing on a node. Return false to cancel the default action.
30985 * @param {Node} node The node
30986 * @param {Roo.EventObject} e The event object
30988 "beforeclick":true,
30990 * @event checkchange
30991 * Fires when a node with a checkbox's checked property changes
30992 * @param {Node} this This node
30993 * @param {Boolean} checked
30995 "checkchange":true,
30998 * Fires when a node is clicked
30999 * @param {Node} node The node
31000 * @param {Roo.EventObject} e The event object
31005 * Fires when a node is double clicked
31006 * @param {Node} node The node
31007 * @param {Roo.EventObject} e The event object
31011 * @event contextmenu
31012 * Fires when a node is right clicked
31013 * @param {Node} node The node
31014 * @param {Roo.EventObject} e The event object
31016 "contextmenu":true,
31018 * @event beforechildrenrendered
31019 * Fires right before the child nodes for a node are rendered
31020 * @param {Node} node The node
31022 "beforechildrenrendered":true,
31025 * Fires when a node starts being dragged
31026 * @param {Roo.tree.TreePanel} this
31027 * @param {Roo.tree.TreeNode} node
31028 * @param {event} e The raw browser event
31030 "startdrag" : true,
31033 * Fires when a drag operation is complete
31034 * @param {Roo.tree.TreePanel} this
31035 * @param {Roo.tree.TreeNode} node
31036 * @param {event} e The raw browser event
31041 * Fires when a dragged node is dropped on a valid DD target
31042 * @param {Roo.tree.TreePanel} this
31043 * @param {Roo.tree.TreeNode} node
31044 * @param {DD} dd The dd it was dropped on
31045 * @param {event} e The raw browser event
31049 * @event beforenodedrop
31050 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
31051 * passed to handlers has the following properties:<br />
31052 * <ul style="padding:5px;padding-left:16px;">
31053 * <li>tree - The TreePanel</li>
31054 * <li>target - The node being targeted for the drop</li>
31055 * <li>data - The drag data from the drag source</li>
31056 * <li>point - The point of the drop - append, above or below</li>
31057 * <li>source - The drag source</li>
31058 * <li>rawEvent - Raw mouse event</li>
31059 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
31060 * to be inserted by setting them on this object.</li>
31061 * <li>cancel - Set this to true to cancel the drop.</li>
31063 * @param {Object} dropEvent
31065 "beforenodedrop" : true,
31068 * Fires after a DD object is dropped on a node in this tree. The dropEvent
31069 * passed to handlers has the following properties:<br />
31070 * <ul style="padding:5px;padding-left:16px;">
31071 * <li>tree - The TreePanel</li>
31072 * <li>target - The node being targeted for the drop</li>
31073 * <li>data - The drag data from the drag source</li>
31074 * <li>point - The point of the drop - append, above or below</li>
31075 * <li>source - The drag source</li>
31076 * <li>rawEvent - Raw mouse event</li>
31077 * <li>dropNode - Dropped node(s).</li>
31079 * @param {Object} dropEvent
31083 * @event nodedragover
31084 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31085 * passed to handlers has the following properties:<br />
31086 * <ul style="padding:5px;padding-left:16px;">
31087 * <li>tree - The TreePanel</li>
31088 * <li>target - The node being targeted for the drop</li>
31089 * <li>data - The drag data from the drag source</li>
31090 * <li>point - The point of the drop - append, above or below</li>
31091 * <li>source - The drag source</li>
31092 * <li>rawEvent - Raw mouse event</li>
31093 * <li>dropNode - Drop node(s) provided by the source.</li>
31094 * <li>cancel - Set this to true to signal drop not allowed.</li>
31096 * @param {Object} dragOverEvent
31098 "nodedragover" : true
31101 if(this.singleExpand){
31102 this.on("beforeexpand", this.restrictExpand, this);
31105 this.editor.tree = this;
31106 this.editor = Roo.factory(this.editor, Roo.tree);
31109 if (this.selModel) {
31110 this.selModel = Roo.factory(this.selModel, Roo.tree);
31114 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31115 rootVisible : true,
31116 animate: Roo.enableFx,
31119 hlDrop : Roo.enableFx,
31123 rendererTip: false,
31125 restrictExpand : function(node){
31126 var p = node.parentNode;
31128 if(p.expandedChild && p.expandedChild.parentNode == p){
31129 p.expandedChild.collapse();
31131 p.expandedChild = node;
31135 // private override
31136 setRootNode : function(node){
31137 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31138 if(!this.rootVisible){
31139 node.ui = new Roo.tree.RootTreeNodeUI(node);
31145 * Returns the container element for this TreePanel
31147 getEl : function(){
31152 * Returns the default TreeLoader for this TreePanel
31154 getLoader : function(){
31155 return this.loader;
31161 expandAll : function(){
31162 this.root.expand(true);
31166 * Collapse all nodes
31168 collapseAll : function(){
31169 this.root.collapse(true);
31173 * Returns the selection model used by this TreePanel
31175 getSelectionModel : function(){
31176 if(!this.selModel){
31177 this.selModel = new Roo.tree.DefaultSelectionModel();
31179 return this.selModel;
31183 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31184 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31185 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31188 getChecked : function(a, startNode){
31189 startNode = startNode || this.root;
31191 var f = function(){
31192 if(this.attributes.checked){
31193 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31196 startNode.cascade(f);
31201 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31202 * @param {String} path
31203 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31204 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31205 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31207 expandPath : function(path, attr, callback){
31208 attr = attr || "id";
31209 var keys = path.split(this.pathSeparator);
31210 var curNode = this.root;
31211 if(curNode.attributes[attr] != keys[1]){ // invalid root
31213 callback(false, null);
31218 var f = function(){
31219 if(++index == keys.length){
31221 callback(true, curNode);
31225 var c = curNode.findChild(attr, keys[index]);
31228 callback(false, curNode);
31233 c.expand(false, false, f);
31235 curNode.expand(false, false, f);
31239 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31240 * @param {String} path
31241 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31242 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31243 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31245 selectPath : function(path, attr, callback){
31246 attr = attr || "id";
31247 var keys = path.split(this.pathSeparator);
31248 var v = keys.pop();
31249 if(keys.length > 0){
31250 var f = function(success, node){
31251 if(success && node){
31252 var n = node.findChild(attr, v);
31258 }else if(callback){
31259 callback(false, n);
31263 callback(false, n);
31267 this.expandPath(keys.join(this.pathSeparator), attr, f);
31269 this.root.select();
31271 callback(true, this.root);
31276 getTreeEl : function(){
31281 * Trigger rendering of this TreePanel
31283 render : function(){
31284 if (this.innerCt) {
31285 return this; // stop it rendering more than once!!
31288 this.innerCt = this.el.createChild({tag:"ul",
31289 cls:"x-tree-root-ct " +
31290 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31292 if(this.containerScroll){
31293 Roo.dd.ScrollManager.register(this.el);
31295 if((this.enableDD || this.enableDrop) && !this.dropZone){
31297 * The dropZone used by this tree if drop is enabled
31298 * @type Roo.tree.TreeDropZone
31300 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31301 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31304 if((this.enableDD || this.enableDrag) && !this.dragZone){
31306 * The dragZone used by this tree if drag is enabled
31307 * @type Roo.tree.TreeDragZone
31309 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31310 ddGroup: this.ddGroup || "TreeDD",
31311 scroll: this.ddScroll
31314 this.getSelectionModel().init(this);
31316 console.log("ROOT not set in tree");
31319 this.root.render();
31320 if(!this.rootVisible){
31321 this.root.renderChildren();
31327 * Ext JS Library 1.1.1
31328 * Copyright(c) 2006-2007, Ext JS, LLC.
31330 * Originally Released Under LGPL - original licence link has changed is not relivant.
31333 * <script type="text/javascript">
31338 * @class Roo.tree.DefaultSelectionModel
31339 * @extends Roo.util.Observable
31340 * The default single selection for a TreePanel.
31341 * @param {Object} cfg Configuration
31343 Roo.tree.DefaultSelectionModel = function(cfg){
31344 this.selNode = null;
31350 * @event selectionchange
31351 * Fires when the selected node changes
31352 * @param {DefaultSelectionModel} this
31353 * @param {TreeNode} node the new selection
31355 "selectionchange" : true,
31358 * @event beforeselect
31359 * Fires before the selected node changes, return false to cancel the change
31360 * @param {DefaultSelectionModel} this
31361 * @param {TreeNode} node the new selection
31362 * @param {TreeNode} node the old selection
31364 "beforeselect" : true
31367 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
31370 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31371 init : function(tree){
31373 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31374 tree.on("click", this.onNodeClick, this);
31377 onNodeClick : function(node, e){
31378 if (e.ctrlKey && this.selNode == node) {
31379 this.unselect(node);
31387 * @param {TreeNode} node The node to select
31388 * @return {TreeNode} The selected node
31390 select : function(node){
31391 var last = this.selNode;
31392 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31394 last.ui.onSelectedChange(false);
31396 this.selNode = node;
31397 node.ui.onSelectedChange(true);
31398 this.fireEvent("selectionchange", this, node, last);
31405 * @param {TreeNode} node The node to unselect
31407 unselect : function(node){
31408 if(this.selNode == node){
31409 this.clearSelections();
31414 * Clear all selections
31416 clearSelections : function(){
31417 var n = this.selNode;
31419 n.ui.onSelectedChange(false);
31420 this.selNode = null;
31421 this.fireEvent("selectionchange", this, null);
31427 * Get the selected node
31428 * @return {TreeNode} The selected node
31430 getSelectedNode : function(){
31431 return this.selNode;
31435 * Returns true if the node is selected
31436 * @param {TreeNode} node The node to check
31437 * @return {Boolean}
31439 isSelected : function(node){
31440 return this.selNode == node;
31444 * Selects the node above the selected node in the tree, intelligently walking the nodes
31445 * @return TreeNode The new selection
31447 selectPrevious : function(){
31448 var s = this.selNode || this.lastSelNode;
31452 var ps = s.previousSibling;
31454 if(!ps.isExpanded() || ps.childNodes.length < 1){
31455 return this.select(ps);
31457 var lc = ps.lastChild;
31458 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31461 return this.select(lc);
31463 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31464 return this.select(s.parentNode);
31470 * Selects the node above the selected node in the tree, intelligently walking the nodes
31471 * @return TreeNode The new selection
31473 selectNext : function(){
31474 var s = this.selNode || this.lastSelNode;
31478 if(s.firstChild && s.isExpanded()){
31479 return this.select(s.firstChild);
31480 }else if(s.nextSibling){
31481 return this.select(s.nextSibling);
31482 }else if(s.parentNode){
31484 s.parentNode.bubble(function(){
31485 if(this.nextSibling){
31486 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31495 onKeyDown : function(e){
31496 var s = this.selNode || this.lastSelNode;
31497 // undesirable, but required
31502 var k = e.getKey();
31510 this.selectPrevious();
31513 e.preventDefault();
31514 if(s.hasChildNodes()){
31515 if(!s.isExpanded()){
31517 }else if(s.firstChild){
31518 this.select(s.firstChild, e);
31523 e.preventDefault();
31524 if(s.hasChildNodes() && s.isExpanded()){
31526 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31527 this.select(s.parentNode, e);
31535 * @class Roo.tree.MultiSelectionModel
31536 * @extends Roo.util.Observable
31537 * Multi selection for a TreePanel.
31538 * @param {Object} cfg Configuration
31540 Roo.tree.MultiSelectionModel = function(){
31541 this.selNodes = [];
31545 * @event selectionchange
31546 * Fires when the selected nodes change
31547 * @param {MultiSelectionModel} this
31548 * @param {Array} nodes Array of the selected nodes
31550 "selectionchange" : true
31552 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
31556 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31557 init : function(tree){
31559 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31560 tree.on("click", this.onNodeClick, this);
31563 onNodeClick : function(node, e){
31564 this.select(node, e, e.ctrlKey);
31569 * @param {TreeNode} node The node to select
31570 * @param {EventObject} e (optional) An event associated with the selection
31571 * @param {Boolean} keepExisting True to retain existing selections
31572 * @return {TreeNode} The selected node
31574 select : function(node, e, keepExisting){
31575 if(keepExisting !== true){
31576 this.clearSelections(true);
31578 if(this.isSelected(node)){
31579 this.lastSelNode = node;
31582 this.selNodes.push(node);
31583 this.selMap[node.id] = node;
31584 this.lastSelNode = node;
31585 node.ui.onSelectedChange(true);
31586 this.fireEvent("selectionchange", this, this.selNodes);
31592 * @param {TreeNode} node The node to unselect
31594 unselect : function(node){
31595 if(this.selMap[node.id]){
31596 node.ui.onSelectedChange(false);
31597 var sn = this.selNodes;
31600 index = sn.indexOf(node);
31602 for(var i = 0, len = sn.length; i < len; i++){
31610 this.selNodes.splice(index, 1);
31612 delete this.selMap[node.id];
31613 this.fireEvent("selectionchange", this, this.selNodes);
31618 * Clear all selections
31620 clearSelections : function(suppressEvent){
31621 var sn = this.selNodes;
31623 for(var i = 0, len = sn.length; i < len; i++){
31624 sn[i].ui.onSelectedChange(false);
31626 this.selNodes = [];
31628 if(suppressEvent !== true){
31629 this.fireEvent("selectionchange", this, this.selNodes);
31635 * Returns true if the node is selected
31636 * @param {TreeNode} node The node to check
31637 * @return {Boolean}
31639 isSelected : function(node){
31640 return this.selMap[node.id] ? true : false;
31644 * Returns an array of the selected nodes
31647 getSelectedNodes : function(){
31648 return this.selNodes;
31651 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31653 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31655 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31658 * Ext JS Library 1.1.1
31659 * Copyright(c) 2006-2007, Ext JS, LLC.
31661 * Originally Released Under LGPL - original licence link has changed is not relivant.
31664 * <script type="text/javascript">
31668 * @class Roo.tree.TreeNode
31669 * @extends Roo.data.Node
31670 * @cfg {String} text The text for this node
31671 * @cfg {Boolean} expanded true to start the node expanded
31672 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31673 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31674 * @cfg {Boolean} disabled true to start the node disabled
31675 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31676 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31677 * @cfg {String} cls A css class to be added to the node
31678 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31679 * @cfg {String} href URL of the link used for the node (defaults to #)
31680 * @cfg {String} hrefTarget target frame for the link
31681 * @cfg {String} qtip An Ext QuickTip for the node
31682 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31683 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31684 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31685 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31686 * (defaults to undefined with no checkbox rendered)
31688 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31690 Roo.tree.TreeNode = function(attributes){
31691 attributes = attributes || {};
31692 if(typeof attributes == "string"){
31693 attributes = {text: attributes};
31695 this.childrenRendered = false;
31696 this.rendered = false;
31697 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31698 this.expanded = attributes.expanded === true;
31699 this.isTarget = attributes.isTarget !== false;
31700 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31701 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31704 * Read-only. The text for this node. To change it use setText().
31707 this.text = attributes.text;
31709 * True if this node is disabled.
31712 this.disabled = attributes.disabled === true;
31716 * @event textchange
31717 * Fires when the text for this node is changed
31718 * @param {Node} this This node
31719 * @param {String} text The new text
31720 * @param {String} oldText The old text
31722 "textchange" : true,
31724 * @event beforeexpand
31725 * Fires before this node is expanded, return false to cancel.
31726 * @param {Node} this This node
31727 * @param {Boolean} deep
31728 * @param {Boolean} anim
31730 "beforeexpand" : true,
31732 * @event beforecollapse
31733 * Fires before this node is collapsed, return false to cancel.
31734 * @param {Node} this This node
31735 * @param {Boolean} deep
31736 * @param {Boolean} anim
31738 "beforecollapse" : true,
31741 * Fires when this node is expanded
31742 * @param {Node} this This node
31746 * @event disabledchange
31747 * Fires when the disabled status of this node changes
31748 * @param {Node} this This node
31749 * @param {Boolean} disabled
31751 "disabledchange" : true,
31754 * Fires when this node is collapsed
31755 * @param {Node} this This node
31759 * @event beforeclick
31760 * Fires before click processing. Return false to cancel the default action.
31761 * @param {Node} this This node
31762 * @param {Roo.EventObject} e The event object
31764 "beforeclick":true,
31766 * @event checkchange
31767 * Fires when a node with a checkbox's checked property changes
31768 * @param {Node} this This node
31769 * @param {Boolean} checked
31771 "checkchange":true,
31774 * Fires when this node is clicked
31775 * @param {Node} this This node
31776 * @param {Roo.EventObject} e The event object
31781 * Fires when this node is double clicked
31782 * @param {Node} this This node
31783 * @param {Roo.EventObject} e The event object
31787 * @event contextmenu
31788 * Fires when this node is right clicked
31789 * @param {Node} this This node
31790 * @param {Roo.EventObject} e The event object
31792 "contextmenu":true,
31794 * @event beforechildrenrendered
31795 * Fires right before the child nodes for this node are rendered
31796 * @param {Node} this This node
31798 "beforechildrenrendered":true
31801 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31804 * Read-only. The UI for this node
31807 this.ui = new uiClass(this);
31809 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31810 preventHScroll: true,
31812 * Returns true if this node is expanded
31813 * @return {Boolean}
31815 isExpanded : function(){
31816 return this.expanded;
31820 * Returns the UI object for this node
31821 * @return {TreeNodeUI}
31823 getUI : function(){
31827 // private override
31828 setFirstChild : function(node){
31829 var of = this.firstChild;
31830 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31831 if(this.childrenRendered && of && node != of){
31832 of.renderIndent(true, true);
31835 this.renderIndent(true, true);
31839 // private override
31840 setLastChild : function(node){
31841 var ol = this.lastChild;
31842 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31843 if(this.childrenRendered && ol && node != ol){
31844 ol.renderIndent(true, true);
31847 this.renderIndent(true, true);
31851 // these methods are overridden to provide lazy rendering support
31852 // private override
31853 appendChild : function(){
31854 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31855 if(node && this.childrenRendered){
31858 this.ui.updateExpandIcon();
31862 // private override
31863 removeChild : function(node){
31864 this.ownerTree.getSelectionModel().unselect(node);
31865 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31866 // if it's been rendered remove dom node
31867 if(this.childrenRendered){
31870 if(this.childNodes.length < 1){
31871 this.collapse(false, false);
31873 this.ui.updateExpandIcon();
31875 if(!this.firstChild) {
31876 this.childrenRendered = false;
31881 // private override
31882 insertBefore : function(node, refNode){
31883 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31884 if(newNode && refNode && this.childrenRendered){
31887 this.ui.updateExpandIcon();
31892 * Sets the text for this node
31893 * @param {String} text
31895 setText : function(text){
31896 var oldText = this.text;
31898 this.attributes.text = text;
31899 if(this.rendered){ // event without subscribing
31900 this.ui.onTextChange(this, text, oldText);
31902 this.fireEvent("textchange", this, text, oldText);
31906 * Triggers selection of this node
31908 select : function(){
31909 this.getOwnerTree().getSelectionModel().select(this);
31913 * Triggers deselection of this node
31915 unselect : function(){
31916 this.getOwnerTree().getSelectionModel().unselect(this);
31920 * Returns true if this node is selected
31921 * @return {Boolean}
31923 isSelected : function(){
31924 return this.getOwnerTree().getSelectionModel().isSelected(this);
31928 * Expand this node.
31929 * @param {Boolean} deep (optional) True to expand all children as well
31930 * @param {Boolean} anim (optional) false to cancel the default animation
31931 * @param {Function} callback (optional) A callback to be called when
31932 * expanding this node completes (does not wait for deep expand to complete).
31933 * Called with 1 parameter, this node.
31935 expand : function(deep, anim, callback){
31936 if(!this.expanded){
31937 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31940 if(!this.childrenRendered){
31941 this.renderChildren();
31943 this.expanded = true;
31944 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31945 this.ui.animExpand(function(){
31946 this.fireEvent("expand", this);
31947 if(typeof callback == "function"){
31951 this.expandChildNodes(true);
31953 }.createDelegate(this));
31957 this.fireEvent("expand", this);
31958 if(typeof callback == "function"){
31963 if(typeof callback == "function"){
31968 this.expandChildNodes(true);
31972 isHiddenRoot : function(){
31973 return this.isRoot && !this.getOwnerTree().rootVisible;
31977 * Collapse this node.
31978 * @param {Boolean} deep (optional) True to collapse all children as well
31979 * @param {Boolean} anim (optional) false to cancel the default animation
31981 collapse : function(deep, anim){
31982 if(this.expanded && !this.isHiddenRoot()){
31983 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31986 this.expanded = false;
31987 if((this.getOwnerTree().animate && anim !== false) || anim){
31988 this.ui.animCollapse(function(){
31989 this.fireEvent("collapse", this);
31991 this.collapseChildNodes(true);
31993 }.createDelegate(this));
31996 this.ui.collapse();
31997 this.fireEvent("collapse", this);
32001 var cs = this.childNodes;
32002 for(var i = 0, len = cs.length; i < len; i++) {
32003 cs[i].collapse(true, false);
32009 delayedExpand : function(delay){
32010 if(!this.expandProcId){
32011 this.expandProcId = this.expand.defer(delay, this);
32016 cancelExpand : function(){
32017 if(this.expandProcId){
32018 clearTimeout(this.expandProcId);
32020 this.expandProcId = false;
32024 * Toggles expanded/collapsed state of the node
32026 toggle : function(){
32035 * Ensures all parent nodes are expanded
32037 ensureVisible : function(callback){
32038 var tree = this.getOwnerTree();
32039 tree.expandPath(this.parentNode.getPath(), false, function(){
32040 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
32041 Roo.callback(callback);
32042 }.createDelegate(this));
32046 * Expand all child nodes
32047 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
32049 expandChildNodes : function(deep){
32050 var cs = this.childNodes;
32051 for(var i = 0, len = cs.length; i < len; i++) {
32052 cs[i].expand(deep);
32057 * Collapse all child nodes
32058 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
32060 collapseChildNodes : function(deep){
32061 var cs = this.childNodes;
32062 for(var i = 0, len = cs.length; i < len; i++) {
32063 cs[i].collapse(deep);
32068 * Disables this node
32070 disable : function(){
32071 this.disabled = true;
32073 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32074 this.ui.onDisableChange(this, true);
32076 this.fireEvent("disabledchange", this, true);
32080 * Enables this node
32082 enable : function(){
32083 this.disabled = false;
32084 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32085 this.ui.onDisableChange(this, false);
32087 this.fireEvent("disabledchange", this, false);
32091 renderChildren : function(suppressEvent){
32092 if(suppressEvent !== false){
32093 this.fireEvent("beforechildrenrendered", this);
32095 var cs = this.childNodes;
32096 for(var i = 0, len = cs.length; i < len; i++){
32097 cs[i].render(true);
32099 this.childrenRendered = true;
32103 sort : function(fn, scope){
32104 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32105 if(this.childrenRendered){
32106 var cs = this.childNodes;
32107 for(var i = 0, len = cs.length; i < len; i++){
32108 cs[i].render(true);
32114 render : function(bulkRender){
32115 this.ui.render(bulkRender);
32116 if(!this.rendered){
32117 this.rendered = true;
32119 this.expanded = false;
32120 this.expand(false, false);
32126 renderIndent : function(deep, refresh){
32128 this.ui.childIndent = null;
32130 this.ui.renderIndent();
32131 if(deep === true && this.childrenRendered){
32132 var cs = this.childNodes;
32133 for(var i = 0, len = cs.length; i < len; i++){
32134 cs[i].renderIndent(true, refresh);
32140 * Ext JS Library 1.1.1
32141 * Copyright(c) 2006-2007, Ext JS, LLC.
32143 * Originally Released Under LGPL - original licence link has changed is not relivant.
32146 * <script type="text/javascript">
32150 * @class Roo.tree.AsyncTreeNode
32151 * @extends Roo.tree.TreeNode
32152 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32154 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32156 Roo.tree.AsyncTreeNode = function(config){
32157 this.loaded = false;
32158 this.loading = false;
32159 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32161 * @event beforeload
32162 * Fires before this node is loaded, return false to cancel
32163 * @param {Node} this This node
32165 this.addEvents({'beforeload':true, 'load': true});
32168 * Fires when this node is loaded
32169 * @param {Node} this This node
32172 * The loader used by this node (defaults to using the tree's defined loader)
32177 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32178 expand : function(deep, anim, callback){
32179 if(this.loading){ // if an async load is already running, waiting til it's done
32181 var f = function(){
32182 if(!this.loading){ // done loading
32183 clearInterval(timer);
32184 this.expand(deep, anim, callback);
32186 }.createDelegate(this);
32187 timer = setInterval(f, 200);
32191 if(this.fireEvent("beforeload", this) === false){
32194 this.loading = true;
32195 this.ui.beforeLoad(this);
32196 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32198 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32202 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32206 * Returns true if this node is currently loading
32207 * @return {Boolean}
32209 isLoading : function(){
32210 return this.loading;
32213 loadComplete : function(deep, anim, callback){
32214 this.loading = false;
32215 this.loaded = true;
32216 this.ui.afterLoad(this);
32217 this.fireEvent("load", this);
32218 this.expand(deep, anim, callback);
32222 * Returns true if this node has been loaded
32223 * @return {Boolean}
32225 isLoaded : function(){
32226 return this.loaded;
32229 hasChildNodes : function(){
32230 if(!this.isLeaf() && !this.loaded){
32233 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32238 * Trigger a reload for this node
32239 * @param {Function} callback
32241 reload : function(callback){
32242 this.collapse(false, false);
32243 while(this.firstChild){
32244 this.removeChild(this.firstChild);
32246 this.childrenRendered = false;
32247 this.loaded = false;
32248 if(this.isHiddenRoot()){
32249 this.expanded = false;
32251 this.expand(false, false, callback);
32255 * Ext JS Library 1.1.1
32256 * Copyright(c) 2006-2007, Ext JS, LLC.
32258 * Originally Released Under LGPL - original licence link has changed is not relivant.
32261 * <script type="text/javascript">
32265 * @class Roo.tree.TreeNodeUI
32267 * @param {Object} node The node to render
32268 * The TreeNode UI implementation is separate from the
32269 * tree implementation. Unless you are customizing the tree UI,
32270 * you should never have to use this directly.
32272 Roo.tree.TreeNodeUI = function(node){
32274 this.rendered = false;
32275 this.animating = false;
32276 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32279 Roo.tree.TreeNodeUI.prototype = {
32280 removeChild : function(node){
32282 this.ctNode.removeChild(node.ui.getEl());
32286 beforeLoad : function(){
32287 this.addClass("x-tree-node-loading");
32290 afterLoad : function(){
32291 this.removeClass("x-tree-node-loading");
32294 onTextChange : function(node, text, oldText){
32296 this.textNode.innerHTML = text;
32300 onDisableChange : function(node, state){
32301 this.disabled = state;
32303 this.addClass("x-tree-node-disabled");
32305 this.removeClass("x-tree-node-disabled");
32309 onSelectedChange : function(state){
32312 this.addClass("x-tree-selected");
32315 this.removeClass("x-tree-selected");
32319 onMove : function(tree, node, oldParent, newParent, index, refNode){
32320 this.childIndent = null;
32322 var targetNode = newParent.ui.getContainer();
32323 if(!targetNode){//target not rendered
32324 this.holder = document.createElement("div");
32325 this.holder.appendChild(this.wrap);
32328 var insertBefore = refNode ? refNode.ui.getEl() : null;
32330 targetNode.insertBefore(this.wrap, insertBefore);
32332 targetNode.appendChild(this.wrap);
32334 this.node.renderIndent(true);
32338 addClass : function(cls){
32340 Roo.fly(this.elNode).addClass(cls);
32344 removeClass : function(cls){
32346 Roo.fly(this.elNode).removeClass(cls);
32350 remove : function(){
32352 this.holder = document.createElement("div");
32353 this.holder.appendChild(this.wrap);
32357 fireEvent : function(){
32358 return this.node.fireEvent.apply(this.node, arguments);
32361 initEvents : function(){
32362 this.node.on("move", this.onMove, this);
32363 var E = Roo.EventManager;
32364 var a = this.anchor;
32366 var el = Roo.fly(a, '_treeui');
32368 if(Roo.isOpera){ // opera render bug ignores the CSS
32369 el.setStyle("text-decoration", "none");
32372 el.on("click", this.onClick, this);
32373 el.on("dblclick", this.onDblClick, this);
32376 Roo.EventManager.on(this.checkbox,
32377 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32380 el.on("contextmenu", this.onContextMenu, this);
32382 var icon = Roo.fly(this.iconNode);
32383 icon.on("click", this.onClick, this);
32384 icon.on("dblclick", this.onDblClick, this);
32385 icon.on("contextmenu", this.onContextMenu, this);
32386 E.on(this.ecNode, "click", this.ecClick, this, true);
32388 if(this.node.disabled){
32389 this.addClass("x-tree-node-disabled");
32391 if(this.node.hidden){
32392 this.addClass("x-tree-node-disabled");
32394 var ot = this.node.getOwnerTree();
32395 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32396 if(dd && (!this.node.isRoot || ot.rootVisible)){
32397 Roo.dd.Registry.register(this.elNode, {
32399 handles: this.getDDHandles(),
32405 getDDHandles : function(){
32406 return [this.iconNode, this.textNode];
32411 this.wrap.style.display = "none";
32417 this.wrap.style.display = "";
32421 onContextMenu : function(e){
32422 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32423 e.preventDefault();
32425 this.fireEvent("contextmenu", this.node, e);
32429 onClick : function(e){
32434 if(this.fireEvent("beforeclick", this.node, e) !== false){
32435 if(!this.disabled && this.node.attributes.href){
32436 this.fireEvent("click", this.node, e);
32439 e.preventDefault();
32444 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32445 this.node.toggle();
32448 this.fireEvent("click", this.node, e);
32454 onDblClick : function(e){
32455 e.preventDefault();
32460 this.toggleCheck();
32462 if(!this.animating && this.node.hasChildNodes()){
32463 this.node.toggle();
32465 this.fireEvent("dblclick", this.node, e);
32468 onCheckChange : function(){
32469 var checked = this.checkbox.checked;
32470 this.node.attributes.checked = checked;
32471 this.fireEvent('checkchange', this.node, checked);
32474 ecClick : function(e){
32475 if(!this.animating && this.node.hasChildNodes()){
32476 this.node.toggle();
32480 startDrop : function(){
32481 this.dropping = true;
32484 // delayed drop so the click event doesn't get fired on a drop
32485 endDrop : function(){
32486 setTimeout(function(){
32487 this.dropping = false;
32488 }.createDelegate(this), 50);
32491 expand : function(){
32492 this.updateExpandIcon();
32493 this.ctNode.style.display = "";
32496 focus : function(){
32497 if(!this.node.preventHScroll){
32498 try{this.anchor.focus();
32500 }else if(!Roo.isIE){
32502 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32503 var l = noscroll.scrollLeft;
32504 this.anchor.focus();
32505 noscroll.scrollLeft = l;
32510 toggleCheck : function(value){
32511 var cb = this.checkbox;
32513 cb.checked = (value === undefined ? !cb.checked : value);
32519 this.anchor.blur();
32523 animExpand : function(callback){
32524 var ct = Roo.get(this.ctNode);
32526 if(!this.node.hasChildNodes()){
32527 this.updateExpandIcon();
32528 this.ctNode.style.display = "";
32529 Roo.callback(callback);
32532 this.animating = true;
32533 this.updateExpandIcon();
32536 callback : function(){
32537 this.animating = false;
32538 Roo.callback(callback);
32541 duration: this.node.ownerTree.duration || .25
32545 highlight : function(){
32546 var tree = this.node.getOwnerTree();
32547 Roo.fly(this.wrap).highlight(
32548 tree.hlColor || "C3DAF9",
32549 {endColor: tree.hlBaseColor}
32553 collapse : function(){
32554 this.updateExpandIcon();
32555 this.ctNode.style.display = "none";
32558 animCollapse : function(callback){
32559 var ct = Roo.get(this.ctNode);
32560 ct.enableDisplayMode('block');
32563 this.animating = true;
32564 this.updateExpandIcon();
32567 callback : function(){
32568 this.animating = false;
32569 Roo.callback(callback);
32572 duration: this.node.ownerTree.duration || .25
32576 getContainer : function(){
32577 return this.ctNode;
32580 getEl : function(){
32584 appendDDGhost : function(ghostNode){
32585 ghostNode.appendChild(this.elNode.cloneNode(true));
32588 getDDRepairXY : function(){
32589 return Roo.lib.Dom.getXY(this.iconNode);
32592 onRender : function(){
32596 render : function(bulkRender){
32597 var n = this.node, a = n.attributes;
32598 var targetNode = n.parentNode ?
32599 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32601 if(!this.rendered){
32602 this.rendered = true;
32604 this.renderElements(n, a, targetNode, bulkRender);
32607 if(this.textNode.setAttributeNS){
32608 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32610 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32613 this.textNode.setAttribute("ext:qtip", a.qtip);
32615 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32618 }else if(a.qtipCfg){
32619 a.qtipCfg.target = Roo.id(this.textNode);
32620 Roo.QuickTips.register(a.qtipCfg);
32623 if(!this.node.expanded){
32624 this.updateExpandIcon();
32627 if(bulkRender === true) {
32628 targetNode.appendChild(this.wrap);
32633 renderElements : function(n, a, targetNode, bulkRender)
32635 // add some indent caching, this helps performance when rendering a large tree
32636 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32637 var t = n.getOwnerTree();
32638 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32639 if (typeof(n.attributes.html) != 'undefined') {
32640 txt = n.attributes.html;
32642 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32643 var cb = typeof a.checked == 'boolean';
32644 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32645 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32646 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32647 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32648 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32649 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32650 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32651 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32652 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32653 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32656 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32657 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32658 n.nextSibling.ui.getEl(), buf.join(""));
32660 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32663 this.elNode = this.wrap.childNodes[0];
32664 this.ctNode = this.wrap.childNodes[1];
32665 var cs = this.elNode.childNodes;
32666 this.indentNode = cs[0];
32667 this.ecNode = cs[1];
32668 this.iconNode = cs[2];
32671 this.checkbox = cs[3];
32674 this.anchor = cs[index];
32675 this.textNode = cs[index].firstChild;
32678 getAnchor : function(){
32679 return this.anchor;
32682 getTextEl : function(){
32683 return this.textNode;
32686 getIconEl : function(){
32687 return this.iconNode;
32690 isChecked : function(){
32691 return this.checkbox ? this.checkbox.checked : false;
32694 updateExpandIcon : function(){
32696 var n = this.node, c1, c2;
32697 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32698 var hasChild = n.hasChildNodes();
32702 c1 = "x-tree-node-collapsed";
32703 c2 = "x-tree-node-expanded";
32706 c1 = "x-tree-node-expanded";
32707 c2 = "x-tree-node-collapsed";
32710 this.removeClass("x-tree-node-leaf");
32711 this.wasLeaf = false;
32713 if(this.c1 != c1 || this.c2 != c2){
32714 Roo.fly(this.elNode).replaceClass(c1, c2);
32715 this.c1 = c1; this.c2 = c2;
32718 // this changes non-leafs into leafs if they have no children.
32719 // it's not very rational behaviour..
32721 if(!this.wasLeaf && this.node.leaf){
32722 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32725 this.wasLeaf = true;
32728 var ecc = "x-tree-ec-icon "+cls;
32729 if(this.ecc != ecc){
32730 this.ecNode.className = ecc;
32736 getChildIndent : function(){
32737 if(!this.childIndent){
32741 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32743 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32745 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32750 this.childIndent = buf.join("");
32752 return this.childIndent;
32755 renderIndent : function(){
32758 var p = this.node.parentNode;
32760 indent = p.ui.getChildIndent();
32762 if(this.indentMarkup != indent){ // don't rerender if not required
32763 this.indentNode.innerHTML = indent;
32764 this.indentMarkup = indent;
32766 this.updateExpandIcon();
32771 Roo.tree.RootTreeNodeUI = function(){
32772 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32774 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32775 render : function(){
32776 if(!this.rendered){
32777 var targetNode = this.node.ownerTree.innerCt.dom;
32778 this.node.expanded = true;
32779 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32780 this.wrap = this.ctNode = targetNode.firstChild;
32783 collapse : function(){
32785 expand : function(){
32789 * Ext JS Library 1.1.1
32790 * Copyright(c) 2006-2007, Ext JS, LLC.
32792 * Originally Released Under LGPL - original licence link has changed is not relivant.
32795 * <script type="text/javascript">
32798 * @class Roo.tree.TreeLoader
32799 * @extends Roo.util.Observable
32800 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32801 * nodes from a specified URL. The response must be a javascript Array definition
32802 * who's elements are node definition objects. eg:
32804 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32805 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32808 * A server request is sent, and child nodes are loaded only when a node is expanded.
32809 * The loading node's id is passed to the server under the parameter name "node" to
32810 * enable the server to produce the correct child nodes.
32812 * To pass extra parameters, an event handler may be attached to the "beforeload"
32813 * event, and the parameters specified in the TreeLoader's baseParams property:
32815 myTreeLoader.on("beforeload", function(treeLoader, node) {
32816 this.baseParams.category = node.attributes.category;
32819 * This would pass an HTTP parameter called "category" to the server containing
32820 * the value of the Node's "category" attribute.
32822 * Creates a new Treeloader.
32823 * @param {Object} config A config object containing config properties.
32825 Roo.tree.TreeLoader = function(config){
32826 this.baseParams = {};
32827 this.requestMethod = "POST";
32828 Roo.apply(this, config);
32833 * @event beforeload
32834 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32835 * @param {Object} This TreeLoader object.
32836 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32837 * @param {Object} callback The callback function specified in the {@link #load} call.
32842 * Fires when the node has been successfuly loaded.
32843 * @param {Object} This TreeLoader object.
32844 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32845 * @param {Object} response The response object containing the data from the server.
32849 * @event loadexception
32850 * Fires if the network request failed.
32851 * @param {Object} This TreeLoader object.
32852 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32853 * @param {Object} response The response object containing the data from the server.
32855 loadexception : true,
32858 * Fires before a node is created, enabling you to return custom Node types
32859 * @param {Object} This TreeLoader object.
32860 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32865 Roo.tree.TreeLoader.superclass.constructor.call(this);
32868 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32870 * @cfg {String} dataUrl The URL from which to request a Json string which
32871 * specifies an array of node definition object representing the child nodes
32875 * @cfg {Object} baseParams (optional) An object containing properties which
32876 * specify HTTP parameters to be passed to each request for child nodes.
32879 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32880 * created by this loader. If the attributes sent by the server have an attribute in this object,
32881 * they take priority.
32884 * @cfg {Object} uiProviders (optional) An object containing properties which
32886 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
32887 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32888 * <i>uiProvider</i> attribute of a returned child node is a string rather
32889 * than a reference to a TreeNodeUI implementation, this that string value
32890 * is used as a property name in the uiProviders object. You can define the provider named
32891 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32896 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32897 * child nodes before loading.
32899 clearOnLoad : true,
32902 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32903 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32904 * Grid query { data : [ .....] }
32909 * @cfg {String} queryParam (optional)
32910 * Name of the query as it will be passed on the querystring (defaults to 'node')
32911 * eg. the request will be ?node=[id]
32918 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32919 * This is called automatically when a node is expanded, but may be used to reload
32920 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32921 * @param {Roo.tree.TreeNode} node
32922 * @param {Function} callback
32924 load : function(node, callback){
32925 if(this.clearOnLoad){
32926 while(node.firstChild){
32927 node.removeChild(node.firstChild);
32930 if(node.attributes.children){ // preloaded json children
32931 var cs = node.attributes.children;
32932 for(var i = 0, len = cs.length; i < len; i++){
32933 node.appendChild(this.createNode(cs[i]));
32935 if(typeof callback == "function"){
32938 }else if(this.dataUrl){
32939 this.requestData(node, callback);
32943 getParams: function(node){
32944 var buf = [], bp = this.baseParams;
32945 for(var key in bp){
32946 if(typeof bp[key] != "function"){
32947 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32950 var n = this.queryParam === false ? 'node' : this.queryParam;
32951 buf.push(n + "=", encodeURIComponent(node.id));
32952 return buf.join("");
32955 requestData : function(node, callback){
32956 if(this.fireEvent("beforeload", this, node, callback) !== false){
32957 this.transId = Roo.Ajax.request({
32958 method:this.requestMethod,
32959 url: this.dataUrl||this.url,
32960 success: this.handleResponse,
32961 failure: this.handleFailure,
32963 argument: {callback: callback, node: node},
32964 params: this.getParams(node)
32967 // if the load is cancelled, make sure we notify
32968 // the node that we are done
32969 if(typeof callback == "function"){
32975 isLoading : function(){
32976 return this.transId ? true : false;
32979 abort : function(){
32980 if(this.isLoading()){
32981 Roo.Ajax.abort(this.transId);
32986 createNode : function(attr)
32988 // apply baseAttrs, nice idea Corey!
32989 if(this.baseAttrs){
32990 Roo.applyIf(attr, this.baseAttrs);
32992 if(this.applyLoader !== false){
32993 attr.loader = this;
32995 // uiProvider = depreciated..
32997 if(typeof(attr.uiProvider) == 'string'){
32998 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32999 /** eval:var:attr */ eval(attr.uiProvider);
33001 if(typeof(this.uiProviders['default']) != 'undefined') {
33002 attr.uiProvider = this.uiProviders['default'];
33005 this.fireEvent('create', this, attr);
33007 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
33009 new Roo.tree.TreeNode(attr) :
33010 new Roo.tree.AsyncTreeNode(attr));
33013 processResponse : function(response, node, callback)
33015 var json = response.responseText;
33018 var o = Roo.decode(json);
33021 // it's a failure condition.
33022 var a = response.argument;
33023 this.fireEvent("loadexception", this, a.node, response);
33024 Roo.log("Load failed - should have a handler really");
33028 if (this.root !== false) {
33032 for(var i = 0, len = o.length; i < len; i++){
33033 var n = this.createNode(o[i]);
33035 node.appendChild(n);
33038 if(typeof callback == "function"){
33039 callback(this, node);
33042 this.handleFailure(response);
33046 handleResponse : function(response){
33047 this.transId = false;
33048 var a = response.argument;
33049 this.processResponse(response, a.node, a.callback);
33050 this.fireEvent("load", this, a.node, response);
33053 handleFailure : function(response)
33055 // should handle failure better..
33056 this.transId = false;
33057 var a = response.argument;
33058 this.fireEvent("loadexception", this, a.node, response);
33059 if(typeof a.callback == "function"){
33060 a.callback(this, a.node);
33065 * Ext JS Library 1.1.1
33066 * Copyright(c) 2006-2007, Ext JS, LLC.
33068 * Originally Released Under LGPL - original licence link has changed is not relivant.
33071 * <script type="text/javascript">
33075 * @class Roo.tree.TreeFilter
33076 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
33077 * @param {TreePanel} tree
33078 * @param {Object} config (optional)
33080 Roo.tree.TreeFilter = function(tree, config){
33082 this.filtered = {};
33083 Roo.apply(this, config);
33086 Roo.tree.TreeFilter.prototype = {
33093 * Filter the data by a specific attribute.
33094 * @param {String/RegExp} value Either string that the attribute value
33095 * should start with or a RegExp to test against the attribute
33096 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
33097 * @param {TreeNode} startNode (optional) The node to start the filter at.
33099 filter : function(value, attr, startNode){
33100 attr = attr || "text";
33102 if(typeof value == "string"){
33103 var vlen = value.length;
33104 // auto clear empty filter
33105 if(vlen == 0 && this.clearBlank){
33109 value = value.toLowerCase();
33111 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
33113 }else if(value.exec){ // regex?
33115 return value.test(n.attributes[attr]);
33118 throw 'Illegal filter type, must be string or regex';
33120 this.filterBy(f, null, startNode);
33124 * Filter by a function. The passed function will be called with each
33125 * node in the tree (or from the startNode). If the function returns true, the node is kept
33126 * otherwise it is filtered. If a node is filtered, its children are also filtered.
33127 * @param {Function} fn The filter function
33128 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33130 filterBy : function(fn, scope, startNode){
33131 startNode = startNode || this.tree.root;
33132 if(this.autoClear){
33135 var af = this.filtered, rv = this.reverse;
33136 var f = function(n){
33137 if(n == startNode){
33143 var m = fn.call(scope || n, n);
33151 startNode.cascade(f);
33154 if(typeof id != "function"){
33156 if(n && n.parentNode){
33157 n.parentNode.removeChild(n);
33165 * Clears the current filter. Note: with the "remove" option
33166 * set a filter cannot be cleared.
33168 clear : function(){
33170 var af = this.filtered;
33172 if(typeof id != "function"){
33179 this.filtered = {};
33184 * Ext JS Library 1.1.1
33185 * Copyright(c) 2006-2007, Ext JS, LLC.
33187 * Originally Released Under LGPL - original licence link has changed is not relivant.
33190 * <script type="text/javascript">
33195 * @class Roo.tree.TreeSorter
33196 * Provides sorting of nodes in a TreePanel
33198 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33199 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33200 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33201 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33202 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33203 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33205 * @param {TreePanel} tree
33206 * @param {Object} config
33208 Roo.tree.TreeSorter = function(tree, config){
33209 Roo.apply(this, config);
33210 tree.on("beforechildrenrendered", this.doSort, this);
33211 tree.on("append", this.updateSort, this);
33212 tree.on("insert", this.updateSort, this);
33214 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33215 var p = this.property || "text";
33216 var sortType = this.sortType;
33217 var fs = this.folderSort;
33218 var cs = this.caseSensitive === true;
33219 var leafAttr = this.leafAttr || 'leaf';
33221 this.sortFn = function(n1, n2){
33223 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33226 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33230 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33231 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33233 return dsc ? +1 : -1;
33235 return dsc ? -1 : +1;
33242 Roo.tree.TreeSorter.prototype = {
33243 doSort : function(node){
33244 node.sort(this.sortFn);
33247 compareNodes : function(n1, n2){
33248 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33251 updateSort : function(tree, node){
33252 if(node.childrenRendered){
33253 this.doSort.defer(1, this, [node]);
33258 * Ext JS Library 1.1.1
33259 * Copyright(c) 2006-2007, Ext JS, LLC.
33261 * Originally Released Under LGPL - original licence link has changed is not relivant.
33264 * <script type="text/javascript">
33267 if(Roo.dd.DropZone){
33269 Roo.tree.TreeDropZone = function(tree, config){
33270 this.allowParentInsert = false;
33271 this.allowContainerDrop = false;
33272 this.appendOnly = false;
33273 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33275 this.lastInsertClass = "x-tree-no-status";
33276 this.dragOverData = {};
33279 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33280 ddGroup : "TreeDD",
33282 expandDelay : 1000,
33284 expandNode : function(node){
33285 if(node.hasChildNodes() && !node.isExpanded()){
33286 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33290 queueExpand : function(node){
33291 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33294 cancelExpand : function(){
33295 if(this.expandProcId){
33296 clearTimeout(this.expandProcId);
33297 this.expandProcId = false;
33301 isValidDropPoint : function(n, pt, dd, e, data){
33302 if(!n || !data){ return false; }
33303 var targetNode = n.node;
33304 var dropNode = data.node;
33305 // default drop rules
33306 if(!(targetNode && targetNode.isTarget && pt)){
33309 if(pt == "append" && targetNode.allowChildren === false){
33312 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33315 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33318 // reuse the object
33319 var overEvent = this.dragOverData;
33320 overEvent.tree = this.tree;
33321 overEvent.target = targetNode;
33322 overEvent.data = data;
33323 overEvent.point = pt;
33324 overEvent.source = dd;
33325 overEvent.rawEvent = e;
33326 overEvent.dropNode = dropNode;
33327 overEvent.cancel = false;
33328 var result = this.tree.fireEvent("nodedragover", overEvent);
33329 return overEvent.cancel === false && result !== false;
33332 getDropPoint : function(e, n, dd){
33335 return tn.allowChildren !== false ? "append" : false; // always append for root
33337 var dragEl = n.ddel;
33338 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33339 var y = Roo.lib.Event.getPageY(e);
33340 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33342 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33343 var noAppend = tn.allowChildren === false;
33344 if(this.appendOnly || tn.parentNode.allowChildren === false){
33345 return noAppend ? false : "append";
33347 var noBelow = false;
33348 if(!this.allowParentInsert){
33349 noBelow = tn.hasChildNodes() && tn.isExpanded();
33351 var q = (b - t) / (noAppend ? 2 : 3);
33352 if(y >= t && y < (t + q)){
33354 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33361 onNodeEnter : function(n, dd, e, data){
33362 this.cancelExpand();
33365 onNodeOver : function(n, dd, e, data){
33366 var pt = this.getDropPoint(e, n, dd);
33369 // auto node expand check
33370 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33371 this.queueExpand(node);
33372 }else if(pt != "append"){
33373 this.cancelExpand();
33376 // set the insert point style on the target node
33377 var returnCls = this.dropNotAllowed;
33378 if(this.isValidDropPoint(n, pt, dd, e, data)){
33383 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33384 cls = "x-tree-drag-insert-above";
33385 }else if(pt == "below"){
33386 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33387 cls = "x-tree-drag-insert-below";
33389 returnCls = "x-tree-drop-ok-append";
33390 cls = "x-tree-drag-append";
33392 if(this.lastInsertClass != cls){
33393 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33394 this.lastInsertClass = cls;
33401 onNodeOut : function(n, dd, e, data){
33402 this.cancelExpand();
33403 this.removeDropIndicators(n);
33406 onNodeDrop : function(n, dd, e, data){
33407 var point = this.getDropPoint(e, n, dd);
33408 var targetNode = n.node;
33409 targetNode.ui.startDrop();
33410 if(!this.isValidDropPoint(n, point, dd, e, data)){
33411 targetNode.ui.endDrop();
33414 // first try to find the drop node
33415 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33418 target: targetNode,
33423 dropNode: dropNode,
33426 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33427 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33428 targetNode.ui.endDrop();
33431 // allow target changing
33432 targetNode = dropEvent.target;
33433 if(point == "append" && !targetNode.isExpanded()){
33434 targetNode.expand(false, null, function(){
33435 this.completeDrop(dropEvent);
33436 }.createDelegate(this));
33438 this.completeDrop(dropEvent);
33443 completeDrop : function(de){
33444 var ns = de.dropNode, p = de.point, t = de.target;
33445 if(!(ns instanceof Array)){
33449 for(var i = 0, len = ns.length; i < len; i++){
33452 t.parentNode.insertBefore(n, t);
33453 }else if(p == "below"){
33454 t.parentNode.insertBefore(n, t.nextSibling);
33460 if(this.tree.hlDrop){
33464 this.tree.fireEvent("nodedrop", de);
33467 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33468 if(this.tree.hlDrop){
33469 dropNode.ui.focus();
33470 dropNode.ui.highlight();
33472 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33475 getTree : function(){
33479 removeDropIndicators : function(n){
33482 Roo.fly(el).removeClass([
33483 "x-tree-drag-insert-above",
33484 "x-tree-drag-insert-below",
33485 "x-tree-drag-append"]);
33486 this.lastInsertClass = "_noclass";
33490 beforeDragDrop : function(target, e, id){
33491 this.cancelExpand();
33495 afterRepair : function(data){
33496 if(data && Roo.enableFx){
33497 data.node.ui.highlight();
33506 * Ext JS Library 1.1.1
33507 * Copyright(c) 2006-2007, Ext JS, LLC.
33509 * Originally Released Under LGPL - original licence link has changed is not relivant.
33512 * <script type="text/javascript">
33516 if(Roo.dd.DragZone){
33517 Roo.tree.TreeDragZone = function(tree, config){
33518 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33522 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33523 ddGroup : "TreeDD",
33525 onBeforeDrag : function(data, e){
33527 return n && n.draggable && !n.disabled;
33530 onInitDrag : function(e){
33531 var data = this.dragData;
33532 this.tree.getSelectionModel().select(data.node);
33533 this.proxy.update("");
33534 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33535 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33538 getRepairXY : function(e, data){
33539 return data.node.ui.getDDRepairXY();
33542 onEndDrag : function(data, e){
33543 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33546 onValidDrop : function(dd, e, id){
33547 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33551 beforeInvalidDrop : function(e, id){
33552 // this scrolls the original position back into view
33553 var sm = this.tree.getSelectionModel();
33554 sm.clearSelections();
33555 sm.select(this.dragData.node);
33560 * Ext JS Library 1.1.1
33561 * Copyright(c) 2006-2007, Ext JS, LLC.
33563 * Originally Released Under LGPL - original licence link has changed is not relivant.
33566 * <script type="text/javascript">
33569 * @class Roo.tree.TreeEditor
33570 * @extends Roo.Editor
33571 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33572 * as the editor field.
33574 * @param {Object} config (used to be the tree panel.)
33575 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33577 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
33578 * @cfg {Roo.form.TextField|Object} field The field configuration
33582 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
33585 if (oldconfig) { // old style..
33586 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
33589 tree = config.tree;
33590 config.field = config.field || {};
33591 config.field.xtype = 'TextField';
33592 field = Roo.factory(config.field, Roo.form);
33594 config = config || {};
33599 * @event beforenodeedit
33600 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
33601 * false from the handler of this event.
33602 * @param {Editor} this
33603 * @param {Roo.tree.Node} node
33605 "beforenodeedit" : true
33609 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
33613 tree.on('beforeclick', this.beforeNodeClick, this);
33614 tree.getTreeEl().on('mousedown', this.hide, this);
33615 this.on('complete', this.updateNode, this);
33616 this.on('beforestartedit', this.fitToTree, this);
33617 this.on('startedit', this.bindScroll, this, {delay:10});
33618 this.on('specialkey', this.onSpecialKey, this);
33621 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33623 * @cfg {String} alignment
33624 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33630 * @cfg {Boolean} hideEl
33631 * True to hide the bound element while the editor is displayed (defaults to false)
33635 * @cfg {String} cls
33636 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33638 cls: "x-small-editor x-tree-editor",
33640 * @cfg {Boolean} shim
33641 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33647 * @cfg {Number} maxWidth
33648 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33649 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33650 * scroll and client offsets into account prior to each edit.
33657 fitToTree : function(ed, el){
33658 var td = this.tree.getTreeEl().dom, nd = el.dom;
33659 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33660 td.scrollLeft = nd.offsetLeft;
33664 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33665 this.setSize(w, '');
33667 return this.fireEvent('beforenodeedit', this, this.editNode);
33672 triggerEdit : function(node){
33673 this.completeEdit();
33674 this.editNode = node;
33675 this.startEdit(node.ui.textNode, node.text);
33679 bindScroll : function(){
33680 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33684 beforeNodeClick : function(node, e){
33685 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33686 this.lastClick = new Date();
33687 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33689 this.triggerEdit(node);
33696 updateNode : function(ed, value){
33697 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33698 this.editNode.setText(value);
33702 onHide : function(){
33703 Roo.tree.TreeEditor.superclass.onHide.call(this);
33705 this.editNode.ui.focus();
33710 onSpecialKey : function(field, e){
33711 var k = e.getKey();
33715 }else if(k == e.ENTER && !e.hasModifier()){
33717 this.completeEdit();
33720 });//<Script type="text/javascript">
33723 * Ext JS Library 1.1.1
33724 * Copyright(c) 2006-2007, Ext JS, LLC.
33726 * Originally Released Under LGPL - original licence link has changed is not relivant.
33729 * <script type="text/javascript">
33733 * Not documented??? - probably should be...
33736 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33737 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33739 renderElements : function(n, a, targetNode, bulkRender){
33740 //consel.log("renderElements?");
33741 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33743 var t = n.getOwnerTree();
33744 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33746 var cols = t.columns;
33747 var bw = t.borderWidth;
33749 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33750 var cb = typeof a.checked == "boolean";
33751 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33752 var colcls = 'x-t-' + tid + '-c0';
33754 '<li class="x-tree-node">',
33757 '<div class="x-tree-node-el ', a.cls,'">',
33759 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33762 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33763 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33764 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33765 (a.icon ? ' x-tree-node-inline-icon' : ''),
33766 (a.iconCls ? ' '+a.iconCls : ''),
33767 '" unselectable="on" />',
33768 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33769 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33771 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33772 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33773 '<span unselectable="on" qtip="' + tx + '">',
33777 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33778 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33780 for(var i = 1, len = cols.length; i < len; i++){
33782 colcls = 'x-t-' + tid + '-c' +i;
33783 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33784 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33785 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33791 '<div class="x-clear"></div></div>',
33792 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33795 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33796 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33797 n.nextSibling.ui.getEl(), buf.join(""));
33799 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33801 var el = this.wrap.firstChild;
33803 this.elNode = el.firstChild;
33804 this.ranchor = el.childNodes[1];
33805 this.ctNode = this.wrap.childNodes[1];
33806 var cs = el.firstChild.childNodes;
33807 this.indentNode = cs[0];
33808 this.ecNode = cs[1];
33809 this.iconNode = cs[2];
33812 this.checkbox = cs[3];
33815 this.anchor = cs[index];
33817 this.textNode = cs[index].firstChild;
33819 //el.on("click", this.onClick, this);
33820 //el.on("dblclick", this.onDblClick, this);
33823 // console.log(this);
33825 initEvents : function(){
33826 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33829 var a = this.ranchor;
33831 var el = Roo.get(a);
33833 if(Roo.isOpera){ // opera render bug ignores the CSS
33834 el.setStyle("text-decoration", "none");
33837 el.on("click", this.onClick, this);
33838 el.on("dblclick", this.onDblClick, this);
33839 el.on("contextmenu", this.onContextMenu, this);
33843 /*onSelectedChange : function(state){
33846 this.addClass("x-tree-selected");
33849 this.removeClass("x-tree-selected");
33852 addClass : function(cls){
33854 Roo.fly(this.elRow).addClass(cls);
33860 removeClass : function(cls){
33862 Roo.fly(this.elRow).removeClass(cls);
33868 });//<Script type="text/javascript">
33872 * Ext JS Library 1.1.1
33873 * Copyright(c) 2006-2007, Ext JS, LLC.
33875 * Originally Released Under LGPL - original licence link has changed is not relivant.
33878 * <script type="text/javascript">
33883 * @class Roo.tree.ColumnTree
33884 * @extends Roo.data.TreePanel
33885 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33886 * @cfg {int} borderWidth compined right/left border allowance
33888 * @param {String/HTMLElement/Element} el The container element
33889 * @param {Object} config
33891 Roo.tree.ColumnTree = function(el, config)
33893 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33897 * Fire this event on a container when it resizes
33898 * @param {int} w Width
33899 * @param {int} h Height
33903 this.on('resize', this.onResize, this);
33906 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33910 borderWidth: Roo.isBorderBox ? 0 : 2,
33913 render : function(){
33914 // add the header.....
33916 Roo.tree.ColumnTree.superclass.render.apply(this);
33918 this.el.addClass('x-column-tree');
33920 this.headers = this.el.createChild(
33921 {cls:'x-tree-headers'},this.innerCt.dom);
33923 var cols = this.columns, c;
33924 var totalWidth = 0;
33926 var len = cols.length;
33927 for(var i = 0; i < len; i++){
33929 totalWidth += c.width;
33930 this.headEls.push(this.headers.createChild({
33931 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33933 cls:'x-tree-hd-text',
33936 style:'width:'+(c.width-this.borderWidth)+'px;'
33939 this.headers.createChild({cls:'x-clear'});
33940 // prevent floats from wrapping when clipped
33941 this.headers.setWidth(totalWidth);
33942 //this.innerCt.setWidth(totalWidth);
33943 this.innerCt.setStyle({ overflow: 'auto' });
33944 this.onResize(this.width, this.height);
33948 onResize : function(w,h)
33953 this.innerCt.setWidth(this.width);
33954 this.innerCt.setHeight(this.height-20);
33957 var cols = this.columns, c;
33958 var totalWidth = 0;
33960 var len = cols.length;
33961 for(var i = 0; i < len; i++){
33963 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33964 // it's the expander..
33965 expEl = this.headEls[i];
33968 totalWidth += c.width;
33972 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33974 this.headers.setWidth(w-20);
33983 * Ext JS Library 1.1.1
33984 * Copyright(c) 2006-2007, Ext JS, LLC.
33986 * Originally Released Under LGPL - original licence link has changed is not relivant.
33989 * <script type="text/javascript">
33993 * @class Roo.menu.Menu
33994 * @extends Roo.util.Observable
33995 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33996 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33998 * Creates a new Menu
33999 * @param {Object} config Configuration options
34001 Roo.menu.Menu = function(config){
34002 Roo.apply(this, config);
34003 this.id = this.id || Roo.id();
34006 * @event beforeshow
34007 * Fires before this menu is displayed
34008 * @param {Roo.menu.Menu} this
34012 * @event beforehide
34013 * Fires before this menu is hidden
34014 * @param {Roo.menu.Menu} this
34019 * Fires after this menu is displayed
34020 * @param {Roo.menu.Menu} this
34025 * Fires after this menu is hidden
34026 * @param {Roo.menu.Menu} this
34031 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
34032 * @param {Roo.menu.Menu} this
34033 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34034 * @param {Roo.EventObject} e
34039 * Fires when the mouse is hovering over this menu
34040 * @param {Roo.menu.Menu} this
34041 * @param {Roo.EventObject} e
34042 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34047 * Fires when the mouse exits this menu
34048 * @param {Roo.menu.Menu} this
34049 * @param {Roo.EventObject} e
34050 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34055 * Fires when a menu item contained in this menu is clicked
34056 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
34057 * @param {Roo.EventObject} e
34061 if (this.registerMenu) {
34062 Roo.menu.MenuMgr.register(this);
34065 var mis = this.items;
34066 this.items = new Roo.util.MixedCollection();
34068 this.add.apply(this, mis);
34072 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
34074 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
34078 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
34079 * for bottom-right shadow (defaults to "sides")
34083 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
34084 * this menu (defaults to "tl-tr?")
34086 subMenuAlign : "tl-tr?",
34088 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
34089 * relative to its element of origin (defaults to "tl-bl?")
34091 defaultAlign : "tl-bl?",
34093 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
34095 allowOtherMenus : false,
34097 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
34099 registerMenu : true,
34104 render : function(){
34108 var el = this.el = new Roo.Layer({
34110 shadow:this.shadow,
34112 parentEl: this.parentEl || document.body,
34116 this.keyNav = new Roo.menu.MenuNav(this);
34119 el.addClass("x-menu-plain");
34122 el.addClass(this.cls);
34124 // generic focus element
34125 this.focusEl = el.createChild({
34126 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
34128 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
34129 ul.on("click", this.onClick, this);
34130 ul.on("mouseover", this.onMouseOver, this);
34131 ul.on("mouseout", this.onMouseOut, this);
34132 this.items.each(function(item){
34133 var li = document.createElement("li");
34134 li.className = "x-menu-list-item";
34135 ul.dom.appendChild(li);
34136 item.render(li, this);
34143 autoWidth : function(){
34144 var el = this.el, ul = this.ul;
34148 var w = this.width;
34151 }else if(Roo.isIE){
34152 el.setWidth(this.minWidth);
34153 var t = el.dom.offsetWidth; // force recalc
34154 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34159 delayAutoWidth : function(){
34162 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
34164 this.awTask.delay(20);
34169 findTargetItem : function(e){
34170 var t = e.getTarget(".x-menu-list-item", this.ul, true);
34171 if(t && t.menuItemId){
34172 return this.items.get(t.menuItemId);
34177 onClick : function(e){
34179 if(t = this.findTargetItem(e)){
34181 this.fireEvent("click", this, t, e);
34186 setActiveItem : function(item, autoExpand){
34187 if(item != this.activeItem){
34188 if(this.activeItem){
34189 this.activeItem.deactivate();
34191 this.activeItem = item;
34192 item.activate(autoExpand);
34193 }else if(autoExpand){
34199 tryActivate : function(start, step){
34200 var items = this.items;
34201 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34202 var item = items.get(i);
34203 if(!item.disabled && item.canActivate){
34204 this.setActiveItem(item, false);
34212 onMouseOver : function(e){
34214 if(t = this.findTargetItem(e)){
34215 if(t.canActivate && !t.disabled){
34216 this.setActiveItem(t, true);
34219 this.fireEvent("mouseover", this, e, t);
34223 onMouseOut : function(e){
34225 if(t = this.findTargetItem(e)){
34226 if(t == this.activeItem && t.shouldDeactivate(e)){
34227 this.activeItem.deactivate();
34228 delete this.activeItem;
34231 this.fireEvent("mouseout", this, e, t);
34235 * Read-only. Returns true if the menu is currently displayed, else false.
34238 isVisible : function(){
34239 return this.el && !this.hidden;
34243 * Displays this menu relative to another element
34244 * @param {String/HTMLElement/Roo.Element} element The element to align to
34245 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34246 * the element (defaults to this.defaultAlign)
34247 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34249 show : function(el, pos, parentMenu){
34250 this.parentMenu = parentMenu;
34254 this.fireEvent("beforeshow", this);
34255 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34259 * Displays this menu at a specific xy position
34260 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34261 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34263 showAt : function(xy, parentMenu, /* private: */_e){
34264 this.parentMenu = parentMenu;
34269 this.fireEvent("beforeshow", this);
34270 xy = this.el.adjustForConstraints(xy);
34274 this.hidden = false;
34276 this.fireEvent("show", this);
34279 focus : function(){
34281 this.doFocus.defer(50, this);
34285 doFocus : function(){
34287 this.focusEl.focus();
34292 * Hides this menu and optionally all parent menus
34293 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34295 hide : function(deep){
34296 if(this.el && this.isVisible()){
34297 this.fireEvent("beforehide", this);
34298 if(this.activeItem){
34299 this.activeItem.deactivate();
34300 this.activeItem = null;
34303 this.hidden = true;
34304 this.fireEvent("hide", this);
34306 if(deep === true && this.parentMenu){
34307 this.parentMenu.hide(true);
34312 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34313 * Any of the following are valid:
34315 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34316 * <li>An HTMLElement object which will be converted to a menu item</li>
34317 * <li>A menu item config object that will be created as a new menu item</li>
34318 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34319 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34324 var menu = new Roo.menu.Menu();
34326 // Create a menu item to add by reference
34327 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34329 // Add a bunch of items at once using different methods.
34330 // Only the last item added will be returned.
34331 var item = menu.add(
34332 menuItem, // add existing item by ref
34333 'Dynamic Item', // new TextItem
34334 '-', // new separator
34335 { text: 'Config Item' } // new item by config
34338 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34339 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34342 var a = arguments, l = a.length, item;
34343 for(var i = 0; i < l; i++){
34345 if ((typeof(el) == "object") && el.xtype && el.xns) {
34346 el = Roo.factory(el, Roo.menu);
34349 if(el.render){ // some kind of Item
34350 item = this.addItem(el);
34351 }else if(typeof el == "string"){ // string
34352 if(el == "separator" || el == "-"){
34353 item = this.addSeparator();
34355 item = this.addText(el);
34357 }else if(el.tagName || el.el){ // element
34358 item = this.addElement(el);
34359 }else if(typeof el == "object"){ // must be menu item config?
34360 item = this.addMenuItem(el);
34367 * Returns this menu's underlying {@link Roo.Element} object
34368 * @return {Roo.Element} The element
34370 getEl : function(){
34378 * Adds a separator bar to the menu
34379 * @return {Roo.menu.Item} The menu item that was added
34381 addSeparator : function(){
34382 return this.addItem(new Roo.menu.Separator());
34386 * Adds an {@link Roo.Element} object to the menu
34387 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34388 * @return {Roo.menu.Item} The menu item that was added
34390 addElement : function(el){
34391 return this.addItem(new Roo.menu.BaseItem(el));
34395 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34396 * @param {Roo.menu.Item} item The menu item to add
34397 * @return {Roo.menu.Item} The menu item that was added
34399 addItem : function(item){
34400 this.items.add(item);
34402 var li = document.createElement("li");
34403 li.className = "x-menu-list-item";
34404 this.ul.dom.appendChild(li);
34405 item.render(li, this);
34406 this.delayAutoWidth();
34412 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34413 * @param {Object} config A MenuItem config object
34414 * @return {Roo.menu.Item} The menu item that was added
34416 addMenuItem : function(config){
34417 if(!(config instanceof Roo.menu.Item)){
34418 if(typeof config.checked == "boolean"){ // must be check menu item config?
34419 config = new Roo.menu.CheckItem(config);
34421 config = new Roo.menu.Item(config);
34424 return this.addItem(config);
34428 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34429 * @param {String} text The text to display in the menu item
34430 * @return {Roo.menu.Item} The menu item that was added
34432 addText : function(text){
34433 return this.addItem(new Roo.menu.TextItem({ text : text }));
34437 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34438 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34439 * @param {Roo.menu.Item} item The menu item to add
34440 * @return {Roo.menu.Item} The menu item that was added
34442 insert : function(index, item){
34443 this.items.insert(index, item);
34445 var li = document.createElement("li");
34446 li.className = "x-menu-list-item";
34447 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34448 item.render(li, this);
34449 this.delayAutoWidth();
34455 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34456 * @param {Roo.menu.Item} item The menu item to remove
34458 remove : function(item){
34459 this.items.removeKey(item.id);
34464 * Removes and destroys all items in the menu
34466 removeAll : function(){
34468 while(f = this.items.first()){
34474 // MenuNav is a private utility class used internally by the Menu
34475 Roo.menu.MenuNav = function(menu){
34476 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34477 this.scope = this.menu = menu;
34480 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34481 doRelay : function(e, h){
34482 var k = e.getKey();
34483 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34484 this.menu.tryActivate(0, 1);
34487 return h.call(this.scope || this, e, this.menu);
34490 up : function(e, m){
34491 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34492 m.tryActivate(m.items.length-1, -1);
34496 down : function(e, m){
34497 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34498 m.tryActivate(0, 1);
34502 right : function(e, m){
34504 m.activeItem.expandMenu(true);
34508 left : function(e, m){
34510 if(m.parentMenu && m.parentMenu.activeItem){
34511 m.parentMenu.activeItem.activate();
34515 enter : function(e, m){
34517 e.stopPropagation();
34518 m.activeItem.onClick(e);
34519 m.fireEvent("click", this, m.activeItem);
34525 * Ext JS Library 1.1.1
34526 * Copyright(c) 2006-2007, Ext JS, LLC.
34528 * Originally Released Under LGPL - original licence link has changed is not relivant.
34531 * <script type="text/javascript">
34535 * @class Roo.menu.MenuMgr
34536 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34539 Roo.menu.MenuMgr = function(){
34540 var menus, active, groups = {}, attached = false, lastShow = new Date();
34542 // private - called when first menu is created
34545 active = new Roo.util.MixedCollection();
34546 Roo.get(document).addKeyListener(27, function(){
34547 if(active.length > 0){
34554 function hideAll(){
34555 if(active && active.length > 0){
34556 var c = active.clone();
34557 c.each(function(m){
34564 function onHide(m){
34566 if(active.length < 1){
34567 Roo.get(document).un("mousedown", onMouseDown);
34573 function onShow(m){
34574 var last = active.last();
34575 lastShow = new Date();
34578 Roo.get(document).on("mousedown", onMouseDown);
34582 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34583 m.parentMenu.activeChild = m;
34584 }else if(last && last.isVisible()){
34585 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34590 function onBeforeHide(m){
34592 m.activeChild.hide();
34594 if(m.autoHideTimer){
34595 clearTimeout(m.autoHideTimer);
34596 delete m.autoHideTimer;
34601 function onBeforeShow(m){
34602 var pm = m.parentMenu;
34603 if(!pm && !m.allowOtherMenus){
34605 }else if(pm && pm.activeChild && active != m){
34606 pm.activeChild.hide();
34611 function onMouseDown(e){
34612 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34618 function onBeforeCheck(mi, state){
34620 var g = groups[mi.group];
34621 for(var i = 0, l = g.length; i < l; i++){
34623 g[i].setChecked(false);
34632 * Hides all menus that are currently visible
34634 hideAll : function(){
34639 register : function(menu){
34643 menus[menu.id] = menu;
34644 menu.on("beforehide", onBeforeHide);
34645 menu.on("hide", onHide);
34646 menu.on("beforeshow", onBeforeShow);
34647 menu.on("show", onShow);
34648 var g = menu.group;
34649 if(g && menu.events["checkchange"]){
34653 groups[g].push(menu);
34654 menu.on("checkchange", onCheck);
34659 * Returns a {@link Roo.menu.Menu} object
34660 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34661 * be used to generate and return a new Menu instance.
34663 get : function(menu){
34664 if(typeof menu == "string"){ // menu id
34665 return menus[menu];
34666 }else if(menu.events){ // menu instance
34668 }else if(typeof menu.length == 'number'){ // array of menu items?
34669 return new Roo.menu.Menu({items:menu});
34670 }else{ // otherwise, must be a config
34671 return new Roo.menu.Menu(menu);
34676 unregister : function(menu){
34677 delete menus[menu.id];
34678 menu.un("beforehide", onBeforeHide);
34679 menu.un("hide", onHide);
34680 menu.un("beforeshow", onBeforeShow);
34681 menu.un("show", onShow);
34682 var g = menu.group;
34683 if(g && menu.events["checkchange"]){
34684 groups[g].remove(menu);
34685 menu.un("checkchange", onCheck);
34690 registerCheckable : function(menuItem){
34691 var g = menuItem.group;
34696 groups[g].push(menuItem);
34697 menuItem.on("beforecheckchange", onBeforeCheck);
34702 unregisterCheckable : function(menuItem){
34703 var g = menuItem.group;
34705 groups[g].remove(menuItem);
34706 menuItem.un("beforecheckchange", onBeforeCheck);
34712 * Ext JS Library 1.1.1
34713 * Copyright(c) 2006-2007, Ext JS, LLC.
34715 * Originally Released Under LGPL - original licence link has changed is not relivant.
34718 * <script type="text/javascript">
34723 * @class Roo.menu.BaseItem
34724 * @extends Roo.Component
34725 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34726 * management and base configuration options shared by all menu components.
34728 * Creates a new BaseItem
34729 * @param {Object} config Configuration options
34731 Roo.menu.BaseItem = function(config){
34732 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34737 * Fires when this item is clicked
34738 * @param {Roo.menu.BaseItem} this
34739 * @param {Roo.EventObject} e
34744 * Fires when this item is activated
34745 * @param {Roo.menu.BaseItem} this
34749 * @event deactivate
34750 * Fires when this item is deactivated
34751 * @param {Roo.menu.BaseItem} this
34757 this.on("click", this.handler, this.scope, true);
34761 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34763 * @cfg {Function} handler
34764 * A function that will handle the click event of this menu item (defaults to undefined)
34767 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34769 canActivate : false,
34771 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34773 activeClass : "x-menu-item-active",
34775 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34777 hideOnClick : true,
34779 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34784 ctype: "Roo.menu.BaseItem",
34787 actionMode : "container",
34790 render : function(container, parentMenu){
34791 this.parentMenu = parentMenu;
34792 Roo.menu.BaseItem.superclass.render.call(this, container);
34793 this.container.menuItemId = this.id;
34797 onRender : function(container, position){
34798 this.el = Roo.get(this.el);
34799 container.dom.appendChild(this.el.dom);
34803 onClick : function(e){
34804 if(!this.disabled && this.fireEvent("click", this, e) !== false
34805 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34806 this.handleClick(e);
34813 activate : function(){
34817 var li = this.container;
34818 li.addClass(this.activeClass);
34819 this.region = li.getRegion().adjust(2, 2, -2, -2);
34820 this.fireEvent("activate", this);
34825 deactivate : function(){
34826 this.container.removeClass(this.activeClass);
34827 this.fireEvent("deactivate", this);
34831 shouldDeactivate : function(e){
34832 return !this.region || !this.region.contains(e.getPoint());
34836 handleClick : function(e){
34837 if(this.hideOnClick){
34838 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34843 expandMenu : function(autoActivate){
34848 hideMenu : function(){
34853 * Ext JS Library 1.1.1
34854 * Copyright(c) 2006-2007, Ext JS, LLC.
34856 * Originally Released Under LGPL - original licence link has changed is not relivant.
34859 * <script type="text/javascript">
34863 * @class Roo.menu.Adapter
34864 * @extends Roo.menu.BaseItem
34865 * 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.
34866 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34868 * Creates a new Adapter
34869 * @param {Object} config Configuration options
34871 Roo.menu.Adapter = function(component, config){
34872 Roo.menu.Adapter.superclass.constructor.call(this, config);
34873 this.component = component;
34875 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34877 canActivate : true,
34880 onRender : function(container, position){
34881 this.component.render(container);
34882 this.el = this.component.getEl();
34886 activate : function(){
34890 this.component.focus();
34891 this.fireEvent("activate", this);
34896 deactivate : function(){
34897 this.fireEvent("deactivate", this);
34901 disable : function(){
34902 this.component.disable();
34903 Roo.menu.Adapter.superclass.disable.call(this);
34907 enable : function(){
34908 this.component.enable();
34909 Roo.menu.Adapter.superclass.enable.call(this);
34913 * Ext JS Library 1.1.1
34914 * Copyright(c) 2006-2007, Ext JS, LLC.
34916 * Originally Released Under LGPL - original licence link has changed is not relivant.
34919 * <script type="text/javascript">
34923 * @class Roo.menu.TextItem
34924 * @extends Roo.menu.BaseItem
34925 * Adds a static text string to a menu, usually used as either a heading or group separator.
34926 * Note: old style constructor with text is still supported.
34929 * Creates a new TextItem
34930 * @param {Object} cfg Configuration
34932 Roo.menu.TextItem = function(cfg){
34933 if (typeof(cfg) == 'string') {
34936 Roo.apply(this,cfg);
34939 Roo.menu.TextItem.superclass.constructor.call(this);
34942 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34944 * @cfg {Boolean} text Text to show on item.
34949 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34951 hideOnClick : false,
34953 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34955 itemCls : "x-menu-text",
34958 onRender : function(){
34959 var s = document.createElement("span");
34960 s.className = this.itemCls;
34961 s.innerHTML = this.text;
34963 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34967 * Ext JS Library 1.1.1
34968 * Copyright(c) 2006-2007, Ext JS, LLC.
34970 * Originally Released Under LGPL - original licence link has changed is not relivant.
34973 * <script type="text/javascript">
34977 * @class Roo.menu.Separator
34978 * @extends Roo.menu.BaseItem
34979 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34980 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34982 * @param {Object} config Configuration options
34984 Roo.menu.Separator = function(config){
34985 Roo.menu.Separator.superclass.constructor.call(this, config);
34988 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34990 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34992 itemCls : "x-menu-sep",
34994 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34996 hideOnClick : false,
34999 onRender : function(li){
35000 var s = document.createElement("span");
35001 s.className = this.itemCls;
35002 s.innerHTML = " ";
35004 li.addClass("x-menu-sep-li");
35005 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
35009 * Ext JS Library 1.1.1
35010 * Copyright(c) 2006-2007, Ext JS, LLC.
35012 * Originally Released Under LGPL - original licence link has changed is not relivant.
35015 * <script type="text/javascript">
35018 * @class Roo.menu.Item
35019 * @extends Roo.menu.BaseItem
35020 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
35021 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
35022 * activation and click handling.
35024 * Creates a new Item
35025 * @param {Object} config Configuration options
35027 Roo.menu.Item = function(config){
35028 Roo.menu.Item.superclass.constructor.call(this, config);
35030 this.menu = Roo.menu.MenuMgr.get(this.menu);
35033 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
35036 * @cfg {String} text
35037 * The text to show on the menu item.
35041 * @cfg {String} HTML to render in menu
35042 * The text to show on the menu item (HTML version).
35046 * @cfg {String} icon
35047 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
35051 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
35053 itemCls : "x-menu-item",
35055 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
35057 canActivate : true,
35059 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
35062 // doc'd in BaseItem
35066 ctype: "Roo.menu.Item",
35069 onRender : function(container, position){
35070 var el = document.createElement("a");
35071 el.hideFocus = true;
35072 el.unselectable = "on";
35073 el.href = this.href || "#";
35074 if(this.hrefTarget){
35075 el.target = this.hrefTarget;
35077 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
35079 var html = this.html.length ? this.html : String.format('{0}',this.text);
35081 el.innerHTML = String.format(
35082 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
35083 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
35085 Roo.menu.Item.superclass.onRender.call(this, container, position);
35089 * Sets the text to display in this menu item
35090 * @param {String} text The text to display
35091 * @param {Boolean} isHTML true to indicate text is pure html.
35093 setText : function(text, isHTML){
35101 var html = this.html.length ? this.html : String.format('{0}',this.text);
35103 this.el.update(String.format(
35104 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
35105 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
35106 this.parentMenu.autoWidth();
35111 handleClick : function(e){
35112 if(!this.href){ // if no link defined, stop the event automatically
35115 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
35119 activate : function(autoExpand){
35120 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
35130 shouldDeactivate : function(e){
35131 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
35132 if(this.menu && this.menu.isVisible()){
35133 return !this.menu.getEl().getRegion().contains(e.getPoint());
35141 deactivate : function(){
35142 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
35147 expandMenu : function(autoActivate){
35148 if(!this.disabled && this.menu){
35149 clearTimeout(this.hideTimer);
35150 delete this.hideTimer;
35151 if(!this.menu.isVisible() && !this.showTimer){
35152 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
35153 }else if (this.menu.isVisible() && autoActivate){
35154 this.menu.tryActivate(0, 1);
35160 deferExpand : function(autoActivate){
35161 delete this.showTimer;
35162 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35164 this.menu.tryActivate(0, 1);
35169 hideMenu : function(){
35170 clearTimeout(this.showTimer);
35171 delete this.showTimer;
35172 if(!this.hideTimer && this.menu && this.menu.isVisible()){
35173 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35178 deferHide : function(){
35179 delete this.hideTimer;
35184 * Ext JS Library 1.1.1
35185 * Copyright(c) 2006-2007, Ext JS, LLC.
35187 * Originally Released Under LGPL - original licence link has changed is not relivant.
35190 * <script type="text/javascript">
35194 * @class Roo.menu.CheckItem
35195 * @extends Roo.menu.Item
35196 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35198 * Creates a new CheckItem
35199 * @param {Object} config Configuration options
35201 Roo.menu.CheckItem = function(config){
35202 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35205 * @event beforecheckchange
35206 * Fires before the checked value is set, providing an opportunity to cancel if needed
35207 * @param {Roo.menu.CheckItem} this
35208 * @param {Boolean} checked The new checked value that will be set
35210 "beforecheckchange" : true,
35212 * @event checkchange
35213 * Fires after the checked value has been set
35214 * @param {Roo.menu.CheckItem} this
35215 * @param {Boolean} checked The checked value that was set
35217 "checkchange" : true
35219 if(this.checkHandler){
35220 this.on('checkchange', this.checkHandler, this.scope);
35223 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35225 * @cfg {String} group
35226 * All check items with the same group name will automatically be grouped into a single-select
35227 * radio button group (defaults to '')
35230 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35232 itemCls : "x-menu-item x-menu-check-item",
35234 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35236 groupClass : "x-menu-group-item",
35239 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35240 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35241 * initialized with checked = true will be rendered as checked.
35246 ctype: "Roo.menu.CheckItem",
35249 onRender : function(c){
35250 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35252 this.el.addClass(this.groupClass);
35254 Roo.menu.MenuMgr.registerCheckable(this);
35256 this.checked = false;
35257 this.setChecked(true, true);
35262 destroy : function(){
35264 Roo.menu.MenuMgr.unregisterCheckable(this);
35266 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35270 * Set the checked state of this item
35271 * @param {Boolean} checked The new checked value
35272 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35274 setChecked : function(state, suppressEvent){
35275 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35276 if(this.container){
35277 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35279 this.checked = state;
35280 if(suppressEvent !== true){
35281 this.fireEvent("checkchange", this, state);
35287 handleClick : function(e){
35288 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35289 this.setChecked(!this.checked);
35291 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35295 * Ext JS Library 1.1.1
35296 * Copyright(c) 2006-2007, Ext JS, LLC.
35298 * Originally Released Under LGPL - original licence link has changed is not relivant.
35301 * <script type="text/javascript">
35305 * @class Roo.menu.DateItem
35306 * @extends Roo.menu.Adapter
35307 * A menu item that wraps the {@link Roo.DatPicker} component.
35309 * Creates a new DateItem
35310 * @param {Object} config Configuration options
35312 Roo.menu.DateItem = function(config){
35313 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35314 /** The Roo.DatePicker object @type Roo.DatePicker */
35315 this.picker = this.component;
35316 this.addEvents({select: true});
35318 this.picker.on("render", function(picker){
35319 picker.getEl().swallowEvent("click");
35320 picker.container.addClass("x-menu-date-item");
35323 this.picker.on("select", this.onSelect, this);
35326 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35328 onSelect : function(picker, date){
35329 this.fireEvent("select", this, date, picker);
35330 Roo.menu.DateItem.superclass.handleClick.call(this);
35334 * Ext JS Library 1.1.1
35335 * Copyright(c) 2006-2007, Ext JS, LLC.
35337 * Originally Released Under LGPL - original licence link has changed is not relivant.
35340 * <script type="text/javascript">
35344 * @class Roo.menu.ColorItem
35345 * @extends Roo.menu.Adapter
35346 * A menu item that wraps the {@link Roo.ColorPalette} component.
35348 * Creates a new ColorItem
35349 * @param {Object} config Configuration options
35351 Roo.menu.ColorItem = function(config){
35352 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35353 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35354 this.palette = this.component;
35355 this.relayEvents(this.palette, ["select"]);
35356 if(this.selectHandler){
35357 this.on('select', this.selectHandler, this.scope);
35360 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35362 * Ext JS Library 1.1.1
35363 * Copyright(c) 2006-2007, Ext JS, LLC.
35365 * Originally Released Under LGPL - original licence link has changed is not relivant.
35368 * <script type="text/javascript">
35373 * @class Roo.menu.DateMenu
35374 * @extends Roo.menu.Menu
35375 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35377 * Creates a new DateMenu
35378 * @param {Object} config Configuration options
35380 Roo.menu.DateMenu = function(config){
35381 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35383 var di = new Roo.menu.DateItem(config);
35386 * The {@link Roo.DatePicker} instance for this DateMenu
35389 this.picker = di.picker;
35392 * @param {DatePicker} picker
35393 * @param {Date} date
35395 this.relayEvents(di, ["select"]);
35397 this.on('beforeshow', function(){
35399 this.picker.hideMonthPicker(true);
35403 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35407 * Ext JS Library 1.1.1
35408 * Copyright(c) 2006-2007, Ext JS, LLC.
35410 * Originally Released Under LGPL - original licence link has changed is not relivant.
35413 * <script type="text/javascript">
35418 * @class Roo.menu.ColorMenu
35419 * @extends Roo.menu.Menu
35420 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35422 * Creates a new ColorMenu
35423 * @param {Object} config Configuration options
35425 Roo.menu.ColorMenu = function(config){
35426 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35428 var ci = new Roo.menu.ColorItem(config);
35431 * The {@link Roo.ColorPalette} instance for this ColorMenu
35432 * @type ColorPalette
35434 this.palette = ci.palette;
35437 * @param {ColorPalette} palette
35438 * @param {String} color
35440 this.relayEvents(ci, ["select"]);
35442 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35444 * Ext JS Library 1.1.1
35445 * Copyright(c) 2006-2007, Ext JS, LLC.
35447 * Originally Released Under LGPL - original licence link has changed is not relivant.
35450 * <script type="text/javascript">
35454 * @class Roo.form.Field
35455 * @extends Roo.BoxComponent
35456 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35458 * Creates a new Field
35459 * @param {Object} config Configuration options
35461 Roo.form.Field = function(config){
35462 Roo.form.Field.superclass.constructor.call(this, config);
35465 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35467 * @cfg {String} fieldLabel Label to use when rendering a form.
35470 * @cfg {String} qtip Mouse over tip
35474 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35476 invalidClass : "x-form-invalid",
35478 * @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")
35480 invalidText : "The value in this field is invalid",
35482 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35484 focusClass : "x-form-focus",
35486 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35487 automatic validation (defaults to "keyup").
35489 validationEvent : "keyup",
35491 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35493 validateOnBlur : true,
35495 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35497 validationDelay : 250,
35499 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35500 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35502 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35504 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35506 fieldClass : "x-form-field",
35508 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35511 ----------- ----------------------------------------------------------------------
35512 qtip Display a quick tip when the user hovers over the field
35513 title Display a default browser title attribute popup
35514 under Add a block div beneath the field containing the error text
35515 side Add an error icon to the right of the field with a popup on hover
35516 [element id] Add the error text directly to the innerHTML of the specified element
35519 msgTarget : 'qtip',
35521 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35526 * @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.
35531 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35536 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35538 inputType : undefined,
35541 * @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).
35543 tabIndex : undefined,
35546 isFormField : true,
35551 * @property {Roo.Element} fieldEl
35552 * Element Containing the rendered Field (with label etc.)
35555 * @cfg {Mixed} value A value to initialize this field with.
35560 * @cfg {String} name The field's HTML name attribute.
35563 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35567 initComponent : function(){
35568 Roo.form.Field.superclass.initComponent.call(this);
35572 * Fires when this field receives input focus.
35573 * @param {Roo.form.Field} this
35578 * Fires when this field loses input focus.
35579 * @param {Roo.form.Field} this
35583 * @event specialkey
35584 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35585 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35586 * @param {Roo.form.Field} this
35587 * @param {Roo.EventObject} e The event object
35592 * Fires just before the field blurs if the field value has changed.
35593 * @param {Roo.form.Field} this
35594 * @param {Mixed} newValue The new value
35595 * @param {Mixed} oldValue The original value
35600 * Fires after the field has been marked as invalid.
35601 * @param {Roo.form.Field} this
35602 * @param {String} msg The validation message
35607 * Fires after the field has been validated with no errors.
35608 * @param {Roo.form.Field} this
35613 * Fires after the key up
35614 * @param {Roo.form.Field} this
35615 * @param {Roo.EventObject} e The event Object
35622 * Returns the name attribute of the field if available
35623 * @return {String} name The field name
35625 getName: function(){
35626 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35630 onRender : function(ct, position){
35631 Roo.form.Field.superclass.onRender.call(this, ct, position);
35633 var cfg = this.getAutoCreate();
35635 cfg.name = this.name || this.id;
35637 if(this.inputType){
35638 cfg.type = this.inputType;
35640 this.el = ct.createChild(cfg, position);
35642 var type = this.el.dom.type;
35644 if(type == 'password'){
35647 this.el.addClass('x-form-'+type);
35650 this.el.dom.readOnly = true;
35652 if(this.tabIndex !== undefined){
35653 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35656 this.el.addClass([this.fieldClass, this.cls]);
35661 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35662 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35663 * @return {Roo.form.Field} this
35665 applyTo : function(target){
35666 this.allowDomMove = false;
35667 this.el = Roo.get(target);
35668 this.render(this.el.dom.parentNode);
35673 initValue : function(){
35674 if(this.value !== undefined){
35675 this.setValue(this.value);
35676 }else if(this.el.dom.value.length > 0){
35677 this.setValue(this.el.dom.value);
35682 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35684 isDirty : function() {
35685 if(this.disabled) {
35688 return String(this.getValue()) !== String(this.originalValue);
35692 afterRender : function(){
35693 Roo.form.Field.superclass.afterRender.call(this);
35698 fireKey : function(e){
35699 //Roo.log('field ' + e.getKey());
35700 if(e.isNavKeyPress()){
35701 this.fireEvent("specialkey", this, e);
35706 * Resets the current field value to the originally loaded value and clears any validation messages
35708 reset : function(){
35709 this.setValue(this.originalValue);
35710 this.clearInvalid();
35714 initEvents : function(){
35715 // safari killled keypress - so keydown is now used..
35716 this.el.on("keydown" , this.fireKey, this);
35717 this.el.on("focus", this.onFocus, this);
35718 this.el.on("blur", this.onBlur, this);
35719 this.el.relayEvent('keyup', this);
35721 // reference to original value for reset
35722 this.originalValue = this.getValue();
35726 onFocus : function(){
35727 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35728 this.el.addClass(this.focusClass);
35730 if(!this.hasFocus){
35731 this.hasFocus = true;
35732 this.startValue = this.getValue();
35733 this.fireEvent("focus", this);
35737 beforeBlur : Roo.emptyFn,
35740 onBlur : function(){
35742 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35743 this.el.removeClass(this.focusClass);
35745 this.hasFocus = false;
35746 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35749 var v = this.getValue();
35750 if(String(v) !== String(this.startValue)){
35751 this.fireEvent('change', this, v, this.startValue);
35753 this.fireEvent("blur", this);
35757 * Returns whether or not the field value is currently valid
35758 * @param {Boolean} preventMark True to disable marking the field invalid
35759 * @return {Boolean} True if the value is valid, else false
35761 isValid : function(preventMark){
35765 var restore = this.preventMark;
35766 this.preventMark = preventMark === true;
35767 var v = this.validateValue(this.processValue(this.getRawValue()));
35768 this.preventMark = restore;
35773 * Validates the field value
35774 * @return {Boolean} True if the value is valid, else false
35776 validate : function(){
35777 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35778 this.clearInvalid();
35784 processValue : function(value){
35789 // Subclasses should provide the validation implementation by overriding this
35790 validateValue : function(value){
35795 * Mark this field as invalid
35796 * @param {String} msg The validation message
35798 markInvalid : function(msg){
35799 if(!this.rendered || this.preventMark){ // not rendered
35802 this.el.addClass(this.invalidClass);
35803 msg = msg || this.invalidText;
35804 switch(this.msgTarget){
35806 this.el.dom.qtip = msg;
35807 this.el.dom.qclass = 'x-form-invalid-tip';
35808 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35809 Roo.QuickTips.enable();
35813 this.el.dom.title = msg;
35817 var elp = this.el.findParent('.x-form-element', 5, true);
35818 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35819 this.errorEl.setWidth(elp.getWidth(true)-20);
35821 this.errorEl.update(msg);
35822 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35825 if(!this.errorIcon){
35826 var elp = this.el.findParent('.x-form-element', 5, true);
35827 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35829 this.alignErrorIcon();
35830 this.errorIcon.dom.qtip = msg;
35831 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35832 this.errorIcon.show();
35833 this.on('resize', this.alignErrorIcon, this);
35836 var t = Roo.getDom(this.msgTarget);
35838 t.style.display = this.msgDisplay;
35841 this.fireEvent('invalid', this, msg);
35845 alignErrorIcon : function(){
35846 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35850 * Clear any invalid styles/messages for this field
35852 clearInvalid : function(){
35853 if(!this.rendered || this.preventMark){ // not rendered
35856 this.el.removeClass(this.invalidClass);
35857 switch(this.msgTarget){
35859 this.el.dom.qtip = '';
35862 this.el.dom.title = '';
35866 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35870 if(this.errorIcon){
35871 this.errorIcon.dom.qtip = '';
35872 this.errorIcon.hide();
35873 this.un('resize', this.alignErrorIcon, this);
35877 var t = Roo.getDom(this.msgTarget);
35879 t.style.display = 'none';
35882 this.fireEvent('valid', this);
35886 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35887 * @return {Mixed} value The field value
35889 getRawValue : function(){
35890 var v = this.el.getValue();
35891 if(v === this.emptyText){
35898 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35899 * @return {Mixed} value The field value
35901 getValue : function(){
35902 var v = this.el.getValue();
35903 if(v === this.emptyText || v === undefined){
35910 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35911 * @param {Mixed} value The value to set
35913 setRawValue : function(v){
35914 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35918 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35919 * @param {Mixed} value The value to set
35921 setValue : function(v){
35924 this.el.dom.value = (v === null || v === undefined ? '' : v);
35929 adjustSize : function(w, h){
35930 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35931 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35935 adjustWidth : function(tag, w){
35936 tag = tag.toLowerCase();
35937 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35938 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35939 if(tag == 'input'){
35942 if(tag = 'textarea'){
35945 }else if(Roo.isOpera){
35946 if(tag == 'input'){
35949 if(tag = 'textarea'){
35959 // anything other than normal should be considered experimental
35960 Roo.form.Field.msgFx = {
35962 show: function(msgEl, f){
35963 msgEl.setDisplayed('block');
35966 hide : function(msgEl, f){
35967 msgEl.setDisplayed(false).update('');
35972 show: function(msgEl, f){
35973 msgEl.slideIn('t', {stopFx:true});
35976 hide : function(msgEl, f){
35977 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35982 show: function(msgEl, f){
35983 msgEl.fixDisplay();
35984 msgEl.alignTo(f.el, 'tl-tr');
35985 msgEl.slideIn('l', {stopFx:true});
35988 hide : function(msgEl, f){
35989 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35994 * Ext JS Library 1.1.1
35995 * Copyright(c) 2006-2007, Ext JS, LLC.
35997 * Originally Released Under LGPL - original licence link has changed is not relivant.
36000 * <script type="text/javascript">
36005 * @class Roo.form.TextField
36006 * @extends Roo.form.Field
36007 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
36008 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
36010 * Creates a new TextField
36011 * @param {Object} config Configuration options
36013 Roo.form.TextField = function(config){
36014 Roo.form.TextField.superclass.constructor.call(this, config);
36018 * Fires when the autosize function is triggered. The field may or may not have actually changed size
36019 * according to the default logic, but this event provides a hook for the developer to apply additional
36020 * logic at runtime to resize the field if needed.
36021 * @param {Roo.form.Field} this This text field
36022 * @param {Number} width The new field width
36028 Roo.extend(Roo.form.TextField, Roo.form.Field, {
36030 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
36034 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
36038 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
36042 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
36046 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
36050 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
36052 disableKeyFilter : false,
36054 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
36058 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
36062 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
36064 maxLength : Number.MAX_VALUE,
36066 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
36068 minLengthText : "The minimum length for this field is {0}",
36070 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
36072 maxLengthText : "The maximum length for this field is {0}",
36074 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
36076 selectOnFocus : false,
36078 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
36080 blankText : "This field is required",
36082 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
36083 * If available, this function will be called only after the basic validators all return true, and will be passed the
36084 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
36088 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
36089 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
36090 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
36094 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
36098 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
36102 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
36103 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
36105 emptyClass : 'x-form-empty-field',
36108 initEvents : function(){
36109 Roo.form.TextField.superclass.initEvents.call(this);
36110 if(this.validationEvent == 'keyup'){
36111 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
36112 this.el.on('keyup', this.filterValidation, this);
36114 else if(this.validationEvent !== false){
36115 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
36117 if(this.selectOnFocus || this.emptyText){
36118 this.on("focus", this.preFocus, this);
36119 if(this.emptyText){
36120 this.on('blur', this.postBlur, this);
36121 this.applyEmptyText();
36124 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
36125 this.el.on("keypress", this.filterKeys, this);
36128 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
36129 this.el.on("click", this.autoSize, this);
36133 processValue : function(value){
36134 if(this.stripCharsRe){
36135 var newValue = value.replace(this.stripCharsRe, '');
36136 if(newValue !== value){
36137 this.setRawValue(newValue);
36144 filterValidation : function(e){
36145 if(!e.isNavKeyPress()){
36146 this.validationTask.delay(this.validationDelay);
36151 onKeyUp : function(e){
36152 if(!e.isNavKeyPress()){
36158 * Resets the current field value to the originally-loaded value and clears any validation messages.
36159 * Also adds emptyText and emptyClass if the original value was blank.
36161 reset : function(){
36162 Roo.form.TextField.superclass.reset.call(this);
36163 this.applyEmptyText();
36166 applyEmptyText : function(){
36167 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
36168 this.setRawValue(this.emptyText);
36169 this.el.addClass(this.emptyClass);
36174 preFocus : function(){
36175 if(this.emptyText){
36176 if(this.el.dom.value == this.emptyText){
36177 this.setRawValue('');
36179 this.el.removeClass(this.emptyClass);
36181 if(this.selectOnFocus){
36182 this.el.dom.select();
36187 postBlur : function(){
36188 this.applyEmptyText();
36192 filterKeys : function(e){
36193 var k = e.getKey();
36194 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36197 var c = e.getCharCode(), cc = String.fromCharCode(c);
36198 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36201 if(!this.maskRe.test(cc)){
36206 setValue : function(v){
36207 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
36208 this.el.removeClass(this.emptyClass);
36210 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36211 this.applyEmptyText();
36216 * Validates a value according to the field's validation rules and marks the field as invalid
36217 * if the validation fails
36218 * @param {Mixed} value The value to validate
36219 * @return {Boolean} True if the value is valid, else false
36221 validateValue : function(value){
36222 if(value.length < 1 || value === this.emptyText){ // if it's blank
36223 if(this.allowBlank){
36224 this.clearInvalid();
36227 this.markInvalid(this.blankText);
36231 if(value.length < this.minLength){
36232 this.markInvalid(String.format(this.minLengthText, this.minLength));
36235 if(value.length > this.maxLength){
36236 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36240 var vt = Roo.form.VTypes;
36241 if(!vt[this.vtype](value, this)){
36242 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36246 if(typeof this.validator == "function"){
36247 var msg = this.validator(value);
36249 this.markInvalid(msg);
36253 if(this.regex && !this.regex.test(value)){
36254 this.markInvalid(this.regexText);
36261 * Selects text in this field
36262 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36263 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36265 selectText : function(start, end){
36266 var v = this.getRawValue();
36268 start = start === undefined ? 0 : start;
36269 end = end === undefined ? v.length : end;
36270 var d = this.el.dom;
36271 if(d.setSelectionRange){
36272 d.setSelectionRange(start, end);
36273 }else if(d.createTextRange){
36274 var range = d.createTextRange();
36275 range.moveStart("character", start);
36276 range.moveEnd("character", v.length-end);
36283 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36284 * This only takes effect if grow = true, and fires the autosize event.
36286 autoSize : function(){
36287 if(!this.grow || !this.rendered){
36291 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36294 var v = el.dom.value;
36295 var d = document.createElement('div');
36296 d.appendChild(document.createTextNode(v));
36300 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36301 this.el.setWidth(w);
36302 this.fireEvent("autosize", this, w);
36306 * Ext JS Library 1.1.1
36307 * Copyright(c) 2006-2007, Ext JS, LLC.
36309 * Originally Released Under LGPL - original licence link has changed is not relivant.
36312 * <script type="text/javascript">
36316 * @class Roo.form.Hidden
36317 * @extends Roo.form.TextField
36318 * Simple Hidden element used on forms
36320 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36323 * Creates a new Hidden form element.
36324 * @param {Object} config Configuration options
36329 // easy hidden field...
36330 Roo.form.Hidden = function(config){
36331 Roo.form.Hidden.superclass.constructor.call(this, config);
36334 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36336 inputType: 'hidden',
36339 labelSeparator: '',
36341 itemCls : 'x-form-item-display-none'
36349 * Ext JS Library 1.1.1
36350 * Copyright(c) 2006-2007, Ext JS, LLC.
36352 * Originally Released Under LGPL - original licence link has changed is not relivant.
36355 * <script type="text/javascript">
36359 * @class Roo.form.TriggerField
36360 * @extends Roo.form.TextField
36361 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36362 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36363 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36364 * for which you can provide a custom implementation. For example:
36366 var trigger = new Roo.form.TriggerField();
36367 trigger.onTriggerClick = myTriggerFn;
36368 trigger.applyTo('my-field');
36371 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36372 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36373 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36374 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36376 * Create a new TriggerField.
36377 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36378 * to the base TextField)
36380 Roo.form.TriggerField = function(config){
36381 this.mimicing = false;
36382 Roo.form.TriggerField.superclass.constructor.call(this, config);
36385 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36387 * @cfg {String} triggerClass A CSS class to apply to the trigger
36390 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36391 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36393 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36395 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36399 /** @cfg {Boolean} grow @hide */
36400 /** @cfg {Number} growMin @hide */
36401 /** @cfg {Number} growMax @hide */
36407 autoSize: Roo.emptyFn,
36411 deferHeight : true,
36414 actionMode : 'wrap',
36416 onResize : function(w, h){
36417 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36418 if(typeof w == 'number'){
36419 var x = w - this.trigger.getWidth();
36420 this.el.setWidth(this.adjustWidth('input', x));
36421 this.trigger.setStyle('left', x+'px');
36426 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36429 getResizeEl : function(){
36434 getPositionEl : function(){
36439 alignErrorIcon : function(){
36440 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36444 onRender : function(ct, position){
36445 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36446 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36447 this.trigger = this.wrap.createChild(this.triggerConfig ||
36448 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36449 if(this.hideTrigger){
36450 this.trigger.setDisplayed(false);
36452 this.initTrigger();
36454 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36459 initTrigger : function(){
36460 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36461 this.trigger.addClassOnOver('x-form-trigger-over');
36462 this.trigger.addClassOnClick('x-form-trigger-click');
36466 onDestroy : function(){
36468 this.trigger.removeAllListeners();
36469 this.trigger.remove();
36472 this.wrap.remove();
36474 Roo.form.TriggerField.superclass.onDestroy.call(this);
36478 onFocus : function(){
36479 Roo.form.TriggerField.superclass.onFocus.call(this);
36480 if(!this.mimicing){
36481 this.wrap.addClass('x-trigger-wrap-focus');
36482 this.mimicing = true;
36483 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36484 if(this.monitorTab){
36485 this.el.on("keydown", this.checkTab, this);
36491 checkTab : function(e){
36492 if(e.getKey() == e.TAB){
36493 this.triggerBlur();
36498 onBlur : function(){
36503 mimicBlur : function(e, t){
36504 if(!this.wrap.contains(t) && this.validateBlur()){
36505 this.triggerBlur();
36510 triggerBlur : function(){
36511 this.mimicing = false;
36512 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36513 if(this.monitorTab){
36514 this.el.un("keydown", this.checkTab, this);
36516 this.wrap.removeClass('x-trigger-wrap-focus');
36517 Roo.form.TriggerField.superclass.onBlur.call(this);
36521 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36522 validateBlur : function(e, t){
36527 onDisable : function(){
36528 Roo.form.TriggerField.superclass.onDisable.call(this);
36530 this.wrap.addClass('x-item-disabled');
36535 onEnable : function(){
36536 Roo.form.TriggerField.superclass.onEnable.call(this);
36538 this.wrap.removeClass('x-item-disabled');
36543 onShow : function(){
36544 var ae = this.getActionEl();
36547 ae.dom.style.display = '';
36548 ae.dom.style.visibility = 'visible';
36554 onHide : function(){
36555 var ae = this.getActionEl();
36556 ae.dom.style.display = 'none';
36560 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36561 * by an implementing function.
36563 * @param {EventObject} e
36565 onTriggerClick : Roo.emptyFn
36568 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36569 // to be extended by an implementing class. For an example of implementing this class, see the custom
36570 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36571 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36572 initComponent : function(){
36573 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36575 this.triggerConfig = {
36576 tag:'span', cls:'x-form-twin-triggers', cn:[
36577 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36578 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36582 getTrigger : function(index){
36583 return this.triggers[index];
36586 initTrigger : function(){
36587 var ts = this.trigger.select('.x-form-trigger', true);
36588 this.wrap.setStyle('overflow', 'hidden');
36589 var triggerField = this;
36590 ts.each(function(t, all, index){
36591 t.hide = function(){
36592 var w = triggerField.wrap.getWidth();
36593 this.dom.style.display = 'none';
36594 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36596 t.show = function(){
36597 var w = triggerField.wrap.getWidth();
36598 this.dom.style.display = '';
36599 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36601 var triggerIndex = 'Trigger'+(index+1);
36603 if(this['hide'+triggerIndex]){
36604 t.dom.style.display = 'none';
36606 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36607 t.addClassOnOver('x-form-trigger-over');
36608 t.addClassOnClick('x-form-trigger-click');
36610 this.triggers = ts.elements;
36613 onTrigger1Click : Roo.emptyFn,
36614 onTrigger2Click : Roo.emptyFn
36617 * Ext JS Library 1.1.1
36618 * Copyright(c) 2006-2007, Ext JS, LLC.
36620 * Originally Released Under LGPL - original licence link has changed is not relivant.
36623 * <script type="text/javascript">
36627 * @class Roo.form.TextArea
36628 * @extends Roo.form.TextField
36629 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36630 * support for auto-sizing.
36632 * Creates a new TextArea
36633 * @param {Object} config Configuration options
36635 Roo.form.TextArea = function(config){
36636 Roo.form.TextArea.superclass.constructor.call(this, config);
36637 // these are provided exchanges for backwards compat
36638 // minHeight/maxHeight were replaced by growMin/growMax to be
36639 // compatible with TextField growing config values
36640 if(this.minHeight !== undefined){
36641 this.growMin = this.minHeight;
36643 if(this.maxHeight !== undefined){
36644 this.growMax = this.maxHeight;
36648 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36650 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36654 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36658 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36659 * in the field (equivalent to setting overflow: hidden, defaults to false)
36661 preventScrollbars: false,
36663 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36664 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36668 onRender : function(ct, position){
36670 this.defaultAutoCreate = {
36672 style:"width:300px;height:60px;",
36673 autocomplete: "off"
36676 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36678 this.textSizeEl = Roo.DomHelper.append(document.body, {
36679 tag: "pre", cls: "x-form-grow-sizer"
36681 if(this.preventScrollbars){
36682 this.el.setStyle("overflow", "hidden");
36684 this.el.setHeight(this.growMin);
36688 onDestroy : function(){
36689 if(this.textSizeEl){
36690 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36692 Roo.form.TextArea.superclass.onDestroy.call(this);
36696 onKeyUp : function(e){
36697 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36703 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36704 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36706 autoSize : function(){
36707 if(!this.grow || !this.textSizeEl){
36711 var v = el.dom.value;
36712 var ts = this.textSizeEl;
36715 ts.appendChild(document.createTextNode(v));
36718 Roo.fly(ts).setWidth(this.el.getWidth());
36720 v = "  ";
36723 v = v.replace(/\n/g, '<p> </p>');
36725 v += " \n ";
36728 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36729 if(h != this.lastHeight){
36730 this.lastHeight = h;
36731 this.el.setHeight(h);
36732 this.fireEvent("autosize", this, h);
36737 * Ext JS Library 1.1.1
36738 * Copyright(c) 2006-2007, Ext JS, LLC.
36740 * Originally Released Under LGPL - original licence link has changed is not relivant.
36743 * <script type="text/javascript">
36748 * @class Roo.form.NumberField
36749 * @extends Roo.form.TextField
36750 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36752 * Creates a new NumberField
36753 * @param {Object} config Configuration options
36755 Roo.form.NumberField = function(config){
36756 Roo.form.NumberField.superclass.constructor.call(this, config);
36759 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36761 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36763 fieldClass: "x-form-field x-form-num-field",
36765 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36767 allowDecimals : true,
36769 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36771 decimalSeparator : ".",
36773 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36775 decimalPrecision : 2,
36777 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36779 allowNegative : true,
36781 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36783 minValue : Number.NEGATIVE_INFINITY,
36785 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36787 maxValue : Number.MAX_VALUE,
36789 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36791 minText : "The minimum value for this field is {0}",
36793 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36795 maxText : "The maximum value for this field is {0}",
36797 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36798 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36800 nanText : "{0} is not a valid number",
36803 initEvents : function(){
36804 Roo.form.NumberField.superclass.initEvents.call(this);
36805 var allowed = "0123456789";
36806 if(this.allowDecimals){
36807 allowed += this.decimalSeparator;
36809 if(this.allowNegative){
36812 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36813 var keyPress = function(e){
36814 var k = e.getKey();
36815 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36818 var c = e.getCharCode();
36819 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36823 this.el.on("keypress", keyPress, this);
36827 validateValue : function(value){
36828 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36831 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36834 var num = this.parseValue(value);
36836 this.markInvalid(String.format(this.nanText, value));
36839 if(num < this.minValue){
36840 this.markInvalid(String.format(this.minText, this.minValue));
36843 if(num > this.maxValue){
36844 this.markInvalid(String.format(this.maxText, this.maxValue));
36850 getValue : function(){
36851 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36855 parseValue : function(value){
36856 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36857 return isNaN(value) ? '' : value;
36861 fixPrecision : function(value){
36862 var nan = isNaN(value);
36863 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36864 return nan ? '' : value;
36866 return parseFloat(value).toFixed(this.decimalPrecision);
36869 setValue : function(v){
36870 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36874 decimalPrecisionFcn : function(v){
36875 return Math.floor(v);
36878 beforeBlur : function(){
36879 var v = this.parseValue(this.getRawValue());
36881 this.setValue(this.fixPrecision(v));
36886 * Ext JS Library 1.1.1
36887 * Copyright(c) 2006-2007, Ext JS, LLC.
36889 * Originally Released Under LGPL - original licence link has changed is not relivant.
36892 * <script type="text/javascript">
36896 * @class Roo.form.DateField
36897 * @extends Roo.form.TriggerField
36898 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36900 * Create a new DateField
36901 * @param {Object} config
36903 Roo.form.DateField = function(config){
36904 Roo.form.DateField.superclass.constructor.call(this, config);
36910 * Fires when a date is selected
36911 * @param {Roo.form.DateField} combo This combo box
36912 * @param {Date} date The date selected
36919 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36920 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36921 this.ddMatch = null;
36922 if(this.disabledDates){
36923 var dd = this.disabledDates;
36925 for(var i = 0; i < dd.length; i++){
36927 if(i != dd.length-1) re += "|";
36929 this.ddMatch = new RegExp(re + ")");
36933 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36935 * @cfg {String} format
36936 * The default date format string which can be overriden for localization support. The format must be
36937 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36941 * @cfg {String} altFormats
36942 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36943 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36945 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36947 * @cfg {Array} disabledDays
36948 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36950 disabledDays : null,
36952 * @cfg {String} disabledDaysText
36953 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36955 disabledDaysText : "Disabled",
36957 * @cfg {Array} disabledDates
36958 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36959 * expression so they are very powerful. Some examples:
36961 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36962 * <li>["03/08", "09/16"] would disable those days for every year</li>
36963 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36964 * <li>["03/../2006"] would disable every day in March 2006</li>
36965 * <li>["^03"] would disable every day in every March</li>
36967 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36968 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36970 disabledDates : null,
36972 * @cfg {String} disabledDatesText
36973 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36975 disabledDatesText : "Disabled",
36977 * @cfg {Date/String} minValue
36978 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36979 * valid format (defaults to null).
36983 * @cfg {Date/String} maxValue
36984 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36985 * valid format (defaults to null).
36989 * @cfg {String} minText
36990 * The error text to display when the date in the cell is before minValue (defaults to
36991 * 'The date in this field must be after {minValue}').
36993 minText : "The date in this field must be equal to or after {0}",
36995 * @cfg {String} maxText
36996 * The error text to display when the date in the cell is after maxValue (defaults to
36997 * 'The date in this field must be before {maxValue}').
36999 maxText : "The date in this field must be equal to or before {0}",
37001 * @cfg {String} invalidText
37002 * The error text to display when the date in the field is invalid (defaults to
37003 * '{value} is not a valid date - it must be in the format {format}').
37005 invalidText : "{0} is not a valid date - it must be in the format {1}",
37007 * @cfg {String} triggerClass
37008 * An additional CSS class used to style the trigger button. The trigger will always get the
37009 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
37010 * which displays a calendar icon).
37012 triggerClass : 'x-form-date-trigger',
37016 * @cfg {bool} useIso
37017 * if enabled, then the date field will use a hidden field to store the
37018 * real value as iso formated date. default (false)
37022 * @cfg {String/Object} autoCreate
37023 * A DomHelper element spec, or true for a default element spec (defaults to
37024 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
37027 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
37030 hiddenField: false,
37032 onRender : function(ct, position)
37034 Roo.form.DateField.superclass.onRender.call(this, ct, position);
37036 this.el.dom.removeAttribute('name');
37037 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
37039 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
37040 // prevent input submission
37041 this.hiddenName = this.name;
37048 validateValue : function(value)
37050 value = this.formatDate(value);
37051 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
37054 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37057 var svalue = value;
37058 value = this.parseDate(value);
37060 this.markInvalid(String.format(this.invalidText, svalue, this.format));
37063 var time = value.getTime();
37064 if(this.minValue && time < this.minValue.getTime()){
37065 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
37068 if(this.maxValue && time > this.maxValue.getTime()){
37069 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
37072 if(this.disabledDays){
37073 var day = value.getDay();
37074 for(var i = 0; i < this.disabledDays.length; i++) {
37075 if(day === this.disabledDays[i]){
37076 this.markInvalid(this.disabledDaysText);
37081 var fvalue = this.formatDate(value);
37082 if(this.ddMatch && this.ddMatch.test(fvalue)){
37083 this.markInvalid(String.format(this.disabledDatesText, fvalue));
37090 // Provides logic to override the default TriggerField.validateBlur which just returns true
37091 validateBlur : function(){
37092 return !this.menu || !this.menu.isVisible();
37096 * Returns the current date value of the date field.
37097 * @return {Date} The date value
37099 getValue : function(){
37101 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
37105 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
37106 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
37107 * (the default format used is "m/d/y").
37110 //All of these calls set the same date value (May 4, 2006)
37112 //Pass a date object:
37113 var dt = new Date('5/4/06');
37114 dateField.setValue(dt);
37116 //Pass a date string (default format):
37117 dateField.setValue('5/4/06');
37119 //Pass a date string (custom format):
37120 dateField.format = 'Y-m-d';
37121 dateField.setValue('2006-5-4');
37123 * @param {String/Date} date The date or valid date string
37125 setValue : function(date){
37126 if (this.hiddenField) {
37127 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
37129 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
37133 parseDate : function(value){
37134 if(!value || value instanceof Date){
37137 var v = Date.parseDate(value, this.format);
37138 if(!v && this.altFormats){
37139 if(!this.altFormatsArray){
37140 this.altFormatsArray = this.altFormats.split("|");
37142 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
37143 v = Date.parseDate(value, this.altFormatsArray[i]);
37150 formatDate : function(date, fmt){
37151 return (!date || !(date instanceof Date)) ?
37152 date : date.dateFormat(fmt || this.format);
37157 select: function(m, d){
37159 this.fireEvent('select', this, d);
37161 show : function(){ // retain focus styling
37165 this.focus.defer(10, this);
37166 var ml = this.menuListeners;
37167 this.menu.un("select", ml.select, this);
37168 this.menu.un("show", ml.show, this);
37169 this.menu.un("hide", ml.hide, this);
37174 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37175 onTriggerClick : function(){
37179 if(this.menu == null){
37180 this.menu = new Roo.menu.DateMenu();
37182 Roo.apply(this.menu.picker, {
37183 showClear: this.allowBlank,
37184 minDate : this.minValue,
37185 maxDate : this.maxValue,
37186 disabledDatesRE : this.ddMatch,
37187 disabledDatesText : this.disabledDatesText,
37188 disabledDays : this.disabledDays,
37189 disabledDaysText : this.disabledDaysText,
37190 format : this.format,
37191 minText : String.format(this.minText, this.formatDate(this.minValue)),
37192 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37194 this.menu.on(Roo.apply({}, this.menuListeners, {
37197 this.menu.picker.setValue(this.getValue() || new Date());
37198 this.menu.show(this.el, "tl-bl?");
37201 beforeBlur : function(){
37202 var v = this.parseDate(this.getRawValue());
37208 /** @cfg {Boolean} grow @hide */
37209 /** @cfg {Number} growMin @hide */
37210 /** @cfg {Number} growMax @hide */
37217 * Ext JS Library 1.1.1
37218 * Copyright(c) 2006-2007, Ext JS, LLC.
37220 * Originally Released Under LGPL - original licence link has changed is not relivant.
37223 * <script type="text/javascript">
37228 * @class Roo.form.ComboBox
37229 * @extends Roo.form.TriggerField
37230 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
37232 * Create a new ComboBox.
37233 * @param {Object} config Configuration options
37235 Roo.form.ComboBox = function(config){
37236 Roo.form.ComboBox.superclass.constructor.call(this, config);
37240 * Fires when the dropdown list is expanded
37241 * @param {Roo.form.ComboBox} combo This combo box
37246 * Fires when the dropdown list is collapsed
37247 * @param {Roo.form.ComboBox} combo This combo box
37251 * @event beforeselect
37252 * Fires before a list item is selected. Return false to cancel the selection.
37253 * @param {Roo.form.ComboBox} combo This combo box
37254 * @param {Roo.data.Record} record The data record returned from the underlying store
37255 * @param {Number} index The index of the selected item in the dropdown list
37257 'beforeselect' : true,
37260 * Fires when a list item is selected
37261 * @param {Roo.form.ComboBox} combo This combo box
37262 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37263 * @param {Number} index The index of the selected item in the dropdown list
37267 * @event beforequery
37268 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37269 * The event object passed has these properties:
37270 * @param {Roo.form.ComboBox} combo This combo box
37271 * @param {String} query The query
37272 * @param {Boolean} forceAll true to force "all" query
37273 * @param {Boolean} cancel true to cancel the query
37274 * @param {Object} e The query event object
37276 'beforequery': true,
37279 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37280 * @param {Roo.form.ComboBox} combo This combo box
37285 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37286 * @param {Roo.form.ComboBox} combo This combo box
37287 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37293 if(this.transform){
37294 this.allowDomMove = false;
37295 var s = Roo.getDom(this.transform);
37296 if(!this.hiddenName){
37297 this.hiddenName = s.name;
37300 this.mode = 'local';
37301 var d = [], opts = s.options;
37302 for(var i = 0, len = opts.length;i < len; i++){
37304 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37306 this.value = value;
37308 d.push([value, o.text]);
37310 this.store = new Roo.data.SimpleStore({
37312 fields: ['value', 'text'],
37315 this.valueField = 'value';
37316 this.displayField = 'text';
37318 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37319 if(!this.lazyRender){
37320 this.target = true;
37321 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37322 s.parentNode.removeChild(s); // remove it
37323 this.render(this.el.parentNode);
37325 s.parentNode.removeChild(s); // remove it
37330 this.store = Roo.factory(this.store, Roo.data);
37333 this.selectedIndex = -1;
37334 if(this.mode == 'local'){
37335 if(config.queryDelay === undefined){
37336 this.queryDelay = 10;
37338 if(config.minChars === undefined){
37344 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37346 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37349 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37350 * rendering into an Roo.Editor, defaults to false)
37353 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37354 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37357 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37360 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37361 * the dropdown list (defaults to undefined, with no header element)
37365 * @cfg {String/Roo.Template} tpl The template to use to render the output
37369 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37371 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37373 listWidth: undefined,
37375 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37376 * mode = 'remote' or 'text' if mode = 'local')
37378 displayField: undefined,
37380 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37381 * mode = 'remote' or 'value' if mode = 'local').
37382 * Note: use of a valueField requires the user make a selection
37383 * in order for a value to be mapped.
37385 valueField: undefined,
37389 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37390 * field's data value (defaults to the underlying DOM element's name)
37392 hiddenName: undefined,
37394 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37398 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37400 selectedClass: 'x-combo-selected',
37402 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37403 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37404 * which displays a downward arrow icon).
37406 triggerClass : 'x-form-arrow-trigger',
37408 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37412 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37413 * anchor positions (defaults to 'tl-bl')
37415 listAlign: 'tl-bl?',
37417 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37421 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37422 * query specified by the allQuery config option (defaults to 'query')
37424 triggerAction: 'query',
37426 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37427 * (defaults to 4, does not apply if editable = false)
37431 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37432 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37436 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37437 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37441 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37442 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37446 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37447 * when editable = true (defaults to false)
37449 selectOnFocus:false,
37451 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37453 queryParam: 'query',
37455 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37456 * when mode = 'remote' (defaults to 'Loading...')
37458 loadingText: 'Loading...',
37460 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37464 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37468 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37469 * traditional select (defaults to true)
37473 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37477 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37481 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37482 * listWidth has a higher value)
37486 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37487 * allow the user to set arbitrary text into the field (defaults to false)
37489 forceSelection:false,
37491 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37492 * if typeAhead = true (defaults to 250)
37494 typeAheadDelay : 250,
37496 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37497 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37499 valueNotFoundText : undefined,
37501 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37503 blockFocus : false,
37506 * @cfg {Boolean} disableClear Disable showing of clear button.
37508 disableClear : false,
37510 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37512 alwaysQuery : false,
37518 // element that contains real text value.. (when hidden is used..)
37521 onRender : function(ct, position){
37522 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37523 if(this.hiddenName){
37524 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37526 this.hiddenField.value =
37527 this.hiddenValue !== undefined ? this.hiddenValue :
37528 this.value !== undefined ? this.value : '';
37530 // prevent input submission
37531 this.el.dom.removeAttribute('name');
37536 this.el.dom.setAttribute('autocomplete', 'off');
37539 var cls = 'x-combo-list';
37541 this.list = new Roo.Layer({
37542 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37545 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37546 this.list.setWidth(lw);
37547 this.list.swallowEvent('mousewheel');
37548 this.assetHeight = 0;
37551 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37552 this.assetHeight += this.header.getHeight();
37555 this.innerList = this.list.createChild({cls:cls+'-inner'});
37556 this.innerList.on('mouseover', this.onViewOver, this);
37557 this.innerList.on('mousemove', this.onViewMove, this);
37558 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37560 if(this.allowBlank && !this.pageSize && !this.disableClear){
37561 this.footer = this.list.createChild({cls:cls+'-ft'});
37562 this.pageTb = new Roo.Toolbar(this.footer);
37566 this.footer = this.list.createChild({cls:cls+'-ft'});
37567 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37568 {pageSize: this.pageSize});
37572 if (this.pageTb && this.allowBlank && !this.disableClear) {
37574 this.pageTb.add(new Roo.Toolbar.Fill(), {
37575 cls: 'x-btn-icon x-btn-clear',
37577 handler: function()
37580 _this.clearValue();
37581 _this.onSelect(false, -1);
37586 this.assetHeight += this.footer.getHeight();
37591 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37594 this.view = new Roo.View(this.innerList, this.tpl, {
37595 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37598 this.view.on('click', this.onViewClick, this);
37600 this.store.on('beforeload', this.onBeforeLoad, this);
37601 this.store.on('load', this.onLoad, this);
37602 this.store.on('loadexception', this.onLoadException, this);
37604 if(this.resizable){
37605 this.resizer = new Roo.Resizable(this.list, {
37606 pinned:true, handles:'se'
37608 this.resizer.on('resize', function(r, w, h){
37609 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37610 this.listWidth = w;
37611 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37612 this.restrictHeight();
37614 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37616 if(!this.editable){
37617 this.editable = true;
37618 this.setEditable(false);
37622 if (typeof(this.events.add.listeners) != 'undefined') {
37624 this.addicon = this.wrap.createChild(
37625 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37627 this.addicon.on('click', function(e) {
37628 this.fireEvent('add', this);
37631 if (typeof(this.events.edit.listeners) != 'undefined') {
37633 this.editicon = this.wrap.createChild(
37634 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37635 if (this.addicon) {
37636 this.editicon.setStyle('margin-left', '40px');
37638 this.editicon.on('click', function(e) {
37640 // we fire even if inothing is selected..
37641 this.fireEvent('edit', this, this.lastData );
37651 initEvents : function(){
37652 Roo.form.ComboBox.superclass.initEvents.call(this);
37654 this.keyNav = new Roo.KeyNav(this.el, {
37655 "up" : function(e){
37656 this.inKeyMode = true;
37660 "down" : function(e){
37661 if(!this.isExpanded()){
37662 this.onTriggerClick();
37664 this.inKeyMode = true;
37669 "enter" : function(e){
37670 this.onViewClick();
37674 "esc" : function(e){
37678 "tab" : function(e){
37679 this.onViewClick(false);
37680 this.fireEvent("specialkey", this, e);
37686 doRelay : function(foo, bar, hname){
37687 if(hname == 'down' || this.scope.isExpanded()){
37688 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37695 this.queryDelay = Math.max(this.queryDelay || 10,
37696 this.mode == 'local' ? 10 : 250);
37697 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37698 if(this.typeAhead){
37699 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37701 if(this.editable !== false){
37702 this.el.on("keyup", this.onKeyUp, this);
37704 if(this.forceSelection){
37705 this.on('blur', this.doForce, this);
37709 onDestroy : function(){
37711 this.view.setStore(null);
37712 this.view.el.removeAllListeners();
37713 this.view.el.remove();
37714 this.view.purgeListeners();
37717 this.list.destroy();
37720 this.store.un('beforeload', this.onBeforeLoad, this);
37721 this.store.un('load', this.onLoad, this);
37722 this.store.un('loadexception', this.onLoadException, this);
37724 Roo.form.ComboBox.superclass.onDestroy.call(this);
37728 fireKey : function(e){
37729 if(e.isNavKeyPress() && !this.list.isVisible()){
37730 this.fireEvent("specialkey", this, e);
37735 onResize: function(w, h){
37736 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37738 if(typeof w != 'number'){
37739 // we do not handle it!?!?
37742 var tw = this.trigger.getWidth();
37743 tw += this.addicon ? this.addicon.getWidth() : 0;
37744 tw += this.editicon ? this.editicon.getWidth() : 0;
37746 this.el.setWidth( this.adjustWidth('input', x));
37748 this.trigger.setStyle('left', x+'px');
37750 if(this.list && this.listWidth === undefined){
37751 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37752 this.list.setWidth(lw);
37753 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37761 * Allow or prevent the user from directly editing the field text. If false is passed,
37762 * the user will only be able to select from the items defined in the dropdown list. This method
37763 * is the runtime equivalent of setting the 'editable' config option at config time.
37764 * @param {Boolean} value True to allow the user to directly edit the field text
37766 setEditable : function(value){
37767 if(value == this.editable){
37770 this.editable = value;
37772 this.el.dom.setAttribute('readOnly', true);
37773 this.el.on('mousedown', this.onTriggerClick, this);
37774 this.el.addClass('x-combo-noedit');
37776 this.el.dom.setAttribute('readOnly', false);
37777 this.el.un('mousedown', this.onTriggerClick, this);
37778 this.el.removeClass('x-combo-noedit');
37783 onBeforeLoad : function(){
37784 if(!this.hasFocus){
37787 this.innerList.update(this.loadingText ?
37788 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37789 this.restrictHeight();
37790 this.selectedIndex = -1;
37794 onLoad : function(){
37795 if(!this.hasFocus){
37798 if(this.store.getCount() > 0){
37800 this.restrictHeight();
37801 if(this.lastQuery == this.allQuery){
37803 this.el.dom.select();
37805 if(!this.selectByValue(this.value, true)){
37806 this.select(0, true);
37810 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37811 this.taTask.delay(this.typeAheadDelay);
37815 this.onEmptyResults();
37820 onLoadException : function()
37823 Roo.log(this.store.reader.jsonData);
37824 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
37825 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
37831 onTypeAhead : function(){
37832 if(this.store.getCount() > 0){
37833 var r = this.store.getAt(0);
37834 var newValue = r.data[this.displayField];
37835 var len = newValue.length;
37836 var selStart = this.getRawValue().length;
37837 if(selStart != len){
37838 this.setRawValue(newValue);
37839 this.selectText(selStart, newValue.length);
37845 onSelect : function(record, index){
37846 if(this.fireEvent('beforeselect', this, record, index) !== false){
37847 this.setFromData(index > -1 ? record.data : false);
37849 this.fireEvent('select', this, record, index);
37854 * Returns the currently selected field value or empty string if no value is set.
37855 * @return {String} value The selected value
37857 getValue : function(){
37858 if(this.valueField){
37859 return typeof this.value != 'undefined' ? this.value : '';
37861 return Roo.form.ComboBox.superclass.getValue.call(this);
37866 * Clears any text/value currently set in the field
37868 clearValue : function(){
37869 if(this.hiddenField){
37870 this.hiddenField.value = '';
37873 this.setRawValue('');
37874 this.lastSelectionText = '';
37875 this.applyEmptyText();
37879 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37880 * will be displayed in the field. If the value does not match the data value of an existing item,
37881 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37882 * Otherwise the field will be blank (although the value will still be set).
37883 * @param {String} value The value to match
37885 setValue : function(v){
37887 if(this.valueField){
37888 var r = this.findRecord(this.valueField, v);
37890 text = r.data[this.displayField];
37891 }else if(this.valueNotFoundText !== undefined){
37892 text = this.valueNotFoundText;
37895 this.lastSelectionText = text;
37896 if(this.hiddenField){
37897 this.hiddenField.value = v;
37899 Roo.form.ComboBox.superclass.setValue.call(this, text);
37903 * @property {Object} the last set data for the element
37908 * Sets the value of the field based on a object which is related to the record format for the store.
37909 * @param {Object} value the value to set as. or false on reset?
37911 setFromData : function(o){
37912 var dv = ''; // display value
37913 var vv = ''; // value value..
37915 if (this.displayField) {
37916 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37918 // this is an error condition!!!
37919 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
37922 if(this.valueField){
37923 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37925 if(this.hiddenField){
37926 this.hiddenField.value = vv;
37928 this.lastSelectionText = dv;
37929 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37933 // no hidden field.. - we store the value in 'value', but still display
37934 // display field!!!!
37935 this.lastSelectionText = dv;
37936 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37942 reset : function(){
37943 // overridden so that last data is reset..
37944 this.setValue(this.originalValue);
37945 this.clearInvalid();
37946 this.lastData = false;
37949 findRecord : function(prop, value){
37951 if(this.store.getCount() > 0){
37952 this.store.each(function(r){
37953 if(r.data[prop] == value){
37963 getName: function()
37965 // returns hidden if it's set..
37966 if (!this.rendered) {return ''};
37967 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37971 onViewMove : function(e, t){
37972 this.inKeyMode = false;
37976 onViewOver : function(e, t){
37977 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37980 var item = this.view.findItemFromChild(t);
37982 var index = this.view.indexOf(item);
37983 this.select(index, false);
37988 onViewClick : function(doFocus)
37990 var index = this.view.getSelectedIndexes()[0];
37991 var r = this.store.getAt(index);
37993 this.onSelect(r, index);
37995 if(doFocus !== false && !this.blockFocus){
38001 restrictHeight : function(){
38002 this.innerList.dom.style.height = '';
38003 var inner = this.innerList.dom;
38004 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
38005 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
38006 this.list.beginUpdate();
38007 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
38008 this.list.alignTo(this.el, this.listAlign);
38009 this.list.endUpdate();
38013 onEmptyResults : function(){
38018 * Returns true if the dropdown list is expanded, else false.
38020 isExpanded : function(){
38021 return this.list.isVisible();
38025 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
38026 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
38027 * @param {String} value The data value of the item to select
38028 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
38029 * selected item if it is not currently in view (defaults to true)
38030 * @return {Boolean} True if the value matched an item in the list, else false
38032 selectByValue : function(v, scrollIntoView){
38033 if(v !== undefined && v !== null){
38034 var r = this.findRecord(this.valueField || this.displayField, v);
38036 this.select(this.store.indexOf(r), scrollIntoView);
38044 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
38045 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
38046 * @param {Number} index The zero-based index of the list item to select
38047 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
38048 * selected item if it is not currently in view (defaults to true)
38050 select : function(index, scrollIntoView){
38051 this.selectedIndex = index;
38052 this.view.select(index);
38053 if(scrollIntoView !== false){
38054 var el = this.view.getNode(index);
38056 this.innerList.scrollChildIntoView(el, false);
38062 selectNext : function(){
38063 var ct = this.store.getCount();
38065 if(this.selectedIndex == -1){
38067 }else if(this.selectedIndex < ct-1){
38068 this.select(this.selectedIndex+1);
38074 selectPrev : function(){
38075 var ct = this.store.getCount();
38077 if(this.selectedIndex == -1){
38079 }else if(this.selectedIndex != 0){
38080 this.select(this.selectedIndex-1);
38086 onKeyUp : function(e){
38087 if(this.editable !== false && !e.isSpecialKey()){
38088 this.lastKey = e.getKey();
38089 this.dqTask.delay(this.queryDelay);
38094 validateBlur : function(){
38095 return !this.list || !this.list.isVisible();
38099 initQuery : function(){
38100 this.doQuery(this.getRawValue());
38104 doForce : function(){
38105 if(this.el.dom.value.length > 0){
38106 this.el.dom.value =
38107 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
38108 this.applyEmptyText();
38113 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
38114 * query allowing the query action to be canceled if needed.
38115 * @param {String} query The SQL query to execute
38116 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
38117 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
38118 * saved in the current store (defaults to false)
38120 doQuery : function(q, forceAll){
38121 if(q === undefined || q === null){
38126 forceAll: forceAll,
38130 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
38134 forceAll = qe.forceAll;
38135 if(forceAll === true || (q.length >= this.minChars)){
38136 if(this.lastQuery != q || this.alwaysQuery){
38137 this.lastQuery = q;
38138 if(this.mode == 'local'){
38139 this.selectedIndex = -1;
38141 this.store.clearFilter();
38143 this.store.filter(this.displayField, q);
38147 this.store.baseParams[this.queryParam] = q;
38149 params: this.getParams(q)
38154 this.selectedIndex = -1;
38161 getParams : function(q){
38163 //p[this.queryParam] = q;
38166 p.limit = this.pageSize;
38172 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
38174 collapse : function(){
38175 if(!this.isExpanded()){
38179 Roo.get(document).un('mousedown', this.collapseIf, this);
38180 Roo.get(document).un('mousewheel', this.collapseIf, this);
38181 if (!this.editable) {
38182 Roo.get(document).un('keydown', this.listKeyPress, this);
38184 this.fireEvent('collapse', this);
38188 collapseIf : function(e){
38189 if(!e.within(this.wrap) && !e.within(this.list)){
38195 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
38197 expand : function(){
38198 if(this.isExpanded() || !this.hasFocus){
38201 this.list.alignTo(this.el, this.listAlign);
38203 Roo.get(document).on('mousedown', this.collapseIf, this);
38204 Roo.get(document).on('mousewheel', this.collapseIf, this);
38205 if (!this.editable) {
38206 Roo.get(document).on('keydown', this.listKeyPress, this);
38209 this.fireEvent('expand', this);
38213 // Implements the default empty TriggerField.onTriggerClick function
38214 onTriggerClick : function(){
38218 if(this.isExpanded()){
38220 if (!this.blockFocus) {
38225 this.hasFocus = true;
38226 if(this.triggerAction == 'all') {
38227 this.doQuery(this.allQuery, true);
38229 this.doQuery(this.getRawValue());
38231 if (!this.blockFocus) {
38236 listKeyPress : function(e)
38238 //Roo.log('listkeypress');
38239 // scroll to first matching element based on key pres..
38240 if (e.isSpecialKey()) {
38243 var k = String.fromCharCode(e.getKey()).toUpperCase();
38246 var csel = this.view.getSelectedNodes();
38247 var cselitem = false;
38249 var ix = this.view.indexOf(csel[0]);
38250 cselitem = this.store.getAt(ix);
38251 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
38257 this.store.each(function(v) {
38259 // start at existing selection.
38260 if (cselitem.id == v.id) {
38266 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
38267 match = this.store.indexOf(v);
38272 if (match === false) {
38273 return true; // no more action?
38276 this.view.select(match);
38277 var sn = Roo.get(this.view.getSelectedNodes()[0])
38278 sn.scrollIntoView(sn.dom.parentNode, false);
38282 * @cfg {Boolean} grow
38286 * @cfg {Number} growMin
38290 * @cfg {Number} growMax
38299 * Ext JS Library 1.1.1
38300 * Copyright(c) 2006-2007, Ext JS, LLC.
38302 * Originally Released Under LGPL - original licence link has changed is not relivant.
38305 * <script type="text/javascript">
38308 * @class Roo.form.Checkbox
38309 * @extends Roo.form.Field
38310 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
38312 * Creates a new Checkbox
38313 * @param {Object} config Configuration options
38315 Roo.form.Checkbox = function(config){
38316 Roo.form.Checkbox.superclass.constructor.call(this, config);
38320 * Fires when the checkbox is checked or unchecked.
38321 * @param {Roo.form.Checkbox} this This checkbox
38322 * @param {Boolean} checked The new checked value
38328 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38330 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38332 focusClass : undefined,
38334 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38336 fieldClass: "x-form-field",
38338 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38342 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38343 * {tag: "input", type: "checkbox", autocomplete: "off"})
38345 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38347 * @cfg {String} boxLabel The text that appears beside the checkbox
38351 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38355 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38357 valueOff: '0', // value when not checked..
38359 actionMode : 'viewEl',
38362 itemCls : 'x-menu-check-item x-form-item',
38363 groupClass : 'x-menu-group-item',
38364 inputType : 'hidden',
38367 inSetChecked: false, // check that we are not calling self...
38369 inputElement: false, // real input element?
38370 basedOn: false, // ????
38372 isFormField: true, // not sure where this is needed!!!!
38374 onResize : function(){
38375 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38376 if(!this.boxLabel){
38377 this.el.alignTo(this.wrap, 'c-c');
38381 initEvents : function(){
38382 Roo.form.Checkbox.superclass.initEvents.call(this);
38383 this.el.on("click", this.onClick, this);
38384 this.el.on("change", this.onClick, this);
38388 getResizeEl : function(){
38392 getPositionEl : function(){
38397 onRender : function(ct, position){
38398 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38400 if(this.inputValue !== undefined){
38401 this.el.dom.value = this.inputValue;
38404 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38405 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38406 var viewEl = this.wrap.createChild({
38407 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38408 this.viewEl = viewEl;
38409 this.wrap.on('click', this.onClick, this);
38411 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38412 this.el.on('propertychange', this.setFromHidden, this); //ie
38417 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38418 // viewEl.on('click', this.onClick, this);
38420 //if(this.checked){
38421 this.setChecked(this.checked);
38423 //this.checked = this.el.dom;
38429 initValue : Roo.emptyFn,
38432 * Returns the checked state of the checkbox.
38433 * @return {Boolean} True if checked, else false
38435 getValue : function(){
38437 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38439 return this.valueOff;
38444 onClick : function(){
38445 this.setChecked(!this.checked);
38447 //if(this.el.dom.checked != this.checked){
38448 // this.setValue(this.el.dom.checked);
38453 * Sets the checked state of the checkbox.
38454 * On is always based on a string comparison between inputValue and the param.
38455 * @param {Boolean/String} value - the value to set
38456 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38458 setValue : function(v,suppressEvent){
38461 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38462 //if(this.el && this.el.dom){
38463 // this.el.dom.checked = this.checked;
38464 // this.el.dom.defaultChecked = this.checked;
38466 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38467 //this.fireEvent("check", this, this.checked);
38470 setChecked : function(state,suppressEvent)
38472 if (this.inSetChecked) {
38473 this.checked = state;
38479 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38481 this.checked = state;
38482 if(suppressEvent !== true){
38483 this.fireEvent('check', this, state);
38485 this.inSetChecked = true;
38486 this.el.dom.value = state ? this.inputValue : this.valueOff;
38487 this.inSetChecked = false;
38490 // handle setting of hidden value by some other method!!?!?
38491 setFromHidden: function()
38496 //console.log("SET FROM HIDDEN");
38497 //alert('setFrom hidden');
38498 this.setValue(this.el.dom.value);
38501 onDestroy : function()
38504 Roo.get(this.viewEl).remove();
38507 Roo.form.Checkbox.superclass.onDestroy.call(this);
38512 * Ext JS Library 1.1.1
38513 * Copyright(c) 2006-2007, Ext JS, LLC.
38515 * Originally Released Under LGPL - original licence link has changed is not relivant.
38518 * <script type="text/javascript">
38522 * @class Roo.form.Radio
38523 * @extends Roo.form.Checkbox
38524 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38525 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38527 * Creates a new Radio
38528 * @param {Object} config Configuration options
38530 Roo.form.Radio = function(){
38531 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38533 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38534 inputType: 'radio',
38537 * If this radio is part of a group, it will return the selected value
38540 getGroupValue : function(){
38541 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38543 });//<script type="text/javascript">
38546 * Ext JS Library 1.1.1
38547 * Copyright(c) 2006-2007, Ext JS, LLC.
38548 * licensing@extjs.com
38550 * http://www.extjs.com/license
38556 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38557 * - IE ? - no idea how much works there.
38565 * @class Ext.form.HtmlEditor
38566 * @extends Ext.form.Field
38567 * Provides a lightweight HTML Editor component.
38568 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38570 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38571 * supported by this editor.</b><br/><br/>
38572 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38573 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38575 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38577 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38581 * @cfg {String} createLinkText The default text for the create link prompt
38583 createLinkText : 'Please enter the URL for the link:',
38585 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38587 defaultLinkValue : 'http:/'+'/',
38590 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
38595 * @cfg {Number} height (in pixels)
38599 * @cfg {Number} width (in pixels)
38604 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
38607 stylesheets: false,
38612 // private properties
38613 validationEvent : false,
38615 initialized : false,
38617 sourceEditMode : false,
38618 onFocus : Roo.emptyFn,
38620 hideMode:'offsets',
38622 defaultAutoCreate : { // modified by initCompnoent..
38624 style:"width:500px;height:300px;",
38625 autocomplete: "off"
38629 initComponent : function(){
38632 * @event initialize
38633 * Fires when the editor is fully initialized (including the iframe)
38634 * @param {HtmlEditor} this
38639 * Fires when the editor is first receives the focus. Any insertion must wait
38640 * until after this event.
38641 * @param {HtmlEditor} this
38645 * @event beforesync
38646 * Fires before the textarea is updated with content from the editor iframe. Return false
38647 * to cancel the sync.
38648 * @param {HtmlEditor} this
38649 * @param {String} html
38653 * @event beforepush
38654 * Fires before the iframe editor is updated with content from the textarea. Return false
38655 * to cancel the push.
38656 * @param {HtmlEditor} this
38657 * @param {String} html
38662 * Fires when the textarea is updated with content from the editor iframe.
38663 * @param {HtmlEditor} this
38664 * @param {String} html
38669 * Fires when the iframe editor is updated with content from the textarea.
38670 * @param {HtmlEditor} this
38671 * @param {String} html
38675 * @event editmodechange
38676 * Fires when the editor switches edit modes
38677 * @param {HtmlEditor} this
38678 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38680 editmodechange: true,
38682 * @event editorevent
38683 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38684 * @param {HtmlEditor} this
38688 this.defaultAutoCreate = {
38690 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
38691 autocomplete: "off"
38696 * Protected method that will not generally be called directly. It
38697 * is called when the editor creates its toolbar. Override this method if you need to
38698 * add custom toolbar buttons.
38699 * @param {HtmlEditor} editor
38701 createToolbar : function(editor){
38702 if (!editor.toolbars || !editor.toolbars.length) {
38703 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38706 for (var i =0 ; i < editor.toolbars.length;i++) {
38707 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38708 editor.toolbars[i].init(editor);
38715 * Protected method that will not generally be called directly. It
38716 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38717 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38719 getDocMarkup : function(){
38722 if (this.stylesheets === false) {
38724 Roo.get(document.head).select('style').each(function(node) {
38725 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
38728 Roo.get(document.head).select('link').each(function(node) {
38729 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
38732 } else if (!this.stylesheets.length) {
38734 st = '<style type="text/css">' +
38735 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
38738 Roo.each(this.stylesheets, function(s) {
38739 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
38744 return '<html><head>' + st +
38745 //<style type="text/css">' +
38746 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
38748 ' </head><body></body></html>';
38752 onRender : function(ct, position)
38755 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38756 this.el.dom.style.border = '0 none';
38757 this.el.dom.setAttribute('tabIndex', -1);
38758 this.el.addClass('x-hidden');
38759 if(Roo.isIE){ // fix IE 1px bogus margin
38760 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38762 this.wrap = this.el.wrap({
38763 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38766 if (this.resizable) {
38767 this.resizeEl = new Roo.Resizable(this.wrap, {
38771 minHeight : this.height,
38772 height: this.height,
38773 handles : this.resizable,
38776 resize : function(r, w, h) {
38777 _t.onResize(w,h); // -something
38784 this.frameId = Roo.id();
38786 this.createToolbar(this);
38790 var iframe = this.wrap.createChild({
38793 name: this.frameId,
38794 frameBorder : 'no',
38795 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38799 // console.log(iframe);
38800 //this.wrap.dom.appendChild(iframe);
38802 this.iframe = iframe.dom;
38804 this.assignDocWin();
38806 this.doc.designMode = 'on';
38809 this.doc.write(this.getDocMarkup());
38813 var task = { // must defer to wait for browser to be ready
38815 //console.log("run task?" + this.doc.readyState);
38816 this.assignDocWin();
38817 if(this.doc.body || this.doc.readyState == 'complete'){
38819 this.doc.designMode="on";
38823 Roo.TaskMgr.stop(task);
38824 this.initEditor.defer(10, this);
38831 Roo.TaskMgr.start(task);
38834 this.setSize(this.wrap.getSize());
38836 if (this.resizeEl) {
38837 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
38838 // should trigger onReize..
38843 onResize : function(w, h)
38845 //Roo.log('resize: ' +w + ',' + h );
38846 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38847 if(this.el && this.iframe){
38848 if(typeof w == 'number'){
38849 var aw = w - this.wrap.getFrameWidth('lr');
38850 this.el.setWidth(this.adjustWidth('textarea', aw));
38851 this.iframe.style.width = aw + 'px';
38853 if(typeof h == 'number'){
38855 for (var i =0; i < this.toolbars.length;i++) {
38856 // fixme - ask toolbars for heights?
38857 tbh += this.toolbars[i].tb.el.getHeight();
38858 if (this.toolbars[i].footer) {
38859 tbh += this.toolbars[i].footer.el.getHeight();
38866 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38867 ah -= 5; // knock a few pixes off for look..
38868 this.el.setHeight(this.adjustWidth('textarea', ah));
38869 this.iframe.style.height = ah + 'px';
38871 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38878 * Toggles the editor between standard and source edit mode.
38879 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38881 toggleSourceEdit : function(sourceEditMode){
38883 this.sourceEditMode = sourceEditMode === true;
38885 if(this.sourceEditMode){
38888 this.iframe.className = 'x-hidden';
38889 this.el.removeClass('x-hidden');
38890 this.el.dom.removeAttribute('tabIndex');
38895 this.iframe.className = '';
38896 this.el.addClass('x-hidden');
38897 this.el.dom.setAttribute('tabIndex', -1);
38900 this.setSize(this.wrap.getSize());
38901 this.fireEvent('editmodechange', this, this.sourceEditMode);
38904 // private used internally
38905 createLink : function(){
38906 var url = prompt(this.createLinkText, this.defaultLinkValue);
38907 if(url && url != 'http:/'+'/'){
38908 this.relayCmd('createlink', url);
38912 // private (for BoxComponent)
38913 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38915 // private (for BoxComponent)
38916 getResizeEl : function(){
38920 // private (for BoxComponent)
38921 getPositionEl : function(){
38926 initEvents : function(){
38927 this.originalValue = this.getValue();
38931 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38934 markInvalid : Roo.emptyFn,
38936 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38939 clearInvalid : Roo.emptyFn,
38941 setValue : function(v){
38942 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38947 * Protected method that will not generally be called directly. If you need/want
38948 * custom HTML cleanup, this is the method you should override.
38949 * @param {String} html The HTML to be cleaned
38950 * return {String} The cleaned HTML
38952 cleanHtml : function(html){
38953 html = String(html);
38954 if(html.length > 5){
38955 if(Roo.isSafari){ // strip safari nonsense
38956 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38959 if(html == ' '){
38966 * Protected method that will not generally be called directly. Syncs the contents
38967 * of the editor iframe with the textarea.
38969 syncValue : function(){
38970 if(this.initialized){
38971 var bd = (this.doc.body || this.doc.documentElement);
38972 this.cleanUpPaste();
38973 var html = bd.innerHTML;
38975 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38976 var m = bs.match(/text-align:(.*?);/i);
38978 html = '<div style="'+m[0]+'">' + html + '</div>';
38981 html = this.cleanHtml(html);
38982 if(this.fireEvent('beforesync', this, html) !== false){
38983 this.el.dom.value = html;
38984 this.fireEvent('sync', this, html);
38990 * Protected method that will not generally be called directly. Pushes the value of the textarea
38991 * into the iframe editor.
38993 pushValue : function(){
38994 if(this.initialized){
38995 var v = this.el.dom.value;
39000 if(this.fireEvent('beforepush', this, v) !== false){
39001 var d = (this.doc.body || this.doc.documentElement);
39003 this.cleanUpPaste();
39004 this.el.dom.value = d.innerHTML;
39005 this.fireEvent('push', this, v);
39011 deferFocus : function(){
39012 this.focus.defer(10, this);
39016 focus : function(){
39017 if(this.win && !this.sourceEditMode){
39024 assignDocWin: function()
39026 var iframe = this.iframe;
39029 this.doc = iframe.contentWindow.document;
39030 this.win = iframe.contentWindow;
39032 if (!Roo.get(this.frameId)) {
39035 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
39036 this.win = Roo.get(this.frameId).dom.contentWindow;
39041 initEditor : function(){
39042 //console.log("INIT EDITOR");
39043 this.assignDocWin();
39047 this.doc.designMode="on";
39049 this.doc.write(this.getDocMarkup());
39052 var dbody = (this.doc.body || this.doc.documentElement);
39053 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
39054 // this copies styles from the containing element into thsi one..
39055 // not sure why we need all of this..
39056 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
39057 ss['background-attachment'] = 'fixed'; // w3c
39058 dbody.bgProperties = 'fixed'; // ie
39059 Roo.DomHelper.applyStyles(dbody, ss);
39060 Roo.EventManager.on(this.doc, {
39061 //'mousedown': this.onEditorEvent,
39062 'mouseup': this.onEditorEvent,
39063 'dblclick': this.onEditorEvent,
39064 'click': this.onEditorEvent,
39065 'keyup': this.onEditorEvent,
39070 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
39072 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
39073 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
39075 this.initialized = true;
39077 this.fireEvent('initialize', this);
39082 onDestroy : function(){
39088 for (var i =0; i < this.toolbars.length;i++) {
39089 // fixme - ask toolbars for heights?
39090 this.toolbars[i].onDestroy();
39093 this.wrap.dom.innerHTML = '';
39094 this.wrap.remove();
39099 onFirstFocus : function(){
39101 this.assignDocWin();
39104 this.activated = true;
39105 for (var i =0; i < this.toolbars.length;i++) {
39106 this.toolbars[i].onFirstFocus();
39109 if(Roo.isGecko){ // prevent silly gecko errors
39111 var s = this.win.getSelection();
39112 if(!s.focusNode || s.focusNode.nodeType != 3){
39113 var r = s.getRangeAt(0);
39114 r.selectNodeContents((this.doc.body || this.doc.documentElement));
39119 this.execCmd('useCSS', true);
39120 this.execCmd('styleWithCSS', false);
39123 this.fireEvent('activate', this);
39127 adjustFont: function(btn){
39128 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
39129 //if(Roo.isSafari){ // safari
39132 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
39133 if(Roo.isSafari){ // safari
39134 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
39135 v = (v < 10) ? 10 : v;
39136 v = (v > 48) ? 48 : v;
39137 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
39142 v = Math.max(1, v+adjust);
39144 this.execCmd('FontSize', v );
39147 onEditorEvent : function(e){
39148 this.fireEvent('editorevent', this, e);
39149 // this.updateToolbar();
39153 insertTag : function(tg)
39155 // could be a bit smarter... -> wrap the current selected tRoo..
39157 this.execCmd("formatblock", tg);
39161 insertText : function(txt)
39165 range = this.createRange();
39166 range.deleteContents();
39167 //alert(Sender.getAttribute('label'));
39169 range.insertNode(this.doc.createTextNode(txt));
39173 relayBtnCmd : function(btn){
39174 this.relayCmd(btn.cmd);
39178 * Executes a Midas editor command on the editor document and performs necessary focus and
39179 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
39180 * @param {String} cmd The Midas command
39181 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
39183 relayCmd : function(cmd, value){
39185 this.execCmd(cmd, value);
39186 this.fireEvent('editorevent', this);
39187 //this.updateToolbar();
39192 * Executes a Midas editor command directly on the editor document.
39193 * For visual commands, you should use {@link #relayCmd} instead.
39194 * <b>This should only be called after the editor is initialized.</b>
39195 * @param {String} cmd The Midas command
39196 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
39198 execCmd : function(cmd, value){
39199 this.doc.execCommand(cmd, false, value === undefined ? null : value);
39205 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
39207 * @param {String} text
39209 insertAtCursor : function(text){
39210 if(!this.activated){
39215 var r = this.doc.selection.createRange();
39222 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
39224 this.execCmd('InsertHTML', text);
39229 mozKeyPress : function(e){
39231 var c = e.getCharCode(), cmd;
39234 c = String.fromCharCode(c).toLowerCase();
39245 this.cleanUpPaste.defer(100, this);
39253 e.preventDefault();
39261 fixKeys : function(){ // load time branching for fastest keydown performance
39263 return function(e){
39264 var k = e.getKey(), r;
39267 r = this.doc.selection.createRange();
39270 r.pasteHTML('    ');
39277 r = this.doc.selection.createRange();
39279 var target = r.parentElement();
39280 if(!target || target.tagName.toLowerCase() != 'li'){
39282 r.pasteHTML('<br />');
39288 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39289 this.cleanUpPaste.defer(100, this);
39295 }else if(Roo.isOpera){
39296 return function(e){
39297 var k = e.getKey();
39301 this.execCmd('InsertHTML','    ');
39304 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39305 this.cleanUpPaste.defer(100, this);
39310 }else if(Roo.isSafari){
39311 return function(e){
39312 var k = e.getKey();
39316 this.execCmd('InsertText','\t');
39320 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39321 this.cleanUpPaste.defer(100, this);
39329 getAllAncestors: function()
39331 var p = this.getSelectedNode();
39334 a.push(p); // push blank onto stack..
39335 p = this.getParentElement();
39339 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
39343 a.push(this.doc.body);
39347 lastSelNode : false,
39350 getSelection : function()
39352 this.assignDocWin();
39353 return Roo.isIE ? this.doc.selection : this.win.getSelection();
39356 getSelectedNode: function()
39358 // this may only work on Gecko!!!
39360 // should we cache this!!!!
39365 var range = this.createRange(this.getSelection()).cloneRange();
39368 var parent = range.parentElement();
39370 var testRange = range.duplicate();
39371 testRange.moveToElementText(parent);
39372 if (testRange.inRange(range)) {
39375 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
39378 parent = parent.parentElement;
39383 // is ancestor a text element.
39384 var ac = range.commonAncestorContainer;
39385 if (ac.nodeType == 3) {
39386 ac = ac.parentNode;
39389 var ar = ac.childNodes;
39392 var other_nodes = [];
39393 var has_other_nodes = false;
39394 for (var i=0;i<ar.length;i++) {
39395 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
39398 // fullly contained node.
39400 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
39405 // probably selected..
39406 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
39407 other_nodes.push(ar[i]);
39411 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39416 has_other_nodes = true;
39418 if (!nodes.length && other_nodes.length) {
39419 nodes= other_nodes;
39421 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39427 createRange: function(sel)
39429 // this has strange effects when using with
39430 // top toolbar - not sure if it's a great idea.
39431 //this.editor.contentWindow.focus();
39432 if (typeof sel != "undefined") {
39434 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39436 return this.doc.createRange();
39439 return this.doc.createRange();
39442 getParentElement: function()
39445 this.assignDocWin();
39446 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39448 var range = this.createRange(sel);
39451 var p = range.commonAncestorContainer;
39452 while (p.nodeType == 3) { // text node
39463 * Range intersection.. the hard stuff...
39467 * [ -- selected range --- ]
39471 * if end is before start or hits it. fail.
39472 * if start is after end or hits it fail.
39474 * if either hits (but other is outside. - then it's not
39480 // @see http://www.thismuchiknow.co.uk/?p=64.
39481 rangeIntersectsNode : function(range, node)
39483 var nodeRange = node.ownerDocument.createRange();
39485 nodeRange.selectNode(node);
39487 nodeRange.selectNodeContents(node);
39490 var rangeStartRange = range.cloneRange();
39491 rangeStartRange.collapse(true);
39493 var rangeEndRange = range.cloneRange();
39494 rangeEndRange.collapse(false);
39496 var nodeStartRange = nodeRange.cloneRange();
39497 nodeStartRange.collapse(true);
39499 var nodeEndRange = nodeRange.cloneRange();
39500 nodeEndRange.collapse(false);
39502 return rangeStartRange.compareBoundaryPoints(
39503 Range.START_TO_START, nodeEndRange) == -1 &&
39504 rangeEndRange.compareBoundaryPoints(
39505 Range.START_TO_START, nodeStartRange) == 1;
39509 rangeCompareNode : function(range, node)
39511 var nodeRange = node.ownerDocument.createRange();
39513 nodeRange.selectNode(node);
39515 nodeRange.selectNodeContents(node);
39519 range.collapse(true);
39521 nodeRange.collapse(true);
39523 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
39524 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
39526 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
39528 var nodeIsBefore = ss == 1;
39529 var nodeIsAfter = ee == -1;
39531 if (nodeIsBefore && nodeIsAfter)
39533 if (!nodeIsBefore && nodeIsAfter)
39534 return 1; //right trailed.
39536 if (nodeIsBefore && !nodeIsAfter)
39537 return 2; // left trailed.
39542 // private? - in a new class?
39543 cleanUpPaste : function()
39545 // cleans up the whole document..
39546 // console.log('cleanuppaste');
39547 this.cleanUpChildren(this.doc.body);
39548 this.doc.body.innerHTML = this.cleanWordChars(this.doc.body.innerHTML);
39552 cleanWordChars : function(input) {
39553 var he = Roo.form.HtmlEditor;
39555 var output = input;
39556 Roo.each(he.swapCodes, function(sw) {
39558 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
39559 output = output.replace(swapper, sw[1]);
39565 cleanUpChildren : function (n)
39567 if (!n.childNodes.length) {
39570 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39571 this.cleanUpChild(n.childNodes[i]);
39578 cleanUpChild : function (node)
39580 //console.log(node);
39581 if (node.nodeName == "#text") {
39582 // clean up silly Windows -- stuff?
39585 if (node.nodeName == "#comment") {
39586 node.parentNode.removeChild(node);
39587 // clean up silly Windows -- stuff?
39591 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39593 node.parentNode.removeChild(node);
39598 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
39600 // remove <a name=....> as rendering on yahoo mailer is bored with this.
39602 if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
39603 remove_keep_children = true;
39606 if (remove_keep_children) {
39607 this.cleanUpChildren(node);
39608 // inserts everything just before this node...
39609 while (node.childNodes.length) {
39610 var cn = node.childNodes[0];
39611 node.removeChild(cn);
39612 node.parentNode.insertBefore(cn, node);
39614 node.parentNode.removeChild(node);
39618 if (!node.attributes || !node.attributes.length) {
39619 this.cleanUpChildren(node);
39623 function cleanAttr(n,v)
39626 if (v.match(/^\./) || v.match(/^\//)) {
39629 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39632 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39633 node.removeAttribute(n);
39637 function cleanStyle(n,v)
39639 if (v.match(/expression/)) { //XSS?? should we even bother..
39640 node.removeAttribute(n);
39645 var parts = v.split(/;/);
39646 Roo.each(parts, function(p) {
39647 p = p.replace(/\s+/g,'');
39651 var l = p.split(':').shift().replace(/\s+/g,'');
39653 // only allow 'c whitelisted system attributes'
39654 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39655 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39656 node.removeAttribute(n);
39666 for (var i = node.attributes.length-1; i > -1 ; i--) {
39667 var a = node.attributes[i];
39669 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39670 node.removeAttribute(a.name);
39673 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39674 cleanAttr(a.name,a.value); // fixme..
39677 if (a.name == 'style') {
39678 cleanStyle(a.name,a.value);
39680 /// clean up MS crap..
39681 // tecnically this should be a list of valid class'es..
39684 if (a.name == 'class') {
39685 if (a.value.match(/^Mso/)) {
39686 node.className = '';
39689 if (a.value.match(/body/)) {
39690 node.className = '';
39700 this.cleanUpChildren(node);
39706 // hide stuff that is not compatible
39720 * @event specialkey
39724 * @cfg {String} fieldClass @hide
39727 * @cfg {String} focusClass @hide
39730 * @cfg {String} autoCreate @hide
39733 * @cfg {String} inputType @hide
39736 * @cfg {String} invalidClass @hide
39739 * @cfg {String} invalidText @hide
39742 * @cfg {String} msgFx @hide
39745 * @cfg {String} validateOnBlur @hide
39749 Roo.form.HtmlEditor.white = [
39750 'area', 'br', 'img', 'input', 'hr', 'wbr',
39752 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39753 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39754 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39755 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39756 'table', 'ul', 'xmp',
39758 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39761 'dir', 'menu', 'ol', 'ul', 'dl',
39767 Roo.form.HtmlEditor.black = [
39768 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39770 'base', 'basefont', 'bgsound', 'blink', 'body',
39771 'frame', 'frameset', 'head', 'html', 'ilayer',
39772 'iframe', 'layer', 'link', 'meta', 'object',
39773 'script', 'style' ,'title', 'xml' // clean later..
39775 Roo.form.HtmlEditor.clean = [
39776 'script', 'style', 'title', 'xml'
39778 Roo.form.HtmlEditor.remove = [
39783 Roo.form.HtmlEditor.ablack = [
39787 Roo.form.HtmlEditor.aclean = [
39788 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39792 Roo.form.HtmlEditor.pwhite= [
39793 'http', 'https', 'mailto'
39796 // white listed style attributes.
39797 Roo.form.HtmlEditor.cwhite= [
39803 Roo.form.HtmlEditor.swapCodes =[
39814 // <script type="text/javascript">
39817 * Ext JS Library 1.1.1
39818 * Copyright(c) 2006-2007, Ext JS, LLC.
39824 * @class Roo.form.HtmlEditorToolbar1
39829 new Roo.form.HtmlEditor({
39832 new Roo.form.HtmlEditorToolbar1({
39833 disable : { fonts: 1 , format: 1, ..., ... , ...],
39839 * @cfg {Object} disable List of elements to disable..
39840 * @cfg {Array} btns List of additional buttons.
39844 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39847 Roo.form.HtmlEditor.ToolbarStandard = function(config)
39850 Roo.apply(this, config);
39852 // default disabled, based on 'good practice'..
39853 this.disable = this.disable || {};
39854 Roo.applyIf(this.disable, {
39857 specialElements : true
39861 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39862 // dont call parent... till later.
39865 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
39873 * @cfg {Object} disable List of toolbar elements to disable
39878 * @cfg {Array} fontFamilies An array of available font families
39896 // "á" , ?? a acute?
39901 "°" // , // degrees
39903 // "é" , // e ecute
39904 // "ú" , // u ecute?
39907 specialElements : [
39909 text: "Insert Table",
39912 ihtml : '<table><tr><td>Cell</td></tr></table>'
39916 text: "Insert Image",
39919 ihtml : '<img src="about:blank"/>'
39928 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
39929 "input:submit", "input:button", "select", "textarea", "label" ],
39932 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
39934 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39937 * @cfg {String} defaultFont default font to use.
39939 defaultFont: 'tahoma',
39941 fontSelect : false,
39944 formatCombo : false,
39946 init : function(editor)
39948 this.editor = editor;
39951 var fid = editor.frameId;
39953 function btn(id, toggle, handler){
39954 var xid = fid + '-'+ id ;
39958 cls : 'x-btn-icon x-edit-'+id,
39959 enableToggle:toggle !== false,
39960 scope: editor, // was editor...
39961 handler:handler||editor.relayBtnCmd,
39962 clickEvent:'mousedown',
39963 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39970 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
39972 // stop form submits
39973 tb.el.on('click', function(e){
39974 e.preventDefault(); // what does this do?
39977 if(!this.disable.font && !Roo.isSafari){
39978 /* why no safari for fonts
39979 editor.fontSelect = tb.el.createChild({
39982 cls:'x-font-select',
39983 html: editor.createFontOptions()
39985 editor.fontSelect.on('change', function(){
39986 var font = editor.fontSelect.dom.value;
39987 editor.relayCmd('fontname', font);
39988 editor.deferFocus();
39991 editor.fontSelect.dom,
39996 if(!this.disable.formats){
39997 this.formatCombo = new Roo.form.ComboBox({
39998 store: new Roo.data.SimpleStore({
40001 data : this.formats // from states.js
40004 //autoCreate : {tag: "div", size: "20"},
40005 displayField:'tag',
40009 triggerAction: 'all',
40010 emptyText:'Add tag',
40011 selectOnFocus:true,
40014 'select': function(c, r, i) {
40015 editor.insertTag(r.get('tag'));
40021 tb.addField(this.formatCombo);
40025 if(!this.disable.format){
40032 if(!this.disable.fontSize){
40037 btn('increasefontsize', false, editor.adjustFont),
40038 btn('decreasefontsize', false, editor.adjustFont)
40043 if(!this.disable.colors){
40046 id:editor.frameId +'-forecolor',
40047 cls:'x-btn-icon x-edit-forecolor',
40048 clickEvent:'mousedown',
40049 tooltip: this.buttonTips['forecolor'] || undefined,
40051 menu : new Roo.menu.ColorMenu({
40052 allowReselect: true,
40053 focus: Roo.emptyFn,
40056 selectHandler: function(cp, color){
40057 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
40058 editor.deferFocus();
40061 clickEvent:'mousedown'
40064 id:editor.frameId +'backcolor',
40065 cls:'x-btn-icon x-edit-backcolor',
40066 clickEvent:'mousedown',
40067 tooltip: this.buttonTips['backcolor'] || undefined,
40069 menu : new Roo.menu.ColorMenu({
40070 focus: Roo.emptyFn,
40073 allowReselect: true,
40074 selectHandler: function(cp, color){
40076 editor.execCmd('useCSS', false);
40077 editor.execCmd('hilitecolor', color);
40078 editor.execCmd('useCSS', true);
40079 editor.deferFocus();
40081 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
40082 Roo.isSafari || Roo.isIE ? '#'+color : color);
40083 editor.deferFocus();
40087 clickEvent:'mousedown'
40092 // now add all the items...
40095 if(!this.disable.alignments){
40098 btn('justifyleft'),
40099 btn('justifycenter'),
40100 btn('justifyright')
40104 //if(!Roo.isSafari){
40105 if(!this.disable.links){
40108 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
40112 if(!this.disable.lists){
40115 btn('insertorderedlist'),
40116 btn('insertunorderedlist')
40119 if(!this.disable.sourceEdit){
40122 btn('sourceedit', true, function(btn){
40123 this.toggleSourceEdit(btn.pressed);
40130 // special menu.. - needs to be tidied up..
40131 if (!this.disable.special) {
40134 cls: 'x-edit-none',
40140 for (var i =0; i < this.specialChars.length; i++) {
40141 smenu.menu.items.push({
40143 html: this.specialChars[i],
40144 handler: function(a,b) {
40145 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
40158 if (!this.disable.specialElements) {
40161 cls: 'x-edit-none',
40166 for (var i =0; i < this.specialElements.length; i++) {
40167 semenu.menu.items.push(
40169 handler: function(a,b) {
40170 editor.insertAtCursor(this.ihtml);
40172 }, this.specialElements[i])
40184 for(var i =0; i< this.btns.length;i++) {
40185 var b = this.btns[i];
40186 b.cls = 'x-edit-none';
40195 // disable everything...
40197 this.tb.items.each(function(item){
40198 if(item.id != editor.frameId+ '-sourceedit'){
40202 this.rendered = true;
40204 // the all the btns;
40205 editor.on('editorevent', this.updateToolbar, this);
40206 // other toolbars need to implement this..
40207 //editor.on('editmodechange', this.updateToolbar, this);
40213 * Protected method that will not generally be called directly. It triggers
40214 * a toolbar update by reading the markup state of the current selection in the editor.
40216 updateToolbar: function(){
40218 if(!this.editor.activated){
40219 this.editor.onFirstFocus();
40223 var btns = this.tb.items.map,
40224 doc = this.editor.doc,
40225 frameId = this.editor.frameId;
40227 if(!this.disable.font && !Roo.isSafari){
40229 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
40230 if(name != this.fontSelect.dom.value){
40231 this.fontSelect.dom.value = name;
40235 if(!this.disable.format){
40236 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
40237 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
40238 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
40240 if(!this.disable.alignments){
40241 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
40242 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
40243 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
40245 if(!Roo.isSafari && !this.disable.lists){
40246 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
40247 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
40250 var ans = this.editor.getAllAncestors();
40251 if (this.formatCombo) {
40254 var store = this.formatCombo.store;
40255 this.formatCombo.setValue("");
40256 for (var i =0; i < ans.length;i++) {
40257 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
40259 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
40267 // hides menus... - so this cant be on a menu...
40268 Roo.menu.MenuMgr.hideAll();
40270 //this.editorsyncValue();
40274 createFontOptions : function(){
40275 var buf = [], fs = this.fontFamilies, ff, lc;
40276 for(var i = 0, len = fs.length; i< len; i++){
40278 lc = ff.toLowerCase();
40280 '<option value="',lc,'" style="font-family:',ff,';"',
40281 (this.defaultFont == lc ? ' selected="true">' : '>'),
40286 return buf.join('');
40289 toggleSourceEdit : function(sourceEditMode){
40290 if(sourceEditMode === undefined){
40291 sourceEditMode = !this.sourceEditMode;
40293 this.sourceEditMode = sourceEditMode === true;
40294 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
40295 // just toggle the button?
40296 if(btn.pressed !== this.editor.sourceEditMode){
40297 btn.toggle(this.editor.sourceEditMode);
40301 if(this.sourceEditMode){
40302 this.tb.items.each(function(item){
40303 if(item.cmd != 'sourceedit'){
40309 if(this.initialized){
40310 this.tb.items.each(function(item){
40316 // tell the editor that it's been pressed..
40317 this.editor.toggleSourceEdit(sourceEditMode);
40321 * Object collection of toolbar tooltips for the buttons in the editor. The key
40322 * is the command id associated with that button and the value is a valid QuickTips object.
40327 title: 'Bold (Ctrl+B)',
40328 text: 'Make the selected text bold.',
40329 cls: 'x-html-editor-tip'
40332 title: 'Italic (Ctrl+I)',
40333 text: 'Make the selected text italic.',
40334 cls: 'x-html-editor-tip'
40342 title: 'Bold (Ctrl+B)',
40343 text: 'Make the selected text bold.',
40344 cls: 'x-html-editor-tip'
40347 title: 'Italic (Ctrl+I)',
40348 text: 'Make the selected text italic.',
40349 cls: 'x-html-editor-tip'
40352 title: 'Underline (Ctrl+U)',
40353 text: 'Underline the selected text.',
40354 cls: 'x-html-editor-tip'
40356 increasefontsize : {
40357 title: 'Grow Text',
40358 text: 'Increase the font size.',
40359 cls: 'x-html-editor-tip'
40361 decreasefontsize : {
40362 title: 'Shrink Text',
40363 text: 'Decrease the font size.',
40364 cls: 'x-html-editor-tip'
40367 title: 'Text Highlight Color',
40368 text: 'Change the background color of the selected text.',
40369 cls: 'x-html-editor-tip'
40372 title: 'Font Color',
40373 text: 'Change the color of the selected text.',
40374 cls: 'x-html-editor-tip'
40377 title: 'Align Text Left',
40378 text: 'Align text to the left.',
40379 cls: 'x-html-editor-tip'
40382 title: 'Center Text',
40383 text: 'Center text in the editor.',
40384 cls: 'x-html-editor-tip'
40387 title: 'Align Text Right',
40388 text: 'Align text to the right.',
40389 cls: 'x-html-editor-tip'
40391 insertunorderedlist : {
40392 title: 'Bullet List',
40393 text: 'Start a bulleted list.',
40394 cls: 'x-html-editor-tip'
40396 insertorderedlist : {
40397 title: 'Numbered List',
40398 text: 'Start a numbered list.',
40399 cls: 'x-html-editor-tip'
40402 title: 'Hyperlink',
40403 text: 'Make the selected text a hyperlink.',
40404 cls: 'x-html-editor-tip'
40407 title: 'Source Edit',
40408 text: 'Switch to source editing mode.',
40409 cls: 'x-html-editor-tip'
40413 onDestroy : function(){
40416 this.tb.items.each(function(item){
40418 item.menu.removeAll();
40420 item.menu.el.destroy();
40428 onFirstFocus: function() {
40429 this.tb.items.each(function(item){
40438 // <script type="text/javascript">
40441 * Ext JS Library 1.1.1
40442 * Copyright(c) 2006-2007, Ext JS, LLC.
40449 * @class Roo.form.HtmlEditor.ToolbarContext
40454 new Roo.form.HtmlEditor({
40457 { xtype: 'ToolbarStandard', styles : {} }
40458 { xtype: 'ToolbarContext', disable : {} }
40464 * @config : {Object} disable List of elements to disable.. (not done yet.)
40465 * @config : {Object} styles Map of styles available.
40469 Roo.form.HtmlEditor.ToolbarContext = function(config)
40472 Roo.apply(this, config);
40473 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
40474 // dont call parent... till later.
40475 this.styles = this.styles || {};
40477 Roo.form.HtmlEditor.ToolbarContext.types = {
40489 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
40551 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
40556 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40610 // should we really allow this??
40611 // should this just be
40626 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40634 * @cfg {Object} disable List of toolbar elements to disable
40639 * @cfg {Object} styles List of styles
40640 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
40642 * These must be defined in the page, so they get rendered correctly..
40653 init : function(editor)
40655 this.editor = editor;
40658 var fid = editor.frameId;
40660 function btn(id, toggle, handler){
40661 var xid = fid + '-'+ id ;
40665 cls : 'x-btn-icon x-edit-'+id,
40666 enableToggle:toggle !== false,
40667 scope: editor, // was editor...
40668 handler:handler||editor.relayBtnCmd,
40669 clickEvent:'mousedown',
40670 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40674 // create a new element.
40675 var wdiv = editor.wrap.createChild({
40677 }, editor.wrap.dom.firstChild.nextSibling, true);
40679 // can we do this more than once??
40681 // stop form submits
40684 // disable everything...
40685 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40686 this.toolbars = {};
40688 for (var i in ty) {
40690 this.toolbars[i] = this.buildToolbar(ty[i],i);
40692 this.tb = this.toolbars.BODY;
40694 this.buildFooter();
40695 this.footer.show();
40697 this.rendered = true;
40699 // the all the btns;
40700 editor.on('editorevent', this.updateToolbar, this);
40701 // other toolbars need to implement this..
40702 //editor.on('editmodechange', this.updateToolbar, this);
40708 * Protected method that will not generally be called directly. It triggers
40709 * a toolbar update by reading the markup state of the current selection in the editor.
40711 updateToolbar: function(ignore_a,ignore_b,sel){
40714 if(!this.editor.activated){
40715 this.editor.onFirstFocus();
40718 var updateFooter = sel ? false : true;
40721 var ans = this.editor.getAllAncestors();
40724 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40727 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40728 sel = sel ? sel : this.editor.doc.body;
40729 sel = sel.tagName.length ? sel : this.editor.doc.body;
40732 // pick a menu that exists..
40733 var tn = sel.tagName.toUpperCase();
40734 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40736 tn = sel.tagName.toUpperCase();
40738 var lastSel = this.tb.selectedNode
40740 this.tb.selectedNode = sel;
40742 // if current menu does not match..
40743 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
40746 ///console.log("show: " + tn);
40747 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
40750 this.tb.items.first().el.innerHTML = tn + ': ';
40753 // update attributes
40754 if (this.tb.fields) {
40755 this.tb.fields.each(function(e) {
40756 e.setValue(sel.getAttribute(e.name));
40761 var st = this.tb.fields.item(0);
40762 st.store.removeAll();
40763 var cn = sel.className.split(/\s+/);
40766 if (this.styles['*']) {
40768 Roo.each(this.styles['*'], function(v) {
40769 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
40772 if (this.styles[tn]) {
40773 Roo.each(this.styles[tn], function(v) {
40774 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
40778 st.store.loadData(avs);
40782 // flag our selected Node.
40783 this.tb.selectedNode = sel;
40786 Roo.menu.MenuMgr.hideAll();
40790 if (!updateFooter) {
40793 // update the footer
40797 this.footerEls = ans.reverse();
40798 Roo.each(this.footerEls, function(a,i) {
40799 if (!a) { return; }
40800 html += html.length ? ' > ' : '';
40802 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
40807 var sz = this.footDisp.up('td').getSize();
40808 this.footDisp.dom.style.width = (sz.width -10) + 'px';
40809 this.footDisp.dom.style.marginLeft = '5px';
40811 this.footDisp.dom.style.overflow = 'hidden';
40813 this.footDisp.dom.innerHTML = html;
40815 //this.editorsyncValue();
40820 onDestroy : function(){
40823 this.tb.items.each(function(item){
40825 item.menu.removeAll();
40827 item.menu.el.destroy();
40835 onFirstFocus: function() {
40836 // need to do this for all the toolbars..
40837 this.tb.items.each(function(item){
40841 buildToolbar: function(tlist, nm)
40843 var editor = this.editor;
40844 // create a new element.
40845 var wdiv = editor.wrap.createChild({
40847 }, editor.wrap.dom.firstChild.nextSibling, true);
40850 var tb = new Roo.Toolbar(wdiv);
40853 tb.add(nm+ ": ");
40858 // this needs a multi-select checkbox...
40859 tb.addField( new Roo.form.ComboBox({
40860 store: new Roo.data.SimpleStore({
40862 fields: ['val', 'selected'],
40865 name : 'className',
40866 displayField:'val',
40870 triggerAction: 'all',
40871 emptyText:'Select Style',
40872 selectOnFocus:true,
40875 'select': function(c, r, i) {
40876 // initial support only for on class per el..
40877 tb.selectedNode.className = r ? r.get('val') : '';
40886 for (var i in tlist) {
40888 var item = tlist[i];
40889 tb.add(item.title + ": ");
40895 // opts == pulldown..
40896 tb.addField( new Roo.form.ComboBox({
40897 store: new Roo.data.SimpleStore({
40903 displayField:'val',
40907 triggerAction: 'all',
40908 emptyText:'Select',
40909 selectOnFocus:true,
40910 width: item.width ? item.width : 130,
40912 'select': function(c, r, i) {
40913 tb.selectedNode.setAttribute(c.name, r.get('val'));
40922 tb.addField( new Roo.form.TextField({
40925 //allowBlank:false,
40930 tb.addField( new Roo.form.TextField({
40936 'change' : function(f, nv, ov) {
40937 tb.selectedNode.setAttribute(f.name, nv);
40943 tb.el.on('click', function(e){
40944 e.preventDefault(); // what does this do?
40946 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40949 // dont need to disable them... as they will get hidden
40954 buildFooter : function()
40957 var fel = this.editor.wrap.createChild();
40958 this.footer = new Roo.Toolbar(fel);
40959 // toolbar has scrolly on left / right?
40960 var footDisp= new Roo.Toolbar.Fill();
40966 handler : function() {
40967 _t.footDisp.scrollTo('left',0,true)
40971 this.footer.add( footDisp );
40976 handler : function() {
40978 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
40982 var fel = Roo.get(footDisp.el);
40983 fel.addClass('x-editor-context');
40984 this.footDispWrap = fel;
40985 this.footDispWrap.overflow = 'hidden';
40987 this.footDisp = fel.createChild();
40988 this.footDispWrap.on('click', this.onContextClick, this)
40992 onContextClick : function (ev,dom)
40994 ev.preventDefault();
40995 var cn = dom.className;
40997 if (!cn.match(/x-ed-loc-/)) {
41000 var n = cn.split('-').pop();
41001 var ans = this.footerEls;
41005 var range = this.editor.createRange();
41007 range.selectNodeContents(sel);
41008 //range.selectNode(sel);
41011 var selection = this.editor.getSelection();
41012 selection.removeAllRanges();
41013 selection.addRange(range);
41017 this.updateToolbar(null, null, sel);
41034 * Ext JS Library 1.1.1
41035 * Copyright(c) 2006-2007, Ext JS, LLC.
41037 * Originally Released Under LGPL - original licence link has changed is not relivant.
41040 * <script type="text/javascript">
41044 * @class Roo.form.BasicForm
41045 * @extends Roo.util.Observable
41046 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
41048 * @param {String/HTMLElement/Roo.Element} el The form element or its id
41049 * @param {Object} config Configuration options
41051 Roo.form.BasicForm = function(el, config){
41052 this.allItems = [];
41053 this.childForms = [];
41054 Roo.apply(this, config);
41056 * The Roo.form.Field items in this form.
41057 * @type MixedCollection
41061 this.items = new Roo.util.MixedCollection(false, function(o){
41062 return o.id || (o.id = Roo.id());
41066 * @event beforeaction
41067 * Fires before any action is performed. Return false to cancel the action.
41068 * @param {Form} this
41069 * @param {Action} action The action to be performed
41071 beforeaction: true,
41073 * @event actionfailed
41074 * Fires when an action fails.
41075 * @param {Form} this
41076 * @param {Action} action The action that failed
41078 actionfailed : true,
41080 * @event actioncomplete
41081 * Fires when an action is completed.
41082 * @param {Form} this
41083 * @param {Action} action The action that completed
41085 actioncomplete : true
41090 Roo.form.BasicForm.superclass.constructor.call(this);
41093 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
41095 * @cfg {String} method
41096 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
41099 * @cfg {DataReader} reader
41100 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
41101 * This is optional as there is built-in support for processing JSON.
41104 * @cfg {DataReader} errorReader
41105 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
41106 * This is completely optional as there is built-in support for processing JSON.
41109 * @cfg {String} url
41110 * The URL to use for form actions if one isn't supplied in the action options.
41113 * @cfg {Boolean} fileUpload
41114 * Set to true if this form is a file upload.
41118 * @cfg {Object} baseParams
41119 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
41124 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
41129 activeAction : null,
41132 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
41133 * or setValues() data instead of when the form was first created.
41135 trackResetOnLoad : false,
41139 * childForms - used for multi-tab forms
41142 childForms : false,
41145 * allItems - full list of fields.
41151 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
41152 * element by passing it or its id or mask the form itself by passing in true.
41155 waitMsgTarget : false,
41158 initEl : function(el){
41159 this.el = Roo.get(el);
41160 this.id = this.el.id || Roo.id();
41161 this.el.on('submit', this.onSubmit, this);
41162 this.el.addClass('x-form');
41166 onSubmit : function(e){
41171 * Returns true if client-side validation on the form is successful.
41174 isValid : function(){
41176 this.items.each(function(f){
41185 * Returns true if any fields in this form have changed since their original load.
41188 isDirty : function(){
41190 this.items.each(function(f){
41200 * Performs a predefined action (submit or load) or custom actions you define on this form.
41201 * @param {String} actionName The name of the action type
41202 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
41203 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
41204 * accept other config options):
41206 Property Type Description
41207 ---------------- --------------- ----------------------------------------------------------------------------------
41208 url String The url for the action (defaults to the form's url)
41209 method String The form method to use (defaults to the form's method, or POST if not defined)
41210 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
41211 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
41212 validate the form on the client (defaults to false)
41214 * @return {BasicForm} this
41216 doAction : function(action, options){
41217 if(typeof action == 'string'){
41218 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
41220 if(this.fireEvent('beforeaction', this, action) !== false){
41221 this.beforeAction(action);
41222 action.run.defer(100, action);
41228 * Shortcut to do a submit action.
41229 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
41230 * @return {BasicForm} this
41232 submit : function(options){
41233 this.doAction('submit', options);
41238 * Shortcut to do a load action.
41239 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
41240 * @return {BasicForm} this
41242 load : function(options){
41243 this.doAction('load', options);
41248 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
41249 * @param {Record} record The record to edit
41250 * @return {BasicForm} this
41252 updateRecord : function(record){
41253 record.beginEdit();
41254 var fs = record.fields;
41255 fs.each(function(f){
41256 var field = this.findField(f.name);
41258 record.set(f.name, field.getValue());
41266 * Loads an Roo.data.Record into this form.
41267 * @param {Record} record The record to load
41268 * @return {BasicForm} this
41270 loadRecord : function(record){
41271 this.setValues(record.data);
41276 beforeAction : function(action){
41277 var o = action.options;
41280 if(this.waitMsgTarget === true){
41281 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
41282 }else if(this.waitMsgTarget){
41283 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
41284 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
41286 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
41292 afterAction : function(action, success){
41293 this.activeAction = null;
41294 var o = action.options;
41296 if(this.waitMsgTarget === true){
41298 }else if(this.waitMsgTarget){
41299 this.waitMsgTarget.unmask();
41301 Roo.MessageBox.updateProgress(1);
41302 Roo.MessageBox.hide();
41309 Roo.callback(o.success, o.scope, [this, action]);
41310 this.fireEvent('actioncomplete', this, action);
41313 Roo.callback(o.failure, o.scope, [this, action]);
41314 // show an error message if no failed handler is set..
41315 if (!this.hasListener('actionfailed')) {
41316 Roo.MessageBox.alert("Error",
41317 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
41318 action.result.errorMsg :
41319 "Saving Failed, please check your entries"
41323 this.fireEvent('actionfailed', this, action);
41329 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
41330 * @param {String} id The value to search for
41333 findField : function(id){
41334 var field = this.items.get(id);
41336 this.items.each(function(f){
41337 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
41343 return field || null;
41347 * Add a secondary form to this one,
41348 * Used to provide tabbed forms. One form is primary, with hidden values
41349 * which mirror the elements from the other forms.
41351 * @param {Roo.form.Form} form to add.
41354 addForm : function(form)
41357 if (this.childForms.indexOf(form) > -1) {
41361 this.childForms.push(form);
41363 Roo.each(form.allItems, function (fe) {
41365 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
41366 if (this.findField(n)) { // already added..
41369 var add = new Roo.form.Hidden({
41372 add.render(this.el);
41379 * Mark fields in this form invalid in bulk.
41380 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
41381 * @return {BasicForm} this
41383 markInvalid : function(errors){
41384 if(errors instanceof Array){
41385 for(var i = 0, len = errors.length; i < len; i++){
41386 var fieldError = errors[i];
41387 var f = this.findField(fieldError.id);
41389 f.markInvalid(fieldError.msg);
41395 if(typeof errors[id] != 'function' && (field = this.findField(id))){
41396 field.markInvalid(errors[id]);
41400 Roo.each(this.childForms || [], function (f) {
41401 f.markInvalid(errors);
41408 * Set values for fields in this form in bulk.
41409 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
41410 * @return {BasicForm} this
41412 setValues : function(values){
41413 if(values instanceof Array){ // array of objects
41414 for(var i = 0, len = values.length; i < len; i++){
41416 var f = this.findField(v.id);
41418 f.setValue(v.value);
41419 if(this.trackResetOnLoad){
41420 f.originalValue = f.getValue();
41424 }else{ // object hash
41427 if(typeof values[id] != 'function' && (field = this.findField(id))){
41429 if (field.setFromData &&
41430 field.valueField &&
41431 field.displayField &&
41432 // combos' with local stores can
41433 // be queried via setValue()
41434 // to set their value..
41435 (field.store && !field.store.isLocal)
41439 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
41440 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
41441 field.setFromData(sd);
41444 field.setValue(values[id]);
41448 if(this.trackResetOnLoad){
41449 field.originalValue = field.getValue();
41455 Roo.each(this.childForms || [], function (f) {
41456 f.setValues(values);
41463 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
41464 * they are returned as an array.
41465 * @param {Boolean} asString
41468 getValues : function(asString){
41469 if (this.childForms) {
41470 // copy values from the child forms
41471 Roo.each(this.childForms, function (f) {
41472 this.setValues(f.getValues());
41478 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
41479 if(asString === true){
41482 return Roo.urlDecode(fs);
41486 * Returns the fields in this form as an object with key/value pairs.
41487 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
41490 getFieldValues : function(with_hidden)
41492 if (this.childForms) {
41493 // copy values from the child forms
41494 // should this call getFieldValues - probably not as we do not currently copy
41495 // hidden fields when we generate..
41496 Roo.each(this.childForms, function (f) {
41497 this.setValues(f.getValues());
41502 this.items.each(function(f){
41503 if (!f.getName()) {
41506 var v = f.getValue();
41507 // not sure if this supported any more..
41508 if ((typeof(v) == 'object') && f.getRawValue) {
41509 v = f.getRawValue() ; // dates..
41511 // combo boxes where name != hiddenName...
41512 if (f.name != f.getName()) {
41513 ret[f.name] = f.getRawValue();
41515 ret[f.getName()] = v;
41522 * Clears all invalid messages in this form.
41523 * @return {BasicForm} this
41525 clearInvalid : function(){
41526 this.items.each(function(f){
41530 Roo.each(this.childForms || [], function (f) {
41539 * Resets this form.
41540 * @return {BasicForm} this
41542 reset : function(){
41543 this.items.each(function(f){
41547 Roo.each(this.childForms || [], function (f) {
41556 * Add Roo.form components to this form.
41557 * @param {Field} field1
41558 * @param {Field} field2 (optional)
41559 * @param {Field} etc (optional)
41560 * @return {BasicForm} this
41563 this.items.addAll(Array.prototype.slice.call(arguments, 0));
41569 * Removes a field from the items collection (does NOT remove its markup).
41570 * @param {Field} field
41571 * @return {BasicForm} this
41573 remove : function(field){
41574 this.items.remove(field);
41579 * Looks at the fields in this form, checks them for an id attribute,
41580 * and calls applyTo on the existing dom element with that id.
41581 * @return {BasicForm} this
41583 render : function(){
41584 this.items.each(function(f){
41585 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
41593 * Calls {@link Ext#apply} for all fields in this form with the passed object.
41594 * @param {Object} values
41595 * @return {BasicForm} this
41597 applyToFields : function(o){
41598 this.items.each(function(f){
41605 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
41606 * @param {Object} values
41607 * @return {BasicForm} this
41609 applyIfToFields : function(o){
41610 this.items.each(function(f){
41618 Roo.BasicForm = Roo.form.BasicForm;/*
41620 * Ext JS Library 1.1.1
41621 * Copyright(c) 2006-2007, Ext JS, LLC.
41623 * Originally Released Under LGPL - original licence link has changed is not relivant.
41626 * <script type="text/javascript">
41630 * @class Roo.form.Form
41631 * @extends Roo.form.BasicForm
41632 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
41634 * @param {Object} config Configuration options
41636 Roo.form.Form = function(config){
41638 if (config.items) {
41639 xitems = config.items;
41640 delete config.items;
41644 Roo.form.Form.superclass.constructor.call(this, null, config);
41645 this.url = this.url || this.action;
41647 this.root = new Roo.form.Layout(Roo.applyIf({
41651 this.active = this.root;
41653 * Array of all the buttons that have been added to this form via {@link addButton}
41657 this.allItems = [];
41660 * @event clientvalidation
41661 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
41662 * @param {Form} this
41663 * @param {Boolean} valid true if the form has passed client-side validation
41665 clientvalidation: true,
41668 * Fires when the form is rendered
41669 * @param {Roo.form.Form} form
41674 if (this.progressUrl) {
41675 // push a hidden field onto the list of fields..
41679 name : 'UPLOAD_IDENTIFIER'
41684 Roo.each(xitems, this.addxtype, this);
41690 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
41692 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
41695 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
41698 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
41700 buttonAlign:'center',
41703 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
41708 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
41709 * This property cascades to child containers if not set.
41714 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
41715 * fires a looping event with that state. This is required to bind buttons to the valid
41716 * state using the config value formBind:true on the button.
41718 monitorValid : false,
41721 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
41726 * @cfg {String} progressUrl - Url to return progress data
41729 progressUrl : false,
41732 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
41733 * fields are added and the column is closed. If no fields are passed the column remains open
41734 * until end() is called.
41735 * @param {Object} config The config to pass to the column
41736 * @param {Field} field1 (optional)
41737 * @param {Field} field2 (optional)
41738 * @param {Field} etc (optional)
41739 * @return Column The column container object
41741 column : function(c){
41742 var col = new Roo.form.Column(c);
41744 if(arguments.length > 1){ // duplicate code required because of Opera
41745 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41752 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
41753 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
41754 * until end() is called.
41755 * @param {Object} config The config to pass to the fieldset
41756 * @param {Field} field1 (optional)
41757 * @param {Field} field2 (optional)
41758 * @param {Field} etc (optional)
41759 * @return FieldSet The fieldset container object
41761 fieldset : function(c){
41762 var fs = new Roo.form.FieldSet(c);
41764 if(arguments.length > 1){ // duplicate code required because of Opera
41765 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41772 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
41773 * fields are added and the container is closed. If no fields are passed the container remains open
41774 * until end() is called.
41775 * @param {Object} config The config to pass to the Layout
41776 * @param {Field} field1 (optional)
41777 * @param {Field} field2 (optional)
41778 * @param {Field} etc (optional)
41779 * @return Layout The container object
41781 container : function(c){
41782 var l = new Roo.form.Layout(c);
41784 if(arguments.length > 1){ // duplicate code required because of Opera
41785 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41792 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41793 * @param {Object} container A Roo.form.Layout or subclass of Layout
41794 * @return {Form} this
41796 start : function(c){
41797 // cascade label info
41798 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
41799 this.active.stack.push(c);
41800 c.ownerCt = this.active;
41806 * Closes the current open container
41807 * @return {Form} this
41810 if(this.active == this.root){
41813 this.active = this.active.ownerCt;
41818 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
41819 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
41820 * as the label of the field.
41821 * @param {Field} field1
41822 * @param {Field} field2 (optional)
41823 * @param {Field} etc. (optional)
41824 * @return {Form} this
41827 this.active.stack.push.apply(this.active.stack, arguments);
41828 this.allItems.push.apply(this.allItems,arguments);
41830 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
41831 if(a[i].isFormField){
41836 Roo.form.Form.superclass.add.apply(this, r);
41846 * Find any element that has been added to a form, using it's ID or name
41847 * This can include framesets, columns etc. along with regular fields..
41848 * @param {String} id - id or name to find.
41850 * @return {Element} e - or false if nothing found.
41852 findbyId : function(id)
41858 Roo.each(this.allItems, function(f){
41859 if (f.id == id || f.name == id ){
41870 * Render this form into the passed container. This should only be called once!
41871 * @param {String/HTMLElement/Element} container The element this component should be rendered into
41872 * @return {Form} this
41874 render : function(ct)
41880 var o = this.autoCreate || {
41882 method : this.method || 'POST',
41883 id : this.id || Roo.id()
41885 this.initEl(ct.createChild(o));
41887 this.root.render(this.el);
41891 this.items.each(function(f){
41892 f.render('x-form-el-'+f.id);
41895 if(this.buttons.length > 0){
41896 // tables are required to maintain order and for correct IE layout
41897 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
41898 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
41899 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
41901 var tr = tb.getElementsByTagName('tr')[0];
41902 for(var i = 0, len = this.buttons.length; i < len; i++) {
41903 var b = this.buttons[i];
41904 var td = document.createElement('td');
41905 td.className = 'x-form-btn-td';
41906 b.render(tr.appendChild(td));
41909 if(this.monitorValid){ // initialize after render
41910 this.startMonitoring();
41912 this.fireEvent('rendered', this);
41917 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
41918 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
41919 * object or a valid Roo.DomHelper element config
41920 * @param {Function} handler The function called when the button is clicked
41921 * @param {Object} scope (optional) The scope of the handler function
41922 * @return {Roo.Button}
41924 addButton : function(config, handler, scope){
41928 minWidth: this.minButtonWidth,
41931 if(typeof config == "string"){
41934 Roo.apply(bc, config);
41936 var btn = new Roo.Button(null, bc);
41937 this.buttons.push(btn);
41942 * Adds a series of form elements (using the xtype property as the factory method.
41943 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41944 * @param {Object} config
41947 addxtype : function()
41949 var ar = Array.prototype.slice.call(arguments, 0);
41951 for(var i = 0; i < ar.length; i++) {
41953 continue; // skip -- if this happends something invalid got sent, we
41954 // should ignore it, as basically that interface element will not show up
41955 // and that should be pretty obvious!!
41958 if (Roo.form[ar[i].xtype]) {
41960 var fe = Roo.factory(ar[i], Roo.form);
41966 fe.store.form = this;
41971 this.allItems.push(fe);
41972 if (fe.items && fe.addxtype) {
41973 fe.addxtype.apply(fe, fe.items);
41983 // console.log('adding ' + ar[i].xtype);
41985 if (ar[i].xtype == 'Button') {
41986 //console.log('adding button');
41987 //console.log(ar[i]);
41988 this.addButton(ar[i]);
41989 this.allItems.push(fe);
41993 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
41994 alert('end is not supported on xtype any more, use items');
41996 // //console.log('adding end');
42004 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
42005 * option "monitorValid"
42007 startMonitoring : function(){
42010 Roo.TaskMgr.start({
42011 run : this.bindHandler,
42012 interval : this.monitorPoll || 200,
42019 * Stops monitoring of the valid state of this form
42021 stopMonitoring : function(){
42022 this.bound = false;
42026 bindHandler : function(){
42028 return false; // stops binding
42031 this.items.each(function(f){
42032 if(!f.isValid(true)){
42037 for(var i = 0, len = this.buttons.length; i < len; i++){
42038 var btn = this.buttons[i];
42039 if(btn.formBind === true && btn.disabled === valid){
42040 btn.setDisabled(!valid);
42043 this.fireEvent('clientvalidation', this, valid);
42057 Roo.Form = Roo.form.Form;
42060 * Ext JS Library 1.1.1
42061 * Copyright(c) 2006-2007, Ext JS, LLC.
42063 * Originally Released Under LGPL - original licence link has changed is not relivant.
42066 * <script type="text/javascript">
42070 * @class Roo.form.Action
42071 * Internal Class used to handle form actions
42073 * @param {Roo.form.BasicForm} el The form element or its id
42074 * @param {Object} config Configuration options
42078 // define the action interface
42079 Roo.form.Action = function(form, options){
42081 this.options = options || {};
42084 * Client Validation Failed
42087 Roo.form.Action.CLIENT_INVALID = 'client';
42089 * Server Validation Failed
42092 Roo.form.Action.SERVER_INVALID = 'server';
42094 * Connect to Server Failed
42097 Roo.form.Action.CONNECT_FAILURE = 'connect';
42099 * Reading Data from Server Failed
42102 Roo.form.Action.LOAD_FAILURE = 'load';
42104 Roo.form.Action.prototype = {
42106 failureType : undefined,
42107 response : undefined,
42108 result : undefined,
42110 // interface method
42111 run : function(options){
42115 // interface method
42116 success : function(response){
42120 // interface method
42121 handleResponse : function(response){
42125 // default connection failure
42126 failure : function(response){
42128 this.response = response;
42129 this.failureType = Roo.form.Action.CONNECT_FAILURE;
42130 this.form.afterAction(this, false);
42133 processResponse : function(response){
42134 this.response = response;
42135 if(!response.responseText){
42138 this.result = this.handleResponse(response);
42139 return this.result;
42142 // utility functions used internally
42143 getUrl : function(appendParams){
42144 var url = this.options.url || this.form.url || this.form.el.dom.action;
42146 var p = this.getParams();
42148 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
42154 getMethod : function(){
42155 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
42158 getParams : function(){
42159 var bp = this.form.baseParams;
42160 var p = this.options.params;
42162 if(typeof p == "object"){
42163 p = Roo.urlEncode(Roo.applyIf(p, bp));
42164 }else if(typeof p == 'string' && bp){
42165 p += '&' + Roo.urlEncode(bp);
42168 p = Roo.urlEncode(bp);
42173 createCallback : function(){
42175 success: this.success,
42176 failure: this.failure,
42178 timeout: (this.form.timeout*1000),
42179 upload: this.form.fileUpload ? this.success : undefined
42184 Roo.form.Action.Submit = function(form, options){
42185 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
42188 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
42191 haveProgress : false,
42192 uploadComplete : false,
42194 // uploadProgress indicator.
42195 uploadProgress : function()
42197 if (!this.form.progressUrl) {
42201 if (!this.haveProgress) {
42202 Roo.MessageBox.progress("Uploading", "Uploading");
42204 if (this.uploadComplete) {
42205 Roo.MessageBox.hide();
42209 this.haveProgress = true;
42211 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
42213 var c = new Roo.data.Connection();
42215 url : this.form.progressUrl,
42220 success : function(req){
42221 //console.log(data);
42225 rdata = Roo.decode(req.responseText)
42227 Roo.log("Invalid data from server..");
42231 if (!rdata || !rdata.success) {
42235 var data = rdata.data;
42237 if (this.uploadComplete) {
42238 Roo.MessageBox.hide();
42243 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
42244 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
42247 this.uploadProgress.defer(2000,this);
42250 failure: function(data) {
42251 Roo.log('progress url failed ');
42262 // run get Values on the form, so it syncs any secondary forms.
42263 this.form.getValues();
42265 var o = this.options;
42266 var method = this.getMethod();
42267 var isPost = method == 'POST';
42268 if(o.clientValidation === false || this.form.isValid()){
42270 if (this.form.progressUrl) {
42271 this.form.findField('UPLOAD_IDENTIFIER').setValue(
42272 (new Date() * 1) + '' + Math.random());
42277 Roo.Ajax.request(Roo.apply(this.createCallback(), {
42278 form:this.form.el.dom,
42279 url:this.getUrl(!isPost),
42281 params:isPost ? this.getParams() : null,
42282 isUpload: this.form.fileUpload
42285 this.uploadProgress();
42287 }else if (o.clientValidation !== false){ // client validation failed
42288 this.failureType = Roo.form.Action.CLIENT_INVALID;
42289 this.form.afterAction(this, false);
42293 success : function(response)
42295 this.uploadComplete= true;
42296 if (this.haveProgress) {
42297 Roo.MessageBox.hide();
42301 var result = this.processResponse(response);
42302 if(result === true || result.success){
42303 this.form.afterAction(this, true);
42307 this.form.markInvalid(result.errors);
42308 this.failureType = Roo.form.Action.SERVER_INVALID;
42310 this.form.afterAction(this, false);
42312 failure : function(response)
42314 this.uploadComplete= true;
42315 if (this.haveProgress) {
42316 Roo.MessageBox.hide();
42319 this.response = response;
42320 this.failureType = Roo.form.Action.CONNECT_FAILURE;
42321 this.form.afterAction(this, false);
42324 handleResponse : function(response){
42325 if(this.form.errorReader){
42326 var rs = this.form.errorReader.read(response);
42329 for(var i = 0, len = rs.records.length; i < len; i++) {
42330 var r = rs.records[i];
42331 errors[i] = r.data;
42334 if(errors.length < 1){
42338 success : rs.success,
42344 ret = Roo.decode(response.responseText);
42348 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
42358 Roo.form.Action.Load = function(form, options){
42359 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
42360 this.reader = this.form.reader;
42363 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
42368 Roo.Ajax.request(Roo.apply(
42369 this.createCallback(), {
42370 method:this.getMethod(),
42371 url:this.getUrl(false),
42372 params:this.getParams()
42376 success : function(response){
42378 var result = this.processResponse(response);
42379 if(result === true || !result.success || !result.data){
42380 this.failureType = Roo.form.Action.LOAD_FAILURE;
42381 this.form.afterAction(this, false);
42384 this.form.clearInvalid();
42385 this.form.setValues(result.data);
42386 this.form.afterAction(this, true);
42389 handleResponse : function(response){
42390 if(this.form.reader){
42391 var rs = this.form.reader.read(response);
42392 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
42394 success : rs.success,
42398 return Roo.decode(response.responseText);
42402 Roo.form.Action.ACTION_TYPES = {
42403 'load' : Roo.form.Action.Load,
42404 'submit' : Roo.form.Action.Submit
42407 * Ext JS Library 1.1.1
42408 * Copyright(c) 2006-2007, Ext JS, LLC.
42410 * Originally Released Under LGPL - original licence link has changed is not relivant.
42413 * <script type="text/javascript">
42417 * @class Roo.form.Layout
42418 * @extends Roo.Component
42419 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
42421 * @param {Object} config Configuration options
42423 Roo.form.Layout = function(config){
42425 if (config.items) {
42426 xitems = config.items;
42427 delete config.items;
42429 Roo.form.Layout.superclass.constructor.call(this, config);
42431 Roo.each(xitems, this.addxtype, this);
42435 Roo.extend(Roo.form.Layout, Roo.Component, {
42437 * @cfg {String/Object} autoCreate
42438 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
42441 * @cfg {String/Object/Function} style
42442 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
42443 * a function which returns such a specification.
42446 * @cfg {String} labelAlign
42447 * Valid values are "left," "top" and "right" (defaults to "left")
42450 * @cfg {Number} labelWidth
42451 * Fixed width in pixels of all field labels (defaults to undefined)
42454 * @cfg {Boolean} clear
42455 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
42459 * @cfg {String} labelSeparator
42460 * The separator to use after field labels (defaults to ':')
42462 labelSeparator : ':',
42464 * @cfg {Boolean} hideLabels
42465 * True to suppress the display of field labels in this layout (defaults to false)
42467 hideLabels : false,
42470 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
42475 onRender : function(ct, position){
42476 if(this.el){ // from markup
42477 this.el = Roo.get(this.el);
42478 }else { // generate
42479 var cfg = this.getAutoCreate();
42480 this.el = ct.createChild(cfg, position);
42483 this.el.applyStyles(this.style);
42485 if(this.labelAlign){
42486 this.el.addClass('x-form-label-'+this.labelAlign);
42488 if(this.hideLabels){
42489 this.labelStyle = "display:none";
42490 this.elementStyle = "padding-left:0;";
42492 if(typeof this.labelWidth == 'number'){
42493 this.labelStyle = "width:"+this.labelWidth+"px;";
42494 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
42496 if(this.labelAlign == 'top'){
42497 this.labelStyle = "width:auto;";
42498 this.elementStyle = "padding-left:0;";
42501 var stack = this.stack;
42502 var slen = stack.length;
42504 if(!this.fieldTpl){
42505 var t = new Roo.Template(
42506 '<div class="x-form-item {5}">',
42507 '<label for="{0}" style="{2}">{1}{4}</label>',
42508 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
42510 '</div><div class="x-form-clear-left"></div>'
42512 t.disableFormats = true;
42514 Roo.form.Layout.prototype.fieldTpl = t;
42516 for(var i = 0; i < slen; i++) {
42517 if(stack[i].isFormField){
42518 this.renderField(stack[i]);
42520 this.renderComponent(stack[i]);
42525 this.el.createChild({cls:'x-form-clear'});
42530 renderField : function(f){
42531 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
42534 f.labelStyle||this.labelStyle||'', //2
42535 this.elementStyle||'', //3
42536 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
42537 f.itemCls||this.itemCls||'' //5
42538 ], true).getPrevSibling());
42542 renderComponent : function(c){
42543 c.render(c.isLayout ? this.el : this.el.createChild());
42546 * Adds a object form elements (using the xtype property as the factory method.)
42547 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
42548 * @param {Object} config
42550 addxtype : function(o)
42552 // create the lement.
42553 o.form = this.form;
42554 var fe = Roo.factory(o, Roo.form);
42555 this.form.allItems.push(fe);
42556 this.stack.push(fe);
42558 if (fe.isFormField) {
42559 this.form.items.add(fe);
42567 * @class Roo.form.Column
42568 * @extends Roo.form.Layout
42569 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
42571 * @param {Object} config Configuration options
42573 Roo.form.Column = function(config){
42574 Roo.form.Column.superclass.constructor.call(this, config);
42577 Roo.extend(Roo.form.Column, Roo.form.Layout, {
42579 * @cfg {Number/String} width
42580 * The fixed width of the column in pixels or CSS value (defaults to "auto")
42583 * @cfg {String/Object} autoCreate
42584 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
42588 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
42591 onRender : function(ct, position){
42592 Roo.form.Column.superclass.onRender.call(this, ct, position);
42594 this.el.setWidth(this.width);
42601 * @class Roo.form.Row
42602 * @extends Roo.form.Layout
42603 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
42605 * @param {Object} config Configuration options
42609 Roo.form.Row = function(config){
42610 Roo.form.Row.superclass.constructor.call(this, config);
42613 Roo.extend(Roo.form.Row, Roo.form.Layout, {
42615 * @cfg {Number/String} width
42616 * The fixed width of the column in pixels or CSS value (defaults to "auto")
42619 * @cfg {Number/String} height
42620 * The fixed height of the column in pixels or CSS value (defaults to "auto")
42622 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
42626 onRender : function(ct, position){
42627 //console.log('row render');
42629 var t = new Roo.Template(
42630 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
42631 '<label for="{0}" style="{2}">{1}{4}</label>',
42632 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
42636 t.disableFormats = true;
42638 Roo.form.Layout.prototype.rowTpl = t;
42640 this.fieldTpl = this.rowTpl;
42642 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
42643 var labelWidth = 100;
42645 if ((this.labelAlign != 'top')) {
42646 if (typeof this.labelWidth == 'number') {
42647 labelWidth = this.labelWidth
42649 this.padWidth = 20 + labelWidth;
42653 Roo.form.Column.superclass.onRender.call(this, ct, position);
42655 this.el.setWidth(this.width);
42658 this.el.setHeight(this.height);
42663 renderField : function(f){
42664 f.fieldEl = this.fieldTpl.append(this.el, [
42665 f.id, f.fieldLabel,
42666 f.labelStyle||this.labelStyle||'',
42667 this.elementStyle||'',
42668 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
42669 f.itemCls||this.itemCls||'',
42670 f.width ? f.width + this.padWidth : 160 + this.padWidth
42677 * @class Roo.form.FieldSet
42678 * @extends Roo.form.Layout
42679 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
42681 * @param {Object} config Configuration options
42683 Roo.form.FieldSet = function(config){
42684 Roo.form.FieldSet.superclass.constructor.call(this, config);
42687 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
42689 * @cfg {String} legend
42690 * The text to display as the legend for the FieldSet (defaults to '')
42693 * @cfg {String/Object} autoCreate
42694 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
42698 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
42701 onRender : function(ct, position){
42702 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
42704 this.setLegend(this.legend);
42709 setLegend : function(text){
42711 this.el.child('legend').update(text);
42716 * Ext JS Library 1.1.1
42717 * Copyright(c) 2006-2007, Ext JS, LLC.
42719 * Originally Released Under LGPL - original licence link has changed is not relivant.
42722 * <script type="text/javascript">
42725 * @class Roo.form.VTypes
42726 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
42729 Roo.form.VTypes = function(){
42730 // closure these in so they are only created once.
42731 var alpha = /^[a-zA-Z_]+$/;
42732 var alphanum = /^[a-zA-Z0-9_]+$/;
42733 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
42734 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
42736 // All these messages and functions are configurable
42739 * The function used to validate email addresses
42740 * @param {String} value The email address
42742 'email' : function(v){
42743 return email.test(v);
42746 * The error text to display when the email validation function returns false
42749 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
42751 * The keystroke filter mask to be applied on email input
42754 'emailMask' : /[a-z0-9_\.\-@]/i,
42757 * The function used to validate URLs
42758 * @param {String} value The URL
42760 'url' : function(v){
42761 return url.test(v);
42764 * The error text to display when the url validation function returns false
42767 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
42770 * The function used to validate alpha values
42771 * @param {String} value The value
42773 'alpha' : function(v){
42774 return alpha.test(v);
42777 * The error text to display when the alpha validation function returns false
42780 'alphaText' : 'This field should only contain letters and _',
42782 * The keystroke filter mask to be applied on alpha input
42785 'alphaMask' : /[a-z_]/i,
42788 * The function used to validate alphanumeric values
42789 * @param {String} value The value
42791 'alphanum' : function(v){
42792 return alphanum.test(v);
42795 * The error text to display when the alphanumeric validation function returns false
42798 'alphanumText' : 'This field should only contain letters, numbers and _',
42800 * The keystroke filter mask to be applied on alphanumeric input
42803 'alphanumMask' : /[a-z0-9_]/i
42805 }();//<script type="text/javascript">
42808 * @class Roo.form.FCKeditor
42809 * @extends Roo.form.TextArea
42810 * Wrapper around the FCKEditor http://www.fckeditor.net
42812 * Creates a new FCKeditor
42813 * @param {Object} config Configuration options
42815 Roo.form.FCKeditor = function(config){
42816 Roo.form.FCKeditor.superclass.constructor.call(this, config);
42819 * @event editorinit
42820 * Fired when the editor is initialized - you can add extra handlers here..
42821 * @param {FCKeditor} this
42822 * @param {Object} the FCK object.
42829 Roo.form.FCKeditor.editors = { };
42830 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
42832 //defaultAutoCreate : {
42833 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
42837 * @cfg {Object} fck options - see fck manual for details.
42842 * @cfg {Object} fck toolbar set (Basic or Default)
42844 toolbarSet : 'Basic',
42846 * @cfg {Object} fck BasePath
42848 basePath : '/fckeditor/',
42856 onRender : function(ct, position)
42859 this.defaultAutoCreate = {
42861 style:"width:300px;height:60px;",
42862 autocomplete: "off"
42865 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
42868 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
42869 if(this.preventScrollbars){
42870 this.el.setStyle("overflow", "hidden");
42872 this.el.setHeight(this.growMin);
42875 //console.log('onrender' + this.getId() );
42876 Roo.form.FCKeditor.editors[this.getId()] = this;
42879 this.replaceTextarea() ;
42883 getEditor : function() {
42884 return this.fckEditor;
42887 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
42888 * @param {Mixed} value The value to set
42892 setValue : function(value)
42894 //console.log('setValue: ' + value);
42896 if(typeof(value) == 'undefined') { // not sure why this is happending...
42899 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42901 //if(!this.el || !this.getEditor()) {
42902 // this.value = value;
42903 //this.setValue.defer(100,this,[value]);
42907 if(!this.getEditor()) {
42911 this.getEditor().SetData(value);
42918 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
42919 * @return {Mixed} value The field value
42921 getValue : function()
42924 if (this.frame && this.frame.dom.style.display == 'none') {
42925 return Roo.form.FCKeditor.superclass.getValue.call(this);
42928 if(!this.el || !this.getEditor()) {
42930 // this.getValue.defer(100,this);
42935 var value=this.getEditor().GetData();
42936 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42937 return Roo.form.FCKeditor.superclass.getValue.call(this);
42943 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
42944 * @return {Mixed} value The field value
42946 getRawValue : function()
42948 if (this.frame && this.frame.dom.style.display == 'none') {
42949 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42952 if(!this.el || !this.getEditor()) {
42953 //this.getRawValue.defer(100,this);
42960 var value=this.getEditor().GetData();
42961 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
42962 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42966 setSize : function(w,h) {
42970 //if (this.frame && this.frame.dom.style.display == 'none') {
42971 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42974 //if(!this.el || !this.getEditor()) {
42975 // this.setSize.defer(100,this, [w,h]);
42981 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42983 this.frame.dom.setAttribute('width', w);
42984 this.frame.dom.setAttribute('height', h);
42985 this.frame.setSize(w,h);
42989 toggleSourceEdit : function(value) {
42993 this.el.dom.style.display = value ? '' : 'none';
42994 this.frame.dom.style.display = value ? 'none' : '';
42999 focus: function(tag)
43001 if (this.frame.dom.style.display == 'none') {
43002 return Roo.form.FCKeditor.superclass.focus.call(this);
43004 if(!this.el || !this.getEditor()) {
43005 this.focus.defer(100,this, [tag]);
43012 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
43013 this.getEditor().Focus();
43015 if (!this.getEditor().Selection.GetSelection()) {
43016 this.focus.defer(100,this, [tag]);
43021 var r = this.getEditor().EditorDocument.createRange();
43022 r.setStart(tgs[0],0);
43023 r.setEnd(tgs[0],0);
43024 this.getEditor().Selection.GetSelection().removeAllRanges();
43025 this.getEditor().Selection.GetSelection().addRange(r);
43026 this.getEditor().Focus();
43033 replaceTextarea : function()
43035 if ( document.getElementById( this.getId() + '___Frame' ) )
43037 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
43039 // We must check the elements firstly using the Id and then the name.
43040 var oTextarea = document.getElementById( this.getId() );
43042 var colElementsByName = document.getElementsByName( this.getId() ) ;
43044 oTextarea.style.display = 'none' ;
43046 if ( oTextarea.tabIndex ) {
43047 this.TabIndex = oTextarea.tabIndex ;
43050 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
43051 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
43052 this.frame = Roo.get(this.getId() + '___Frame')
43055 _getConfigHtml : function()
43059 for ( var o in this.fckconfig ) {
43060 sConfig += sConfig.length > 0 ? '&' : '';
43061 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
43064 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
43068 _getIFrameHtml : function()
43070 var sFile = 'fckeditor.html' ;
43071 /* no idea what this is about..
43074 if ( (/fcksource=true/i).test( window.top.location.search ) )
43075 sFile = 'fckeditor.original.html' ;
43080 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
43081 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
43084 var html = '<iframe id="' + this.getId() +
43085 '___Frame" src="' + sLink +
43086 '" width="' + this.width +
43087 '" height="' + this.height + '"' +
43088 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
43089 ' frameborder="0" scrolling="no"></iframe>' ;
43094 _insertHtmlBefore : function( html, element )
43096 if ( element.insertAdjacentHTML ) {
43098 element.insertAdjacentHTML( 'beforeBegin', html ) ;
43100 var oRange = document.createRange() ;
43101 oRange.setStartBefore( element ) ;
43102 var oFragment = oRange.createContextualFragment( html );
43103 element.parentNode.insertBefore( oFragment, element ) ;
43116 //Roo.reg('fckeditor', Roo.form.FCKeditor);
43118 function FCKeditor_OnComplete(editorInstance){
43119 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
43120 f.fckEditor = editorInstance;
43121 //console.log("loaded");
43122 f.fireEvent('editorinit', f, editorInstance);
43142 //<script type="text/javascript">
43144 * @class Roo.form.GridField
43145 * @extends Roo.form.Field
43146 * Embed a grid (or editable grid into a form)
43149 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
43151 * xgrid.store = Roo.data.Store
43152 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
43153 * xgrid.store.reader = Roo.data.JsonReader
43157 * Creates a new GridField
43158 * @param {Object} config Configuration options
43160 Roo.form.GridField = function(config){
43161 Roo.form.GridField.superclass.constructor.call(this, config);
43165 Roo.extend(Roo.form.GridField, Roo.form.Field, {
43167 * @cfg {Number} width - used to restrict width of grid..
43171 * @cfg {Number} height - used to restrict height of grid..
43175 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
43181 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43182 * {tag: "input", type: "checkbox", autocomplete: "off"})
43184 // defaultAutoCreate : { tag: 'div' },
43185 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
43187 * @cfg {String} addTitle Text to include for adding a title.
43191 onResize : function(){
43192 Roo.form.Field.superclass.onResize.apply(this, arguments);
43195 initEvents : function(){
43196 // Roo.form.Checkbox.superclass.initEvents.call(this);
43197 // has no events...
43202 getResizeEl : function(){
43206 getPositionEl : function(){
43211 onRender : function(ct, position){
43213 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
43214 var style = this.style;
43217 Roo.form.GridField.superclass.onRender.call(this, ct, position);
43218 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
43219 this.viewEl = this.wrap.createChild({ tag: 'div' });
43221 this.viewEl.applyStyles(style);
43224 this.viewEl.setWidth(this.width);
43227 this.viewEl.setHeight(this.height);
43229 //if(this.inputValue !== undefined){
43230 //this.setValue(this.value);
43233 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
43236 this.grid.render();
43237 this.grid.getDataSource().on('remove', this.refreshValue, this);
43238 this.grid.getDataSource().on('update', this.refreshValue, this);
43239 this.grid.on('afteredit', this.refreshValue, this);
43245 * Sets the value of the item.
43246 * @param {String} either an object or a string..
43248 setValue : function(v){
43250 v = v || []; // empty set..
43251 // this does not seem smart - it really only affects memoryproxy grids..
43252 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
43253 var ds = this.grid.getDataSource();
43254 // assumes a json reader..
43256 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
43257 ds.loadData( data);
43259 // clear selection so it does not get stale.
43260 if (this.grid.sm) {
43261 this.grid.sm.clearSelections();
43264 Roo.form.GridField.superclass.setValue.call(this, v);
43265 this.refreshValue();
43266 // should load data in the grid really....
43270 refreshValue: function() {
43272 this.grid.getDataSource().each(function(r) {
43275 this.el.dom.value = Roo.encode(val);
43283 * Ext JS Library 1.1.1
43284 * Copyright(c) 2006-2007, Ext JS, LLC.
43286 * Originally Released Under LGPL - original licence link has changed is not relivant.
43289 * <script type="text/javascript">
43292 * @class Roo.form.DisplayField
43293 * @extends Roo.form.Field
43294 * A generic Field to display non-editable data.
43296 * Creates a new Display Field item.
43297 * @param {Object} config Configuration options
43299 Roo.form.DisplayField = function(config){
43300 Roo.form.DisplayField.superclass.constructor.call(this, config);
43304 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
43305 inputType: 'hidden',
43311 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43313 focusClass : undefined,
43315 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43317 fieldClass: 'x-form-field',
43320 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
43322 valueRenderer: undefined,
43326 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43327 * {tag: "input", type: "checkbox", autocomplete: "off"})
43330 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
43332 onResize : function(){
43333 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
43337 initEvents : function(){
43338 // Roo.form.Checkbox.superclass.initEvents.call(this);
43339 // has no events...
43344 getResizeEl : function(){
43348 getPositionEl : function(){
43353 onRender : function(ct, position){
43355 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
43356 //if(this.inputValue !== undefined){
43357 this.wrap = this.el.wrap();
43359 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
43361 if (this.bodyStyle) {
43362 this.viewEl.applyStyles(this.bodyStyle);
43364 //this.viewEl.setStyle('padding', '2px');
43366 this.setValue(this.value);
43371 initValue : Roo.emptyFn,
43376 onClick : function(){
43381 * Sets the checked state of the checkbox.
43382 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
43384 setValue : function(v){
43386 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
43387 // this might be called before we have a dom element..
43388 if (!this.viewEl) {
43391 this.viewEl.dom.innerHTML = html;
43392 Roo.form.DisplayField.superclass.setValue.call(this, v);
43402 * @class Roo.form.DayPicker
43403 * @extends Roo.form.Field
43404 * A Day picker show [M] [T] [W] ....
43406 * Creates a new Day Picker
43407 * @param {Object} config Configuration options
43409 Roo.form.DayPicker= function(config){
43410 Roo.form.DayPicker.superclass.constructor.call(this, config);
43414 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
43416 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43418 focusClass : undefined,
43420 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43422 fieldClass: "x-form-field",
43425 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43426 * {tag: "input", type: "checkbox", autocomplete: "off"})
43428 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
43431 actionMode : 'viewEl',
43435 inputType : 'hidden',
43438 inputElement: false, // real input element?
43439 basedOn: false, // ????
43441 isFormField: true, // not sure where this is needed!!!!
43443 onResize : function(){
43444 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
43445 if(!this.boxLabel){
43446 this.el.alignTo(this.wrap, 'c-c');
43450 initEvents : function(){
43451 Roo.form.Checkbox.superclass.initEvents.call(this);
43452 this.el.on("click", this.onClick, this);
43453 this.el.on("change", this.onClick, this);
43457 getResizeEl : function(){
43461 getPositionEl : function(){
43467 onRender : function(ct, position){
43468 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43470 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
43472 var r1 = '<table><tr>';
43473 var r2 = '<tr class="x-form-daypick-icons">';
43474 for (var i=0; i < 7; i++) {
43475 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
43476 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
43479 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
43480 viewEl.select('img').on('click', this.onClick, this);
43481 this.viewEl = viewEl;
43484 // this will not work on Chrome!!!
43485 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43486 this.el.on('propertychange', this.setFromHidden, this); //ie
43494 initValue : Roo.emptyFn,
43497 * Returns the checked state of the checkbox.
43498 * @return {Boolean} True if checked, else false
43500 getValue : function(){
43501 return this.el.dom.value;
43506 onClick : function(e){
43507 //this.setChecked(!this.checked);
43508 Roo.get(e.target).toggleClass('x-menu-item-checked');
43509 this.refreshValue();
43510 //if(this.el.dom.checked != this.checked){
43511 // this.setValue(this.el.dom.checked);
43516 refreshValue : function()
43519 this.viewEl.select('img',true).each(function(e,i,n) {
43520 val += e.is(".x-menu-item-checked") ? String(n) : '';
43522 this.setValue(val, true);
43526 * Sets the checked state of the checkbox.
43527 * On is always based on a string comparison between inputValue and the param.
43528 * @param {Boolean/String} value - the value to set
43529 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
43531 setValue : function(v,suppressEvent){
43532 if (!this.el.dom) {
43535 var old = this.el.dom.value ;
43536 this.el.dom.value = v;
43537 if (suppressEvent) {
43541 // update display..
43542 this.viewEl.select('img',true).each(function(e,i,n) {
43544 var on = e.is(".x-menu-item-checked");
43545 var newv = v.indexOf(String(n)) > -1;
43547 e.toggleClass('x-menu-item-checked');
43553 this.fireEvent('change', this, v, old);
43558 // handle setting of hidden value by some other method!!?!?
43559 setFromHidden: function()
43564 //console.log("SET FROM HIDDEN");
43565 //alert('setFrom hidden');
43566 this.setValue(this.el.dom.value);
43569 onDestroy : function()
43572 Roo.get(this.viewEl).remove();
43575 Roo.form.DayPicker.superclass.onDestroy.call(this);
43579 * RooJS Library 1.1.1
43580 * Copyright(c) 2008-2011 Alan Knowles
43587 * @class Roo.form.ComboCheck
43588 * @extends Roo.form.ComboBox
43589 * A combobox for multiple select items.
43591 * FIXME - could do with a reset button..
43594 * Create a new ComboCheck
43595 * @param {Object} config Configuration options
43597 Roo.form.ComboCheck = function(config){
43598 Roo.form.ComboCheck.superclass.constructor.call(this, config);
43599 // should verify some data...
43601 // hiddenName = required..
43602 // displayField = required
43603 // valudField == required
43604 var req= [ 'hiddenName', 'displayField', 'valueField' ];
43606 Roo.each(req, function(e) {
43607 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
43608 throw "Roo.form.ComboCheck : missing value for: " + e;
43615 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
43620 selectedClass: 'x-menu-item-checked',
43623 onRender : function(ct, position){
43629 var cls = 'x-combo-list';
43632 this.tpl = new Roo.Template({
43633 html : '<div class="'+cls+'-item x-menu-check-item">' +
43634 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
43635 '<span>{' + this.displayField + '}</span>' +
43642 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
43643 this.view.singleSelect = false;
43644 this.view.multiSelect = true;
43645 this.view.toggleSelect = true;
43646 this.pageTb.add(new Roo.Toolbar.Fill(), {
43649 handler: function()
43656 onViewOver : function(e, t){
43662 onViewClick : function(doFocus,index){
43666 select: function () {
43667 //Roo.log("SELECT CALLED");
43670 selectByValue : function(xv, scrollIntoView){
43671 var ar = this.getValueArray();
43674 Roo.each(ar, function(v) {
43675 if(v === undefined || v === null){
43678 var r = this.findRecord(this.valueField, v);
43680 sels.push(this.store.indexOf(r))
43684 this.view.select(sels);
43690 onSelect : function(record, index){
43691 // Roo.log("onselect Called");
43692 // this is only called by the clear button now..
43693 this.view.clearSelections();
43694 this.setValue('[]');
43695 if (this.value != this.valueBefore) {
43696 this.fireEvent('change', this, this.value, this.valueBefore);
43699 getValueArray : function()
43704 //Roo.log(this.value);
43705 if (typeof(this.value) == 'undefined') {
43708 var ar = Roo.decode(this.value);
43709 return ar instanceof Array ? ar : []; //?? valid?
43712 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
43717 expand : function ()
43719 Roo.form.ComboCheck.superclass.expand.call(this);
43720 this.valueBefore = this.value;
43725 collapse : function(){
43726 Roo.form.ComboCheck.superclass.collapse.call(this);
43727 var sl = this.view.getSelectedIndexes();
43728 var st = this.store;
43732 Roo.each(sl, function(i) {
43734 nv.push(r.get(this.valueField));
43736 this.setValue(Roo.encode(nv));
43737 if (this.value != this.valueBefore) {
43739 this.fireEvent('change', this, this.value, this.valueBefore);
43744 setValue : function(v){
43748 var vals = this.getValueArray();
43750 Roo.each(vals, function(k) {
43751 var r = this.findRecord(this.valueField, k);
43753 tv.push(r.data[this.displayField]);
43754 }else if(this.valueNotFoundText !== undefined){
43755 tv.push( this.valueNotFoundText );
43760 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
43761 this.hiddenField.value = v;
43765 });//<script type="text/javasscript">
43769 * @class Roo.DDView
43770 * A DnD enabled version of Roo.View.
43771 * @param {Element/String} container The Element in which to create the View.
43772 * @param {String} tpl The template string used to create the markup for each element of the View
43773 * @param {Object} config The configuration properties. These include all the config options of
43774 * {@link Roo.View} plus some specific to this class.<br>
43776 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
43777 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
43779 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
43780 .x-view-drag-insert-above {
43781 border-top:1px dotted #3366cc;
43783 .x-view-drag-insert-below {
43784 border-bottom:1px dotted #3366cc;
43790 Roo.DDView = function(container, tpl, config) {
43791 Roo.DDView.superclass.constructor.apply(this, arguments);
43792 this.getEl().setStyle("outline", "0px none");
43793 this.getEl().unselectable();
43794 if (this.dragGroup) {
43795 this.setDraggable(this.dragGroup.split(","));
43797 if (this.dropGroup) {
43798 this.setDroppable(this.dropGroup.split(","));
43800 if (this.deletable) {
43801 this.setDeletable();
43803 this.isDirtyFlag = false;
43809 Roo.extend(Roo.DDView, Roo.View, {
43810 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
43811 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
43812 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
43813 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
43817 reset: Roo.emptyFn,
43819 clearInvalid: Roo.form.Field.prototype.clearInvalid,
43821 validate: function() {
43825 destroy: function() {
43826 this.purgeListeners();
43827 this.getEl.removeAllListeners();
43828 this.getEl().remove();
43829 if (this.dragZone) {
43830 if (this.dragZone.destroy) {
43831 this.dragZone.destroy();
43834 if (this.dropZone) {
43835 if (this.dropZone.destroy) {
43836 this.dropZone.destroy();
43841 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
43842 getName: function() {
43846 /** Loads the View from a JSON string representing the Records to put into the Store. */
43847 setValue: function(v) {
43849 throw "DDView.setValue(). DDView must be constructed with a valid Store";
43852 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
43853 this.store.proxy = new Roo.data.MemoryProxy(data);
43857 /** @return {String} a parenthesised list of the ids of the Records in the View. */
43858 getValue: function() {
43860 this.store.each(function(rec) {
43861 result += rec.id + ',';
43863 return result.substr(0, result.length - 1) + ')';
43866 getIds: function() {
43867 var i = 0, result = new Array(this.store.getCount());
43868 this.store.each(function(rec) {
43869 result[i++] = rec.id;
43874 isDirty: function() {
43875 return this.isDirtyFlag;
43879 * Part of the Roo.dd.DropZone interface. If no target node is found, the
43880 * whole Element becomes the target, and this causes the drop gesture to append.
43882 getTargetFromEvent : function(e) {
43883 var target = e.getTarget();
43884 while ((target !== null) && (target.parentNode != this.el.dom)) {
43885 target = target.parentNode;
43888 target = this.el.dom.lastChild || this.el.dom;
43894 * Create the drag data which consists of an object which has the property "ddel" as
43895 * the drag proxy element.
43897 getDragData : function(e) {
43898 var target = this.findItemFromChild(e.getTarget());
43900 this.handleSelection(e);
43901 var selNodes = this.getSelectedNodes();
43904 copy: this.copy || (this.allowCopy && e.ctrlKey),
43908 var selectedIndices = this.getSelectedIndexes();
43909 for (var i = 0; i < selectedIndices.length; i++) {
43910 dragData.records.push(this.store.getAt(selectedIndices[i]));
43912 if (selNodes.length == 1) {
43913 dragData.ddel = target.cloneNode(true); // the div element
43915 var div = document.createElement('div'); // create the multi element drag "ghost"
43916 div.className = 'multi-proxy';
43917 for (var i = 0, len = selNodes.length; i < len; i++) {
43918 div.appendChild(selNodes[i].cloneNode(true));
43920 dragData.ddel = div;
43922 //console.log(dragData)
43923 //console.log(dragData.ddel.innerHTML)
43926 //console.log('nodragData')
43930 /** Specify to which ddGroup items in this DDView may be dragged. */
43931 setDraggable: function(ddGroup) {
43932 if (ddGroup instanceof Array) {
43933 Roo.each(ddGroup, this.setDraggable, this);
43936 if (this.dragZone) {
43937 this.dragZone.addToGroup(ddGroup);
43939 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
43940 containerScroll: true,
43944 // Draggability implies selection. DragZone's mousedown selects the element.
43945 if (!this.multiSelect) { this.singleSelect = true; }
43947 // Wire the DragZone's handlers up to methods in *this*
43948 this.dragZone.getDragData = this.getDragData.createDelegate(this);
43952 /** Specify from which ddGroup this DDView accepts drops. */
43953 setDroppable: function(ddGroup) {
43954 if (ddGroup instanceof Array) {
43955 Roo.each(ddGroup, this.setDroppable, this);
43958 if (this.dropZone) {
43959 this.dropZone.addToGroup(ddGroup);
43961 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
43962 containerScroll: true,
43966 // Wire the DropZone's handlers up to methods in *this*
43967 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
43968 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
43969 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
43970 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
43971 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
43975 /** Decide whether to drop above or below a View node. */
43976 getDropPoint : function(e, n, dd){
43977 if (n == this.el.dom) { return "above"; }
43978 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
43979 var c = t + (b - t) / 2;
43980 var y = Roo.lib.Event.getPageY(e);
43988 onNodeEnter : function(n, dd, e, data){
43992 onNodeOver : function(n, dd, e, data){
43993 var pt = this.getDropPoint(e, n, dd);
43994 // set the insert point style on the target node
43995 var dragElClass = this.dropNotAllowed;
43998 if (pt == "above"){
43999 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
44000 targetElClass = "x-view-drag-insert-above";
44002 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
44003 targetElClass = "x-view-drag-insert-below";
44005 if (this.lastInsertClass != targetElClass){
44006 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
44007 this.lastInsertClass = targetElClass;
44010 return dragElClass;
44013 onNodeOut : function(n, dd, e, data){
44014 this.removeDropIndicators(n);
44017 onNodeDrop : function(n, dd, e, data){
44018 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
44021 var pt = this.getDropPoint(e, n, dd);
44022 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
44023 if (pt == "below") { insertAt++; }
44024 for (var i = 0; i < data.records.length; i++) {
44025 var r = data.records[i];
44026 var dup = this.store.getById(r.id);
44027 if (dup && (dd != this.dragZone)) {
44028 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
44031 this.store.insert(insertAt++, r.copy());
44033 data.source.isDirtyFlag = true;
44035 this.store.insert(insertAt++, r);
44037 this.isDirtyFlag = true;
44040 this.dragZone.cachedTarget = null;
44044 removeDropIndicators : function(n){
44046 Roo.fly(n).removeClass([
44047 "x-view-drag-insert-above",
44048 "x-view-drag-insert-below"]);
44049 this.lastInsertClass = "_noclass";
44054 * Utility method. Add a delete option to the DDView's context menu.
44055 * @param {String} imageUrl The URL of the "delete" icon image.
44057 setDeletable: function(imageUrl) {
44058 if (!this.singleSelect && !this.multiSelect) {
44059 this.singleSelect = true;
44061 var c = this.getContextMenu();
44062 this.contextMenu.on("itemclick", function(item) {
44065 this.remove(this.getSelectedIndexes());
44069 this.contextMenu.add({
44076 /** Return the context menu for this DDView. */
44077 getContextMenu: function() {
44078 if (!this.contextMenu) {
44079 // Create the View's context menu
44080 this.contextMenu = new Roo.menu.Menu({
44081 id: this.id + "-contextmenu"
44083 this.el.on("contextmenu", this.showContextMenu, this);
44085 return this.contextMenu;
44088 disableContextMenu: function() {
44089 if (this.contextMenu) {
44090 this.el.un("contextmenu", this.showContextMenu, this);
44094 showContextMenu: function(e, item) {
44095 item = this.findItemFromChild(e.getTarget());
44098 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
44099 this.contextMenu.showAt(e.getXY());
44104 * Remove {@link Roo.data.Record}s at the specified indices.
44105 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
44107 remove: function(selectedIndices) {
44108 selectedIndices = [].concat(selectedIndices);
44109 for (var i = 0; i < selectedIndices.length; i++) {
44110 var rec = this.store.getAt(selectedIndices[i]);
44111 this.store.remove(rec);
44116 * Double click fires the event, but also, if this is draggable, and there is only one other
44117 * related DropZone, it transfers the selected node.
44119 onDblClick : function(e){
44120 var item = this.findItemFromChild(e.getTarget());
44122 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
44125 if (this.dragGroup) {
44126 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
44127 while (targets.indexOf(this.dropZone) > -1) {
44128 targets.remove(this.dropZone);
44130 if (targets.length == 1) {
44131 this.dragZone.cachedTarget = null;
44132 var el = Roo.get(targets[0].getEl());
44133 var box = el.getBox(true);
44134 targets[0].onNodeDrop(el.dom, {
44136 xy: [box.x, box.y + box.height - 1]
44137 }, null, this.getDragData(e));
44143 handleSelection: function(e) {
44144 this.dragZone.cachedTarget = null;
44145 var item = this.findItemFromChild(e.getTarget());
44147 this.clearSelections(true);
44150 if (item && (this.multiSelect || this.singleSelect)){
44151 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
44152 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
44153 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
44154 this.unselect(item);
44156 this.select(item, this.multiSelect && e.ctrlKey);
44157 this.lastSelection = item;
44162 onItemClick : function(item, index, e){
44163 if(this.fireEvent("beforeclick", this, index, item, e) === false){
44169 unselect : function(nodeInfo, suppressEvent){
44170 var node = this.getNode(nodeInfo);
44171 if(node && this.isSelected(node)){
44172 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
44173 Roo.fly(node).removeClass(this.selectedClass);
44174 this.selections.remove(node);
44175 if(!suppressEvent){
44176 this.fireEvent("selectionchange", this, this.selections);
44184 * Ext JS Library 1.1.1
44185 * Copyright(c) 2006-2007, Ext JS, LLC.
44187 * Originally Released Under LGPL - original licence link has changed is not relivant.
44190 * <script type="text/javascript">
44194 * @class Roo.LayoutManager
44195 * @extends Roo.util.Observable
44196 * Base class for layout managers.
44198 Roo.LayoutManager = function(container, config){
44199 Roo.LayoutManager.superclass.constructor.call(this);
44200 this.el = Roo.get(container);
44201 // ie scrollbar fix
44202 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
44203 document.body.scroll = "no";
44204 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
44205 this.el.position('relative');
44207 this.id = this.el.id;
44208 this.el.addClass("x-layout-container");
44209 /** false to disable window resize monitoring @type Boolean */
44210 this.monitorWindowResize = true;
44215 * Fires when a layout is performed.
44216 * @param {Roo.LayoutManager} this
44220 * @event regionresized
44221 * Fires when the user resizes a region.
44222 * @param {Roo.LayoutRegion} region The resized region
44223 * @param {Number} newSize The new size (width for east/west, height for north/south)
44225 "regionresized" : true,
44227 * @event regioncollapsed
44228 * Fires when a region is collapsed.
44229 * @param {Roo.LayoutRegion} region The collapsed region
44231 "regioncollapsed" : true,
44233 * @event regionexpanded
44234 * Fires when a region is expanded.
44235 * @param {Roo.LayoutRegion} region The expanded region
44237 "regionexpanded" : true
44239 this.updating = false;
44240 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
44243 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
44245 * Returns true if this layout is currently being updated
44246 * @return {Boolean}
44248 isUpdating : function(){
44249 return this.updating;
44253 * Suspend the LayoutManager from doing auto-layouts while
44254 * making multiple add or remove calls
44256 beginUpdate : function(){
44257 this.updating = true;
44261 * Restore auto-layouts and optionally disable the manager from performing a layout
44262 * @param {Boolean} noLayout true to disable a layout update
44264 endUpdate : function(noLayout){
44265 this.updating = false;
44271 layout: function(){
44275 onRegionResized : function(region, newSize){
44276 this.fireEvent("regionresized", region, newSize);
44280 onRegionCollapsed : function(region){
44281 this.fireEvent("regioncollapsed", region);
44284 onRegionExpanded : function(region){
44285 this.fireEvent("regionexpanded", region);
44289 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
44290 * performs box-model adjustments.
44291 * @return {Object} The size as an object {width: (the width), height: (the height)}
44293 getViewSize : function(){
44295 if(this.el.dom != document.body){
44296 size = this.el.getSize();
44298 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
44300 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
44301 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
44306 * Returns the Element this layout is bound to.
44307 * @return {Roo.Element}
44309 getEl : function(){
44314 * Returns the specified region.
44315 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
44316 * @return {Roo.LayoutRegion}
44318 getRegion : function(target){
44319 return this.regions[target.toLowerCase()];
44322 onWindowResize : function(){
44323 if(this.monitorWindowResize){
44329 * Ext JS Library 1.1.1
44330 * Copyright(c) 2006-2007, Ext JS, LLC.
44332 * Originally Released Under LGPL - original licence link has changed is not relivant.
44335 * <script type="text/javascript">
44338 * @class Roo.BorderLayout
44339 * @extends Roo.LayoutManager
44340 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
44341 * please see: <br><br>
44342 * <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>
44343 * <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>
44346 var layout = new Roo.BorderLayout(document.body, {
44380 preferredTabWidth: 150
44385 var CP = Roo.ContentPanel;
44387 layout.beginUpdate();
44388 layout.add("north", new CP("north", "North"));
44389 layout.add("south", new CP("south", {title: "South", closable: true}));
44390 layout.add("west", new CP("west", {title: "West"}));
44391 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
44392 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
44393 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
44394 layout.getRegion("center").showPanel("center1");
44395 layout.endUpdate();
44398 <b>The container the layout is rendered into can be either the body element or any other element.
44399 If it is not the body element, the container needs to either be an absolute positioned element,
44400 or you will need to add "position:relative" to the css of the container. You will also need to specify
44401 the container size if it is not the body element.</b>
44404 * Create a new BorderLayout
44405 * @param {String/HTMLElement/Element} container The container this layout is bound to
44406 * @param {Object} config Configuration options
44408 Roo.BorderLayout = function(container, config){
44409 config = config || {};
44410 Roo.BorderLayout.superclass.constructor.call(this, container, config);
44411 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
44412 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
44413 var target = this.factory.validRegions[i];
44414 if(config[target]){
44415 this.addRegion(target, config[target]);
44420 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
44422 * Creates and adds a new region if it doesn't already exist.
44423 * @param {String} target The target region key (north, south, east, west or center).
44424 * @param {Object} config The regions config object
44425 * @return {BorderLayoutRegion} The new region
44427 addRegion : function(target, config){
44428 if(!this.regions[target]){
44429 var r = this.factory.create(target, this, config);
44430 this.bindRegion(target, r);
44432 return this.regions[target];
44436 bindRegion : function(name, r){
44437 this.regions[name] = r;
44438 r.on("visibilitychange", this.layout, this);
44439 r.on("paneladded", this.layout, this);
44440 r.on("panelremoved", this.layout, this);
44441 r.on("invalidated", this.layout, this);
44442 r.on("resized", this.onRegionResized, this);
44443 r.on("collapsed", this.onRegionCollapsed, this);
44444 r.on("expanded", this.onRegionExpanded, this);
44448 * Performs a layout update.
44450 layout : function(){
44451 if(this.updating) return;
44452 var size = this.getViewSize();
44453 var w = size.width;
44454 var h = size.height;
44459 //var x = 0, y = 0;
44461 var rs = this.regions;
44462 var north = rs["north"];
44463 var south = rs["south"];
44464 var west = rs["west"];
44465 var east = rs["east"];
44466 var center = rs["center"];
44467 //if(this.hideOnLayout){ // not supported anymore
44468 //c.el.setStyle("display", "none");
44470 if(north && north.isVisible()){
44471 var b = north.getBox();
44472 var m = north.getMargins();
44473 b.width = w - (m.left+m.right);
44476 centerY = b.height + b.y + m.bottom;
44477 centerH -= centerY;
44478 north.updateBox(this.safeBox(b));
44480 if(south && south.isVisible()){
44481 var b = south.getBox();
44482 var m = south.getMargins();
44483 b.width = w - (m.left+m.right);
44485 var totalHeight = (b.height + m.top + m.bottom);
44486 b.y = h - totalHeight + m.top;
44487 centerH -= totalHeight;
44488 south.updateBox(this.safeBox(b));
44490 if(west && west.isVisible()){
44491 var b = west.getBox();
44492 var m = west.getMargins();
44493 b.height = centerH - (m.top+m.bottom);
44495 b.y = centerY + m.top;
44496 var totalWidth = (b.width + m.left + m.right);
44497 centerX += totalWidth;
44498 centerW -= totalWidth;
44499 west.updateBox(this.safeBox(b));
44501 if(east && east.isVisible()){
44502 var b = east.getBox();
44503 var m = east.getMargins();
44504 b.height = centerH - (m.top+m.bottom);
44505 var totalWidth = (b.width + m.left + m.right);
44506 b.x = w - totalWidth + m.left;
44507 b.y = centerY + m.top;
44508 centerW -= totalWidth;
44509 east.updateBox(this.safeBox(b));
44512 var m = center.getMargins();
44514 x: centerX + m.left,
44515 y: centerY + m.top,
44516 width: centerW - (m.left+m.right),
44517 height: centerH - (m.top+m.bottom)
44519 //if(this.hideOnLayout){
44520 //center.el.setStyle("display", "block");
44522 center.updateBox(this.safeBox(centerBox));
44525 this.fireEvent("layout", this);
44529 safeBox : function(box){
44530 box.width = Math.max(0, box.width);
44531 box.height = Math.max(0, box.height);
44536 * Adds a ContentPanel (or subclass) to this layout.
44537 * @param {String} target The target region key (north, south, east, west or center).
44538 * @param {Roo.ContentPanel} panel The panel to add
44539 * @return {Roo.ContentPanel} The added panel
44541 add : function(target, panel){
44543 target = target.toLowerCase();
44544 return this.regions[target].add(panel);
44548 * Remove a ContentPanel (or subclass) to this layout.
44549 * @param {String} target The target region key (north, south, east, west or center).
44550 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
44551 * @return {Roo.ContentPanel} The removed panel
44553 remove : function(target, panel){
44554 target = target.toLowerCase();
44555 return this.regions[target].remove(panel);
44559 * Searches all regions for a panel with the specified id
44560 * @param {String} panelId
44561 * @return {Roo.ContentPanel} The panel or null if it wasn't found
44563 findPanel : function(panelId){
44564 var rs = this.regions;
44565 for(var target in rs){
44566 if(typeof rs[target] != "function"){
44567 var p = rs[target].getPanel(panelId);
44577 * Searches all regions for a panel with the specified id and activates (shows) it.
44578 * @param {String/ContentPanel} panelId The panels id or the panel itself
44579 * @return {Roo.ContentPanel} The shown panel or null
44581 showPanel : function(panelId) {
44582 var rs = this.regions;
44583 for(var target in rs){
44584 var r = rs[target];
44585 if(typeof r != "function"){
44586 if(r.hasPanel(panelId)){
44587 return r.showPanel(panelId);
44595 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
44596 * @param {Roo.state.Provider} provider (optional) An alternate state provider
44598 restoreState : function(provider){
44600 provider = Roo.state.Manager;
44602 var sm = new Roo.LayoutStateManager();
44603 sm.init(this, provider);
44607 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
44608 * object should contain properties for each region to add ContentPanels to, and each property's value should be
44609 * a valid ContentPanel config object. Example:
44611 // Create the main layout
44612 var layout = new Roo.BorderLayout('main-ct', {
44623 // Create and add multiple ContentPanels at once via configs
44626 id: 'source-files',
44628 title:'Ext Source Files',
44641 * @param {Object} regions An object containing ContentPanel configs by region name
44643 batchAdd : function(regions){
44644 this.beginUpdate();
44645 for(var rname in regions){
44646 var lr = this.regions[rname];
44648 this.addTypedPanels(lr, regions[rname]);
44655 addTypedPanels : function(lr, ps){
44656 if(typeof ps == 'string'){
44657 lr.add(new Roo.ContentPanel(ps));
44659 else if(ps instanceof Array){
44660 for(var i =0, len = ps.length; i < len; i++){
44661 this.addTypedPanels(lr, ps[i]);
44664 else if(!ps.events){ // raw config?
44666 delete ps.el; // prevent conflict
44667 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
44669 else { // panel object assumed!
44674 * Adds a xtype elements to the layout.
44678 xtype : 'ContentPanel',
44685 xtype : 'NestedLayoutPanel',
44691 items : [ ... list of content panels or nested layout panels.. ]
44695 * @param {Object} cfg Xtype definition of item to add.
44697 addxtype : function(cfg)
44699 // basically accepts a pannel...
44700 // can accept a layout region..!?!?
44701 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
44703 if (!cfg.xtype.match(/Panel$/)) {
44708 if (typeof(cfg.region) == 'undefined') {
44709 Roo.log("Failed to add Panel, region was not set");
44713 var region = cfg.region;
44719 xitems = cfg.items;
44726 case 'ContentPanel': // ContentPanel (el, cfg)
44727 case 'ScrollPanel': // ContentPanel (el, cfg)
44728 if(cfg.autoCreate) {
44729 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
44731 var el = this.el.createChild();
44732 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
44735 this.add(region, ret);
44739 case 'TreePanel': // our new panel!
44740 cfg.el = this.el.createChild();
44741 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
44742 this.add(region, ret);
44745 case 'NestedLayoutPanel':
44746 // create a new Layout (which is a Border Layout...
44747 var el = this.el.createChild();
44748 var clayout = cfg.layout;
44750 clayout.items = clayout.items || [];
44751 // replace this exitems with the clayout ones..
44752 xitems = clayout.items;
44755 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
44756 cfg.background = false;
44758 var layout = new Roo.BorderLayout(el, clayout);
44760 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
44761 //console.log('adding nested layout panel ' + cfg.toSource());
44762 this.add(region, ret);
44763 nb = {}; /// find first...
44768 // needs grid and region
44770 //var el = this.getRegion(region).el.createChild();
44771 var el = this.el.createChild();
44772 // create the grid first...
44774 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
44776 if (region == 'center' && this.active ) {
44777 cfg.background = false;
44779 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
44781 this.add(region, ret);
44782 if (cfg.background) {
44783 ret.on('activate', function(gp) {
44784 if (!gp.grid.rendered) {
44797 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
44799 // GridPanel (grid, cfg)
44802 this.beginUpdate();
44806 Roo.each(xitems, function(i) {
44807 region = nb && i.region ? i.region : false;
44809 var add = ret.addxtype(i);
44812 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
44813 if (!i.background) {
44814 abn[region] = nb[region] ;
44821 // make the last non-background panel active..
44822 //if (nb) { Roo.log(abn); }
44825 for(var r in abn) {
44826 region = this.getRegion(r);
44828 // tried using nb[r], but it does not work..
44830 region.showPanel(abn[r]);
44841 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
44842 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
44843 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
44844 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
44847 var CP = Roo.ContentPanel;
44849 var layout = Roo.BorderLayout.create({
44853 panels: [new CP("north", "North")]
44862 panels: [new CP("west", {title: "West"})]
44871 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
44880 panels: [new CP("south", {title: "South", closable: true})]
44887 preferredTabWidth: 150,
44889 new CP("center1", {title: "Close Me", closable: true}),
44890 new CP("center2", {title: "Center Panel", closable: false})
44895 layout.getRegion("center").showPanel("center1");
44900 Roo.BorderLayout.create = function(config, targetEl){
44901 var layout = new Roo.BorderLayout(targetEl || document.body, config);
44902 layout.beginUpdate();
44903 var regions = Roo.BorderLayout.RegionFactory.validRegions;
44904 for(var j = 0, jlen = regions.length; j < jlen; j++){
44905 var lr = regions[j];
44906 if(layout.regions[lr] && config[lr].panels){
44907 var r = layout.regions[lr];
44908 var ps = config[lr].panels;
44909 layout.addTypedPanels(r, ps);
44912 layout.endUpdate();
44917 Roo.BorderLayout.RegionFactory = {
44919 validRegions : ["north","south","east","west","center"],
44922 create : function(target, mgr, config){
44923 target = target.toLowerCase();
44924 if(config.lightweight || config.basic){
44925 return new Roo.BasicLayoutRegion(mgr, config, target);
44929 return new Roo.NorthLayoutRegion(mgr, config);
44931 return new Roo.SouthLayoutRegion(mgr, config);
44933 return new Roo.EastLayoutRegion(mgr, config);
44935 return new Roo.WestLayoutRegion(mgr, config);
44937 return new Roo.CenterLayoutRegion(mgr, config);
44939 throw 'Layout region "'+target+'" not supported.';
44943 * Ext JS Library 1.1.1
44944 * Copyright(c) 2006-2007, Ext JS, LLC.
44946 * Originally Released Under LGPL - original licence link has changed is not relivant.
44949 * <script type="text/javascript">
44953 * @class Roo.BasicLayoutRegion
44954 * @extends Roo.util.Observable
44955 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
44956 * and does not have a titlebar, tabs or any other features. All it does is size and position
44957 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
44959 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
44961 this.position = pos;
44964 * @scope Roo.BasicLayoutRegion
44968 * @event beforeremove
44969 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
44970 * @param {Roo.LayoutRegion} this
44971 * @param {Roo.ContentPanel} panel The panel
44972 * @param {Object} e The cancel event object
44974 "beforeremove" : true,
44976 * @event invalidated
44977 * Fires when the layout for this region is changed.
44978 * @param {Roo.LayoutRegion} this
44980 "invalidated" : true,
44982 * @event visibilitychange
44983 * Fires when this region is shown or hidden
44984 * @param {Roo.LayoutRegion} this
44985 * @param {Boolean} visibility true or false
44987 "visibilitychange" : true,
44989 * @event paneladded
44990 * Fires when a panel is added.
44991 * @param {Roo.LayoutRegion} this
44992 * @param {Roo.ContentPanel} panel The panel
44994 "paneladded" : true,
44996 * @event panelremoved
44997 * Fires when a panel is removed.
44998 * @param {Roo.LayoutRegion} this
44999 * @param {Roo.ContentPanel} panel The panel
45001 "panelremoved" : true,
45004 * Fires when this region is collapsed.
45005 * @param {Roo.LayoutRegion} this
45007 "collapsed" : true,
45010 * Fires when this region is expanded.
45011 * @param {Roo.LayoutRegion} this
45016 * Fires when this region is slid into view.
45017 * @param {Roo.LayoutRegion} this
45019 "slideshow" : true,
45022 * Fires when this region slides out of view.
45023 * @param {Roo.LayoutRegion} this
45025 "slidehide" : true,
45027 * @event panelactivated
45028 * Fires when a panel is activated.
45029 * @param {Roo.LayoutRegion} this
45030 * @param {Roo.ContentPanel} panel The activated panel
45032 "panelactivated" : true,
45035 * Fires when the user resizes this region.
45036 * @param {Roo.LayoutRegion} this
45037 * @param {Number} newSize The new size (width for east/west, height for north/south)
45041 /** A collection of panels in this region. @type Roo.util.MixedCollection */
45042 this.panels = new Roo.util.MixedCollection();
45043 this.panels.getKey = this.getPanelId.createDelegate(this);
45045 this.activePanel = null;
45046 // ensure listeners are added...
45048 if (config.listeners || config.events) {
45049 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
45050 listeners : config.listeners || {},
45051 events : config.events || {}
45055 if(skipConfig !== true){
45056 this.applyConfig(config);
45060 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
45061 getPanelId : function(p){
45065 applyConfig : function(config){
45066 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
45067 this.config = config;
45072 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
45073 * the width, for horizontal (north, south) the height.
45074 * @param {Number} newSize The new width or height
45076 resizeTo : function(newSize){
45077 var el = this.el ? this.el :
45078 (this.activePanel ? this.activePanel.getEl() : null);
45080 switch(this.position){
45083 el.setWidth(newSize);
45084 this.fireEvent("resized", this, newSize);
45088 el.setHeight(newSize);
45089 this.fireEvent("resized", this, newSize);
45095 getBox : function(){
45096 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
45099 getMargins : function(){
45100 return this.margins;
45103 updateBox : function(box){
45105 var el = this.activePanel.getEl();
45106 el.dom.style.left = box.x + "px";
45107 el.dom.style.top = box.y + "px";
45108 this.activePanel.setSize(box.width, box.height);
45112 * Returns the container element for this region.
45113 * @return {Roo.Element}
45115 getEl : function(){
45116 return this.activePanel;
45120 * Returns true if this region is currently visible.
45121 * @return {Boolean}
45123 isVisible : function(){
45124 return this.activePanel ? true : false;
45127 setActivePanel : function(panel){
45128 panel = this.getPanel(panel);
45129 if(this.activePanel && this.activePanel != panel){
45130 this.activePanel.setActiveState(false);
45131 this.activePanel.getEl().setLeftTop(-10000,-10000);
45133 this.activePanel = panel;
45134 panel.setActiveState(true);
45136 panel.setSize(this.box.width, this.box.height);
45138 this.fireEvent("panelactivated", this, panel);
45139 this.fireEvent("invalidated");
45143 * Show the specified panel.
45144 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
45145 * @return {Roo.ContentPanel} The shown panel or null
45147 showPanel : function(panel){
45148 if(panel = this.getPanel(panel)){
45149 this.setActivePanel(panel);
45155 * Get the active panel for this region.
45156 * @return {Roo.ContentPanel} The active panel or null
45158 getActivePanel : function(){
45159 return this.activePanel;
45163 * Add the passed ContentPanel(s)
45164 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
45165 * @return {Roo.ContentPanel} The panel added (if only one was added)
45167 add : function(panel){
45168 if(arguments.length > 1){
45169 for(var i = 0, len = arguments.length; i < len; i++) {
45170 this.add(arguments[i]);
45174 if(this.hasPanel(panel)){
45175 this.showPanel(panel);
45178 var el = panel.getEl();
45179 if(el.dom.parentNode != this.mgr.el.dom){
45180 this.mgr.el.dom.appendChild(el.dom);
45182 if(panel.setRegion){
45183 panel.setRegion(this);
45185 this.panels.add(panel);
45186 el.setStyle("position", "absolute");
45187 if(!panel.background){
45188 this.setActivePanel(panel);
45189 if(this.config.initialSize && this.panels.getCount()==1){
45190 this.resizeTo(this.config.initialSize);
45193 this.fireEvent("paneladded", this, panel);
45198 * Returns true if the panel is in this region.
45199 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45200 * @return {Boolean}
45202 hasPanel : function(panel){
45203 if(typeof panel == "object"){ // must be panel obj
45204 panel = panel.getId();
45206 return this.getPanel(panel) ? true : false;
45210 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
45211 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45212 * @param {Boolean} preservePanel Overrides the config preservePanel option
45213 * @return {Roo.ContentPanel} The panel that was removed
45215 remove : function(panel, preservePanel){
45216 panel = this.getPanel(panel);
45221 this.fireEvent("beforeremove", this, panel, e);
45222 if(e.cancel === true){
45225 var panelId = panel.getId();
45226 this.panels.removeKey(panelId);
45231 * Returns the panel specified or null if it's not in this region.
45232 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45233 * @return {Roo.ContentPanel}
45235 getPanel : function(id){
45236 if(typeof id == "object"){ // must be panel obj
45239 return this.panels.get(id);
45243 * Returns this regions position (north/south/east/west/center).
45246 getPosition: function(){
45247 return this.position;
45251 * Ext JS Library 1.1.1
45252 * Copyright(c) 2006-2007, Ext JS, LLC.
45254 * Originally Released Under LGPL - original licence link has changed is not relivant.
45257 * <script type="text/javascript">
45261 * @class Roo.LayoutRegion
45262 * @extends Roo.BasicLayoutRegion
45263 * This class represents a region in a layout manager.
45264 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
45265 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
45266 * @cfg {Boolean} floatable False to disable floating (defaults to true)
45267 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
45268 * @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})
45269 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
45270 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
45271 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
45272 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
45273 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
45274 * @cfg {String} title The title for the region (overrides panel titles)
45275 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
45276 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
45277 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
45278 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
45279 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
45280 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
45281 * the space available, similar to FireFox 1.5 tabs (defaults to false)
45282 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
45283 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
45284 * @cfg {Boolean} showPin True to show a pin button
45285 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
45286 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
45287 * @cfg {Boolean} disableTabTips True to disable tab tooltips
45288 * @cfg {Number} width For East/West panels
45289 * @cfg {Number} height For North/South panels
45290 * @cfg {Boolean} split To show the splitter
45291 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
45293 Roo.LayoutRegion = function(mgr, config, pos){
45294 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
45295 var dh = Roo.DomHelper;
45296 /** This region's container element
45297 * @type Roo.Element */
45298 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
45299 /** This region's title element
45300 * @type Roo.Element */
45302 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
45303 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
45304 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
45306 this.titleEl.enableDisplayMode();
45307 /** This region's title text element
45308 * @type HTMLElement */
45309 this.titleTextEl = this.titleEl.dom.firstChild;
45310 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
45311 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
45312 this.closeBtn.enableDisplayMode();
45313 this.closeBtn.on("click", this.closeClicked, this);
45314 this.closeBtn.hide();
45316 this.createBody(config);
45317 this.visible = true;
45318 this.collapsed = false;
45320 if(config.hideWhenEmpty){
45322 this.on("paneladded", this.validateVisibility, this);
45323 this.on("panelremoved", this.validateVisibility, this);
45325 this.applyConfig(config);
45328 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
45330 createBody : function(){
45331 /** This region's body element
45332 * @type Roo.Element */
45333 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
45336 applyConfig : function(c){
45337 if(c.collapsible && this.position != "center" && !this.collapsedEl){
45338 var dh = Roo.DomHelper;
45339 if(c.titlebar !== false){
45340 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
45341 this.collapseBtn.on("click", this.collapse, this);
45342 this.collapseBtn.enableDisplayMode();
45344 if(c.showPin === true || this.showPin){
45345 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
45346 this.stickBtn.enableDisplayMode();
45347 this.stickBtn.on("click", this.expand, this);
45348 this.stickBtn.hide();
45351 /** This region's collapsed element
45352 * @type Roo.Element */
45353 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
45354 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
45356 if(c.floatable !== false){
45357 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
45358 this.collapsedEl.on("click", this.collapseClick, this);
45361 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
45362 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
45363 id: "message", unselectable: "on", style:{"float":"left"}});
45364 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
45366 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
45367 this.expandBtn.on("click", this.expand, this);
45369 if(this.collapseBtn){
45370 this.collapseBtn.setVisible(c.collapsible == true);
45372 this.cmargins = c.cmargins || this.cmargins ||
45373 (this.position == "west" || this.position == "east" ?
45374 {top: 0, left: 2, right:2, bottom: 0} :
45375 {top: 2, left: 0, right:0, bottom: 2});
45376 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
45377 this.bottomTabs = c.tabPosition != "top";
45378 this.autoScroll = c.autoScroll || false;
45379 if(this.autoScroll){
45380 this.bodyEl.setStyle("overflow", "auto");
45382 this.bodyEl.setStyle("overflow", "hidden");
45384 //if(c.titlebar !== false){
45385 if((!c.titlebar && !c.title) || c.titlebar === false){
45386 this.titleEl.hide();
45388 this.titleEl.show();
45390 this.titleTextEl.innerHTML = c.title;
45394 this.duration = c.duration || .30;
45395 this.slideDuration = c.slideDuration || .45;
45398 this.collapse(true);
45405 * Returns true if this region is currently visible.
45406 * @return {Boolean}
45408 isVisible : function(){
45409 return this.visible;
45413 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
45414 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
45416 setCollapsedTitle : function(title){
45417 title = title || " ";
45418 if(this.collapsedTitleTextEl){
45419 this.collapsedTitleTextEl.innerHTML = title;
45423 getBox : function(){
45425 if(!this.collapsed){
45426 b = this.el.getBox(false, true);
45428 b = this.collapsedEl.getBox(false, true);
45433 getMargins : function(){
45434 return this.collapsed ? this.cmargins : this.margins;
45437 highlight : function(){
45438 this.el.addClass("x-layout-panel-dragover");
45441 unhighlight : function(){
45442 this.el.removeClass("x-layout-panel-dragover");
45445 updateBox : function(box){
45447 if(!this.collapsed){
45448 this.el.dom.style.left = box.x + "px";
45449 this.el.dom.style.top = box.y + "px";
45450 this.updateBody(box.width, box.height);
45452 this.collapsedEl.dom.style.left = box.x + "px";
45453 this.collapsedEl.dom.style.top = box.y + "px";
45454 this.collapsedEl.setSize(box.width, box.height);
45457 this.tabs.autoSizeTabs();
45461 updateBody : function(w, h){
45463 this.el.setWidth(w);
45464 w -= this.el.getBorderWidth("rl");
45465 if(this.config.adjustments){
45466 w += this.config.adjustments[0];
45470 this.el.setHeight(h);
45471 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
45472 h -= this.el.getBorderWidth("tb");
45473 if(this.config.adjustments){
45474 h += this.config.adjustments[1];
45476 this.bodyEl.setHeight(h);
45478 h = this.tabs.syncHeight(h);
45481 if(this.panelSize){
45482 w = w !== null ? w : this.panelSize.width;
45483 h = h !== null ? h : this.panelSize.height;
45485 if(this.activePanel){
45486 var el = this.activePanel.getEl();
45487 w = w !== null ? w : el.getWidth();
45488 h = h !== null ? h : el.getHeight();
45489 this.panelSize = {width: w, height: h};
45490 this.activePanel.setSize(w, h);
45492 if(Roo.isIE && this.tabs){
45493 this.tabs.el.repaint();
45498 * Returns the container element for this region.
45499 * @return {Roo.Element}
45501 getEl : function(){
45506 * Hides this region.
45509 if(!this.collapsed){
45510 this.el.dom.style.left = "-2000px";
45513 this.collapsedEl.dom.style.left = "-2000px";
45514 this.collapsedEl.hide();
45516 this.visible = false;
45517 this.fireEvent("visibilitychange", this, false);
45521 * Shows this region if it was previously hidden.
45524 if(!this.collapsed){
45527 this.collapsedEl.show();
45529 this.visible = true;
45530 this.fireEvent("visibilitychange", this, true);
45533 closeClicked : function(){
45534 if(this.activePanel){
45535 this.remove(this.activePanel);
45539 collapseClick : function(e){
45541 e.stopPropagation();
45544 e.stopPropagation();
45550 * Collapses this region.
45551 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
45553 collapse : function(skipAnim){
45554 if(this.collapsed) return;
45555 this.collapsed = true;
45557 this.split.el.hide();
45559 if(this.config.animate && skipAnim !== true){
45560 this.fireEvent("invalidated", this);
45561 this.animateCollapse();
45563 this.el.setLocation(-20000,-20000);
45565 this.collapsedEl.show();
45566 this.fireEvent("collapsed", this);
45567 this.fireEvent("invalidated", this);
45571 animateCollapse : function(){
45576 * Expands this region if it was previously collapsed.
45577 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
45578 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
45580 expand : function(e, skipAnim){
45581 if(e) e.stopPropagation();
45582 if(!this.collapsed || this.el.hasActiveFx()) return;
45584 this.afterSlideIn();
45587 this.collapsed = false;
45588 if(this.config.animate && skipAnim !== true){
45589 this.animateExpand();
45593 this.split.el.show();
45595 this.collapsedEl.setLocation(-2000,-2000);
45596 this.collapsedEl.hide();
45597 this.fireEvent("invalidated", this);
45598 this.fireEvent("expanded", this);
45602 animateExpand : function(){
45606 initTabs : function()
45608 this.bodyEl.setStyle("overflow", "hidden");
45609 var ts = new Roo.TabPanel(
45612 tabPosition: this.bottomTabs ? 'bottom' : 'top',
45613 disableTooltips: this.config.disableTabTips,
45614 toolbar : this.config.toolbar
45617 if(this.config.hideTabs){
45618 ts.stripWrap.setDisplayed(false);
45621 ts.resizeTabs = this.config.resizeTabs === true;
45622 ts.minTabWidth = this.config.minTabWidth || 40;
45623 ts.maxTabWidth = this.config.maxTabWidth || 250;
45624 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
45625 ts.monitorResize = false;
45626 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
45627 ts.bodyEl.addClass('x-layout-tabs-body');
45628 this.panels.each(this.initPanelAsTab, this);
45631 initPanelAsTab : function(panel){
45632 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
45633 this.config.closeOnTab && panel.isClosable());
45634 if(panel.tabTip !== undefined){
45635 ti.setTooltip(panel.tabTip);
45637 ti.on("activate", function(){
45638 this.setActivePanel(panel);
45640 if(this.config.closeOnTab){
45641 ti.on("beforeclose", function(t, e){
45643 this.remove(panel);
45649 updatePanelTitle : function(panel, title){
45650 if(this.activePanel == panel){
45651 this.updateTitle(title);
45654 var ti = this.tabs.getTab(panel.getEl().id);
45656 if(panel.tabTip !== undefined){
45657 ti.setTooltip(panel.tabTip);
45662 updateTitle : function(title){
45663 if(this.titleTextEl && !this.config.title){
45664 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
45668 setActivePanel : function(panel){
45669 panel = this.getPanel(panel);
45670 if(this.activePanel && this.activePanel != panel){
45671 this.activePanel.setActiveState(false);
45673 this.activePanel = panel;
45674 panel.setActiveState(true);
45675 if(this.panelSize){
45676 panel.setSize(this.panelSize.width, this.panelSize.height);
45679 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
45681 this.updateTitle(panel.getTitle());
45683 this.fireEvent("invalidated", this);
45685 this.fireEvent("panelactivated", this, panel);
45689 * Shows the specified panel.
45690 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
45691 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
45693 showPanel : function(panel){
45694 if(panel = this.getPanel(panel)){
45696 var tab = this.tabs.getTab(panel.getEl().id);
45697 if(tab.isHidden()){
45698 this.tabs.unhideTab(tab.id);
45702 this.setActivePanel(panel);
45709 * Get the active panel for this region.
45710 * @return {Roo.ContentPanel} The active panel or null
45712 getActivePanel : function(){
45713 return this.activePanel;
45716 validateVisibility : function(){
45717 if(this.panels.getCount() < 1){
45718 this.updateTitle(" ");
45719 this.closeBtn.hide();
45722 if(!this.isVisible()){
45729 * Adds the passed ContentPanel(s) to this region.
45730 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
45731 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
45733 add : function(panel){
45734 if(arguments.length > 1){
45735 for(var i = 0, len = arguments.length; i < len; i++) {
45736 this.add(arguments[i]);
45740 if(this.hasPanel(panel)){
45741 this.showPanel(panel);
45744 panel.setRegion(this);
45745 this.panels.add(panel);
45746 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
45747 this.bodyEl.dom.appendChild(panel.getEl().dom);
45748 if(panel.background !== true){
45749 this.setActivePanel(panel);
45751 this.fireEvent("paneladded", this, panel);
45757 this.initPanelAsTab(panel);
45759 if(panel.background !== true){
45760 this.tabs.activate(panel.getEl().id);
45762 this.fireEvent("paneladded", this, panel);
45767 * Hides the tab for the specified panel.
45768 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
45770 hidePanel : function(panel){
45771 if(this.tabs && (panel = this.getPanel(panel))){
45772 this.tabs.hideTab(panel.getEl().id);
45777 * Unhides the tab for a previously hidden panel.
45778 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
45780 unhidePanel : function(panel){
45781 if(this.tabs && (panel = this.getPanel(panel))){
45782 this.tabs.unhideTab(panel.getEl().id);
45786 clearPanels : function(){
45787 while(this.panels.getCount() > 0){
45788 this.remove(this.panels.first());
45793 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
45794 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
45795 * @param {Boolean} preservePanel Overrides the config preservePanel option
45796 * @return {Roo.ContentPanel} The panel that was removed
45798 remove : function(panel, preservePanel){
45799 panel = this.getPanel(panel);
45804 this.fireEvent("beforeremove", this, panel, e);
45805 if(e.cancel === true){
45808 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
45809 var panelId = panel.getId();
45810 this.panels.removeKey(panelId);
45812 document.body.appendChild(panel.getEl().dom);
45815 this.tabs.removeTab(panel.getEl().id);
45816 }else if (!preservePanel){
45817 this.bodyEl.dom.removeChild(panel.getEl().dom);
45819 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
45820 var p = this.panels.first();
45821 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
45822 tempEl.appendChild(p.getEl().dom);
45823 this.bodyEl.update("");
45824 this.bodyEl.dom.appendChild(p.getEl().dom);
45826 this.updateTitle(p.getTitle());
45828 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
45829 this.setActivePanel(p);
45831 panel.setRegion(null);
45832 if(this.activePanel == panel){
45833 this.activePanel = null;
45835 if(this.config.autoDestroy !== false && preservePanel !== true){
45836 try{panel.destroy();}catch(e){}
45838 this.fireEvent("panelremoved", this, panel);
45843 * Returns the TabPanel component used by this region
45844 * @return {Roo.TabPanel}
45846 getTabs : function(){
45850 createTool : function(parentEl, className){
45851 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
45852 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
45853 btn.addClassOnOver("x-layout-tools-button-over");
45858 * Ext JS Library 1.1.1
45859 * Copyright(c) 2006-2007, Ext JS, LLC.
45861 * Originally Released Under LGPL - original licence link has changed is not relivant.
45864 * <script type="text/javascript">
45870 * @class Roo.SplitLayoutRegion
45871 * @extends Roo.LayoutRegion
45872 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
45874 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
45875 this.cursor = cursor;
45876 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
45879 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
45880 splitTip : "Drag to resize.",
45881 collapsibleSplitTip : "Drag to resize. Double click to hide.",
45882 useSplitTips : false,
45884 applyConfig : function(config){
45885 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
45888 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
45889 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
45890 /** The SplitBar for this region
45891 * @type Roo.SplitBar */
45892 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
45893 this.split.on("moved", this.onSplitMove, this);
45894 this.split.useShim = config.useShim === true;
45895 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
45896 if(this.useSplitTips){
45897 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
45899 if(config.collapsible){
45900 this.split.el.on("dblclick", this.collapse, this);
45903 if(typeof config.minSize != "undefined"){
45904 this.split.minSize = config.minSize;
45906 if(typeof config.maxSize != "undefined"){
45907 this.split.maxSize = config.maxSize;
45909 if(config.hideWhenEmpty || config.hidden || config.collapsed){
45910 this.hideSplitter();
45915 getHMaxSize : function(){
45916 var cmax = this.config.maxSize || 10000;
45917 var center = this.mgr.getRegion("center");
45918 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
45921 getVMaxSize : function(){
45922 var cmax = this.config.maxSize || 10000;
45923 var center = this.mgr.getRegion("center");
45924 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
45927 onSplitMove : function(split, newSize){
45928 this.fireEvent("resized", this, newSize);
45932 * Returns the {@link Roo.SplitBar} for this region.
45933 * @return {Roo.SplitBar}
45935 getSplitBar : function(){
45940 this.hideSplitter();
45941 Roo.SplitLayoutRegion.superclass.hide.call(this);
45944 hideSplitter : function(){
45946 this.split.el.setLocation(-2000,-2000);
45947 this.split.el.hide();
45953 this.split.el.show();
45955 Roo.SplitLayoutRegion.superclass.show.call(this);
45958 beforeSlide: function(){
45959 if(Roo.isGecko){// firefox overflow auto bug workaround
45960 this.bodyEl.clip();
45961 if(this.tabs) this.tabs.bodyEl.clip();
45962 if(this.activePanel){
45963 this.activePanel.getEl().clip();
45965 if(this.activePanel.beforeSlide){
45966 this.activePanel.beforeSlide();
45972 afterSlide : function(){
45973 if(Roo.isGecko){// firefox overflow auto bug workaround
45974 this.bodyEl.unclip();
45975 if(this.tabs) this.tabs.bodyEl.unclip();
45976 if(this.activePanel){
45977 this.activePanel.getEl().unclip();
45978 if(this.activePanel.afterSlide){
45979 this.activePanel.afterSlide();
45985 initAutoHide : function(){
45986 if(this.autoHide !== false){
45987 if(!this.autoHideHd){
45988 var st = new Roo.util.DelayedTask(this.slideIn, this);
45989 this.autoHideHd = {
45990 "mouseout": function(e){
45991 if(!e.within(this.el, true)){
45995 "mouseover" : function(e){
46001 this.el.on(this.autoHideHd);
46005 clearAutoHide : function(){
46006 if(this.autoHide !== false){
46007 this.el.un("mouseout", this.autoHideHd.mouseout);
46008 this.el.un("mouseover", this.autoHideHd.mouseover);
46012 clearMonitor : function(){
46013 Roo.get(document).un("click", this.slideInIf, this);
46016 // these names are backwards but not changed for compat
46017 slideOut : function(){
46018 if(this.isSlid || this.el.hasActiveFx()){
46021 this.isSlid = true;
46022 if(this.collapseBtn){
46023 this.collapseBtn.hide();
46025 this.closeBtnState = this.closeBtn.getStyle('display');
46026 this.closeBtn.hide();
46028 this.stickBtn.show();
46031 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
46032 this.beforeSlide();
46033 this.el.setStyle("z-index", 10001);
46034 this.el.slideIn(this.getSlideAnchor(), {
46035 callback: function(){
46037 this.initAutoHide();
46038 Roo.get(document).on("click", this.slideInIf, this);
46039 this.fireEvent("slideshow", this);
46046 afterSlideIn : function(){
46047 this.clearAutoHide();
46048 this.isSlid = false;
46049 this.clearMonitor();
46050 this.el.setStyle("z-index", "");
46051 if(this.collapseBtn){
46052 this.collapseBtn.show();
46054 this.closeBtn.setStyle('display', this.closeBtnState);
46056 this.stickBtn.hide();
46058 this.fireEvent("slidehide", this);
46061 slideIn : function(cb){
46062 if(!this.isSlid || this.el.hasActiveFx()){
46066 this.isSlid = false;
46067 this.beforeSlide();
46068 this.el.slideOut(this.getSlideAnchor(), {
46069 callback: function(){
46070 this.el.setLeftTop(-10000, -10000);
46072 this.afterSlideIn();
46080 slideInIf : function(e){
46081 if(!e.within(this.el)){
46086 animateCollapse : function(){
46087 this.beforeSlide();
46088 this.el.setStyle("z-index", 20000);
46089 var anchor = this.getSlideAnchor();
46090 this.el.slideOut(anchor, {
46091 callback : function(){
46092 this.el.setStyle("z-index", "");
46093 this.collapsedEl.slideIn(anchor, {duration:.3});
46095 this.el.setLocation(-10000,-10000);
46097 this.fireEvent("collapsed", this);
46104 animateExpand : function(){
46105 this.beforeSlide();
46106 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
46107 this.el.setStyle("z-index", 20000);
46108 this.collapsedEl.hide({
46111 this.el.slideIn(this.getSlideAnchor(), {
46112 callback : function(){
46113 this.el.setStyle("z-index", "");
46116 this.split.el.show();
46118 this.fireEvent("invalidated", this);
46119 this.fireEvent("expanded", this);
46147 getAnchor : function(){
46148 return this.anchors[this.position];
46151 getCollapseAnchor : function(){
46152 return this.canchors[this.position];
46155 getSlideAnchor : function(){
46156 return this.sanchors[this.position];
46159 getAlignAdj : function(){
46160 var cm = this.cmargins;
46161 switch(this.position){
46177 getExpandAdj : function(){
46178 var c = this.collapsedEl, cm = this.cmargins;
46179 switch(this.position){
46181 return [-(cm.right+c.getWidth()+cm.left), 0];
46184 return [cm.right+c.getWidth()+cm.left, 0];
46187 return [0, -(cm.top+cm.bottom+c.getHeight())];
46190 return [0, cm.top+cm.bottom+c.getHeight()];
46196 * Ext JS Library 1.1.1
46197 * Copyright(c) 2006-2007, Ext JS, LLC.
46199 * Originally Released Under LGPL - original licence link has changed is not relivant.
46202 * <script type="text/javascript">
46205 * These classes are private internal classes
46207 Roo.CenterLayoutRegion = function(mgr, config){
46208 Roo.LayoutRegion.call(this, mgr, config, "center");
46209 this.visible = true;
46210 this.minWidth = config.minWidth || 20;
46211 this.minHeight = config.minHeight || 20;
46214 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
46216 // center panel can't be hidden
46220 // center panel can't be hidden
46223 getMinWidth: function(){
46224 return this.minWidth;
46227 getMinHeight: function(){
46228 return this.minHeight;
46233 Roo.NorthLayoutRegion = function(mgr, config){
46234 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
46236 this.split.placement = Roo.SplitBar.TOP;
46237 this.split.orientation = Roo.SplitBar.VERTICAL;
46238 this.split.el.addClass("x-layout-split-v");
46240 var size = config.initialSize || config.height;
46241 if(typeof size != "undefined"){
46242 this.el.setHeight(size);
46245 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
46246 orientation: Roo.SplitBar.VERTICAL,
46247 getBox : function(){
46248 if(this.collapsed){
46249 return this.collapsedEl.getBox();
46251 var box = this.el.getBox();
46253 box.height += this.split.el.getHeight();
46258 updateBox : function(box){
46259 if(this.split && !this.collapsed){
46260 box.height -= this.split.el.getHeight();
46261 this.split.el.setLeft(box.x);
46262 this.split.el.setTop(box.y+box.height);
46263 this.split.el.setWidth(box.width);
46265 if(this.collapsed){
46266 this.updateBody(box.width, null);
46268 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46272 Roo.SouthLayoutRegion = function(mgr, config){
46273 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
46275 this.split.placement = Roo.SplitBar.BOTTOM;
46276 this.split.orientation = Roo.SplitBar.VERTICAL;
46277 this.split.el.addClass("x-layout-split-v");
46279 var size = config.initialSize || config.height;
46280 if(typeof size != "undefined"){
46281 this.el.setHeight(size);
46284 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
46285 orientation: Roo.SplitBar.VERTICAL,
46286 getBox : function(){
46287 if(this.collapsed){
46288 return this.collapsedEl.getBox();
46290 var box = this.el.getBox();
46292 var sh = this.split.el.getHeight();
46299 updateBox : function(box){
46300 if(this.split && !this.collapsed){
46301 var sh = this.split.el.getHeight();
46304 this.split.el.setLeft(box.x);
46305 this.split.el.setTop(box.y-sh);
46306 this.split.el.setWidth(box.width);
46308 if(this.collapsed){
46309 this.updateBody(box.width, null);
46311 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46315 Roo.EastLayoutRegion = function(mgr, config){
46316 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
46318 this.split.placement = Roo.SplitBar.RIGHT;
46319 this.split.orientation = Roo.SplitBar.HORIZONTAL;
46320 this.split.el.addClass("x-layout-split-h");
46322 var size = config.initialSize || config.width;
46323 if(typeof size != "undefined"){
46324 this.el.setWidth(size);
46327 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
46328 orientation: Roo.SplitBar.HORIZONTAL,
46329 getBox : function(){
46330 if(this.collapsed){
46331 return this.collapsedEl.getBox();
46333 var box = this.el.getBox();
46335 var sw = this.split.el.getWidth();
46342 updateBox : function(box){
46343 if(this.split && !this.collapsed){
46344 var sw = this.split.el.getWidth();
46346 this.split.el.setLeft(box.x);
46347 this.split.el.setTop(box.y);
46348 this.split.el.setHeight(box.height);
46351 if(this.collapsed){
46352 this.updateBody(null, box.height);
46354 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46358 Roo.WestLayoutRegion = function(mgr, config){
46359 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
46361 this.split.placement = Roo.SplitBar.LEFT;
46362 this.split.orientation = Roo.SplitBar.HORIZONTAL;
46363 this.split.el.addClass("x-layout-split-h");
46365 var size = config.initialSize || config.width;
46366 if(typeof size != "undefined"){
46367 this.el.setWidth(size);
46370 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
46371 orientation: Roo.SplitBar.HORIZONTAL,
46372 getBox : function(){
46373 if(this.collapsed){
46374 return this.collapsedEl.getBox();
46376 var box = this.el.getBox();
46378 box.width += this.split.el.getWidth();
46383 updateBox : function(box){
46384 if(this.split && !this.collapsed){
46385 var sw = this.split.el.getWidth();
46387 this.split.el.setLeft(box.x+box.width);
46388 this.split.el.setTop(box.y);
46389 this.split.el.setHeight(box.height);
46391 if(this.collapsed){
46392 this.updateBody(null, box.height);
46394 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46399 * Ext JS Library 1.1.1
46400 * Copyright(c) 2006-2007, Ext JS, LLC.
46402 * Originally Released Under LGPL - original licence link has changed is not relivant.
46405 * <script type="text/javascript">
46410 * Private internal class for reading and applying state
46412 Roo.LayoutStateManager = function(layout){
46413 // default empty state
46422 Roo.LayoutStateManager.prototype = {
46423 init : function(layout, provider){
46424 this.provider = provider;
46425 var state = provider.get(layout.id+"-layout-state");
46427 var wasUpdating = layout.isUpdating();
46429 layout.beginUpdate();
46431 for(var key in state){
46432 if(typeof state[key] != "function"){
46433 var rstate = state[key];
46434 var r = layout.getRegion(key);
46437 r.resizeTo(rstate.size);
46439 if(rstate.collapsed == true){
46442 r.expand(null, true);
46448 layout.endUpdate();
46450 this.state = state;
46452 this.layout = layout;
46453 layout.on("regionresized", this.onRegionResized, this);
46454 layout.on("regioncollapsed", this.onRegionCollapsed, this);
46455 layout.on("regionexpanded", this.onRegionExpanded, this);
46458 storeState : function(){
46459 this.provider.set(this.layout.id+"-layout-state", this.state);
46462 onRegionResized : function(region, newSize){
46463 this.state[region.getPosition()].size = newSize;
46467 onRegionCollapsed : function(region){
46468 this.state[region.getPosition()].collapsed = true;
46472 onRegionExpanded : function(region){
46473 this.state[region.getPosition()].collapsed = false;
46478 * Ext JS Library 1.1.1
46479 * Copyright(c) 2006-2007, Ext JS, LLC.
46481 * Originally Released Under LGPL - original licence link has changed is not relivant.
46484 * <script type="text/javascript">
46487 * @class Roo.ContentPanel
46488 * @extends Roo.util.Observable
46489 * A basic ContentPanel element.
46490 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
46491 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
46492 * @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
46493 * @cfg {Boolean} closable True if the panel can be closed/removed
46494 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
46495 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
46496 * @cfg {Toolbar} toolbar A toolbar for this panel
46497 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
46498 * @cfg {String} title The title for this panel
46499 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
46500 * @cfg {String} url Calls {@link #setUrl} with this value
46501 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
46502 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
46503 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
46504 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
46507 * Create a new ContentPanel.
46508 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
46509 * @param {String/Object} config A string to set only the title or a config object
46510 * @param {String} content (optional) Set the HTML content for this panel
46511 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
46513 Roo.ContentPanel = function(el, config, content){
46517 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
46521 if (config && config.parentLayout) {
46522 el = config.parentLayout.el.createChild();
46525 if(el.autoCreate){ // xtype is available if this is called from factory
46529 this.el = Roo.get(el);
46530 if(!this.el && config && config.autoCreate){
46531 if(typeof config.autoCreate == "object"){
46532 if(!config.autoCreate.id){
46533 config.autoCreate.id = config.id||el;
46535 this.el = Roo.DomHelper.append(document.body,
46536 config.autoCreate, true);
46538 this.el = Roo.DomHelper.append(document.body,
46539 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
46542 this.closable = false;
46543 this.loaded = false;
46544 this.active = false;
46545 if(typeof config == "string"){
46546 this.title = config;
46548 Roo.apply(this, config);
46551 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
46552 this.wrapEl = this.el.wrap();
46553 this.toolbar.container = this.el.insertSibling(false, 'before');
46554 this.toolbar = new Roo.Toolbar(this.toolbar);
46560 this.resizeEl = Roo.get(this.resizeEl, true);
46562 this.resizeEl = this.el;
46567 * Fires when this panel is activated.
46568 * @param {Roo.ContentPanel} this
46572 * @event deactivate
46573 * Fires when this panel is activated.
46574 * @param {Roo.ContentPanel} this
46576 "deactivate" : true,
46580 * Fires when this panel is resized if fitToFrame is true.
46581 * @param {Roo.ContentPanel} this
46582 * @param {Number} width The width after any component adjustments
46583 * @param {Number} height The height after any component adjustments
46589 * Fires when this tab is created
46590 * @param {Roo.ContentPanel} this
46597 if(this.autoScroll){
46598 this.resizeEl.setStyle("overflow", "auto");
46600 // fix randome scrolling
46601 this.el.on('scroll', function() {
46602 Roo.log('fix random scolling');
46603 this.scrollTo('top',0);
46606 content = content || this.content;
46608 this.setContent(content);
46610 if(config && config.url){
46611 this.setUrl(this.url, this.params, this.loadOnce);
46616 Roo.ContentPanel.superclass.constructor.call(this);
46618 this.fireEvent('render', this);
46621 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
46623 setRegion : function(region){
46624 this.region = region;
46626 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
46628 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
46633 * Returns the toolbar for this Panel if one was configured.
46634 * @return {Roo.Toolbar}
46636 getToolbar : function(){
46637 return this.toolbar;
46640 setActiveState : function(active){
46641 this.active = active;
46643 this.fireEvent("deactivate", this);
46645 this.fireEvent("activate", this);
46649 * Updates this panel's element
46650 * @param {String} content The new content
46651 * @param {Boolean} loadScripts (optional) true to look for and process scripts
46653 setContent : function(content, loadScripts){
46654 this.el.update(content, loadScripts);
46657 ignoreResize : function(w, h){
46658 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
46661 this.lastSize = {width: w, height: h};
46666 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
46667 * @return {Roo.UpdateManager} The UpdateManager
46669 getUpdateManager : function(){
46670 return this.el.getUpdateManager();
46673 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
46674 * @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:
46677 url: "your-url.php",
46678 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
46679 callback: yourFunction,
46680 scope: yourObject, //(optional scope)
46683 text: "Loading...",
46688 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
46689 * 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.
46690 * @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}
46691 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
46692 * @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.
46693 * @return {Roo.ContentPanel} this
46696 var um = this.el.getUpdateManager();
46697 um.update.apply(um, arguments);
46703 * 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.
46704 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
46705 * @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)
46706 * @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)
46707 * @return {Roo.UpdateManager} The UpdateManager
46709 setUrl : function(url, params, loadOnce){
46710 if(this.refreshDelegate){
46711 this.removeListener("activate", this.refreshDelegate);
46713 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
46714 this.on("activate", this.refreshDelegate);
46715 return this.el.getUpdateManager();
46718 _handleRefresh : function(url, params, loadOnce){
46719 if(!loadOnce || !this.loaded){
46720 var updater = this.el.getUpdateManager();
46721 updater.update(url, params, this._setLoaded.createDelegate(this));
46725 _setLoaded : function(){
46726 this.loaded = true;
46730 * Returns this panel's id
46733 getId : function(){
46738 * Returns this panel's element - used by regiosn to add.
46739 * @return {Roo.Element}
46741 getEl : function(){
46742 return this.wrapEl || this.el;
46745 adjustForComponents : function(width, height){
46746 if(this.resizeEl != this.el){
46747 width -= this.el.getFrameWidth('lr');
46748 height -= this.el.getFrameWidth('tb');
46751 var te = this.toolbar.getEl();
46752 height -= te.getHeight();
46753 te.setWidth(width);
46755 if(this.adjustments){
46756 width += this.adjustments[0];
46757 height += this.adjustments[1];
46759 return {"width": width, "height": height};
46762 setSize : function(width, height){
46763 if(this.fitToFrame && !this.ignoreResize(width, height)){
46764 if(this.fitContainer && this.resizeEl != this.el){
46765 this.el.setSize(width, height);
46767 var size = this.adjustForComponents(width, height);
46768 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
46769 this.fireEvent('resize', this, size.width, size.height);
46774 * Returns this panel's title
46777 getTitle : function(){
46782 * Set this panel's title
46783 * @param {String} title
46785 setTitle : function(title){
46786 this.title = title;
46788 this.region.updatePanelTitle(this, title);
46793 * Returns true is this panel was configured to be closable
46794 * @return {Boolean}
46796 isClosable : function(){
46797 return this.closable;
46800 beforeSlide : function(){
46802 this.resizeEl.clip();
46805 afterSlide : function(){
46807 this.resizeEl.unclip();
46811 * Force a content refresh from the URL specified in the {@link #setUrl} method.
46812 * Will fail silently if the {@link #setUrl} method has not been called.
46813 * This does not activate the panel, just updates its content.
46815 refresh : function(){
46816 if(this.refreshDelegate){
46817 this.loaded = false;
46818 this.refreshDelegate();
46823 * Destroys this panel
46825 destroy : function(){
46826 this.el.removeAllListeners();
46827 var tempEl = document.createElement("span");
46828 tempEl.appendChild(this.el.dom);
46829 tempEl.innerHTML = "";
46835 * form - if the content panel contains a form - this is a reference to it.
46836 * @type {Roo.form.Form}
46840 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
46841 * This contains a reference to it.
46847 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
46857 * @param {Object} cfg Xtype definition of item to add.
46860 addxtype : function(cfg) {
46862 if (cfg.xtype.match(/^Form$/)) {
46863 var el = this.el.createChild();
46865 this.form = new Roo.form.Form(cfg);
46868 if ( this.form.allItems.length) this.form.render(el.dom);
46871 // should only have one of theses..
46872 if (['View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
46874 cfg.el = this.el.appendChild(document.createElement("div"));
46877 var ret = new Roo.factory(cfg);
46878 ret.render && ret.render(false, ''); // render blank..
46887 * @class Roo.GridPanel
46888 * @extends Roo.ContentPanel
46890 * Create a new GridPanel.
46891 * @param {Roo.grid.Grid} grid The grid for this panel
46892 * @param {String/Object} config A string to set only the panel's title, or a config object
46894 Roo.GridPanel = function(grid, config){
46897 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
46898 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
46900 this.wrapper.dom.appendChild(grid.getGridEl().dom);
46902 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
46905 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
46907 // xtype created footer. - not sure if will work as we normally have to render first..
46908 if (this.footer && !this.footer.el && this.footer.xtype) {
46910 this.footer.container = this.grid.getView().getFooterPanel(true);
46911 this.footer.dataSource = this.grid.dataSource;
46912 this.footer = Roo.factory(this.footer, Roo);
46916 grid.monitorWindowResize = false; // turn off autosizing
46917 grid.autoHeight = false;
46918 grid.autoWidth = false;
46920 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
46923 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
46924 getId : function(){
46925 return this.grid.id;
46929 * Returns the grid for this panel
46930 * @return {Roo.grid.Grid}
46932 getGrid : function(){
46936 setSize : function(width, height){
46937 if(!this.ignoreResize(width, height)){
46938 var grid = this.grid;
46939 var size = this.adjustForComponents(width, height);
46940 grid.getGridEl().setSize(size.width, size.height);
46945 beforeSlide : function(){
46946 this.grid.getView().scroller.clip();
46949 afterSlide : function(){
46950 this.grid.getView().scroller.unclip();
46953 destroy : function(){
46954 this.grid.destroy();
46956 Roo.GridPanel.superclass.destroy.call(this);
46962 * @class Roo.NestedLayoutPanel
46963 * @extends Roo.ContentPanel
46965 * Create a new NestedLayoutPanel.
46968 * @param {Roo.BorderLayout} layout The layout for this panel
46969 * @param {String/Object} config A string to set only the title or a config object
46971 Roo.NestedLayoutPanel = function(layout, config)
46973 // construct with only one argument..
46974 /* FIXME - implement nicer consturctors
46975 if (layout.layout) {
46977 layout = config.layout;
46978 delete config.layout;
46980 if (layout.xtype && !layout.getEl) {
46981 // then layout needs constructing..
46982 layout = Roo.factory(layout, Roo);
46987 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
46989 layout.monitorWindowResize = false; // turn off autosizing
46990 this.layout = layout;
46991 this.layout.getEl().addClass("x-layout-nested-layout");
46998 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
47000 setSize : function(width, height){
47001 if(!this.ignoreResize(width, height)){
47002 var size = this.adjustForComponents(width, height);
47003 var el = this.layout.getEl();
47004 el.setSize(size.width, size.height);
47005 var touch = el.dom.offsetWidth;
47006 this.layout.layout();
47007 // ie requires a double layout on the first pass
47008 if(Roo.isIE && !this.initialized){
47009 this.initialized = true;
47010 this.layout.layout();
47015 // activate all subpanels if not currently active..
47017 setActiveState : function(active){
47018 this.active = active;
47020 this.fireEvent("deactivate", this);
47024 this.fireEvent("activate", this);
47025 // not sure if this should happen before or after..
47026 if (!this.layout) {
47027 return; // should not happen..
47030 for (var r in this.layout.regions) {
47031 reg = this.layout.getRegion(r);
47032 if (reg.getActivePanel()) {
47033 //reg.showPanel(reg.getActivePanel()); // force it to activate..
47034 reg.setActivePanel(reg.getActivePanel());
47037 if (!reg.panels.length) {
47040 reg.showPanel(reg.getPanel(0));
47049 * Returns the nested BorderLayout for this panel
47050 * @return {Roo.BorderLayout}
47052 getLayout : function(){
47053 return this.layout;
47057 * Adds a xtype elements to the layout of the nested panel
47061 xtype : 'ContentPanel',
47068 xtype : 'NestedLayoutPanel',
47074 items : [ ... list of content panels or nested layout panels.. ]
47078 * @param {Object} cfg Xtype definition of item to add.
47080 addxtype : function(cfg) {
47081 return this.layout.addxtype(cfg);
47086 Roo.ScrollPanel = function(el, config, content){
47087 config = config || {};
47088 config.fitToFrame = true;
47089 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
47091 this.el.dom.style.overflow = "hidden";
47092 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
47093 this.el.removeClass("x-layout-inactive-content");
47094 this.el.on("mousewheel", this.onWheel, this);
47096 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
47097 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
47098 up.unselectable(); down.unselectable();
47099 up.on("click", this.scrollUp, this);
47100 down.on("click", this.scrollDown, this);
47101 up.addClassOnOver("x-scroller-btn-over");
47102 down.addClassOnOver("x-scroller-btn-over");
47103 up.addClassOnClick("x-scroller-btn-click");
47104 down.addClassOnClick("x-scroller-btn-click");
47105 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
47107 this.resizeEl = this.el;
47108 this.el = wrap; this.up = up; this.down = down;
47111 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
47113 wheelIncrement : 5,
47114 scrollUp : function(){
47115 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
47118 scrollDown : function(){
47119 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
47122 afterScroll : function(){
47123 var el = this.resizeEl;
47124 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
47125 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
47126 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
47129 setSize : function(){
47130 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
47131 this.afterScroll();
47134 onWheel : function(e){
47135 var d = e.getWheelDelta();
47136 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
47137 this.afterScroll();
47141 setContent : function(content, loadScripts){
47142 this.resizeEl.update(content, loadScripts);
47156 * @class Roo.TreePanel
47157 * @extends Roo.ContentPanel
47159 * Create a new TreePanel. - defaults to fit/scoll contents.
47160 * @param {String/Object} config A string to set only the panel's title, or a config object
47161 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
47163 Roo.TreePanel = function(config){
47164 var el = config.el;
47165 var tree = config.tree;
47166 delete config.tree;
47167 delete config.el; // hopefull!
47169 // wrapper for IE7 strict & safari scroll issue
47171 var treeEl = el.createChild();
47172 config.resizeEl = treeEl;
47176 Roo.TreePanel.superclass.constructor.call(this, el, config);
47179 this.tree = new Roo.tree.TreePanel(treeEl , tree);
47180 //console.log(tree);
47181 this.on('activate', function()
47183 if (this.tree.rendered) {
47186 //console.log('render tree');
47187 this.tree.render();
47190 this.on('resize', function (cp, w, h) {
47191 this.tree.innerCt.setWidth(w);
47192 this.tree.innerCt.setHeight(h);
47193 this.tree.innerCt.setStyle('overflow-y', 'auto');
47200 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
47217 * Ext JS Library 1.1.1
47218 * Copyright(c) 2006-2007, Ext JS, LLC.
47220 * Originally Released Under LGPL - original licence link has changed is not relivant.
47223 * <script type="text/javascript">
47228 * @class Roo.ReaderLayout
47229 * @extends Roo.BorderLayout
47230 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
47231 * center region containing two nested regions (a top one for a list view and one for item preview below),
47232 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
47233 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
47234 * expedites the setup of the overall layout and regions for this common application style.
47237 var reader = new Roo.ReaderLayout();
47238 var CP = Roo.ContentPanel; // shortcut for adding
47240 reader.beginUpdate();
47241 reader.add("north", new CP("north", "North"));
47242 reader.add("west", new CP("west", {title: "West"}));
47243 reader.add("east", new CP("east", {title: "East"}));
47245 reader.regions.listView.add(new CP("listView", "List"));
47246 reader.regions.preview.add(new CP("preview", "Preview"));
47247 reader.endUpdate();
47250 * Create a new ReaderLayout
47251 * @param {Object} config Configuration options
47252 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
47253 * document.body if omitted)
47255 Roo.ReaderLayout = function(config, renderTo){
47256 var c = config || {size:{}};
47257 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
47258 north: c.north !== false ? Roo.apply({
47262 }, c.north) : false,
47263 west: c.west !== false ? Roo.apply({
47271 margins:{left:5,right:0,bottom:5,top:5},
47272 cmargins:{left:5,right:5,bottom:5,top:5}
47273 }, c.west) : false,
47274 east: c.east !== false ? Roo.apply({
47282 margins:{left:0,right:5,bottom:5,top:5},
47283 cmargins:{left:5,right:5,bottom:5,top:5}
47284 }, c.east) : false,
47285 center: Roo.apply({
47286 tabPosition: 'top',
47290 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
47294 this.el.addClass('x-reader');
47296 this.beginUpdate();
47298 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
47299 south: c.preview !== false ? Roo.apply({
47306 cmargins:{top:5,left:0, right:0, bottom:0}
47307 }, c.preview) : false,
47308 center: Roo.apply({
47314 this.add('center', new Roo.NestedLayoutPanel(inner,
47315 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
47319 this.regions.preview = inner.getRegion('south');
47320 this.regions.listView = inner.getRegion('center');
47323 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
47325 * Ext JS Library 1.1.1
47326 * Copyright(c) 2006-2007, Ext JS, LLC.
47328 * Originally Released Under LGPL - original licence link has changed is not relivant.
47331 * <script type="text/javascript">
47335 * @class Roo.grid.Grid
47336 * @extends Roo.util.Observable
47337 * This class represents the primary interface of a component based grid control.
47338 * <br><br>Usage:<pre><code>
47339 var grid = new Roo.grid.Grid("my-container-id", {
47342 selModel: mySelectionModel,
47343 autoSizeColumns: true,
47344 monitorWindowResize: false,
47345 trackMouseOver: true
47350 * <b>Common Problems:</b><br/>
47351 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
47352 * element will correct this<br/>
47353 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
47354 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
47355 * are unpredictable.<br/>
47356 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
47357 * grid to calculate dimensions/offsets.<br/>
47359 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
47360 * The container MUST have some type of size defined for the grid to fill. The container will be
47361 * automatically set to position relative if it isn't already.
47362 * @param {Object} config A config object that sets properties on this grid.
47364 Roo.grid.Grid = function(container, config){
47365 // initialize the container
47366 this.container = Roo.get(container);
47367 this.container.update("");
47368 this.container.setStyle("overflow", "hidden");
47369 this.container.addClass('x-grid-container');
47371 this.id = this.container.id;
47373 Roo.apply(this, config);
47374 // check and correct shorthanded configs
47376 this.dataSource = this.ds;
47380 this.colModel = this.cm;
47384 this.selModel = this.sm;
47388 if (this.selModel) {
47389 this.selModel = Roo.factory(this.selModel, Roo.grid);
47390 this.sm = this.selModel;
47391 this.sm.xmodule = this.xmodule || false;
47393 if (typeof(this.colModel.config) == 'undefined') {
47394 this.colModel = new Roo.grid.ColumnModel(this.colModel);
47395 this.cm = this.colModel;
47396 this.cm.xmodule = this.xmodule || false;
47398 if (this.dataSource) {
47399 this.dataSource= Roo.factory(this.dataSource, Roo.data);
47400 this.ds = this.dataSource;
47401 this.ds.xmodule = this.xmodule || false;
47408 this.container.setWidth(this.width);
47412 this.container.setHeight(this.height);
47419 * The raw click event for the entire grid.
47420 * @param {Roo.EventObject} e
47425 * The raw dblclick event for the entire grid.
47426 * @param {Roo.EventObject} e
47430 * @event contextmenu
47431 * The raw contextmenu event for the entire grid.
47432 * @param {Roo.EventObject} e
47434 "contextmenu" : true,
47437 * The raw mousedown event for the entire grid.
47438 * @param {Roo.EventObject} e
47440 "mousedown" : true,
47443 * The raw mouseup event for the entire grid.
47444 * @param {Roo.EventObject} e
47449 * The raw mouseover event for the entire grid.
47450 * @param {Roo.EventObject} e
47452 "mouseover" : true,
47455 * The raw mouseout event for the entire grid.
47456 * @param {Roo.EventObject} e
47461 * The raw keypress event for the entire grid.
47462 * @param {Roo.EventObject} e
47467 * The raw keydown event for the entire grid.
47468 * @param {Roo.EventObject} e
47476 * Fires when a cell is clicked
47477 * @param {Grid} this
47478 * @param {Number} rowIndex
47479 * @param {Number} columnIndex
47480 * @param {Roo.EventObject} e
47482 "cellclick" : true,
47484 * @event celldblclick
47485 * Fires when a cell is double clicked
47486 * @param {Grid} this
47487 * @param {Number} rowIndex
47488 * @param {Number} columnIndex
47489 * @param {Roo.EventObject} e
47491 "celldblclick" : true,
47494 * Fires when a row is clicked
47495 * @param {Grid} this
47496 * @param {Number} rowIndex
47497 * @param {Roo.EventObject} e
47501 * @event rowdblclick
47502 * Fires when a row is double clicked
47503 * @param {Grid} this
47504 * @param {Number} rowIndex
47505 * @param {Roo.EventObject} e
47507 "rowdblclick" : true,
47509 * @event headerclick
47510 * Fires when a header is clicked
47511 * @param {Grid} this
47512 * @param {Number} columnIndex
47513 * @param {Roo.EventObject} e
47515 "headerclick" : true,
47517 * @event headerdblclick
47518 * Fires when a header cell is double clicked
47519 * @param {Grid} this
47520 * @param {Number} columnIndex
47521 * @param {Roo.EventObject} e
47523 "headerdblclick" : true,
47525 * @event rowcontextmenu
47526 * Fires when a row is right clicked
47527 * @param {Grid} this
47528 * @param {Number} rowIndex
47529 * @param {Roo.EventObject} e
47531 "rowcontextmenu" : true,
47533 * @event cellcontextmenu
47534 * Fires when a cell is right clicked
47535 * @param {Grid} this
47536 * @param {Number} rowIndex
47537 * @param {Number} cellIndex
47538 * @param {Roo.EventObject} e
47540 "cellcontextmenu" : true,
47542 * @event headercontextmenu
47543 * Fires when a header is right clicked
47544 * @param {Grid} this
47545 * @param {Number} columnIndex
47546 * @param {Roo.EventObject} e
47548 "headercontextmenu" : true,
47550 * @event bodyscroll
47551 * Fires when the body element is scrolled
47552 * @param {Number} scrollLeft
47553 * @param {Number} scrollTop
47555 "bodyscroll" : true,
47557 * @event columnresize
47558 * Fires when the user resizes a column
47559 * @param {Number} columnIndex
47560 * @param {Number} newSize
47562 "columnresize" : true,
47564 * @event columnmove
47565 * Fires when the user moves a column
47566 * @param {Number} oldIndex
47567 * @param {Number} newIndex
47569 "columnmove" : true,
47572 * Fires when row(s) start being dragged
47573 * @param {Grid} this
47574 * @param {Roo.GridDD} dd The drag drop object
47575 * @param {event} e The raw browser event
47577 "startdrag" : true,
47580 * Fires when a drag operation is complete
47581 * @param {Grid} this
47582 * @param {Roo.GridDD} dd The drag drop object
47583 * @param {event} e The raw browser event
47588 * Fires when dragged row(s) are dropped on a valid DD target
47589 * @param {Grid} this
47590 * @param {Roo.GridDD} dd The drag drop object
47591 * @param {String} targetId The target drag drop object
47592 * @param {event} e The raw browser event
47597 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
47598 * @param {Grid} this
47599 * @param {Roo.GridDD} dd The drag drop object
47600 * @param {String} targetId The target drag drop object
47601 * @param {event} e The raw browser event
47606 * Fires when the dragged row(s) first cross another DD target while being dragged
47607 * @param {Grid} this
47608 * @param {Roo.GridDD} dd The drag drop object
47609 * @param {String} targetId The target drag drop object
47610 * @param {event} e The raw browser event
47612 "dragenter" : true,
47615 * Fires when the dragged row(s) leave another DD target while being dragged
47616 * @param {Grid} this
47617 * @param {Roo.GridDD} dd The drag drop object
47618 * @param {String} targetId The target drag drop object
47619 * @param {event} e The raw browser event
47624 * Fires when a row is rendered, so you can change add a style to it.
47625 * @param {GridView} gridview The grid view
47626 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
47632 * Fires when the grid is rendered
47633 * @param {Grid} grid
47638 Roo.grid.Grid.superclass.constructor.call(this);
47640 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
47643 * @cfg {String} ddGroup - drag drop group.
47647 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
47649 minColumnWidth : 25,
47652 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
47653 * <b>on initial render.</b> It is more efficient to explicitly size the columns
47654 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
47656 autoSizeColumns : false,
47659 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
47661 autoSizeHeaders : true,
47664 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
47666 monitorWindowResize : true,
47669 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
47670 * rows measured to get a columns size. Default is 0 (all rows).
47672 maxRowsToMeasure : 0,
47675 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
47677 trackMouseOver : true,
47680 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
47684 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
47686 enableDragDrop : false,
47689 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
47691 enableColumnMove : true,
47694 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
47696 enableColumnHide : true,
47699 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
47701 enableRowHeightSync : false,
47704 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
47709 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
47711 autoHeight : false,
47714 * @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.
47716 autoExpandColumn : false,
47719 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
47722 autoExpandMin : 50,
47725 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
47727 autoExpandMax : 1000,
47730 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
47735 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
47739 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
47749 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
47750 * of a fixed width. Default is false.
47753 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
47756 * Called once after all setup has been completed and the grid is ready to be rendered.
47757 * @return {Roo.grid.Grid} this
47759 render : function()
47761 var c = this.container;
47762 // try to detect autoHeight/width mode
47763 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
47764 this.autoHeight = true;
47766 var view = this.getView();
47769 c.on("click", this.onClick, this);
47770 c.on("dblclick", this.onDblClick, this);
47771 c.on("contextmenu", this.onContextMenu, this);
47772 c.on("keydown", this.onKeyDown, this);
47774 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
47776 this.getSelectionModel().init(this);
47781 this.loadMask = new Roo.LoadMask(this.container,
47782 Roo.apply({store:this.dataSource}, this.loadMask));
47786 if (this.toolbar && this.toolbar.xtype) {
47787 this.toolbar.container = this.getView().getHeaderPanel(true);
47788 this.toolbar = new Roo.Toolbar(this.toolbar);
47790 if (this.footer && this.footer.xtype) {
47791 this.footer.dataSource = this.getDataSource();
47792 this.footer.container = this.getView().getFooterPanel(true);
47793 this.footer = Roo.factory(this.footer, Roo);
47795 if (this.dropTarget && this.dropTarget.xtype) {
47796 delete this.dropTarget.xtype;
47797 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
47801 this.rendered = true;
47802 this.fireEvent('render', this);
47807 * Reconfigures the grid to use a different Store and Column Model.
47808 * The View will be bound to the new objects and refreshed.
47809 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
47810 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
47812 reconfigure : function(dataSource, colModel){
47814 this.loadMask.destroy();
47815 this.loadMask = new Roo.LoadMask(this.container,
47816 Roo.apply({store:dataSource}, this.loadMask));
47818 this.view.bind(dataSource, colModel);
47819 this.dataSource = dataSource;
47820 this.colModel = colModel;
47821 this.view.refresh(true);
47825 onKeyDown : function(e){
47826 this.fireEvent("keydown", e);
47830 * Destroy this grid.
47831 * @param {Boolean} removeEl True to remove the element
47833 destroy : function(removeEl, keepListeners){
47835 this.loadMask.destroy();
47837 var c = this.container;
47838 c.removeAllListeners();
47839 this.view.destroy();
47840 this.colModel.purgeListeners();
47841 if(!keepListeners){
47842 this.purgeListeners();
47845 if(removeEl === true){
47851 processEvent : function(name, e){
47852 this.fireEvent(name, e);
47853 var t = e.getTarget();
47855 var header = v.findHeaderIndex(t);
47856 if(header !== false){
47857 this.fireEvent("header" + name, this, header, e);
47859 var row = v.findRowIndex(t);
47860 var cell = v.findCellIndex(t);
47862 this.fireEvent("row" + name, this, row, e);
47863 if(cell !== false){
47864 this.fireEvent("cell" + name, this, row, cell, e);
47871 onClick : function(e){
47872 this.processEvent("click", e);
47876 onContextMenu : function(e, t){
47877 this.processEvent("contextmenu", e);
47881 onDblClick : function(e){
47882 this.processEvent("dblclick", e);
47886 walkCells : function(row, col, step, fn, scope){
47887 var cm = this.colModel, clen = cm.getColumnCount();
47888 var ds = this.dataSource, rlen = ds.getCount(), first = true;
47900 if(fn.call(scope || this, row, col, cm) === true){
47918 if(fn.call(scope || this, row, col, cm) === true){
47930 getSelections : function(){
47931 return this.selModel.getSelections();
47935 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
47936 * but if manual update is required this method will initiate it.
47938 autoSize : function(){
47940 this.view.layout();
47941 if(this.view.adjustForScroll){
47942 this.view.adjustForScroll();
47948 * Returns the grid's underlying element.
47949 * @return {Element} The element
47951 getGridEl : function(){
47952 return this.container;
47955 // private for compatibility, overridden by editor grid
47956 stopEditing : function(){},
47959 * Returns the grid's SelectionModel.
47960 * @return {SelectionModel}
47962 getSelectionModel : function(){
47963 if(!this.selModel){
47964 this.selModel = new Roo.grid.RowSelectionModel();
47966 return this.selModel;
47970 * Returns the grid's DataSource.
47971 * @return {DataSource}
47973 getDataSource : function(){
47974 return this.dataSource;
47978 * Returns the grid's ColumnModel.
47979 * @return {ColumnModel}
47981 getColumnModel : function(){
47982 return this.colModel;
47986 * Returns the grid's GridView object.
47987 * @return {GridView}
47989 getView : function(){
47991 this.view = new Roo.grid.GridView(this.viewConfig);
47996 * Called to get grid's drag proxy text, by default returns this.ddText.
47999 getDragDropText : function(){
48000 var count = this.selModel.getCount();
48001 return String.format(this.ddText, count, count == 1 ? '' : 's');
48005 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
48006 * %0 is replaced with the number of selected rows.
48009 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
48011 * Ext JS Library 1.1.1
48012 * Copyright(c) 2006-2007, Ext JS, LLC.
48014 * Originally Released Under LGPL - original licence link has changed is not relivant.
48017 * <script type="text/javascript">
48020 Roo.grid.AbstractGridView = function(){
48024 "beforerowremoved" : true,
48025 "beforerowsinserted" : true,
48026 "beforerefresh" : true,
48027 "rowremoved" : true,
48028 "rowsinserted" : true,
48029 "rowupdated" : true,
48032 Roo.grid.AbstractGridView.superclass.constructor.call(this);
48035 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
48036 rowClass : "x-grid-row",
48037 cellClass : "x-grid-cell",
48038 tdClass : "x-grid-td",
48039 hdClass : "x-grid-hd",
48040 splitClass : "x-grid-hd-split",
48042 init: function(grid){
48044 var cid = this.grid.getGridEl().id;
48045 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
48046 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
48047 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
48048 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
48051 getColumnRenderers : function(){
48052 var renderers = [];
48053 var cm = this.grid.colModel;
48054 var colCount = cm.getColumnCount();
48055 for(var i = 0; i < colCount; i++){
48056 renderers[i] = cm.getRenderer(i);
48061 getColumnIds : function(){
48063 var cm = this.grid.colModel;
48064 var colCount = cm.getColumnCount();
48065 for(var i = 0; i < colCount; i++){
48066 ids[i] = cm.getColumnId(i);
48071 getDataIndexes : function(){
48072 if(!this.indexMap){
48073 this.indexMap = this.buildIndexMap();
48075 return this.indexMap.colToData;
48078 getColumnIndexByDataIndex : function(dataIndex){
48079 if(!this.indexMap){
48080 this.indexMap = this.buildIndexMap();
48082 return this.indexMap.dataToCol[dataIndex];
48086 * Set a css style for a column dynamically.
48087 * @param {Number} colIndex The index of the column
48088 * @param {String} name The css property name
48089 * @param {String} value The css value
48091 setCSSStyle : function(colIndex, name, value){
48092 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
48093 Roo.util.CSS.updateRule(selector, name, value);
48096 generateRules : function(cm){
48097 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
48098 Roo.util.CSS.removeStyleSheet(rulesId);
48099 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48100 var cid = cm.getColumnId(i);
48101 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
48102 this.tdSelector, cid, " {\n}\n",
48103 this.hdSelector, cid, " {\n}\n",
48104 this.splitSelector, cid, " {\n}\n");
48106 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
48110 * Ext JS Library 1.1.1
48111 * Copyright(c) 2006-2007, Ext JS, LLC.
48113 * Originally Released Under LGPL - original licence link has changed is not relivant.
48116 * <script type="text/javascript">
48120 // This is a support class used internally by the Grid components
48121 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
48123 this.view = grid.getView();
48124 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
48125 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
48127 this.setHandleElId(Roo.id(hd));
48128 this.setOuterHandleElId(Roo.id(hd2));
48130 this.scroll = false;
48132 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
48134 getDragData : function(e){
48135 var t = Roo.lib.Event.getTarget(e);
48136 var h = this.view.findHeaderCell(t);
48138 return {ddel: h.firstChild, header:h};
48143 onInitDrag : function(e){
48144 this.view.headersDisabled = true;
48145 var clone = this.dragData.ddel.cloneNode(true);
48146 clone.id = Roo.id();
48147 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
48148 this.proxy.update(clone);
48152 afterValidDrop : function(){
48154 setTimeout(function(){
48155 v.headersDisabled = false;
48159 afterInvalidDrop : function(){
48161 setTimeout(function(){
48162 v.headersDisabled = false;
48168 * Ext JS Library 1.1.1
48169 * Copyright(c) 2006-2007, Ext JS, LLC.
48171 * Originally Released Under LGPL - original licence link has changed is not relivant.
48174 * <script type="text/javascript">
48177 // This is a support class used internally by the Grid components
48178 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
48180 this.view = grid.getView();
48181 // split the proxies so they don't interfere with mouse events
48182 this.proxyTop = Roo.DomHelper.append(document.body, {
48183 cls:"col-move-top", html:" "
48185 this.proxyBottom = Roo.DomHelper.append(document.body, {
48186 cls:"col-move-bottom", html:" "
48188 this.proxyTop.hide = this.proxyBottom.hide = function(){
48189 this.setLeftTop(-100,-100);
48190 this.setStyle("visibility", "hidden");
48192 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
48193 // temporarily disabled
48194 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
48195 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
48197 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
48198 proxyOffsets : [-4, -9],
48199 fly: Roo.Element.fly,
48201 getTargetFromEvent : function(e){
48202 var t = Roo.lib.Event.getTarget(e);
48203 var cindex = this.view.findCellIndex(t);
48204 if(cindex !== false){
48205 return this.view.getHeaderCell(cindex);
48210 nextVisible : function(h){
48211 var v = this.view, cm = this.grid.colModel;
48214 if(!cm.isHidden(v.getCellIndex(h))){
48222 prevVisible : function(h){
48223 var v = this.view, cm = this.grid.colModel;
48226 if(!cm.isHidden(v.getCellIndex(h))){
48234 positionIndicator : function(h, n, e){
48235 var x = Roo.lib.Event.getPageX(e);
48236 var r = Roo.lib.Dom.getRegion(n.firstChild);
48237 var px, pt, py = r.top + this.proxyOffsets[1];
48238 if((r.right - x) <= (r.right-r.left)/2){
48239 px = r.right+this.view.borderWidth;
48245 var oldIndex = this.view.getCellIndex(h);
48246 var newIndex = this.view.getCellIndex(n);
48248 if(this.grid.colModel.isFixed(newIndex)){
48252 var locked = this.grid.colModel.isLocked(newIndex);
48257 if(oldIndex < newIndex){
48260 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
48263 px += this.proxyOffsets[0];
48264 this.proxyTop.setLeftTop(px, py);
48265 this.proxyTop.show();
48266 if(!this.bottomOffset){
48267 this.bottomOffset = this.view.mainHd.getHeight();
48269 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
48270 this.proxyBottom.show();
48274 onNodeEnter : function(n, dd, e, data){
48275 if(data.header != n){
48276 this.positionIndicator(data.header, n, e);
48280 onNodeOver : function(n, dd, e, data){
48281 var result = false;
48282 if(data.header != n){
48283 result = this.positionIndicator(data.header, n, e);
48286 this.proxyTop.hide();
48287 this.proxyBottom.hide();
48289 return result ? this.dropAllowed : this.dropNotAllowed;
48292 onNodeOut : function(n, dd, e, data){
48293 this.proxyTop.hide();
48294 this.proxyBottom.hide();
48297 onNodeDrop : function(n, dd, e, data){
48298 var h = data.header;
48300 var cm = this.grid.colModel;
48301 var x = Roo.lib.Event.getPageX(e);
48302 var r = Roo.lib.Dom.getRegion(n.firstChild);
48303 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
48304 var oldIndex = this.view.getCellIndex(h);
48305 var newIndex = this.view.getCellIndex(n);
48306 var locked = cm.isLocked(newIndex);
48310 if(oldIndex < newIndex){
48313 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
48316 cm.setLocked(oldIndex, locked, true);
48317 cm.moveColumn(oldIndex, newIndex);
48318 this.grid.fireEvent("columnmove", oldIndex, newIndex);
48326 * Ext JS Library 1.1.1
48327 * Copyright(c) 2006-2007, Ext JS, LLC.
48329 * Originally Released Under LGPL - original licence link has changed is not relivant.
48332 * <script type="text/javascript">
48336 * @class Roo.grid.GridView
48337 * @extends Roo.util.Observable
48340 * @param {Object} config
48342 Roo.grid.GridView = function(config){
48343 Roo.grid.GridView.superclass.constructor.call(this);
48346 Roo.apply(this, config);
48349 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
48352 * Override this function to apply custom css classes to rows during rendering
48353 * @param {Record} record The record
48354 * @param {Number} index
48355 * @method getRowClass
48357 rowClass : "x-grid-row",
48359 cellClass : "x-grid-col",
48361 tdClass : "x-grid-td",
48363 hdClass : "x-grid-hd",
48365 splitClass : "x-grid-split",
48367 sortClasses : ["sort-asc", "sort-desc"],
48369 enableMoveAnim : false,
48373 dh : Roo.DomHelper,
48375 fly : Roo.Element.fly,
48377 css : Roo.util.CSS,
48383 scrollIncrement : 22,
48385 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
48387 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
48389 bind : function(ds, cm){
48391 this.ds.un("load", this.onLoad, this);
48392 this.ds.un("datachanged", this.onDataChange, this);
48393 this.ds.un("add", this.onAdd, this);
48394 this.ds.un("remove", this.onRemove, this);
48395 this.ds.un("update", this.onUpdate, this);
48396 this.ds.un("clear", this.onClear, this);
48399 ds.on("load", this.onLoad, this);
48400 ds.on("datachanged", this.onDataChange, this);
48401 ds.on("add", this.onAdd, this);
48402 ds.on("remove", this.onRemove, this);
48403 ds.on("update", this.onUpdate, this);
48404 ds.on("clear", this.onClear, this);
48409 this.cm.un("widthchange", this.onColWidthChange, this);
48410 this.cm.un("headerchange", this.onHeaderChange, this);
48411 this.cm.un("hiddenchange", this.onHiddenChange, this);
48412 this.cm.un("columnmoved", this.onColumnMove, this);
48413 this.cm.un("columnlockchange", this.onColumnLock, this);
48416 this.generateRules(cm);
48417 cm.on("widthchange", this.onColWidthChange, this);
48418 cm.on("headerchange", this.onHeaderChange, this);
48419 cm.on("hiddenchange", this.onHiddenChange, this);
48420 cm.on("columnmoved", this.onColumnMove, this);
48421 cm.on("columnlockchange", this.onColumnLock, this);
48426 init: function(grid){
48427 Roo.grid.GridView.superclass.init.call(this, grid);
48429 this.bind(grid.dataSource, grid.colModel);
48431 grid.on("headerclick", this.handleHeaderClick, this);
48433 if(grid.trackMouseOver){
48434 grid.on("mouseover", this.onRowOver, this);
48435 grid.on("mouseout", this.onRowOut, this);
48437 grid.cancelTextSelection = function(){};
48438 this.gridId = grid.id;
48440 var tpls = this.templates || {};
48443 tpls.master = new Roo.Template(
48444 '<div class="x-grid" hidefocus="true">',
48445 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
48446 '<div class="x-grid-topbar"></div>',
48447 '<div class="x-grid-scroller"><div></div></div>',
48448 '<div class="x-grid-locked">',
48449 '<div class="x-grid-header">{lockedHeader}</div>',
48450 '<div class="x-grid-body">{lockedBody}</div>',
48452 '<div class="x-grid-viewport">',
48453 '<div class="x-grid-header">{header}</div>',
48454 '<div class="x-grid-body">{body}</div>',
48456 '<div class="x-grid-bottombar"></div>',
48458 '<div class="x-grid-resize-proxy"> </div>',
48461 tpls.master.disableformats = true;
48465 tpls.header = new Roo.Template(
48466 '<table border="0" cellspacing="0" cellpadding="0">',
48467 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
48470 tpls.header.disableformats = true;
48472 tpls.header.compile();
48475 tpls.hcell = new Roo.Template(
48476 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
48477 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
48480 tpls.hcell.disableFormats = true;
48482 tpls.hcell.compile();
48485 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
48486 tpls.hsplit.disableFormats = true;
48488 tpls.hsplit.compile();
48491 tpls.body = new Roo.Template(
48492 '<table border="0" cellspacing="0" cellpadding="0">',
48493 "<tbody>{rows}</tbody>",
48496 tpls.body.disableFormats = true;
48498 tpls.body.compile();
48501 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
48502 tpls.row.disableFormats = true;
48504 tpls.row.compile();
48507 tpls.cell = new Roo.Template(
48508 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
48509 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
48512 tpls.cell.disableFormats = true;
48514 tpls.cell.compile();
48516 this.templates = tpls;
48519 // remap these for backwards compat
48520 onColWidthChange : function(){
48521 this.updateColumns.apply(this, arguments);
48523 onHeaderChange : function(){
48524 this.updateHeaders.apply(this, arguments);
48526 onHiddenChange : function(){
48527 this.handleHiddenChange.apply(this, arguments);
48529 onColumnMove : function(){
48530 this.handleColumnMove.apply(this, arguments);
48532 onColumnLock : function(){
48533 this.handleLockChange.apply(this, arguments);
48536 onDataChange : function(){
48538 this.updateHeaderSortState();
48541 onClear : function(){
48545 onUpdate : function(ds, record){
48546 this.refreshRow(record);
48549 refreshRow : function(record){
48550 var ds = this.ds, index;
48551 if(typeof record == 'number'){
48553 record = ds.getAt(index);
48555 index = ds.indexOf(record);
48557 this.insertRows(ds, index, index, true);
48558 this.onRemove(ds, record, index+1, true);
48559 this.syncRowHeights(index, index);
48561 this.fireEvent("rowupdated", this, index, record);
48564 onAdd : function(ds, records, index){
48565 this.insertRows(ds, index, index + (records.length-1));
48568 onRemove : function(ds, record, index, isUpdate){
48569 if(isUpdate !== true){
48570 this.fireEvent("beforerowremoved", this, index, record);
48572 var bt = this.getBodyTable(), lt = this.getLockedTable();
48573 if(bt.rows[index]){
48574 bt.firstChild.removeChild(bt.rows[index]);
48576 if(lt.rows[index]){
48577 lt.firstChild.removeChild(lt.rows[index]);
48579 if(isUpdate !== true){
48580 this.stripeRows(index);
48581 this.syncRowHeights(index, index);
48583 this.fireEvent("rowremoved", this, index, record);
48587 onLoad : function(){
48588 this.scrollToTop();
48592 * Scrolls the grid to the top
48594 scrollToTop : function(){
48596 this.scroller.dom.scrollTop = 0;
48602 * Gets a panel in the header of the grid that can be used for toolbars etc.
48603 * After modifying the contents of this panel a call to grid.autoSize() may be
48604 * required to register any changes in size.
48605 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
48606 * @return Roo.Element
48608 getHeaderPanel : function(doShow){
48610 this.headerPanel.show();
48612 return this.headerPanel;
48616 * Gets a panel in the footer of the grid that can be used for toolbars etc.
48617 * After modifying the contents of this panel a call to grid.autoSize() may be
48618 * required to register any changes in size.
48619 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
48620 * @return Roo.Element
48622 getFooterPanel : function(doShow){
48624 this.footerPanel.show();
48626 return this.footerPanel;
48629 initElements : function(){
48630 var E = Roo.Element;
48631 var el = this.grid.getGridEl().dom.firstChild;
48632 var cs = el.childNodes;
48634 this.el = new E(el);
48636 this.focusEl = new E(el.firstChild);
48637 this.focusEl.swallowEvent("click", true);
48639 this.headerPanel = new E(cs[1]);
48640 this.headerPanel.enableDisplayMode("block");
48642 this.scroller = new E(cs[2]);
48643 this.scrollSizer = new E(this.scroller.dom.firstChild);
48645 this.lockedWrap = new E(cs[3]);
48646 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
48647 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
48649 this.mainWrap = new E(cs[4]);
48650 this.mainHd = new E(this.mainWrap.dom.firstChild);
48651 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
48653 this.footerPanel = new E(cs[5]);
48654 this.footerPanel.enableDisplayMode("block");
48656 this.resizeProxy = new E(cs[6]);
48658 this.headerSelector = String.format(
48659 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
48660 this.lockedHd.id, this.mainHd.id
48663 this.splitterSelector = String.format(
48664 '#{0} div.x-grid-split, #{1} div.x-grid-split',
48665 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
48668 idToCssName : function(s)
48670 return s.replace(/[^a-z0-9]+/ig, '-');
48673 getHeaderCell : function(index){
48674 return Roo.DomQuery.select(this.headerSelector)[index];
48677 getHeaderCellMeasure : function(index){
48678 return this.getHeaderCell(index).firstChild;
48681 getHeaderCellText : function(index){
48682 return this.getHeaderCell(index).firstChild.firstChild;
48685 getLockedTable : function(){
48686 return this.lockedBody.dom.firstChild;
48689 getBodyTable : function(){
48690 return this.mainBody.dom.firstChild;
48693 getLockedRow : function(index){
48694 return this.getLockedTable().rows[index];
48697 getRow : function(index){
48698 return this.getBodyTable().rows[index];
48701 getRowComposite : function(index){
48703 this.rowEl = new Roo.CompositeElementLite();
48705 var els = [], lrow, mrow;
48706 if(lrow = this.getLockedRow(index)){
48709 if(mrow = this.getRow(index)){
48712 this.rowEl.elements = els;
48716 * Gets the 'td' of the cell
48718 * @param {Integer} rowIndex row to select
48719 * @param {Integer} colIndex column to select
48723 getCell : function(rowIndex, colIndex){
48724 var locked = this.cm.getLockedCount();
48726 if(colIndex < locked){
48727 source = this.lockedBody.dom.firstChild;
48729 source = this.mainBody.dom.firstChild;
48730 colIndex -= locked;
48732 return source.rows[rowIndex].childNodes[colIndex];
48735 getCellText : function(rowIndex, colIndex){
48736 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
48739 getCellBox : function(cell){
48740 var b = this.fly(cell).getBox();
48741 if(Roo.isOpera){ // opera fails to report the Y
48742 b.y = cell.offsetTop + this.mainBody.getY();
48747 getCellIndex : function(cell){
48748 var id = String(cell.className).match(this.cellRE);
48750 return parseInt(id[1], 10);
48755 findHeaderIndex : function(n){
48756 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
48757 return r ? this.getCellIndex(r) : false;
48760 findHeaderCell : function(n){
48761 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
48762 return r ? r : false;
48765 findRowIndex : function(n){
48769 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
48770 return r ? r.rowIndex : false;
48773 findCellIndex : function(node){
48774 var stop = this.el.dom;
48775 while(node && node != stop){
48776 if(this.findRE.test(node.className)){
48777 return this.getCellIndex(node);
48779 node = node.parentNode;
48784 getColumnId : function(index){
48785 return this.cm.getColumnId(index);
48788 getSplitters : function()
48790 if(this.splitterSelector){
48791 return Roo.DomQuery.select(this.splitterSelector);
48797 getSplitter : function(index){
48798 return this.getSplitters()[index];
48801 onRowOver : function(e, t){
48803 if((row = this.findRowIndex(t)) !== false){
48804 this.getRowComposite(row).addClass("x-grid-row-over");
48808 onRowOut : function(e, t){
48810 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
48811 this.getRowComposite(row).removeClass("x-grid-row-over");
48815 renderHeaders : function(){
48817 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
48818 var cb = [], lb = [], sb = [], lsb = [], p = {};
48819 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48820 p.cellId = "x-grid-hd-0-" + i;
48821 p.splitId = "x-grid-csplit-0-" + i;
48822 p.id = cm.getColumnId(i);
48823 p.title = cm.getColumnTooltip(i) || "";
48824 p.value = cm.getColumnHeader(i) || "";
48825 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
48826 if(!cm.isLocked(i)){
48827 cb[cb.length] = ct.apply(p);
48828 sb[sb.length] = st.apply(p);
48830 lb[lb.length] = ct.apply(p);
48831 lsb[lsb.length] = st.apply(p);
48834 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
48835 ht.apply({cells: cb.join(""), splits:sb.join("")})];
48838 updateHeaders : function(){
48839 var html = this.renderHeaders();
48840 this.lockedHd.update(html[0]);
48841 this.mainHd.update(html[1]);
48845 * Focuses the specified row.
48846 * @param {Number} row The row index
48848 focusRow : function(row)
48850 //Roo.log('GridView.focusRow');
48851 var x = this.scroller.dom.scrollLeft;
48852 this.focusCell(row, 0, false);
48853 this.scroller.dom.scrollLeft = x;
48857 * Focuses the specified cell.
48858 * @param {Number} row The row index
48859 * @param {Number} col The column index
48860 * @param {Boolean} hscroll false to disable horizontal scrolling
48862 focusCell : function(row, col, hscroll)
48864 //Roo.log('GridView.focusCell');
48865 var el = this.ensureVisible(row, col, hscroll);
48866 this.focusEl.alignTo(el, "tl-tl");
48868 this.focusEl.focus();
48870 this.focusEl.focus.defer(1, this.focusEl);
48875 * Scrolls the specified cell into view
48876 * @param {Number} row The row index
48877 * @param {Number} col The column index
48878 * @param {Boolean} hscroll false to disable horizontal scrolling
48880 ensureVisible : function(row, col, hscroll)
48882 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
48883 //return null; //disable for testing.
48884 if(typeof row != "number"){
48885 row = row.rowIndex;
48887 if(row < 0 && row >= this.ds.getCount()){
48890 col = (col !== undefined ? col : 0);
48891 var cm = this.grid.colModel;
48892 while(cm.isHidden(col)){
48896 var el = this.getCell(row, col);
48900 var c = this.scroller.dom;
48902 var ctop = parseInt(el.offsetTop, 10);
48903 var cleft = parseInt(el.offsetLeft, 10);
48904 var cbot = ctop + el.offsetHeight;
48905 var cright = cleft + el.offsetWidth;
48907 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
48908 var stop = parseInt(c.scrollTop, 10);
48909 var sleft = parseInt(c.scrollLeft, 10);
48910 var sbot = stop + ch;
48911 var sright = sleft + c.clientWidth;
48913 Roo.log('GridView.ensureVisible:' +
48915 ' c.clientHeight:' + c.clientHeight +
48916 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
48924 c.scrollTop = ctop;
48925 //Roo.log("set scrolltop to ctop DISABLE?");
48926 }else if(cbot > sbot){
48927 //Roo.log("set scrolltop to cbot-ch");
48928 c.scrollTop = cbot-ch;
48931 if(hscroll !== false){
48933 c.scrollLeft = cleft;
48934 }else if(cright > sright){
48935 c.scrollLeft = cright-c.clientWidth;
48942 updateColumns : function(){
48943 this.grid.stopEditing();
48944 var cm = this.grid.colModel, colIds = this.getColumnIds();
48945 //var totalWidth = cm.getTotalWidth();
48947 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48948 //if(cm.isHidden(i)) continue;
48949 var w = cm.getColumnWidth(i);
48950 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48951 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48953 this.updateSplitters();
48956 generateRules : function(cm){
48957 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
48958 Roo.util.CSS.removeStyleSheet(rulesId);
48959 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48960 var cid = cm.getColumnId(i);
48962 if(cm.config[i].align){
48963 align = 'text-align:'+cm.config[i].align+';';
48966 if(cm.isHidden(i)){
48967 hidden = 'display:none;';
48969 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
48971 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
48972 this.hdSelector, cid, " {\n", align, width, "}\n",
48973 this.tdSelector, cid, " {\n",hidden,"\n}\n",
48974 this.splitSelector, cid, " {\n", hidden , "\n}\n");
48976 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
48979 updateSplitters : function(){
48980 var cm = this.cm, s = this.getSplitters();
48981 if(s){ // splitters not created yet
48982 var pos = 0, locked = true;
48983 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48984 if(cm.isHidden(i)) continue;
48985 var w = cm.getColumnWidth(i); // make sure it's a number
48986 if(!cm.isLocked(i) && locked){
48991 s[i].style.left = (pos-this.splitOffset) + "px";
48996 handleHiddenChange : function(colModel, colIndex, hidden){
48998 this.hideColumn(colIndex);
49000 this.unhideColumn(colIndex);
49004 hideColumn : function(colIndex){
49005 var cid = this.getColumnId(colIndex);
49006 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
49007 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
49009 this.updateHeaders();
49011 this.updateSplitters();
49015 unhideColumn : function(colIndex){
49016 var cid = this.getColumnId(colIndex);
49017 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
49018 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
49021 this.updateHeaders();
49023 this.updateSplitters();
49027 insertRows : function(dm, firstRow, lastRow, isUpdate){
49028 if(firstRow == 0 && lastRow == dm.getCount()-1){
49032 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
49034 var s = this.getScrollState();
49035 var markup = this.renderRows(firstRow, lastRow);
49036 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
49037 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
49038 this.restoreScroll(s);
49040 this.fireEvent("rowsinserted", this, firstRow, lastRow);
49041 this.syncRowHeights(firstRow, lastRow);
49042 this.stripeRows(firstRow);
49048 bufferRows : function(markup, target, index){
49049 var before = null, trows = target.rows, tbody = target.tBodies[0];
49050 if(index < trows.length){
49051 before = trows[index];
49053 var b = document.createElement("div");
49054 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
49055 var rows = b.firstChild.rows;
49056 for(var i = 0, len = rows.length; i < len; i++){
49058 tbody.insertBefore(rows[0], before);
49060 tbody.appendChild(rows[0]);
49067 deleteRows : function(dm, firstRow, lastRow){
49068 if(dm.getRowCount()<1){
49069 this.fireEvent("beforerefresh", this);
49070 this.mainBody.update("");
49071 this.lockedBody.update("");
49072 this.fireEvent("refresh", this);
49074 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
49075 var bt = this.getBodyTable();
49076 var tbody = bt.firstChild;
49077 var rows = bt.rows;
49078 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
49079 tbody.removeChild(rows[firstRow]);
49081 this.stripeRows(firstRow);
49082 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
49086 updateRows : function(dataSource, firstRow, lastRow){
49087 var s = this.getScrollState();
49089 this.restoreScroll(s);
49092 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
49096 this.updateHeaderSortState();
49099 getScrollState : function(){
49101 var sb = this.scroller.dom;
49102 return {left: sb.scrollLeft, top: sb.scrollTop};
49105 stripeRows : function(startRow){
49106 if(!this.grid.stripeRows || this.ds.getCount() < 1){
49109 startRow = startRow || 0;
49110 var rows = this.getBodyTable().rows;
49111 var lrows = this.getLockedTable().rows;
49112 var cls = ' x-grid-row-alt ';
49113 for(var i = startRow, len = rows.length; i < len; i++){
49114 var row = rows[i], lrow = lrows[i];
49115 var isAlt = ((i+1) % 2 == 0);
49116 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
49117 if(isAlt == hasAlt){
49121 row.className += " x-grid-row-alt";
49123 row.className = row.className.replace("x-grid-row-alt", "");
49126 lrow.className = row.className;
49131 restoreScroll : function(state){
49132 //Roo.log('GridView.restoreScroll');
49133 var sb = this.scroller.dom;
49134 sb.scrollLeft = state.left;
49135 sb.scrollTop = state.top;
49139 syncScroll : function(){
49140 //Roo.log('GridView.syncScroll');
49141 var sb = this.scroller.dom;
49142 var sh = this.mainHd.dom;
49143 var bs = this.mainBody.dom;
49144 var lv = this.lockedBody.dom;
49145 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
49146 lv.scrollTop = bs.scrollTop = sb.scrollTop;
49149 handleScroll : function(e){
49151 var sb = this.scroller.dom;
49152 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
49156 handleWheel : function(e){
49157 var d = e.getWheelDelta();
49158 this.scroller.dom.scrollTop -= d*22;
49159 // set this here to prevent jumpy scrolling on large tables
49160 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
49164 renderRows : function(startRow, endRow){
49165 // pull in all the crap needed to render rows
49166 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
49167 var colCount = cm.getColumnCount();
49169 if(ds.getCount() < 1){
49173 // build a map for all the columns
49175 for(var i = 0; i < colCount; i++){
49176 var name = cm.getDataIndex(i);
49178 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
49179 renderer : cm.getRenderer(i),
49180 id : cm.getColumnId(i),
49181 locked : cm.isLocked(i)
49185 startRow = startRow || 0;
49186 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
49188 // records to render
49189 var rs = ds.getRange(startRow, endRow);
49191 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
49194 // As much as I hate to duplicate code, this was branched because FireFox really hates
49195 // [].join("") on strings. The performance difference was substantial enough to
49196 // branch this function
49197 doRender : Roo.isGecko ?
49198 function(cs, rs, ds, startRow, colCount, stripe){
49199 var ts = this.templates, ct = ts.cell, rt = ts.row;
49201 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
49203 var hasListener = this.grid.hasListener('rowclass');
49205 for(var j = 0, len = rs.length; j < len; j++){
49206 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
49207 for(var i = 0; i < colCount; i++){
49209 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
49211 p.css = p.attr = "";
49212 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
49213 if(p.value == undefined || p.value === "") p.value = " ";
49214 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
49215 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
49217 var markup = ct.apply(p);
49225 if(stripe && ((rowIndex+1) % 2 == 0)){
49226 alt.push("x-grid-row-alt")
49229 alt.push( " x-grid-dirty-row");
49232 if(this.getRowClass){
49233 alt.push(this.getRowClass(r, rowIndex));
49239 rowIndex : rowIndex,
49242 this.grid.fireEvent('rowclass', this, rowcfg);
49243 alt.push(rowcfg.rowClass);
49245 rp.alt = alt.join(" ");
49246 lbuf+= rt.apply(rp);
49248 buf+= rt.apply(rp);
49250 return [lbuf, buf];
49252 function(cs, rs, ds, startRow, colCount, stripe){
49253 var ts = this.templates, ct = ts.cell, rt = ts.row;
49255 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
49256 var hasListener = this.grid.hasListener('rowclass');
49258 for(var j = 0, len = rs.length; j < len; j++){
49259 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
49260 for(var i = 0; i < colCount; i++){
49262 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
49264 p.css = p.attr = "";
49265 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
49266 if(p.value == undefined || p.value === "") p.value = " ";
49267 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
49268 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
49270 var markup = ct.apply(p);
49272 cb[cb.length] = markup;
49274 lcb[lcb.length] = markup;
49278 if(stripe && ((rowIndex+1) % 2 == 0)){
49279 alt.push( "x-grid-row-alt");
49282 alt.push(" x-grid-dirty-row");
49285 if(this.getRowClass){
49286 alt.push( this.getRowClass(r, rowIndex));
49292 rowIndex : rowIndex,
49295 this.grid.fireEvent('rowclass', this, rowcfg);
49296 alt.push(rowcfg.rowClass);
49298 rp.alt = alt.join(" ");
49299 rp.cells = lcb.join("");
49300 lbuf[lbuf.length] = rt.apply(rp);
49301 rp.cells = cb.join("");
49302 buf[buf.length] = rt.apply(rp);
49304 return [lbuf.join(""), buf.join("")];
49307 renderBody : function(){
49308 var markup = this.renderRows();
49309 var bt = this.templates.body;
49310 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
49314 * Refreshes the grid
49315 * @param {Boolean} headersToo
49317 refresh : function(headersToo){
49318 this.fireEvent("beforerefresh", this);
49319 this.grid.stopEditing();
49320 var result = this.renderBody();
49321 this.lockedBody.update(result[0]);
49322 this.mainBody.update(result[1]);
49323 if(headersToo === true){
49324 this.updateHeaders();
49325 this.updateColumns();
49326 this.updateSplitters();
49327 this.updateHeaderSortState();
49329 this.syncRowHeights();
49331 this.fireEvent("refresh", this);
49334 handleColumnMove : function(cm, oldIndex, newIndex){
49335 this.indexMap = null;
49336 var s = this.getScrollState();
49337 this.refresh(true);
49338 this.restoreScroll(s);
49339 this.afterMove(newIndex);
49342 afterMove : function(colIndex){
49343 if(this.enableMoveAnim && Roo.enableFx){
49344 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
49346 // if multisort - fix sortOrder, and reload..
49347 if (this.grid.dataSource.multiSort) {
49348 // the we can call sort again..
49349 var dm = this.grid.dataSource;
49350 var cm = this.grid.colModel;
49352 for(var i = 0; i < cm.config.length; i++ ) {
49354 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
49355 continue; // dont' bother, it's not in sort list or being set.
49358 so.push(cm.config[i].dataIndex);
49361 dm.load(dm.lastOptions);
49368 updateCell : function(dm, rowIndex, dataIndex){
49369 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
49370 if(typeof colIndex == "undefined"){ // not present in grid
49373 var cm = this.grid.colModel;
49374 var cell = this.getCell(rowIndex, colIndex);
49375 var cellText = this.getCellText(rowIndex, colIndex);
49378 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
49379 id : cm.getColumnId(colIndex),
49380 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
49382 var renderer = cm.getRenderer(colIndex);
49383 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
49384 if(typeof val == "undefined" || val === "") val = " ";
49385 cellText.innerHTML = val;
49386 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
49387 this.syncRowHeights(rowIndex, rowIndex);
49390 calcColumnWidth : function(colIndex, maxRowsToMeasure){
49392 if(this.grid.autoSizeHeaders){
49393 var h = this.getHeaderCellMeasure(colIndex);
49394 maxWidth = Math.max(maxWidth, h.scrollWidth);
49397 if(this.cm.isLocked(colIndex)){
49398 tb = this.getLockedTable();
49401 tb = this.getBodyTable();
49402 index = colIndex - this.cm.getLockedCount();
49405 var rows = tb.rows;
49406 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
49407 for(var i = 0; i < stopIndex; i++){
49408 var cell = rows[i].childNodes[index].firstChild;
49409 maxWidth = Math.max(maxWidth, cell.scrollWidth);
49412 return maxWidth + /*margin for error in IE*/ 5;
49415 * Autofit a column to its content.
49416 * @param {Number} colIndex
49417 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
49419 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
49420 if(this.cm.isHidden(colIndex)){
49421 return; // can't calc a hidden column
49424 var cid = this.cm.getColumnId(colIndex);
49425 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
49426 if(this.grid.autoSizeHeaders){
49427 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
49430 var newWidth = this.calcColumnWidth(colIndex);
49431 this.cm.setColumnWidth(colIndex,
49432 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
49433 if(!suppressEvent){
49434 this.grid.fireEvent("columnresize", colIndex, newWidth);
49439 * Autofits all columns to their content and then expands to fit any extra space in the grid
49441 autoSizeColumns : function(){
49442 var cm = this.grid.colModel;
49443 var colCount = cm.getColumnCount();
49444 for(var i = 0; i < colCount; i++){
49445 this.autoSizeColumn(i, true, true);
49447 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
49450 this.updateColumns();
49456 * Autofits all columns to the grid's width proportionate with their current size
49457 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
49459 fitColumns : function(reserveScrollSpace){
49460 var cm = this.grid.colModel;
49461 var colCount = cm.getColumnCount();
49465 for (i = 0; i < colCount; i++){
49466 if(!cm.isHidden(i) && !cm.isFixed(i)){
49467 w = cm.getColumnWidth(i);
49473 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
49474 if(reserveScrollSpace){
49477 var frac = (avail - cm.getTotalWidth())/width;
49478 while (cols.length){
49481 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
49483 this.updateColumns();
49487 onRowSelect : function(rowIndex){
49488 var row = this.getRowComposite(rowIndex);
49489 row.addClass("x-grid-row-selected");
49492 onRowDeselect : function(rowIndex){
49493 var row = this.getRowComposite(rowIndex);
49494 row.removeClass("x-grid-row-selected");
49497 onCellSelect : function(row, col){
49498 var cell = this.getCell(row, col);
49500 Roo.fly(cell).addClass("x-grid-cell-selected");
49504 onCellDeselect : function(row, col){
49505 var cell = this.getCell(row, col);
49507 Roo.fly(cell).removeClass("x-grid-cell-selected");
49511 updateHeaderSortState : function(){
49513 // sort state can be single { field: xxx, direction : yyy}
49514 // or { xxx=>ASC , yyy : DESC ..... }
49517 if (!this.ds.multiSort) {
49518 var state = this.ds.getSortState();
49522 mstate[state.field] = state.direction;
49523 // FIXME... - this is not used here.. but might be elsewhere..
49524 this.sortState = state;
49527 mstate = this.ds.sortToggle;
49529 //remove existing sort classes..
49531 var sc = this.sortClasses;
49532 var hds = this.el.select(this.headerSelector).removeClass(sc);
49534 for(var f in mstate) {
49536 var sortColumn = this.cm.findColumnIndex(f);
49538 if(sortColumn != -1){
49539 var sortDir = mstate[f];
49540 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
49549 handleHeaderClick : function(g, index){
49550 if(this.headersDisabled){
49553 var dm = g.dataSource, cm = g.colModel;
49554 if(!cm.isSortable(index)){
49559 if (dm.multiSort) {
49560 // update the sortOrder
49562 for(var i = 0; i < cm.config.length; i++ ) {
49564 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
49565 continue; // dont' bother, it's not in sort list or being set.
49568 so.push(cm.config[i].dataIndex);
49574 dm.sort(cm.getDataIndex(index));
49578 destroy : function(){
49580 this.colMenu.removeAll();
49581 Roo.menu.MenuMgr.unregister(this.colMenu);
49582 this.colMenu.getEl().remove();
49583 delete this.colMenu;
49586 this.hmenu.removeAll();
49587 Roo.menu.MenuMgr.unregister(this.hmenu);
49588 this.hmenu.getEl().remove();
49591 if(this.grid.enableColumnMove){
49592 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
49594 for(var dd in dds){
49595 if(!dds[dd].config.isTarget && dds[dd].dragElId){
49596 var elid = dds[dd].dragElId;
49598 Roo.get(elid).remove();
49599 } else if(dds[dd].config.isTarget){
49600 dds[dd].proxyTop.remove();
49601 dds[dd].proxyBottom.remove();
49604 if(Roo.dd.DDM.locationCache[dd]){
49605 delete Roo.dd.DDM.locationCache[dd];
49608 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
49611 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
49612 this.bind(null, null);
49613 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
49616 handleLockChange : function(){
49617 this.refresh(true);
49620 onDenyColumnLock : function(){
49624 onDenyColumnHide : function(){
49628 handleHdMenuClick : function(item){
49629 var index = this.hdCtxIndex;
49630 var cm = this.cm, ds = this.ds;
49633 ds.sort(cm.getDataIndex(index), "ASC");
49636 ds.sort(cm.getDataIndex(index), "DESC");
49639 var lc = cm.getLockedCount();
49640 if(cm.getColumnCount(true) <= lc+1){
49641 this.onDenyColumnLock();
49645 cm.setLocked(index, true, true);
49646 cm.moveColumn(index, lc);
49647 this.grid.fireEvent("columnmove", index, lc);
49649 cm.setLocked(index, true);
49653 var lc = cm.getLockedCount();
49654 if((lc-1) != index){
49655 cm.setLocked(index, false, true);
49656 cm.moveColumn(index, lc-1);
49657 this.grid.fireEvent("columnmove", index, lc-1);
49659 cm.setLocked(index, false);
49663 index = cm.getIndexById(item.id.substr(4));
49665 if(item.checked && cm.getColumnCount(true) <= 1){
49666 this.onDenyColumnHide();
49669 cm.setHidden(index, item.checked);
49675 beforeColMenuShow : function(){
49676 var cm = this.cm, colCount = cm.getColumnCount();
49677 this.colMenu.removeAll();
49678 for(var i = 0; i < colCount; i++){
49679 this.colMenu.add(new Roo.menu.CheckItem({
49680 id: "col-"+cm.getColumnId(i),
49681 text: cm.getColumnHeader(i),
49682 checked: !cm.isHidden(i),
49688 handleHdCtx : function(g, index, e){
49690 var hd = this.getHeaderCell(index);
49691 this.hdCtxIndex = index;
49692 var ms = this.hmenu.items, cm = this.cm;
49693 ms.get("asc").setDisabled(!cm.isSortable(index));
49694 ms.get("desc").setDisabled(!cm.isSortable(index));
49695 if(this.grid.enableColLock !== false){
49696 ms.get("lock").setDisabled(cm.isLocked(index));
49697 ms.get("unlock").setDisabled(!cm.isLocked(index));
49699 this.hmenu.show(hd, "tl-bl");
49702 handleHdOver : function(e){
49703 var hd = this.findHeaderCell(e.getTarget());
49704 if(hd && !this.headersDisabled){
49705 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
49706 this.fly(hd).addClass("x-grid-hd-over");
49711 handleHdOut : function(e){
49712 var hd = this.findHeaderCell(e.getTarget());
49714 this.fly(hd).removeClass("x-grid-hd-over");
49718 handleSplitDblClick : function(e, t){
49719 var i = this.getCellIndex(t);
49720 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
49721 this.autoSizeColumn(i, true);
49726 render : function(){
49729 var colCount = cm.getColumnCount();
49731 if(this.grid.monitorWindowResize === true){
49732 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
49734 var header = this.renderHeaders();
49735 var body = this.templates.body.apply({rows:""});
49736 var html = this.templates.master.apply({
49739 lockedHeader: header[0],
49743 //this.updateColumns();
49745 this.grid.getGridEl().dom.innerHTML = html;
49747 this.initElements();
49749 // a kludge to fix the random scolling effect in webkit
49750 this.el.on("scroll", function() {
49751 this.el.dom.scrollTop=0; // hopefully not recursive..
49754 this.scroller.on("scroll", this.handleScroll, this);
49755 this.lockedBody.on("mousewheel", this.handleWheel, this);
49756 this.mainBody.on("mousewheel", this.handleWheel, this);
49758 this.mainHd.on("mouseover", this.handleHdOver, this);
49759 this.mainHd.on("mouseout", this.handleHdOut, this);
49760 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
49761 {delegate: "."+this.splitClass});
49763 this.lockedHd.on("mouseover", this.handleHdOver, this);
49764 this.lockedHd.on("mouseout", this.handleHdOut, this);
49765 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
49766 {delegate: "."+this.splitClass});
49768 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
49769 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
49772 this.updateSplitters();
49774 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
49775 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
49776 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
49779 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
49780 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
49782 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
49783 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
49785 if(this.grid.enableColLock !== false){
49786 this.hmenu.add('-',
49787 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
49788 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
49791 if(this.grid.enableColumnHide !== false){
49793 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
49794 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
49795 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
49797 this.hmenu.add('-',
49798 {id:"columns", text: this.columnsText, menu: this.colMenu}
49801 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
49803 this.grid.on("headercontextmenu", this.handleHdCtx, this);
49806 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
49807 this.dd = new Roo.grid.GridDragZone(this.grid, {
49808 ddGroup : this.grid.ddGroup || 'GridDD'
49813 for(var i = 0; i < colCount; i++){
49814 if(cm.isHidden(i)){
49815 this.hideColumn(i);
49817 if(cm.config[i].align){
49818 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
49819 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
49823 this.updateHeaderSortState();
49825 this.beforeInitialResize();
49828 // two part rendering gives faster view to the user
49829 this.renderPhase2.defer(1, this);
49832 renderPhase2 : function(){
49833 // render the rows now
49835 if(this.grid.autoSizeColumns){
49836 this.autoSizeColumns();
49840 beforeInitialResize : function(){
49844 onColumnSplitterMoved : function(i, w){
49845 this.userResized = true;
49846 var cm = this.grid.colModel;
49847 cm.setColumnWidth(i, w, true);
49848 var cid = cm.getColumnId(i);
49849 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
49850 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
49851 this.updateSplitters();
49853 this.grid.fireEvent("columnresize", i, w);
49856 syncRowHeights : function(startIndex, endIndex){
49857 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
49858 startIndex = startIndex || 0;
49859 var mrows = this.getBodyTable().rows;
49860 var lrows = this.getLockedTable().rows;
49861 var len = mrows.length-1;
49862 endIndex = Math.min(endIndex || len, len);
49863 for(var i = startIndex; i <= endIndex; i++){
49864 var m = mrows[i], l = lrows[i];
49865 var h = Math.max(m.offsetHeight, l.offsetHeight);
49866 m.style.height = l.style.height = h + "px";
49871 layout : function(initialRender, is2ndPass){
49873 var auto = g.autoHeight;
49874 var scrollOffset = 16;
49875 var c = g.getGridEl(), cm = this.cm,
49876 expandCol = g.autoExpandColumn,
49878 //c.beginMeasure();
49880 if(!c.dom.offsetWidth){ // display:none?
49882 this.lockedWrap.show();
49883 this.mainWrap.show();
49888 var hasLock = this.cm.isLocked(0);
49890 var tbh = this.headerPanel.getHeight();
49891 var bbh = this.footerPanel.getHeight();
49894 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
49895 var newHeight = ch + c.getBorderWidth("tb");
49897 newHeight = Math.min(g.maxHeight, newHeight);
49899 c.setHeight(newHeight);
49903 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
49906 var s = this.scroller;
49908 var csize = c.getSize(true);
49910 this.el.setSize(csize.width, csize.height);
49912 this.headerPanel.setWidth(csize.width);
49913 this.footerPanel.setWidth(csize.width);
49915 var hdHeight = this.mainHd.getHeight();
49916 var vw = csize.width;
49917 var vh = csize.height - (tbh + bbh);
49921 var bt = this.getBodyTable();
49922 var ltWidth = hasLock ?
49923 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
49925 var scrollHeight = bt.offsetHeight;
49926 var scrollWidth = ltWidth + bt.offsetWidth;
49927 var vscroll = false, hscroll = false;
49929 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
49931 var lw = this.lockedWrap, mw = this.mainWrap;
49932 var lb = this.lockedBody, mb = this.mainBody;
49934 setTimeout(function(){
49935 var t = s.dom.offsetTop;
49936 var w = s.dom.clientWidth,
49937 h = s.dom.clientHeight;
49940 lw.setSize(ltWidth, h);
49942 mw.setLeftTop(ltWidth, t);
49943 mw.setSize(w-ltWidth, h);
49945 lb.setHeight(h-hdHeight);
49946 mb.setHeight(h-hdHeight);
49948 if(is2ndPass !== true && !gv.userResized && expandCol){
49949 // high speed resize without full column calculation
49951 var ci = cm.getIndexById(expandCol);
49953 ci = cm.findColumnIndex(expandCol);
49955 ci = Math.max(0, ci); // make sure it's got at least the first col.
49956 var expandId = cm.getColumnId(ci);
49957 var tw = cm.getTotalWidth(false);
49958 var currentWidth = cm.getColumnWidth(ci);
49959 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
49960 if(currentWidth != cw){
49961 cm.setColumnWidth(ci, cw, true);
49962 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
49963 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
49964 gv.updateSplitters();
49965 gv.layout(false, true);
49977 onWindowResize : function(){
49978 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
49984 appendFooter : function(parentEl){
49988 sortAscText : "Sort Ascending",
49989 sortDescText : "Sort Descending",
49990 lockText : "Lock Column",
49991 unlockText : "Unlock Column",
49992 columnsText : "Columns"
49996 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
49997 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
49998 this.proxy.el.addClass('x-grid3-col-dd');
50001 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
50002 handleMouseDown : function(e){
50006 callHandleMouseDown : function(e){
50007 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
50012 * Ext JS Library 1.1.1
50013 * Copyright(c) 2006-2007, Ext JS, LLC.
50015 * Originally Released Under LGPL - original licence link has changed is not relivant.
50018 * <script type="text/javascript">
50022 // This is a support class used internally by the Grid components
50023 Roo.grid.SplitDragZone = function(grid, hd, hd2){
50025 this.view = grid.getView();
50026 this.proxy = this.view.resizeProxy;
50027 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
50028 "gridSplitters" + this.grid.getGridEl().id, {
50029 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
50031 this.setHandleElId(Roo.id(hd));
50032 this.setOuterHandleElId(Roo.id(hd2));
50033 this.scroll = false;
50035 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
50036 fly: Roo.Element.fly,
50038 b4StartDrag : function(x, y){
50039 this.view.headersDisabled = true;
50040 this.proxy.setHeight(this.view.mainWrap.getHeight());
50041 var w = this.cm.getColumnWidth(this.cellIndex);
50042 var minw = Math.max(w-this.grid.minColumnWidth, 0);
50043 this.resetConstraints();
50044 this.setXConstraint(minw, 1000);
50045 this.setYConstraint(0, 0);
50046 this.minX = x - minw;
50047 this.maxX = x + 1000;
50049 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
50053 handleMouseDown : function(e){
50054 ev = Roo.EventObject.setEvent(e);
50055 var t = this.fly(ev.getTarget());
50056 if(t.hasClass("x-grid-split")){
50057 this.cellIndex = this.view.getCellIndex(t.dom);
50058 this.split = t.dom;
50059 this.cm = this.grid.colModel;
50060 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
50061 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
50066 endDrag : function(e){
50067 this.view.headersDisabled = false;
50068 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
50069 var diff = endX - this.startPos;
50070 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
50073 autoOffset : function(){
50074 this.setDelta(0,0);
50078 * Ext JS Library 1.1.1
50079 * Copyright(c) 2006-2007, Ext JS, LLC.
50081 * Originally Released Under LGPL - original licence link has changed is not relivant.
50084 * <script type="text/javascript">
50088 // This is a support class used internally by the Grid components
50089 Roo.grid.GridDragZone = function(grid, config){
50090 this.view = grid.getView();
50091 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
50092 if(this.view.lockedBody){
50093 this.setHandleElId(Roo.id(this.view.mainBody.dom));
50094 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
50096 this.scroll = false;
50098 this.ddel = document.createElement('div');
50099 this.ddel.className = 'x-grid-dd-wrap';
50102 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
50103 ddGroup : "GridDD",
50105 getDragData : function(e){
50106 var t = Roo.lib.Event.getTarget(e);
50107 var rowIndex = this.view.findRowIndex(t);
50108 if(rowIndex !== false){
50109 var sm = this.grid.selModel;
50110 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
50111 // sm.mouseDown(e, t);
50113 if (e.hasModifier()){
50114 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
50116 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
50121 onInitDrag : function(e){
50122 var data = this.dragData;
50123 this.ddel.innerHTML = this.grid.getDragDropText();
50124 this.proxy.update(this.ddel);
50125 // fire start drag?
50128 afterRepair : function(){
50129 this.dragging = false;
50132 getRepairXY : function(e, data){
50136 onEndDrag : function(data, e){
50140 onValidDrop : function(dd, e, id){
50145 beforeInvalidDrop : function(e, id){
50150 * Ext JS Library 1.1.1
50151 * Copyright(c) 2006-2007, Ext JS, LLC.
50153 * Originally Released Under LGPL - original licence link has changed is not relivant.
50156 * <script type="text/javascript">
50161 * @class Roo.grid.ColumnModel
50162 * @extends Roo.util.Observable
50163 * This is the default implementation of a ColumnModel used by the Grid. It defines
50164 * the columns in the grid.
50167 var colModel = new Roo.grid.ColumnModel([
50168 {header: "Ticker", width: 60, sortable: true, locked: true},
50169 {header: "Company Name", width: 150, sortable: true},
50170 {header: "Market Cap.", width: 100, sortable: true},
50171 {header: "$ Sales", width: 100, sortable: true, renderer: money},
50172 {header: "Employees", width: 100, sortable: true, resizable: false}
50177 * The config options listed for this class are options which may appear in each
50178 * individual column definition.
50179 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
50181 * @param {Object} config An Array of column config objects. See this class's
50182 * config objects for details.
50184 Roo.grid.ColumnModel = function(config){
50186 * The config passed into the constructor
50188 this.config = config;
50191 // if no id, create one
50192 // if the column does not have a dataIndex mapping,
50193 // map it to the order it is in the config
50194 for(var i = 0, len = config.length; i < len; i++){
50196 if(typeof c.dataIndex == "undefined"){
50199 if(typeof c.renderer == "string"){
50200 c.renderer = Roo.util.Format[c.renderer];
50202 if(typeof c.id == "undefined"){
50205 if(c.editor && c.editor.xtype){
50206 c.editor = Roo.factory(c.editor, Roo.grid);
50208 if(c.editor && c.editor.isFormField){
50209 c.editor = new Roo.grid.GridEditor(c.editor);
50211 this.lookup[c.id] = c;
50215 * The width of columns which have no width specified (defaults to 100)
50218 this.defaultWidth = 100;
50221 * Default sortable of columns which have no sortable specified (defaults to false)
50224 this.defaultSortable = false;
50228 * @event widthchange
50229 * Fires when the width of a column changes.
50230 * @param {ColumnModel} this
50231 * @param {Number} columnIndex The column index
50232 * @param {Number} newWidth The new width
50234 "widthchange": true,
50236 * @event headerchange
50237 * Fires when the text of a header changes.
50238 * @param {ColumnModel} this
50239 * @param {Number} columnIndex The column index
50240 * @param {Number} newText The new header text
50242 "headerchange": true,
50244 * @event hiddenchange
50245 * Fires when a column is hidden or "unhidden".
50246 * @param {ColumnModel} this
50247 * @param {Number} columnIndex The column index
50248 * @param {Boolean} hidden true if hidden, false otherwise
50250 "hiddenchange": true,
50252 * @event columnmoved
50253 * Fires when a column is moved.
50254 * @param {ColumnModel} this
50255 * @param {Number} oldIndex
50256 * @param {Number} newIndex
50258 "columnmoved" : true,
50260 * @event columlockchange
50261 * Fires when a column's locked state is changed
50262 * @param {ColumnModel} this
50263 * @param {Number} colIndex
50264 * @param {Boolean} locked true if locked
50266 "columnlockchange" : true
50268 Roo.grid.ColumnModel.superclass.constructor.call(this);
50270 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
50272 * @cfg {String} header The header text to display in the Grid view.
50275 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
50276 * {@link Roo.data.Record} definition from which to draw the column's value. If not
50277 * specified, the column's index is used as an index into the Record's data Array.
50280 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
50281 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
50284 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
50285 * Defaults to the value of the {@link #defaultSortable} property.
50286 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
50289 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
50292 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
50295 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
50298 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
50301 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
50302 * given the cell's data value. See {@link #setRenderer}. If not specified, the
50303 * default renderer uses the raw data value.
50306 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
50309 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
50313 * Returns the id of the column at the specified index.
50314 * @param {Number} index The column index
50315 * @return {String} the id
50317 getColumnId : function(index){
50318 return this.config[index].id;
50322 * Returns the column for a specified id.
50323 * @param {String} id The column id
50324 * @return {Object} the column
50326 getColumnById : function(id){
50327 return this.lookup[id];
50332 * Returns the column for a specified dataIndex.
50333 * @param {String} dataIndex The column dataIndex
50334 * @return {Object|Boolean} the column or false if not found
50336 getColumnByDataIndex: function(dataIndex){
50337 var index = this.findColumnIndex(dataIndex);
50338 return index > -1 ? this.config[index] : false;
50342 * Returns the index for a specified column id.
50343 * @param {String} id The column id
50344 * @return {Number} the index, or -1 if not found
50346 getIndexById : function(id){
50347 for(var i = 0, len = this.config.length; i < len; i++){
50348 if(this.config[i].id == id){
50356 * Returns the index for a specified column dataIndex.
50357 * @param {String} dataIndex The column dataIndex
50358 * @return {Number} the index, or -1 if not found
50361 findColumnIndex : function(dataIndex){
50362 for(var i = 0, len = this.config.length; i < len; i++){
50363 if(this.config[i].dataIndex == dataIndex){
50371 moveColumn : function(oldIndex, newIndex){
50372 var c = this.config[oldIndex];
50373 this.config.splice(oldIndex, 1);
50374 this.config.splice(newIndex, 0, c);
50375 this.dataMap = null;
50376 this.fireEvent("columnmoved", this, oldIndex, newIndex);
50379 isLocked : function(colIndex){
50380 return this.config[colIndex].locked === true;
50383 setLocked : function(colIndex, value, suppressEvent){
50384 if(this.isLocked(colIndex) == value){
50387 this.config[colIndex].locked = value;
50388 if(!suppressEvent){
50389 this.fireEvent("columnlockchange", this, colIndex, value);
50393 getTotalLockedWidth : function(){
50394 var totalWidth = 0;
50395 for(var i = 0; i < this.config.length; i++){
50396 if(this.isLocked(i) && !this.isHidden(i)){
50397 this.totalWidth += this.getColumnWidth(i);
50403 getLockedCount : function(){
50404 for(var i = 0, len = this.config.length; i < len; i++){
50405 if(!this.isLocked(i)){
50412 * Returns the number of columns.
50415 getColumnCount : function(visibleOnly){
50416 if(visibleOnly === true){
50418 for(var i = 0, len = this.config.length; i < len; i++){
50419 if(!this.isHidden(i)){
50425 return this.config.length;
50429 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
50430 * @param {Function} fn
50431 * @param {Object} scope (optional)
50432 * @return {Array} result
50434 getColumnsBy : function(fn, scope){
50436 for(var i = 0, len = this.config.length; i < len; i++){
50437 var c = this.config[i];
50438 if(fn.call(scope||this, c, i) === true){
50446 * Returns true if the specified column is sortable.
50447 * @param {Number} col The column index
50448 * @return {Boolean}
50450 isSortable : function(col){
50451 if(typeof this.config[col].sortable == "undefined"){
50452 return this.defaultSortable;
50454 return this.config[col].sortable;
50458 * Returns the rendering (formatting) function defined for the column.
50459 * @param {Number} col The column index.
50460 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
50462 getRenderer : function(col){
50463 if(!this.config[col].renderer){
50464 return Roo.grid.ColumnModel.defaultRenderer;
50466 return this.config[col].renderer;
50470 * Sets the rendering (formatting) function for a column.
50471 * @param {Number} col The column index
50472 * @param {Function} fn The function to use to process the cell's raw data
50473 * to return HTML markup for the grid view. The render function is called with
50474 * the following parameters:<ul>
50475 * <li>Data value.</li>
50476 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
50477 * <li>css A CSS style string to apply to the table cell.</li>
50478 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
50479 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
50480 * <li>Row index</li>
50481 * <li>Column index</li>
50482 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
50484 setRenderer : function(col, fn){
50485 this.config[col].renderer = fn;
50489 * Returns the width for the specified column.
50490 * @param {Number} col The column index
50493 getColumnWidth : function(col){
50494 return this.config[col].width * 1 || this.defaultWidth;
50498 * Sets the width for a column.
50499 * @param {Number} col The column index
50500 * @param {Number} width The new width
50502 setColumnWidth : function(col, width, suppressEvent){
50503 this.config[col].width = width;
50504 this.totalWidth = null;
50505 if(!suppressEvent){
50506 this.fireEvent("widthchange", this, col, width);
50511 * Returns the total width of all columns.
50512 * @param {Boolean} includeHidden True to include hidden column widths
50515 getTotalWidth : function(includeHidden){
50516 if(!this.totalWidth){
50517 this.totalWidth = 0;
50518 for(var i = 0, len = this.config.length; i < len; i++){
50519 if(includeHidden || !this.isHidden(i)){
50520 this.totalWidth += this.getColumnWidth(i);
50524 return this.totalWidth;
50528 * Returns the header for the specified column.
50529 * @param {Number} col The column index
50532 getColumnHeader : function(col){
50533 return this.config[col].header;
50537 * Sets the header for a column.
50538 * @param {Number} col The column index
50539 * @param {String} header The new header
50541 setColumnHeader : function(col, header){
50542 this.config[col].header = header;
50543 this.fireEvent("headerchange", this, col, header);
50547 * Returns the tooltip for the specified column.
50548 * @param {Number} col The column index
50551 getColumnTooltip : function(col){
50552 return this.config[col].tooltip;
50555 * Sets the tooltip for a column.
50556 * @param {Number} col The column index
50557 * @param {String} tooltip The new tooltip
50559 setColumnTooltip : function(col, tooltip){
50560 this.config[col].tooltip = tooltip;
50564 * Returns the dataIndex for the specified column.
50565 * @param {Number} col The column index
50568 getDataIndex : function(col){
50569 return this.config[col].dataIndex;
50573 * Sets the dataIndex for a column.
50574 * @param {Number} col The column index
50575 * @param {Number} dataIndex The new dataIndex
50577 setDataIndex : function(col, dataIndex){
50578 this.config[col].dataIndex = dataIndex;
50584 * Returns true if the cell is editable.
50585 * @param {Number} colIndex The column index
50586 * @param {Number} rowIndex The row index
50587 * @return {Boolean}
50589 isCellEditable : function(colIndex, rowIndex){
50590 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
50594 * Returns the editor defined for the cell/column.
50595 * return false or null to disable editing.
50596 * @param {Number} colIndex The column index
50597 * @param {Number} rowIndex The row index
50600 getCellEditor : function(colIndex, rowIndex){
50601 return this.config[colIndex].editor;
50605 * Sets if a column is editable.
50606 * @param {Number} col The column index
50607 * @param {Boolean} editable True if the column is editable
50609 setEditable : function(col, editable){
50610 this.config[col].editable = editable;
50615 * Returns true if the column is hidden.
50616 * @param {Number} colIndex The column index
50617 * @return {Boolean}
50619 isHidden : function(colIndex){
50620 return this.config[colIndex].hidden;
50625 * Returns true if the column width cannot be changed
50627 isFixed : function(colIndex){
50628 return this.config[colIndex].fixed;
50632 * Returns true if the column can be resized
50633 * @return {Boolean}
50635 isResizable : function(colIndex){
50636 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
50639 * Sets if a column is hidden.
50640 * @param {Number} colIndex The column index
50641 * @param {Boolean} hidden True if the column is hidden
50643 setHidden : function(colIndex, hidden){
50644 this.config[colIndex].hidden = hidden;
50645 this.totalWidth = null;
50646 this.fireEvent("hiddenchange", this, colIndex, hidden);
50650 * Sets the editor for a column.
50651 * @param {Number} col The column index
50652 * @param {Object} editor The editor object
50654 setEditor : function(col, editor){
50655 this.config[col].editor = editor;
50659 Roo.grid.ColumnModel.defaultRenderer = function(value){
50660 if(typeof value == "string" && value.length < 1){
50666 // Alias for backwards compatibility
50667 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
50670 * Ext JS Library 1.1.1
50671 * Copyright(c) 2006-2007, Ext JS, LLC.
50673 * Originally Released Under LGPL - original licence link has changed is not relivant.
50676 * <script type="text/javascript">
50680 * @class Roo.grid.AbstractSelectionModel
50681 * @extends Roo.util.Observable
50682 * Abstract base class for grid SelectionModels. It provides the interface that should be
50683 * implemented by descendant classes. This class should not be directly instantiated.
50686 Roo.grid.AbstractSelectionModel = function(){
50687 this.locked = false;
50688 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
50691 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
50692 /** @ignore Called by the grid automatically. Do not call directly. */
50693 init : function(grid){
50699 * Locks the selections.
50702 this.locked = true;
50706 * Unlocks the selections.
50708 unlock : function(){
50709 this.locked = false;
50713 * Returns true if the selections are locked.
50714 * @return {Boolean}
50716 isLocked : function(){
50717 return this.locked;
50721 * Ext JS Library 1.1.1
50722 * Copyright(c) 2006-2007, Ext JS, LLC.
50724 * Originally Released Under LGPL - original licence link has changed is not relivant.
50727 * <script type="text/javascript">
50730 * @extends Roo.grid.AbstractSelectionModel
50731 * @class Roo.grid.RowSelectionModel
50732 * The default SelectionModel used by {@link Roo.grid.Grid}.
50733 * It supports multiple selections and keyboard selection/navigation.
50735 * @param {Object} config
50737 Roo.grid.RowSelectionModel = function(config){
50738 Roo.apply(this, config);
50739 this.selections = new Roo.util.MixedCollection(false, function(o){
50744 this.lastActive = false;
50748 * @event selectionchange
50749 * Fires when the selection changes
50750 * @param {SelectionModel} this
50752 "selectionchange" : true,
50754 * @event afterselectionchange
50755 * Fires after the selection changes (eg. by key press or clicking)
50756 * @param {SelectionModel} this
50758 "afterselectionchange" : true,
50760 * @event beforerowselect
50761 * Fires when a row is selected being selected, return false to cancel.
50762 * @param {SelectionModel} this
50763 * @param {Number} rowIndex The selected index
50764 * @param {Boolean} keepExisting False if other selections will be cleared
50766 "beforerowselect" : true,
50769 * Fires when a row is selected.
50770 * @param {SelectionModel} this
50771 * @param {Number} rowIndex The selected index
50772 * @param {Roo.data.Record} r The record
50774 "rowselect" : true,
50776 * @event rowdeselect
50777 * Fires when a row is deselected.
50778 * @param {SelectionModel} this
50779 * @param {Number} rowIndex The selected index
50781 "rowdeselect" : true
50783 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
50784 this.locked = false;
50787 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
50789 * @cfg {Boolean} singleSelect
50790 * True to allow selection of only one row at a time (defaults to false)
50792 singleSelect : false,
50795 initEvents : function(){
50797 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
50798 this.grid.on("mousedown", this.handleMouseDown, this);
50799 }else{ // allow click to work like normal
50800 this.grid.on("rowclick", this.handleDragableRowClick, this);
50803 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
50804 "up" : function(e){
50806 this.selectPrevious(e.shiftKey);
50807 }else if(this.last !== false && this.lastActive !== false){
50808 var last = this.last;
50809 this.selectRange(this.last, this.lastActive-1);
50810 this.grid.getView().focusRow(this.lastActive);
50811 if(last !== false){
50815 this.selectFirstRow();
50817 this.fireEvent("afterselectionchange", this);
50819 "down" : function(e){
50821 this.selectNext(e.shiftKey);
50822 }else if(this.last !== false && this.lastActive !== false){
50823 var last = this.last;
50824 this.selectRange(this.last, this.lastActive+1);
50825 this.grid.getView().focusRow(this.lastActive);
50826 if(last !== false){
50830 this.selectFirstRow();
50832 this.fireEvent("afterselectionchange", this);
50837 var view = this.grid.view;
50838 view.on("refresh", this.onRefresh, this);
50839 view.on("rowupdated", this.onRowUpdated, this);
50840 view.on("rowremoved", this.onRemove, this);
50844 onRefresh : function(){
50845 var ds = this.grid.dataSource, i, v = this.grid.view;
50846 var s = this.selections;
50847 s.each(function(r){
50848 if((i = ds.indexOfId(r.id)) != -1){
50857 onRemove : function(v, index, r){
50858 this.selections.remove(r);
50862 onRowUpdated : function(v, index, r){
50863 if(this.isSelected(r)){
50864 v.onRowSelect(index);
50870 * @param {Array} records The records to select
50871 * @param {Boolean} keepExisting (optional) True to keep existing selections
50873 selectRecords : function(records, keepExisting){
50875 this.clearSelections();
50877 var ds = this.grid.dataSource;
50878 for(var i = 0, len = records.length; i < len; i++){
50879 this.selectRow(ds.indexOf(records[i]), true);
50884 * Gets the number of selected rows.
50887 getCount : function(){
50888 return this.selections.length;
50892 * Selects the first row in the grid.
50894 selectFirstRow : function(){
50899 * Select the last row.
50900 * @param {Boolean} keepExisting (optional) True to keep existing selections
50902 selectLastRow : function(keepExisting){
50903 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
50907 * Selects the row immediately following the last selected row.
50908 * @param {Boolean} keepExisting (optional) True to keep existing selections
50910 selectNext : function(keepExisting){
50911 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
50912 this.selectRow(this.last+1, keepExisting);
50913 this.grid.getView().focusRow(this.last);
50918 * Selects the row that precedes the last selected row.
50919 * @param {Boolean} keepExisting (optional) True to keep existing selections
50921 selectPrevious : function(keepExisting){
50923 this.selectRow(this.last-1, keepExisting);
50924 this.grid.getView().focusRow(this.last);
50929 * Returns the selected records
50930 * @return {Array} Array of selected records
50932 getSelections : function(){
50933 return [].concat(this.selections.items);
50937 * Returns the first selected record.
50940 getSelected : function(){
50941 return this.selections.itemAt(0);
50946 * Clears all selections.
50948 clearSelections : function(fast){
50949 if(this.locked) return;
50951 var ds = this.grid.dataSource;
50952 var s = this.selections;
50953 s.each(function(r){
50954 this.deselectRow(ds.indexOfId(r.id));
50958 this.selections.clear();
50965 * Selects all rows.
50967 selectAll : function(){
50968 if(this.locked) return;
50969 this.selections.clear();
50970 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
50971 this.selectRow(i, true);
50976 * Returns True if there is a selection.
50977 * @return {Boolean}
50979 hasSelection : function(){
50980 return this.selections.length > 0;
50984 * Returns True if the specified row is selected.
50985 * @param {Number/Record} record The record or index of the record to check
50986 * @return {Boolean}
50988 isSelected : function(index){
50989 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
50990 return (r && this.selections.key(r.id) ? true : false);
50994 * Returns True if the specified record id is selected.
50995 * @param {String} id The id of record to check
50996 * @return {Boolean}
50998 isIdSelected : function(id){
50999 return (this.selections.key(id) ? true : false);
51003 handleMouseDown : function(e, t){
51004 var view = this.grid.getView(), rowIndex;
51005 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
51008 if(e.shiftKey && this.last !== false){
51009 var last = this.last;
51010 this.selectRange(last, rowIndex, e.ctrlKey);
51011 this.last = last; // reset the last
51012 view.focusRow(rowIndex);
51014 var isSelected = this.isSelected(rowIndex);
51015 if(e.button !== 0 && isSelected){
51016 view.focusRow(rowIndex);
51017 }else if(e.ctrlKey && isSelected){
51018 this.deselectRow(rowIndex);
51019 }else if(!isSelected){
51020 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
51021 view.focusRow(rowIndex);
51024 this.fireEvent("afterselectionchange", this);
51027 handleDragableRowClick : function(grid, rowIndex, e)
51029 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
51030 this.selectRow(rowIndex, false);
51031 grid.view.focusRow(rowIndex);
51032 this.fireEvent("afterselectionchange", this);
51037 * Selects multiple rows.
51038 * @param {Array} rows Array of the indexes of the row to select
51039 * @param {Boolean} keepExisting (optional) True to keep existing selections
51041 selectRows : function(rows, keepExisting){
51043 this.clearSelections();
51045 for(var i = 0, len = rows.length; i < len; i++){
51046 this.selectRow(rows[i], true);
51051 * Selects a range of rows. All rows in between startRow and endRow are also selected.
51052 * @param {Number} startRow The index of the first row in the range
51053 * @param {Number} endRow The index of the last row in the range
51054 * @param {Boolean} keepExisting (optional) True to retain existing selections
51056 selectRange : function(startRow, endRow, keepExisting){
51057 if(this.locked) return;
51059 this.clearSelections();
51061 if(startRow <= endRow){
51062 for(var i = startRow; i <= endRow; i++){
51063 this.selectRow(i, true);
51066 for(var i = startRow; i >= endRow; i--){
51067 this.selectRow(i, true);
51073 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
51074 * @param {Number} startRow The index of the first row in the range
51075 * @param {Number} endRow The index of the last row in the range
51077 deselectRange : function(startRow, endRow, preventViewNotify){
51078 if(this.locked) return;
51079 for(var i = startRow; i <= endRow; i++){
51080 this.deselectRow(i, preventViewNotify);
51086 * @param {Number} row The index of the row to select
51087 * @param {Boolean} keepExisting (optional) True to keep existing selections
51089 selectRow : function(index, keepExisting, preventViewNotify){
51090 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
51091 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
51092 if(!keepExisting || this.singleSelect){
51093 this.clearSelections();
51095 var r = this.grid.dataSource.getAt(index);
51096 this.selections.add(r);
51097 this.last = this.lastActive = index;
51098 if(!preventViewNotify){
51099 this.grid.getView().onRowSelect(index);
51101 this.fireEvent("rowselect", this, index, r);
51102 this.fireEvent("selectionchange", this);
51108 * @param {Number} row The index of the row to deselect
51110 deselectRow : function(index, preventViewNotify){
51111 if(this.locked) return;
51112 if(this.last == index){
51115 if(this.lastActive == index){
51116 this.lastActive = false;
51118 var r = this.grid.dataSource.getAt(index);
51119 this.selections.remove(r);
51120 if(!preventViewNotify){
51121 this.grid.getView().onRowDeselect(index);
51123 this.fireEvent("rowdeselect", this, index);
51124 this.fireEvent("selectionchange", this);
51128 restoreLast : function(){
51130 this.last = this._last;
51135 acceptsNav : function(row, col, cm){
51136 return !cm.isHidden(col) && cm.isCellEditable(col, row);
51140 onEditorKey : function(field, e){
51141 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
51146 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
51148 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
51150 }else if(k == e.ENTER && !e.ctrlKey){
51154 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
51156 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
51158 }else if(k == e.ESC){
51162 g.startEditing(newCell[0], newCell[1]);
51167 * Ext JS Library 1.1.1
51168 * Copyright(c) 2006-2007, Ext JS, LLC.
51170 * Originally Released Under LGPL - original licence link has changed is not relivant.
51173 * <script type="text/javascript">
51176 * @class Roo.grid.CellSelectionModel
51177 * @extends Roo.grid.AbstractSelectionModel
51178 * This class provides the basic implementation for cell selection in a grid.
51180 * @param {Object} config The object containing the configuration of this model.
51181 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
51183 Roo.grid.CellSelectionModel = function(config){
51184 Roo.apply(this, config);
51186 this.selection = null;
51190 * @event beforerowselect
51191 * Fires before a cell is selected.
51192 * @param {SelectionModel} this
51193 * @param {Number} rowIndex The selected row index
51194 * @param {Number} colIndex The selected cell index
51196 "beforecellselect" : true,
51198 * @event cellselect
51199 * Fires when a cell is selected.
51200 * @param {SelectionModel} this
51201 * @param {Number} rowIndex The selected row index
51202 * @param {Number} colIndex The selected cell index
51204 "cellselect" : true,
51206 * @event selectionchange
51207 * Fires when the active selection changes.
51208 * @param {SelectionModel} this
51209 * @param {Object} selection null for no selection or an object (o) with two properties
51211 <li>o.record: the record object for the row the selection is in</li>
51212 <li>o.cell: An array of [rowIndex, columnIndex]</li>
51215 "selectionchange" : true,
51218 * Fires when the tab (or enter) was pressed on the last editable cell
51219 * You can use this to trigger add new row.
51220 * @param {SelectionModel} this
51224 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
51227 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
51229 enter_is_tab: false,
51232 initEvents : function(){
51233 this.grid.on("mousedown", this.handleMouseDown, this);
51234 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
51235 var view = this.grid.view;
51236 view.on("refresh", this.onViewChange, this);
51237 view.on("rowupdated", this.onRowUpdated, this);
51238 view.on("beforerowremoved", this.clearSelections, this);
51239 view.on("beforerowsinserted", this.clearSelections, this);
51240 if(this.grid.isEditor){
51241 this.grid.on("beforeedit", this.beforeEdit, this);
51246 beforeEdit : function(e){
51247 this.select(e.row, e.column, false, true, e.record);
51251 onRowUpdated : function(v, index, r){
51252 if(this.selection && this.selection.record == r){
51253 v.onCellSelect(index, this.selection.cell[1]);
51258 onViewChange : function(){
51259 this.clearSelections(true);
51263 * Returns the currently selected cell,.
51264 * @return {Array} The selected cell (row, column) or null if none selected.
51266 getSelectedCell : function(){
51267 return this.selection ? this.selection.cell : null;
51271 * Clears all selections.
51272 * @param {Boolean} true to prevent the gridview from being notified about the change.
51274 clearSelections : function(preventNotify){
51275 var s = this.selection;
51277 if(preventNotify !== true){
51278 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
51280 this.selection = null;
51281 this.fireEvent("selectionchange", this, null);
51286 * Returns true if there is a selection.
51287 * @return {Boolean}
51289 hasSelection : function(){
51290 return this.selection ? true : false;
51294 handleMouseDown : function(e, t){
51295 var v = this.grid.getView();
51296 if(this.isLocked()){
51299 var row = v.findRowIndex(t);
51300 var cell = v.findCellIndex(t);
51301 if(row !== false && cell !== false){
51302 this.select(row, cell);
51308 * @param {Number} rowIndex
51309 * @param {Number} collIndex
51311 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
51312 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
51313 this.clearSelections();
51314 r = r || this.grid.dataSource.getAt(rowIndex);
51317 cell : [rowIndex, colIndex]
51319 if(!preventViewNotify){
51320 var v = this.grid.getView();
51321 v.onCellSelect(rowIndex, colIndex);
51322 if(preventFocus !== true){
51323 v.focusCell(rowIndex, colIndex);
51326 this.fireEvent("cellselect", this, rowIndex, colIndex);
51327 this.fireEvent("selectionchange", this, this.selection);
51332 isSelectable : function(rowIndex, colIndex, cm){
51333 return !cm.isHidden(colIndex);
51337 handleKeyDown : function(e){
51338 //Roo.log('Cell Sel Model handleKeyDown');
51339 if(!e.isNavKeyPress()){
51342 var g = this.grid, s = this.selection;
51345 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
51347 this.select(cell[0], cell[1]);
51352 var walk = function(row, col, step){
51353 return g.walkCells(row, col, step, sm.isSelectable, sm);
51355 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
51362 // handled by onEditorKey
51363 if (g.isEditor && g.editing) {
51367 newCell = walk(r, c-1, -1);
51369 newCell = walk(r, c+1, 1);
51374 newCell = walk(r+1, c, 1);
51378 newCell = walk(r-1, c, -1);
51382 newCell = walk(r, c+1, 1);
51386 newCell = walk(r, c-1, -1);
51391 if(g.isEditor && !g.editing){
51392 g.startEditing(r, c);
51401 this.select(newCell[0], newCell[1]);
51407 acceptsNav : function(row, col, cm){
51408 return !cm.isHidden(col) && cm.isCellEditable(col, row);
51412 * @param {Number} field (not used) - as it's normally used as a listener
51413 * @param {Number} e - event - fake it by using
51415 * var e = Roo.EventObjectImpl.prototype;
51416 * e.keyCode = e.TAB
51420 onEditorKey : function(field, e){
51422 var k = e.getKey(),
51425 ed = g.activeEditor,
51427 ///Roo.log('onEditorKey' + k);
51430 if (this.enter_is_tab && k == e.ENTER) {
51436 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
51438 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
51444 }else if(k == e.ENTER && !e.ctrlKey){
51447 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
51448 }else if(k == e.ESC){
51454 //Roo.log('next cell after edit');
51455 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
51456 } else if (forward) {
51457 // tabbed past last
51458 this.fireEvent.defer(100, this, ['tabend',this]);
51463 * Ext JS Library 1.1.1
51464 * Copyright(c) 2006-2007, Ext JS, LLC.
51466 * Originally Released Under LGPL - original licence link has changed is not relivant.
51469 * <script type="text/javascript">
51473 * @class Roo.grid.EditorGrid
51474 * @extends Roo.grid.Grid
51475 * Class for creating and editable grid.
51476 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51477 * The container MUST have some type of size defined for the grid to fill. The container will be
51478 * automatically set to position relative if it isn't already.
51479 * @param {Object} dataSource The data model to bind to
51480 * @param {Object} colModel The column model with info about this grid's columns
51482 Roo.grid.EditorGrid = function(container, config){
51483 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
51484 this.getGridEl().addClass("xedit-grid");
51486 if(!this.selModel){
51487 this.selModel = new Roo.grid.CellSelectionModel();
51490 this.activeEditor = null;
51494 * @event beforeedit
51495 * Fires before cell editing is triggered. The edit event object has the following properties <br />
51496 * <ul style="padding:5px;padding-left:16px;">
51497 * <li>grid - This grid</li>
51498 * <li>record - The record being edited</li>
51499 * <li>field - The field name being edited</li>
51500 * <li>value - The value for the field being edited.</li>
51501 * <li>row - The grid row index</li>
51502 * <li>column - The grid column index</li>
51503 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
51505 * @param {Object} e An edit event (see above for description)
51507 "beforeedit" : true,
51510 * Fires after a cell is edited. <br />
51511 * <ul style="padding:5px;padding-left:16px;">
51512 * <li>grid - This grid</li>
51513 * <li>record - The record being edited</li>
51514 * <li>field - The field name being edited</li>
51515 * <li>value - The value being set</li>
51516 * <li>originalValue - The original value for the field, before the edit.</li>
51517 * <li>row - The grid row index</li>
51518 * <li>column - The grid column index</li>
51520 * @param {Object} e An edit event (see above for description)
51522 "afteredit" : true,
51524 * @event validateedit
51525 * Fires after a cell is edited, but before the value is set in the record.
51526 * You can use this to modify the value being set in the field, Return false
51527 * to cancel the change. The edit event object has the following properties <br />
51528 * <ul style="padding:5px;padding-left:16px;">
51529 * <li>editor - This editor</li>
51530 * <li>grid - This grid</li>
51531 * <li>record - The record being edited</li>
51532 * <li>field - The field name being edited</li>
51533 * <li>value - The value being set</li>
51534 * <li>originalValue - The original value for the field, before the edit.</li>
51535 * <li>row - The grid row index</li>
51536 * <li>column - The grid column index</li>
51537 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
51539 * @param {Object} e An edit event (see above for description)
51541 "validateedit" : true
51543 this.on("bodyscroll", this.stopEditing, this);
51544 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
51547 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
51549 * @cfg {Number} clicksToEdit
51550 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
51557 trackMouseOver: false, // causes very odd FF errors
51559 onCellDblClick : function(g, row, col){
51560 this.startEditing(row, col);
51563 onEditComplete : function(ed, value, startValue){
51564 this.editing = false;
51565 this.activeEditor = null;
51566 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
51568 var field = this.colModel.getDataIndex(ed.col);
51573 originalValue: startValue,
51580 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
51583 if(String(value) !== String(startValue)){
51585 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
51586 r.set(field, e.value);
51587 // if we are dealing with a combo box..
51588 // then we also set the 'name' colum to be the displayField
51589 if (ed.field.displayField && ed.field.name) {
51590 r.set(ed.field.name, ed.field.el.dom.value);
51593 delete e.cancel; //?? why!!!
51594 this.fireEvent("afteredit", e);
51597 this.fireEvent("afteredit", e); // always fire it!
51599 this.view.focusCell(ed.row, ed.col);
51603 * Starts editing the specified for the specified row/column
51604 * @param {Number} rowIndex
51605 * @param {Number} colIndex
51607 startEditing : function(row, col){
51608 this.stopEditing();
51609 if(this.colModel.isCellEditable(col, row)){
51610 this.view.ensureVisible(row, col, true);
51612 var r = this.dataSource.getAt(row);
51613 var field = this.colModel.getDataIndex(col);
51614 var cell = Roo.get(this.view.getCell(row,col));
51619 value: r.data[field],
51624 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
51625 this.editing = true;
51626 var ed = this.colModel.getCellEditor(col, row);
51632 ed.render(ed.parentEl || document.body);
51638 (function(){ // complex but required for focus issues in safari, ie and opera
51642 ed.on("complete", this.onEditComplete, this, {single: true});
51643 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
51644 this.activeEditor = ed;
51645 var v = r.data[field];
51646 ed.startEdit(this.view.getCell(row, col), v);
51647 // combo's with 'displayField and name set
51648 if (ed.field.displayField && ed.field.name) {
51649 ed.field.el.dom.value = r.data[ed.field.name];
51653 }).defer(50, this);
51659 * Stops any active editing
51661 stopEditing : function(){
51662 if(this.activeEditor){
51663 this.activeEditor.completeEdit();
51665 this.activeEditor = null;
51669 * Ext JS Library 1.1.1
51670 * Copyright(c) 2006-2007, Ext JS, LLC.
51672 * Originally Released Under LGPL - original licence link has changed is not relivant.
51675 * <script type="text/javascript">
51678 // private - not really -- you end up using it !
51679 // This is a support class used internally by the Grid components
51682 * @class Roo.grid.GridEditor
51683 * @extends Roo.Editor
51684 * Class for creating and editable grid elements.
51685 * @param {Object} config any settings (must include field)
51687 Roo.grid.GridEditor = function(field, config){
51688 if (!config && field.field) {
51690 field = Roo.factory(config.field, Roo.form);
51692 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
51693 field.monitorTab = false;
51696 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
51699 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
51702 alignment: "tl-tl",
51705 cls: "x-small-editor x-grid-editor",
51710 * Ext JS Library 1.1.1
51711 * Copyright(c) 2006-2007, Ext JS, LLC.
51713 * Originally Released Under LGPL - original licence link has changed is not relivant.
51716 * <script type="text/javascript">
51721 Roo.grid.PropertyRecord = Roo.data.Record.create([
51722 {name:'name',type:'string'}, 'value'
51726 Roo.grid.PropertyStore = function(grid, source){
51728 this.store = new Roo.data.Store({
51729 recordType : Roo.grid.PropertyRecord
51731 this.store.on('update', this.onUpdate, this);
51733 this.setSource(source);
51735 Roo.grid.PropertyStore.superclass.constructor.call(this);
51740 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
51741 setSource : function(o){
51743 this.store.removeAll();
51746 if(this.isEditableValue(o[k])){
51747 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
51750 this.store.loadRecords({records: data}, {}, true);
51753 onUpdate : function(ds, record, type){
51754 if(type == Roo.data.Record.EDIT){
51755 var v = record.data['value'];
51756 var oldValue = record.modified['value'];
51757 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
51758 this.source[record.id] = v;
51760 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
51767 getProperty : function(row){
51768 return this.store.getAt(row);
51771 isEditableValue: function(val){
51772 if(val && val instanceof Date){
51774 }else if(typeof val == 'object' || typeof val == 'function'){
51780 setValue : function(prop, value){
51781 this.source[prop] = value;
51782 this.store.getById(prop).set('value', value);
51785 getSource : function(){
51786 return this.source;
51790 Roo.grid.PropertyColumnModel = function(grid, store){
51793 g.PropertyColumnModel.superclass.constructor.call(this, [
51794 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
51795 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
51797 this.store = store;
51798 this.bselect = Roo.DomHelper.append(document.body, {
51799 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
51800 {tag: 'option', value: 'true', html: 'true'},
51801 {tag: 'option', value: 'false', html: 'false'}
51804 Roo.id(this.bselect);
51807 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
51808 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
51809 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
51810 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
51811 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
51813 this.renderCellDelegate = this.renderCell.createDelegate(this);
51814 this.renderPropDelegate = this.renderProp.createDelegate(this);
51817 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
51821 valueText : 'Value',
51823 dateFormat : 'm/j/Y',
51826 renderDate : function(dateVal){
51827 return dateVal.dateFormat(this.dateFormat);
51830 renderBool : function(bVal){
51831 return bVal ? 'true' : 'false';
51834 isCellEditable : function(colIndex, rowIndex){
51835 return colIndex == 1;
51838 getRenderer : function(col){
51840 this.renderCellDelegate : this.renderPropDelegate;
51843 renderProp : function(v){
51844 return this.getPropertyName(v);
51847 renderCell : function(val){
51849 if(val instanceof Date){
51850 rv = this.renderDate(val);
51851 }else if(typeof val == 'boolean'){
51852 rv = this.renderBool(val);
51854 return Roo.util.Format.htmlEncode(rv);
51857 getPropertyName : function(name){
51858 var pn = this.grid.propertyNames;
51859 return pn && pn[name] ? pn[name] : name;
51862 getCellEditor : function(colIndex, rowIndex){
51863 var p = this.store.getProperty(rowIndex);
51864 var n = p.data['name'], val = p.data['value'];
51866 if(typeof(this.grid.customEditors[n]) == 'string'){
51867 return this.editors[this.grid.customEditors[n]];
51869 if(typeof(this.grid.customEditors[n]) != 'undefined'){
51870 return this.grid.customEditors[n];
51872 if(val instanceof Date){
51873 return this.editors['date'];
51874 }else if(typeof val == 'number'){
51875 return this.editors['number'];
51876 }else if(typeof val == 'boolean'){
51877 return this.editors['boolean'];
51879 return this.editors['string'];
51885 * @class Roo.grid.PropertyGrid
51886 * @extends Roo.grid.EditorGrid
51887 * This class represents the interface of a component based property grid control.
51888 * <br><br>Usage:<pre><code>
51889 var grid = new Roo.grid.PropertyGrid("my-container-id", {
51897 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51898 * The container MUST have some type of size defined for the grid to fill. The container will be
51899 * automatically set to position relative if it isn't already.
51900 * @param {Object} config A config object that sets properties on this grid.
51902 Roo.grid.PropertyGrid = function(container, config){
51903 config = config || {};
51904 var store = new Roo.grid.PropertyStore(this);
51905 this.store = store;
51906 var cm = new Roo.grid.PropertyColumnModel(this, store);
51907 store.store.sort('name', 'ASC');
51908 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
51911 enableColLock:false,
51912 enableColumnMove:false,
51914 trackMouseOver: false,
51917 this.getGridEl().addClass('x-props-grid');
51918 this.lastEditRow = null;
51919 this.on('columnresize', this.onColumnResize, this);
51922 * @event beforepropertychange
51923 * Fires before a property changes (return false to stop?)
51924 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
51925 * @param {String} id Record Id
51926 * @param {String} newval New Value
51927 * @param {String} oldval Old Value
51929 "beforepropertychange": true,
51931 * @event propertychange
51932 * Fires after a property changes
51933 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
51934 * @param {String} id Record Id
51935 * @param {String} newval New Value
51936 * @param {String} oldval Old Value
51938 "propertychange": true
51940 this.customEditors = this.customEditors || {};
51942 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
51945 * @cfg {Object} customEditors map of colnames=> custom editors.
51946 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
51947 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
51948 * false disables editing of the field.
51952 * @cfg {Object} propertyNames map of property Names to their displayed value
51955 render : function(){
51956 Roo.grid.PropertyGrid.superclass.render.call(this);
51957 this.autoSize.defer(100, this);
51960 autoSize : function(){
51961 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
51963 this.view.fitColumns();
51967 onColumnResize : function(){
51968 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
51972 * Sets the data for the Grid
51973 * accepts a Key => Value object of all the elements avaiable.
51974 * @param {Object} data to appear in grid.
51976 setSource : function(source){
51977 this.store.setSource(source);
51981 * Gets all the data from the grid.
51982 * @return {Object} data data stored in grid
51984 getSource : function(){
51985 return this.store.getSource();
51989 * Ext JS Library 1.1.1
51990 * Copyright(c) 2006-2007, Ext JS, LLC.
51992 * Originally Released Under LGPL - original licence link has changed is not relivant.
51995 * <script type="text/javascript">
51999 * @class Roo.LoadMask
52000 * A simple utility class for generically masking elements while loading data. If the element being masked has
52001 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
52002 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
52003 * element's UpdateManager load indicator and will be destroyed after the initial load.
52005 * Create a new LoadMask
52006 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
52007 * @param {Object} config The config object
52009 Roo.LoadMask = function(el, config){
52010 this.el = Roo.get(el);
52011 Roo.apply(this, config);
52013 this.store.on('beforeload', this.onBeforeLoad, this);
52014 this.store.on('load', this.onLoad, this);
52015 this.store.on('loadexception', this.onLoadException, this);
52016 this.removeMask = false;
52018 var um = this.el.getUpdateManager();
52019 um.showLoadIndicator = false; // disable the default indicator
52020 um.on('beforeupdate', this.onBeforeLoad, this);
52021 um.on('update', this.onLoad, this);
52022 um.on('failure', this.onLoad, this);
52023 this.removeMask = true;
52027 Roo.LoadMask.prototype = {
52029 * @cfg {Boolean} removeMask
52030 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
52031 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
52034 * @cfg {String} msg
52035 * The text to display in a centered loading message box (defaults to 'Loading...')
52037 msg : 'Loading...',
52039 * @cfg {String} msgCls
52040 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
52042 msgCls : 'x-mask-loading',
52045 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
52051 * Disables the mask to prevent it from being displayed
52053 disable : function(){
52054 this.disabled = true;
52058 * Enables the mask so that it can be displayed
52060 enable : function(){
52061 this.disabled = false;
52064 onLoadException : function()
52066 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
52067 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
52069 this.el.unmask(this.removeMask);
52072 onLoad : function()
52074 this.el.unmask(this.removeMask);
52078 onBeforeLoad : function(){
52079 if(!this.disabled){
52080 this.el.mask(this.msg, this.msgCls);
52085 destroy : function(){
52087 this.store.un('beforeload', this.onBeforeLoad, this);
52088 this.store.un('load', this.onLoad, this);
52089 this.store.un('loadexception', this.onLoadException, this);
52091 var um = this.el.getUpdateManager();
52092 um.un('beforeupdate', this.onBeforeLoad, this);
52093 um.un('update', this.onLoad, this);
52094 um.un('failure', this.onLoad, this);
52099 * Ext JS Library 1.1.1
52100 * Copyright(c) 2006-2007, Ext JS, LLC.
52102 * Originally Released Under LGPL - original licence link has changed is not relivant.
52105 * <script type="text/javascript">
52107 Roo.XTemplate = function(){
52108 Roo.XTemplate.superclass.constructor.apply(this, arguments);
52111 s = ['<tpl>', s, '</tpl>'].join('');
52113 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
52115 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
52116 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
52117 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
52121 while(m = s.match(re)){
52122 var m2 = m[0].match(nameRe);
52123 var m3 = m[0].match(ifRe);
52124 var m4 = m[0].match(execRe);
52125 var exp = null, fn = null, exec = null;
52126 var name = m2 && m2[1] ? m2[1] : '';
52128 exp = m3 && m3[1] ? m3[1] : null;
52130 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
52134 exp = m4 && m4[1] ? m4[1] : null;
52136 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
52141 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
52142 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
52143 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
52153 s = s.replace(m[0], '{xtpl'+ id + '}');
52156 for(var i = tpls.length-1; i >= 0; --i){
52157 this.compileTpl(tpls[i]);
52159 this.master = tpls[tpls.length-1];
52162 Roo.extend(Roo.XTemplate, Roo.Template, {
52164 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
52166 applySubTemplate : function(id, values, parent){
52167 var t = this.tpls[id];
52168 if(t.test && !t.test.call(this, values, parent)){
52171 if(t.exec && t.exec.call(this, values, parent)){
52174 var vs = t.target ? t.target.call(this, values, parent) : values;
52175 parent = t.target ? values : parent;
52176 if(t.target && vs instanceof Array){
52178 for(var i = 0, len = vs.length; i < len; i++){
52179 buf[buf.length] = t.compiled.call(this, vs[i], parent);
52181 return buf.join('');
52183 return t.compiled.call(this, vs, parent);
52186 compileTpl : function(tpl){
52187 var fm = Roo.util.Format;
52188 var useF = this.disableFormats !== true;
52189 var sep = Roo.isGecko ? "+" : ",";
52190 var fn = function(m, name, format, args){
52191 if(name.substr(0, 4) == 'xtpl'){
52192 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
52195 if(name.indexOf('.') != -1){
52198 v = "values['" + name + "']";
52200 if(format && useF){
52201 args = args ? ',' + args : "";
52202 if(format.substr(0, 5) != "this."){
52203 format = "fm." + format + '(';
52205 format = 'this.call("'+ format.substr(5) + '", ';
52209 args= ''; format = "("+v+" === undefined ? '' : ";
52211 return "'"+ sep + format + v + args + ")"+sep+"'";
52214 // branched to use + in gecko and [].join() in others
52216 body = "tpl.compiled = function(values, parent){ return '" +
52217 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
52220 body = ["tpl.compiled = function(values, parent){ return ['"];
52221 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
52222 body.push("'].join('');};");
52223 body = body.join('');
52225 /** eval:var:zzzzzzz */
52230 applyTemplate : function(values){
52231 return this.master.compiled.call(this, values, {});
52235 apply : function(){
52236 return this.applyTemplate.apply(this, arguments);
52239 compile : function(){return this;}
52242 Roo.XTemplate.from = function(el){
52243 el = Roo.getDom(el);
52244 return new Roo.XTemplate(el.value || el.innerHTML);
52246 * Original code for Roojs - LGPL
52247 * <script type="text/javascript">
52251 * @class Roo.XComponent
52252 * A delayed Element creator...
52253 * Or a way to group chunks of interface together.
52255 * Mypart.xyx = new Roo.XComponent({
52257 parent : 'Mypart.xyz', // empty == document.element.!!
52261 disabled : function() {}
52263 tree : function() { // return an tree of xtype declared components
52267 xtype : 'NestedLayoutPanel',
52274 * It can be used to build a big heiracy, with parent etc.
52275 * or you can just use this to render a single compoent to a dom element
52276 * MYPART.render(Roo.Element | String(id) | dom_element )
52278 * @extends Roo.util.Observable
52280 * @param cfg {Object} configuration of component
52283 Roo.XComponent = function(cfg) {
52284 Roo.apply(this, cfg);
52288 * Fires when this the componnt is built
52289 * @param {Roo.XComponent} c the component
52293 * @event buildcomplete
52294 * Fires on the top level element when all elements have been built
52295 * @param {Roo.XComponent} c the top level component.
52297 'buildcomplete' : true
52300 this.region = this.region || 'center'; // default..
52301 Roo.XComponent.register(this);
52302 this.modules = false;
52303 this.el = false; // where the layout goes..
52307 Roo.extend(Roo.XComponent, Roo.util.Observable, {
52310 * The created element (with Roo.factory())
52311 * @type {Roo.Layout}
52317 * for BC - use el in new code
52318 * @type {Roo.Layout}
52324 * for BC - use el in new code
52325 * @type {Roo.Layout}
52330 * @cfg {Function|boolean} disabled
52331 * If this module is disabled by some rule, return true from the funtion
52336 * @cfg {String} parent
52337 * Name of parent element which it get xtype added to..
52342 * @cfg {String} order
52343 * Used to set the order in which elements are created (usefull for multiple tabs)
52348 * @cfg {String} name
52349 * String to display while loading.
52353 * @cfg {String} region
52354 * Region to render component to (defaults to center)
52359 * @cfg {Array} items
52360 * A single item array - the first element is the root of the tree..
52361 * It's done this way to stay compatible with the Xtype system...
52368 * render element to dom or tree
52369 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
52372 render : function(el)
52376 var hp = this.parent ? 1 : 0;
52378 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
52379 // if parent is a '#.....' string, then let's use that..
52380 var ename = this.parent.substr(1)
52381 this.parent = false;
52382 el = Roo.get(ename);
52384 Roo.log("Warning - element can not be found :#" + ename );
52390 if (!this.parent) {
52392 el = el ? Roo.get(el) : false;
52394 // it's a top level one..
52396 el : new Roo.BorderLayout(el || document.body, {
52402 tabPosition: 'top',
52403 //resizeTabs: true,
52404 alwaysShowTabs: el && hp? false : true,
52405 hideTabs: el || !hp ? true : false,
52414 var tree = this.tree();
52415 tree.region = tree.region || this.region;
52416 this.el = this.parent.el.addxtype(tree);
52417 this.fireEvent('built', this);
52419 this.panel = this.el;
52420 this.layout = this.panel.layout;
52426 Roo.apply(Roo.XComponent, {
52429 * @property buildCompleted
52430 * True when the builder has completed building the interface.
52433 buildCompleted : false,
52436 * @property topModule
52437 * the upper most module - uses document.element as it's constructor.
52444 * @property modules
52445 * array of modules to be created by registration system.
52446 * @type {Array} of Roo.XComponent
52451 * @property elmodules
52452 * array of modules to be created by which use #ID
52453 * @type {Array} of Roo.XComponent
52460 * Register components to be built later.
52462 * This solves the following issues
52463 * - Building is not done on page load, but after an authentication process has occured.
52464 * - Interface elements are registered on page load
52465 * - Parent Interface elements may not be loaded before child, so this handles that..
52472 module : 'Pman.Tab.projectMgr',
52474 parent : 'Pman.layout',
52475 disabled : false, // or use a function..
52478 * * @param {Object} details about module
52480 register : function(obj) {
52481 this.modules.push(obj);
52485 * convert a string to an object..
52486 * eg. 'AAA.BBB' -> finds AAA.BBB
52490 toObject : function(str)
52492 if (!str || typeof(str) == 'object') {
52495 if (str.substring(0,1) == '#') {
52499 var ar = str.split('.');
52504 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
52506 throw "Module not found : " + str;
52510 throw "Module not found : " + str;
52512 Roo.each(ar, function(e) {
52513 if (typeof(o[e]) == 'undefined') {
52514 throw "Module not found : " + str;
52525 * move modules into their correct place in the tree..
52528 preBuild : function ()
52531 Roo.each(this.modules , function (obj)
52533 var opar = obj.parent;
52535 obj.parent = this.toObject(opar);
52537 Roo.log(e.toString());
52542 this.topModule = obj;
52545 if (typeof(obj.parent) == 'string') {
52546 this.elmodules.push(obj);
52549 if (obj.parent.constructor != Roo.XComponent) {
52550 Roo.log("Object Parent is not instance of XComponent:" + obj.name)
52552 if (!obj.parent.modules) {
52553 obj.parent.modules = new Roo.util.MixedCollection(false,
52554 function(o) { return o.order + '' }
52558 obj.parent.modules.add(obj);
52563 * make a list of modules to build.
52564 * @return {Array} list of modules.
52567 buildOrder : function()
52570 var cmp = function(a,b) {
52571 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
52573 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
52574 throw "No top level modules to build";
52577 // make a flat list in order of modules to build.
52578 var mods = this.topModule ? [ this.topModule ] : [];
52579 Roo.each(this.elmodules,function(e) { mods.push(e) });
52582 // add modules to their parents..
52583 var addMod = function(m) {
52584 // Roo.debug && Roo.log(m.modKey);
52588 m.modules.keySort('ASC', cmp );
52589 m.modules.each(addMod);
52591 // not sure if this is used any more..
52593 m.finalize.name = m.name + " (clean up) ";
52594 mods.push(m.finalize);
52598 if (this.topModule) {
52599 this.topModule.modules.keySort('ASC', cmp );
52600 this.topModule.modules.each(addMod);
52606 * Build the registered modules.
52607 * @param {Object} parent element.
52608 * @param {Function} optional method to call after module has been added.
52616 var mods = this.buildOrder();
52618 //this.allmods = mods;
52619 //Roo.debug && Roo.log(mods);
52621 if (!mods.length) { // should not happen
52622 throw "NO modules!!!";
52627 // flash it up as modal - so we store the mask!?
52628 Roo.MessageBox.show({ title: 'loading' });
52629 Roo.MessageBox.show({
52630 title: "Please wait...",
52631 msg: "Building Interface...",
52638 var total = mods.length;
52641 var progressRun = function() {
52642 if (!mods.length) {
52643 Roo.debug && Roo.log('hide?');
52644 Roo.MessageBox.hide();
52645 if (_this.topModule) {
52646 _this.topModule.fireEvent('buildcomplete', _this.topModule);
52652 var m = mods.shift();
52655 Roo.debug && Roo.log(m);
52656 // not sure if this is supported any more.. - modules that are are just function
52657 if (typeof(m) == 'function') {
52659 return progressRun.defer(10, _this);
52664 Roo.MessageBox.updateProgress(
52665 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
52667 (m.name ? (' - ' + m.name) : '')
52671 // is the module disabled?
52672 var disabled = (typeof(m.disabled) == 'function') ?
52673 m.disabled.call(m.module.disabled) : m.disabled;
52677 return progressRun(); // we do not update the display!
52683 // it's 10 on top level, and 1 on others??? why...
52684 return progressRun.defer(10, _this);
52687 progressRun.defer(1, _this);
52698 //<script type="text/javascript">
52703 * @extends Roo.LayoutDialog
52704 * A generic Login Dialog..... - only one needed in theory!?!?
52706 * Fires XComponent builder on success...
52709 * username,password, lang = for login actions.
52710 * check = 1 for periodic checking that sesion is valid.
52711 * passwordRequest = email request password
52712 * logout = 1 = to logout
52714 * Affects: (this id="????" elements)
52715 * loading (removed) (used to indicate application is loading)
52716 * loading-mask (hides) (used to hide application when it's building loading)
52722 * Myapp.login = Roo.Login({
52738 Roo.Login = function(cfg)
52744 Roo.apply(this,cfg);
52746 Roo.onReady(function() {
52752 Roo.Login.superclass.constructor.call(this, this);
52753 //this.addxtype(this.items[0]);
52759 Roo.extend(Roo.Login, Roo.LayoutDialog, {
52762 * @cfg {String} method
52763 * Method used to query for login details.
52768 * @cfg {String} url
52769 * URL to query login data. - eg. baseURL + '/Login.php'
52775 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
52780 * @property checkFails
52781 * Number of times we have attempted to get authentication check, and failed.
52786 * @property intervalID
52787 * The window interval that does the constant login checking.
52793 onLoad : function() // called on page load...
52797 if (Roo.get('loading')) { // clear any loading indicator..
52798 Roo.get('loading').remove();
52801 //this.switchLang('en'); // set the language to english..
52804 success: function(response, opts) { // check successfull...
52806 var res = this.processResponse(response);
52807 this.checkFails =0;
52808 if (!res.success) { // error!
52809 this.checkFails = 5;
52810 //console.log('call failure');
52811 return this.failure(response,opts);
52814 if (!res.data.id) { // id=0 == login failure.
52815 return this.show();
52819 //console.log(success);
52820 this.fillAuth(res.data);
52821 this.checkFails =0;
52822 Roo.XComponent.build();
52824 failure : this.show
52830 check: function(cfg) // called every so often to refresh cookie etc..
52832 if (cfg.again) { // could be undefined..
52835 this.checkFails = 0;
52838 if (this.sending) {
52839 if ( this.checkFails > 4) {
52840 Roo.MessageBox.alert("Error",
52841 "Error getting authentication status. - try reloading, or wait a while", function() {
52842 _this.sending = false;
52847 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
52850 this.sending = true;
52857 method: this.method,
52858 success: cfg.success || this.success,
52859 failure : cfg.failure || this.failure,
52869 window.onbeforeunload = function() { }; // false does not work for IE..
52879 failure : function() {
52880 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
52881 document.location = document.location.toString() + '?ts=' + Math.random();
52885 success : function() {
52886 _this.user = false;
52887 this.checkFails =0;
52889 document.location = document.location.toString() + '?ts=' + Math.random();
52896 processResponse : function (response)
52900 res = Roo.decode(response.responseText);
52902 if (typeof(res) != 'object') {
52903 res = { success : false, errorMsg : res, errors : true };
52905 if (typeof(res.success) == 'undefined') {
52906 res.success = false;
52910 res = { success : false, errorMsg : response.responseText, errors : true };
52915 success : function(response, opts) // check successfull...
52917 this.sending = false;
52918 var res = this.processResponse(response);
52919 if (!res.success) {
52920 return this.failure(response, opts);
52922 if (!res.data || !res.data.id) {
52923 return this.failure(response,opts);
52925 //console.log(res);
52926 this.fillAuth(res.data);
52928 this.checkFails =0;
52933 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
52935 this.authUser = -1;
52936 this.sending = false;
52937 var res = this.processResponse(response);
52938 //console.log(res);
52939 if ( this.checkFails > 2) {
52941 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
52942 "Error getting authentication status. - try reloading");
52945 opts.callCfg.again = true;
52946 this.check.defer(1000, this, [ opts.callCfg ]);
52952 fillAuth: function(au) {
52953 this.startAuthCheck();
52954 this.authUserId = au.id;
52955 this.authUser = au;
52956 this.lastChecked = new Date();
52957 this.fireEvent('refreshed', au);
52958 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
52959 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
52960 au.lang = au.lang || 'en';
52961 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
52962 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
52963 this.switchLang(au.lang );
52966 // open system... - -on setyp..
52967 if (this.authUserId < 0) {
52968 Roo.MessageBox.alert("Warning",
52969 "This is an open system - please set up a admin user with a password.");
52972 //Pman.onload(); // which should do nothing if it's a re-auth result...
52977 startAuthCheck : function() // starter for timeout checking..
52979 if (this.intervalID) { // timer already in place...
52983 this.intervalID = window.setInterval(function() {
52984 _this.check(false);
52985 }, 120000); // every 120 secs = 2mins..
52991 switchLang : function (lang)
52993 _T = typeof(_T) == 'undefined' ? false : _T;
52994 if (!_T || !lang.length) {
52998 if (!_T && lang != 'en') {
52999 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
53003 if (typeof(_T.en) == 'undefined') {
53005 Roo.apply(_T.en, _T);
53008 if (typeof(_T[lang]) == 'undefined') {
53009 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
53014 Roo.apply(_T, _T[lang]);
53015 // just need to set the text values for everything...
53017 /* this will not work ...
53021 function formLabel(name, val) {
53022 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
53025 formLabel('password', "Password"+':');
53026 formLabel('username', "Email Address"+':');
53027 formLabel('lang', "Language"+':');
53028 this.dialog.setTitle("Login");
53029 this.dialog.buttons[0].setText("Forgot Password");
53030 this.dialog.buttons[1].setText("Login");
53049 collapsible: false,
53051 center: { // needed??
53054 // tabPosition: 'top',
53057 alwaysShowTabs: false
53061 show : function(dlg)
53063 //console.log(this);
53064 this.form = this.layout.getRegion('center').activePanel.form;
53065 this.form.dialog = dlg;
53066 this.buttons[0].form = this.form;
53067 this.buttons[0].dialog = dlg;
53068 this.buttons[1].form = this.form;
53069 this.buttons[1].dialog = dlg;
53071 //this.resizeToLogo.defer(1000,this);
53072 // this is all related to resizing for logos..
53073 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
53075 // this.resizeToLogo.defer(1000,this);
53078 //var w = Ext.lib.Dom.getViewWidth() - 100;
53079 //var h = Ext.lib.Dom.getViewHeight() - 100;
53080 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
53082 if (this.disabled) {
53087 if (this.user.id < 0) { // used for inital setup situations.
53091 if (this.intervalID) {
53092 // remove the timer
53093 window.clearInterval(this.intervalID);
53094 this.intervalID = false;
53098 if (Roo.get('loading')) {
53099 Roo.get('loading').remove();
53101 if (Roo.get('loading-mask')) {
53102 Roo.get('loading-mask').hide();
53105 //incomming._node = tnode;
53107 //this.dialog.modal = !modal;
53108 //this.dialog.show();
53112 this.form.setValues({
53113 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
53114 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
53117 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
53118 if (this.form.findField('username').getValue().length > 0 ){
53119 this.form.findField('password').focus();
53121 this.form.findField('username').focus();
53129 xtype : 'ContentPanel',
53141 style : 'margin: 10px;',
53144 actionfailed : function(f, act) {
53145 // form can return { errors: .... }
53147 //act.result.errors // invalid form element list...
53148 //act.result.errorMsg// invalid form element list...
53150 this.dialog.el.unmask();
53151 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
53152 "Login failed - communication error - try again.");
53155 actioncomplete: function(re, act) {
53157 Roo.state.Manager.set(
53158 this.dialog.realm + '.username',
53159 this.findField('username').getValue()
53161 Roo.state.Manager.set(
53162 this.dialog.realm + '.lang',
53163 this.findField('lang').getValue()
53166 this.dialog.fillAuth(act.result.data);
53168 this.dialog.hide();
53170 if (Roo.get('loading-mask')) {
53171 Roo.get('loading-mask').show();
53173 Roo.XComponent.build();
53181 xtype : 'TextField',
53183 fieldLabel: "Email Address",
53186 autoCreate : {tag: "input", type: "text", size: "20"}
53189 xtype : 'TextField',
53191 fieldLabel: "Password",
53192 inputType: 'password',
53195 autoCreate : {tag: "input", type: "text", size: "20"},
53197 specialkey : function(e,ev) {
53198 if (ev.keyCode == 13) {
53199 this.form.dialog.el.mask("Logging in");
53200 this.form.doAction('submit', {
53201 url: this.form.dialog.url,
53202 method: this.form.dialog.method
53209 xtype : 'ComboBox',
53211 fieldLabel: "Language",
53214 xtype : 'SimpleStore',
53215 fields: ['lang', 'ldisp'],
53217 [ 'en', 'English' ],
53218 [ 'zh_HK' , '\u7E41\u4E2D' ],
53219 [ 'zh_CN', '\u7C21\u4E2D' ]
53223 valueField : 'lang',
53224 hiddenName: 'lang',
53226 displayField:'ldisp',
53230 triggerAction: 'all',
53231 emptyText:'Select a Language...',
53232 selectOnFocus:true,
53234 select : function(cb, rec, ix) {
53235 this.form.switchLang(rec.data.lang);
53251 text : "Forgot Password",
53253 click : function() {
53254 //console.log(this);
53255 var n = this.form.findField('username').getValue();
53257 Roo.MessageBox.alert("Error", "Fill in your email address");
53261 url: this.dialog.url,
53265 method: this.dialog.method,
53266 success: function(response, opts) { // check successfull...
53268 var res = this.dialog.processResponse(response);
53269 if (!res.success) { // error!
53270 Roo.MessageBox.alert("Error" ,
53271 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
53274 Roo.MessageBox.alert("Notice" ,
53275 "Please check you email for the Password Reset message");
53277 failure : function() {
53278 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
53291 click : function () {
53293 this.dialog.el.mask("Logging in");
53294 this.form.doAction('submit', {
53295 url: this.dialog.url,
53296 method: this.dialog.method