4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
89 * Turn on debugging output (currently only the factory uses this)
96 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
99 enableGarbageCollector : true,
102 * True to automatically purge event listeners after uncaching an element (defaults to false).
103 * Note: this only happens if enableGarbageCollector is true.
106 enableListenerCollection:false,
109 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110 * the IE insecure content warning (defaults to javascript:false).
113 SSL_SECURE_URL : "javascript:false",
116 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
120 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
122 emptyFn : function(){},
125 * Copies all the properties of config to obj if they don't already exist.
126 * @param {Object} obj The receiver of the properties
127 * @param {Object} config The source of the properties
128 * @return {Object} returns obj
130 applyIf : function(o, c){
133 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
140 * Applies event listeners to elements by selectors when the document is ready.
141 * The event name is specified with an @ suffix.
144 // add a listener for click on all anchors in element with id foo
145 '#foo a@click' : function(e, t){
149 // add the same listener to multiple selectors (separated by comma BEFORE the @)
150 '#foo a, #bar span.some-class@mouseover' : function(){
155 * @param {Object} obj The list of behaviors to apply
157 addBehaviors : function(o){
159 Roo.onReady(function(){
164 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
166 var parts = b.split('@');
167 if(parts[1]){ // for Object prototype breakers
170 cache[s] = Roo.select(s);
172 cache[s].on(parts[1], o[b]);
179 * Generates unique ids. If the element already has an id, it is unchanged
180 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182 * @return {String} The generated Id.
184 id : function(el, prefix){
185 prefix = prefix || "roo-gen";
187 var id = prefix + (++idSeed);
188 return el ? (el.id ? el.id : (el.id = id)) : id;
193 * Extends one class with another class and optionally overrides members with the passed literal. This class
194 * also adds the function "override()" to the class that can be used to override
195 * members on an instance.
196 * @param {Object} subclass The class inheriting the functionality
197 * @param {Object} superclass The class being extended
198 * @param {Object} overrides (optional) A literal with members
203 var io = function(o){
208 return function(sb, sp, overrides){
209 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
212 sb = function(){sp.apply(this, arguments);};
214 var F = function(){}, sbp, spp = sp.prototype;
216 sbp = sb.prototype = new F();
220 if(spp.constructor == Object.prototype.constructor){
225 sb.override = function(o){
229 Roo.override(sb, overrides);
235 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
237 Roo.override(MyClass, {
238 newMethod1: function(){
241 newMethod2: function(foo){
246 * @param {Object} origclass The class to override
247 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
248 * containing one or more methods.
251 override : function(origclass, overrides){
253 var p = origclass.prototype;
254 for(var method in overrides){
255 p[method] = overrides[method];
260 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
266 * @param {String} namespace1
267 * @param {String} namespace2
268 * @param {String} etc
271 namespace : function(){
272 var a=arguments, o=null, i, j, d, rt;
273 for (i=0; i<a.length; ++i) {
277 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278 for (j=1; j<d.length; ++j) {
279 o[d[j]]=o[d[j]] || {};
285 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
290 * @param {String} classname
291 * @param {String} namespace (optional)
295 factory : function(c, ns)
297 // no xtype, no ns or c.xns - or forced off by c.xns
298 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
301 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302 if (c.constructor == ns[c.xtype]) {// already created...
306 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307 var ret = new ns[c.xtype](c);
311 c.xns = false; // prevent recursion..
315 * Logs to console if it can.
317 * @param {String|Object} string
322 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
329 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
333 urlEncode : function(o){
339 var ov = o[key], k = Roo.encodeURIComponent(key);
340 var type = typeof ov;
341 if(type == 'undefined'){
343 }else if(type != "function" && type != "object"){
344 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345 }else if(ov instanceof Array){
347 for(var i = 0, len = ov.length; i < len; i++) {
348 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
359 * Safe version of encodeURIComponent
360 * @param {String} data
364 encodeURIComponent : function (data)
367 return encodeURIComponent(data);
368 } catch(e) {} // should be an uri encode error.
370 if (data == '' || data == null){
373 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374 function nibble_to_hex(nibble){
375 var chars = '0123456789ABCDEF';
376 return chars.charAt(nibble);
378 data = data.toString();
380 for(var i=0; i<data.length; i++){
381 var c = data.charCodeAt(i);
382 var bs = new Array();
385 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388 bs[3] = 0x80 | (c & 0x3F);
389 }else if (c > 0x800){
391 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393 bs[2] = 0x80 | (c & 0x3F);
396 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397 bs[1] = 0x80 | (c & 0x3F);
402 for(var j=0; j<bs.length; j++){
404 var hex = nibble_to_hex((b & 0xF0) >>> 4)
405 + nibble_to_hex(b &0x0F);
414 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415 * @param {String} string
416 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417 * @return {Object} A literal with members
419 urlDecode : function(string, overwrite){
420 if(!string || !string.length){
424 var pairs = string.split('&');
425 var pair, name, value;
426 for(var i = 0, len = pairs.length; i < len; i++){
427 pair = pairs[i].split('=');
428 name = decodeURIComponent(pair[0]);
429 value = decodeURIComponent(pair[1]);
430 if(overwrite !== true){
431 if(typeof obj[name] == "undefined"){
433 }else if(typeof obj[name] == "string"){
434 obj[name] = [obj[name]];
435 obj[name].push(value);
437 obj[name].push(value);
447 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448 * passed array is not really an array, your function is called once with it.
449 * The supplied function is called with (Object item, Number index, Array allItems).
450 * @param {Array/NodeList/Mixed} array
451 * @param {Function} fn
452 * @param {Object} scope
454 each : function(array, fn, scope){
455 if(typeof array.length == "undefined" || typeof array == "string"){
458 for(var i = 0, len = array.length; i < len; i++){
459 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
464 combine : function(){
465 var as = arguments, l = as.length, r = [];
466 for(var i = 0; i < l; i++){
468 if(a instanceof Array){
470 }else if(a.length !== undefined && !a.substr){
471 r = r.concat(Array.prototype.slice.call(a, 0));
480 * Escapes the passed string for use in a regular expression
481 * @param {String} str
484 escapeRe : function(s) {
485 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
489 callback : function(cb, scope, args, delay){
490 if(typeof cb == "function"){
492 cb.defer(delay, scope, args || []);
494 cb.apply(scope, args || []);
500 * Return the dom node for the passed string (id), dom node, or Roo.Element
501 * @param {String/HTMLElement/Roo.Element} el
502 * @return HTMLElement
504 getDom : function(el){
508 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
512 * Shorthand for {@link Roo.ComponentMgr#get}
514 * @return Roo.Component
516 getCmp : function(id){
517 return Roo.ComponentMgr.get(id);
520 num : function(v, defaultValue){
521 if(typeof v != 'number'){
527 destroy : function(){
528 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
532 as.removeAllListeners();
536 if(typeof as.purgeListeners == 'function'){
539 if(typeof as.destroy == 'function'){
546 // inpired by a similar function in mootools library
548 * Returns the type of object that is passed in. If the object passed in is null or undefined it
549 * return false otherwise it returns one of the following values:<ul>
550 * <li><b>string</b>: If the object passed is a string</li>
551 * <li><b>number</b>: If the object passed is a number</li>
552 * <li><b>boolean</b>: If the object passed is a boolean value</li>
553 * <li><b>function</b>: If the object passed is a function reference</li>
554 * <li><b>object</b>: If the object passed is an object</li>
555 * <li><b>array</b>: If the object passed is an array</li>
556 * <li><b>regexp</b>: If the object passed is a regular expression</li>
557 * <li><b>element</b>: If the object passed is a DOM Element</li>
558 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561 * @param {Mixed} object
565 if(o === undefined || o === null){
572 if(t == 'object' && o.nodeName) {
574 case 1: return 'element';
575 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
578 if(t == 'object' || t == 'function') {
579 switch(o.constructor) {
580 case Array: return 'array';
581 case RegExp: return 'regexp';
583 if(typeof o.length == 'number' && typeof o.item == 'function') {
591 * Returns true if the passed value is null, undefined or an empty string (optional).
592 * @param {Mixed} value The value to test
593 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
596 isEmpty : function(v, allowBlank){
597 return v === null || v === undefined || (!allowBlank ? v === '' : false);
611 isBorderBox : isBorderBox,
613 isWindows : isWindows,
620 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
621 * you may want to set this to true.
624 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
629 * Selects a single element as a Roo Element
630 * This is about as close as you can get to jQuery's $('do crazy stuff')
631 * @param {String} selector The selector/xpath query
632 * @param {Node} root (optional) The start of the query (defaults to document).
633 * @return {Roo.Element}
635 selectNode : function(selector, root)
637 var node = Roo.DomQuery.selectNode(selector,root);
638 return node ? Roo.get(node) : new Roo.Element(false);
646 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
647 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
650 * Ext JS Library 1.1.1
651 * Copyright(c) 2006-2007, Ext JS, LLC.
653 * Originally Released Under LGPL - original licence link has changed is not relivant.
656 * <script type="text/javascript">
660 // wrappedn so fnCleanup is not in global scope...
662 function fnCleanUp() {
663 var p = Function.prototype;
664 delete p.createSequence;
666 delete p.createDelegate;
667 delete p.createCallback;
668 delete p.createInterceptor;
670 window.detachEvent("onunload", fnCleanUp);
672 window.attachEvent("onunload", fnCleanUp);
679 * These functions are available on every Function object (any JavaScript function).
681 Roo.apply(Function.prototype, {
683 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
684 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
685 * Will create a function that is bound to those 2 args.
686 * @return {Function} The new function
688 createCallback : function(/*args...*/){
689 // make args available, in function below
690 var args = arguments;
693 return method.apply(window, args);
698 * Creates a delegate (callback) that sets the scope to obj.
699 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
700 * Will create a function that is automatically scoped to this.
701 * @param {Object} obj (optional) The object for which the scope is set
702 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
703 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
704 * if a number the args are inserted at the specified position
705 * @return {Function} The new function
707 createDelegate : function(obj, args, appendArgs){
710 var callArgs = args || arguments;
711 if(appendArgs === true){
712 callArgs = Array.prototype.slice.call(arguments, 0);
713 callArgs = callArgs.concat(args);
714 }else if(typeof appendArgs == "number"){
715 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
716 var applyArgs = [appendArgs, 0].concat(args); // create method call params
717 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
719 return method.apply(obj || window, callArgs);
724 * Calls this function after the number of millseconds specified.
725 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
726 * @param {Object} obj (optional) The object for which the scope is set
727 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
728 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
729 * if a number the args are inserted at the specified position
730 * @return {Number} The timeout id that can be used with clearTimeout
732 defer : function(millis, obj, args, appendArgs){
733 var fn = this.createDelegate(obj, args, appendArgs);
735 return setTimeout(fn, millis);
741 * Create a combined function call sequence of the original function + the passed function.
742 * The resulting function returns the results of the original function.
743 * The passed fcn is called with the parameters of the original function
744 * @param {Function} fcn The function to sequence
745 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
746 * @return {Function} The new function
748 createSequence : function(fcn, scope){
749 if(typeof fcn != "function"){
754 var retval = method.apply(this || window, arguments);
755 fcn.apply(scope || this || window, arguments);
761 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
762 * The resulting function returns the results of the original function.
763 * The passed fcn is called with the parameters of the original function.
765 * @param {Function} fcn The function to call before the original
766 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
767 * @return {Function} The new function
769 createInterceptor : function(fcn, scope){
770 if(typeof fcn != "function"){
777 if(fcn.apply(scope || this || window, arguments) === false){
780 return method.apply(this || window, arguments);
786 * Ext JS Library 1.1.1
787 * Copyright(c) 2006-2007, Ext JS, LLC.
789 * Originally Released Under LGPL - original licence link has changed is not relivant.
792 * <script type="text/javascript">
795 Roo.applyIf(String, {
800 * Escapes the passed string for ' and \
801 * @param {String} string The string to escape
802 * @return {String} The escaped string
805 escape : function(string) {
806 return string.replace(/('|\\)/g, "\\$1");
810 * Pads the left side of a string with a specified character. This is especially useful
811 * for normalizing number and date strings. Example usage:
813 var s = String.leftPad('123', 5, '0');
814 // s now contains the string: '00123'
816 * @param {String} string The original string
817 * @param {Number} size The total length of the output string
818 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
819 * @return {String} The padded string
822 leftPad : function (val, size, ch) {
823 var result = new String(val);
824 if(ch === null || ch === undefined || ch === '') {
827 while (result.length < size) {
828 result = ch + result;
834 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
835 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
837 var cls = 'my-class', text = 'Some text';
838 var s = String.format('<div class="{0}">{1}</div>', cls, text);
839 // s now contains the string: '<div class="my-class">Some text</div>'
841 * @param {String} string The tokenized string to be formatted
842 * @param {String} value1 The value to replace token {0}
843 * @param {String} value2 Etc...
844 * @return {String} The formatted string
847 format : function(format){
848 var args = Array.prototype.slice.call(arguments, 1);
849 return format.replace(/\{(\d+)\}/g, function(m, i){
850 return Roo.util.Format.htmlEncode(args[i]);
856 * Utility function that allows you to easily switch a string between two alternating values. The passed value
857 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
858 * they are already different, the first value passed in is returned. Note that this method returns the new value
859 * but does not change the current string.
861 // alternate sort directions
862 sort = sort.toggle('ASC', 'DESC');
864 // instead of conditional logic:
865 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
867 * @param {String} value The value to compare to the current string
868 * @param {String} other The new value to use if the string already equals the first value passed in
869 * @return {String} The new value
872 String.prototype.toggle = function(value, other){
873 return this == value ? other : value;
876 * Ext JS Library 1.1.1
877 * Copyright(c) 2006-2007, Ext JS, LLC.
879 * Originally Released Under LGPL - original licence link has changed is not relivant.
882 * <script type="text/javascript">
888 Roo.applyIf(Number.prototype, {
890 * Checks whether or not the current number is within a desired range. If the number is already within the
891 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
892 * exceeded. Note that this method returns the constrained value but does not change the current number.
893 * @param {Number} min The minimum number in the range
894 * @param {Number} max The maximum number in the range
895 * @return {Number} The constrained value if outside the range, otherwise the current value
897 constrain : function(min, max){
898 return Math.min(Math.max(this, min), max);
902 * Ext JS Library 1.1.1
903 * Copyright(c) 2006-2007, Ext JS, LLC.
905 * Originally Released Under LGPL - original licence link has changed is not relivant.
908 * <script type="text/javascript">
913 Roo.applyIf(Array.prototype, {
915 * Checks whether or not the specified object exists in the array.
916 * @param {Object} o The object to check for
917 * @return {Number} The index of o in the array (or -1 if it is not found)
919 indexOf : function(o){
920 for (var i = 0, len = this.length; i < len; i++){
921 if(this[i] == o) return i;
927 * Removes the specified object from the array. If the object is not found nothing happens.
928 * @param {Object} o The object to remove
930 remove : function(o){
931 var index = this.indexOf(o);
933 this.splice(index, 1);
937 * Map (JS 1.6 compatibility)
938 * @param {Function} function to call
942 var len = this.length >>> 0;
943 if (typeof fun != "function")
944 throw new TypeError();
946 var res = new Array(len);
947 var thisp = arguments[1];
948 for (var i = 0; i < len; i++)
951 res[i] = fun.call(thisp, this[i], i, this);
962 * Ext JS Library 1.1.1
963 * Copyright(c) 2006-2007, Ext JS, LLC.
965 * Originally Released Under LGPL - original licence link has changed is not relivant.
968 * <script type="text/javascript">
974 * The date parsing and format syntax is a subset of
975 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
976 * supported will provide results equivalent to their PHP versions.
978 * Following is the list of all currently supported formats:
981 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
983 Format Output Description
984 ------ ---------- --------------------------------------------------------------
985 d 10 Day of the month, 2 digits with leading zeros
986 D Wed A textual representation of a day, three letters
987 j 10 Day of the month without leading zeros
988 l Wednesday A full textual representation of the day of the week
989 S th English ordinal day of month suffix, 2 chars (use with j)
990 w 3 Numeric representation of the day of the week
991 z 9 The julian date, or day of the year (0-365)
992 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
993 F January A full textual representation of the month
994 m 01 Numeric representation of a month, with leading zeros
995 M Jan Month name abbreviation, three letters
996 n 1 Numeric representation of a month, without leading zeros
997 t 31 Number of days in the given month
998 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
999 Y 2007 A full numeric representation of a year, 4 digits
1000 y 07 A two digit representation of a year
1001 a pm Lowercase Ante meridiem and Post meridiem
1002 A PM Uppercase Ante meridiem and Post meridiem
1003 g 3 12-hour format of an hour without leading zeros
1004 G 15 24-hour format of an hour without leading zeros
1005 h 03 12-hour format of an hour with leading zeros
1006 H 15 24-hour format of an hour with leading zeros
1007 i 05 Minutes with leading zeros
1008 s 01 Seconds, with leading zeros
1009 O -0600 Difference to Greenwich time (GMT) in hours
1010 T CST Timezone setting of the machine running the code
1011 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1014 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1016 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1017 document.write(dt.format('Y-m-d')); //2007-01-10
1018 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1019 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1022 * Here are some standard date/time patterns that you might find helpful. They
1023 * are not part of the source of Date.js, but to use them you can simply copy this
1024 * block of code into any script that is included after Date.js and they will also become
1025 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1028 ISO8601Long:"Y-m-d H:i:s",
1029 ISO8601Short:"Y-m-d",
1031 LongDate: "l, F d, Y",
1032 FullDateTime: "l, F d, Y g:i:s A",
1035 LongTime: "g:i:s A",
1036 SortableDateTime: "Y-m-d\\TH:i:s",
1037 UniversalSortableDateTime: "Y-m-d H:i:sO",
1044 var dt = new Date();
1045 document.write(dt.format(Date.patterns.ShortDate));
1050 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1051 * They generate precompiled functions from date formats instead of parsing and
1052 * processing the pattern every time you format a date. These functions are available
1053 * on every Date object (any javascript function).
1055 * The original article and download are here:
1056 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1063 Returns the number of milliseconds between this date and date
1064 @param {Date} date (optional) Defaults to now
1065 @return {Number} The diff in milliseconds
1066 @member Date getElapsed
1068 Date.prototype.getElapsed = function(date) {
1069 return Math.abs((date || new Date()).getTime()-this.getTime());
1071 // was in date file..
1075 Date.parseFunctions = {count:0};
1077 Date.parseRegexes = [];
1079 Date.formatFunctions = {count:0};
1082 Date.prototype.dateFormat = function(format) {
1083 if (Date.formatFunctions[format] == null) {
1084 Date.createNewFormat(format);
1086 var func = Date.formatFunctions[format];
1087 return this[func]();
1092 * Formats a date given the supplied format string
1093 * @param {String} format The format string
1094 * @return {String} The formatted date
1097 Date.prototype.format = Date.prototype.dateFormat;
1100 Date.createNewFormat = function(format) {
1101 var funcName = "format" + Date.formatFunctions.count++;
1102 Date.formatFunctions[format] = funcName;
1103 var code = "Date.prototype." + funcName + " = function(){return ";
1104 var special = false;
1106 for (var i = 0; i < format.length; ++i) {
1107 ch = format.charAt(i);
1108 if (!special && ch == "\\") {
1113 code += "'" + String.escape(ch) + "' + ";
1116 code += Date.getFormatCode(ch);
1119 /** eval:var:zzzzzzzzzzzzz */
1120 eval(code.substring(0, code.length - 3) + ";}");
1124 Date.getFormatCode = function(character) {
1125 switch (character) {
1127 return "String.leftPad(this.getDate(), 2, '0') + ";
1129 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1131 return "this.getDate() + ";
1133 return "Date.dayNames[this.getDay()] + ";
1135 return "this.getSuffix() + ";
1137 return "this.getDay() + ";
1139 return "this.getDayOfYear() + ";
1141 return "this.getWeekOfYear() + ";
1143 return "Date.monthNames[this.getMonth()] + ";
1145 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1147 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1149 return "(this.getMonth() + 1) + ";
1151 return "this.getDaysInMonth() + ";
1153 return "(this.isLeapYear() ? 1 : 0) + ";
1155 return "this.getFullYear() + ";
1157 return "('' + this.getFullYear()).substring(2, 4) + ";
1159 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1161 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1163 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1165 return "this.getHours() + ";
1167 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1169 return "String.leftPad(this.getHours(), 2, '0') + ";
1171 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1173 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1175 return "this.getGMTOffset() + ";
1177 return "this.getTimezone() + ";
1179 return "(this.getTimezoneOffset() * -60) + ";
1181 return "'" + String.escape(character) + "' + ";
1186 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1187 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1188 * the date format that is not specified will default to the current date value for that part. Time parts can also
1189 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1190 * string or the parse operation will fail.
1193 //dt = Fri May 25 2007 (current date)
1194 var dt = new Date();
1196 //dt = Thu May 25 2006 (today's month/day in 2006)
1197 dt = Date.parseDate("2006", "Y");
1199 //dt = Sun Jan 15 2006 (all date parts specified)
1200 dt = Date.parseDate("2006-1-15", "Y-m-d");
1202 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1203 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1205 * @param {String} input The unparsed date as a string
1206 * @param {String} format The format the date is in
1207 * @return {Date} The parsed date
1210 Date.parseDate = function(input, format) {
1211 if (Date.parseFunctions[format] == null) {
1212 Date.createParser(format);
1214 var func = Date.parseFunctions[format];
1215 return Date[func](input);
1220 Date.createParser = function(format) {
1221 var funcName = "parse" + Date.parseFunctions.count++;
1222 var regexNum = Date.parseRegexes.length;
1223 var currentGroup = 1;
1224 Date.parseFunctions[format] = funcName;
1226 var code = "Date." + funcName + " = function(input){\n"
1227 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1228 + "var d = new Date();\n"
1229 + "y = d.getFullYear();\n"
1230 + "m = d.getMonth();\n"
1231 + "d = d.getDate();\n"
1232 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1233 + "if (results && results.length > 0) {";
1236 var special = false;
1238 for (var i = 0; i < format.length; ++i) {
1239 ch = format.charAt(i);
1240 if (!special && ch == "\\") {
1245 regex += String.escape(ch);
1248 var obj = Date.formatCodeToRegex(ch, currentGroup);
1249 currentGroup += obj.g;
1251 if (obj.g && obj.c) {
1257 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1258 + "{v = new Date(y, m, d, h, i, s);}\n"
1259 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1260 + "{v = new Date(y, m, d, h, i);}\n"
1261 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1262 + "{v = new Date(y, m, d, h);}\n"
1263 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1264 + "{v = new Date(y, m, d);}\n"
1265 + "else if (y >= 0 && m >= 0)\n"
1266 + "{v = new Date(y, m);}\n"
1267 + "else if (y >= 0)\n"
1268 + "{v = new Date(y);}\n"
1269 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1270 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1271 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1274 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1275 /** eval:var:zzzzzzzzzzzzz */
1280 Date.formatCodeToRegex = function(character, currentGroup) {
1281 switch (character) {
1285 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1288 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1289 s:"(\\d{1,2})"}; // day of month without leading zeroes
1292 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1293 s:"(\\d{2})"}; // day of month with leading zeroes
1297 s:"(?:" + Date.dayNames.join("|") + ")"};
1301 s:"(?:st|nd|rd|th)"};
1316 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1317 s:"(" + Date.monthNames.join("|") + ")"};
1320 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1321 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1324 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1325 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1328 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1329 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1340 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1344 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1345 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1349 c:"if (results[" + currentGroup + "] == 'am') {\n"
1350 + "if (h == 12) { h = 0; }\n"
1351 + "} else { if (h < 12) { h += 12; }}",
1355 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1356 + "if (h == 12) { h = 0; }\n"
1357 + "} else { if (h < 12) { h += 12; }}",
1362 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1363 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1367 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1371 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1375 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1380 "o = results[", currentGroup, "];\n",
1381 "var sn = o.substring(0,1);\n", // get + / - sign
1382 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1383 "var mn = o.substring(3,5) % 60;\n", // get minutes
1384 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1385 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1391 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1394 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1395 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1396 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1400 s:String.escape(character)};
1405 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1406 * @return {String} The abbreviated timezone name (e.g. 'CST')
1408 Date.prototype.getTimezone = function() {
1409 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1413 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1414 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1416 Date.prototype.getGMTOffset = function() {
1417 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1418 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1419 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1423 * Get the numeric day number of the year, adjusted for leap year.
1424 * @return {Number} 0 through 364 (365 in leap years)
1426 Date.prototype.getDayOfYear = function() {
1428 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1429 for (var i = 0; i < this.getMonth(); ++i) {
1430 num += Date.daysInMonth[i];
1432 return num + this.getDate() - 1;
1436 * Get the string representation of the numeric week number of the year
1437 * (equivalent to the format specifier 'W').
1438 * @return {String} '00' through '52'
1440 Date.prototype.getWeekOfYear = function() {
1441 // Skip to Thursday of this week
1442 var now = this.getDayOfYear() + (4 - this.getDay());
1443 // Find the first Thursday of the year
1444 var jan1 = new Date(this.getFullYear(), 0, 1);
1445 var then = (7 - jan1.getDay() + 4);
1446 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1450 * Whether or not the current date is in a leap year.
1451 * @return {Boolean} True if the current date is in a leap year, else false
1453 Date.prototype.isLeapYear = function() {
1454 var year = this.getFullYear();
1455 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1459 * Get the first day of the current month, adjusted for leap year. The returned value
1460 * is the numeric day index within the week (0-6) which can be used in conjunction with
1461 * the {@link #monthNames} array to retrieve the textual day name.
1464 var dt = new Date('1/10/2007');
1465 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1467 * @return {Number} The day number (0-6)
1469 Date.prototype.getFirstDayOfMonth = function() {
1470 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1471 return (day < 0) ? (day + 7) : day;
1475 * Get the last day of the current month, adjusted for leap year. The returned value
1476 * is the numeric day index within the week (0-6) which can be used in conjunction with
1477 * the {@link #monthNames} array to retrieve the textual day name.
1480 var dt = new Date('1/10/2007');
1481 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1483 * @return {Number} The day number (0-6)
1485 Date.prototype.getLastDayOfMonth = function() {
1486 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1487 return (day < 0) ? (day + 7) : day;
1492 * Get the first date of this date's month
1495 Date.prototype.getFirstDateOfMonth = function() {
1496 return new Date(this.getFullYear(), this.getMonth(), 1);
1500 * Get the last date of this date's month
1503 Date.prototype.getLastDateOfMonth = function() {
1504 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1507 * Get the number of days in the current month, adjusted for leap year.
1508 * @return {Number} The number of days in the month
1510 Date.prototype.getDaysInMonth = function() {
1511 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1512 return Date.daysInMonth[this.getMonth()];
1516 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1517 * @return {String} 'st, 'nd', 'rd' or 'th'
1519 Date.prototype.getSuffix = function() {
1520 switch (this.getDate()) {
1537 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1540 * An array of textual month names.
1541 * Override these values for international dates, for example...
1542 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1561 * An array of textual day names.
1562 * Override these values for international dates, for example...
1563 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1579 Date.monthNumbers = {
1594 * Creates and returns a new Date instance with the exact same date value as the called instance.
1595 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1596 * variable will also be changed. When the intention is to create a new variable that will not
1597 * modify the original instance, you should create a clone.
1599 * Example of correctly cloning a date:
1602 var orig = new Date('10/1/2006');
1605 document.write(orig); //returns 'Thu Oct 05 2006'!
1608 var orig = new Date('10/1/2006');
1609 var copy = orig.clone();
1611 document.write(orig); //returns 'Thu Oct 01 2006'
1613 * @return {Date} The new Date instance
1615 Date.prototype.clone = function() {
1616 return new Date(this.getTime());
1620 * Clears any time information from this date
1621 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1622 @return {Date} this or the clone
1624 Date.prototype.clearTime = function(clone){
1626 return this.clone().clearTime();
1631 this.setMilliseconds(0);
1636 // safari setMonth is broken
1638 Date.brokenSetMonth = Date.prototype.setMonth;
1639 Date.prototype.setMonth = function(num){
1641 var n = Math.ceil(-num);
1642 var back_year = Math.ceil(n/12);
1643 var month = (n % 12) ? 12 - n % 12 : 0 ;
1644 this.setFullYear(this.getFullYear() - back_year);
1645 return Date.brokenSetMonth.call(this, month);
1647 return Date.brokenSetMonth.apply(this, arguments);
1652 /** Date interval constant
1656 /** Date interval constant
1660 /** Date interval constant
1664 /** Date interval constant
1668 /** Date interval constant
1672 /** Date interval constant
1676 /** Date interval constant
1682 * Provides a convenient method of performing basic date arithmetic. This method
1683 * does not modify the Date instance being called - it creates and returns
1684 * a new Date instance containing the resulting date value.
1689 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1690 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1692 //Negative values will subtract correctly:
1693 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1694 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1696 //You can even chain several calls together in one line!
1697 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1698 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1701 * @param {String} interval A valid date interval enum value
1702 * @param {Number} value The amount to add to the current date
1703 * @return {Date} The new Date instance
1705 Date.prototype.add = function(interval, value){
1706 var d = this.clone();
1707 if (!interval || value === 0) return d;
1708 switch(interval.toLowerCase()){
1710 d.setMilliseconds(this.getMilliseconds() + value);
1713 d.setSeconds(this.getSeconds() + value);
1716 d.setMinutes(this.getMinutes() + value);
1719 d.setHours(this.getHours() + value);
1722 d.setDate(this.getDate() + value);
1725 var day = this.getDate();
1727 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1730 d.setMonth(this.getMonth() + value);
1733 d.setFullYear(this.getFullYear() + value);
1739 * Ext JS Library 1.1.1
1740 * Copyright(c) 2006-2007, Ext JS, LLC.
1742 * Originally Released Under LGPL - original licence link has changed is not relivant.
1745 * <script type="text/javascript">
1749 getViewWidth : function(full) {
1750 return full ? this.getDocumentWidth() : this.getViewportWidth();
1753 getViewHeight : function(full) {
1754 return full ? this.getDocumentHeight() : this.getViewportHeight();
1757 getDocumentHeight: function() {
1758 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1759 return Math.max(scrollHeight, this.getViewportHeight());
1762 getDocumentWidth: function() {
1763 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1764 return Math.max(scrollWidth, this.getViewportWidth());
1767 getViewportHeight: function() {
1768 var height = self.innerHeight;
1769 var mode = document.compatMode;
1771 if ((mode || Roo.isIE) && !Roo.isOpera) {
1772 height = (mode == "CSS1Compat") ?
1773 document.documentElement.clientHeight :
1774 document.body.clientHeight;
1780 getViewportWidth: function() {
1781 var width = self.innerWidth;
1782 var mode = document.compatMode;
1784 if (mode || Roo.isIE) {
1785 width = (mode == "CSS1Compat") ?
1786 document.documentElement.clientWidth :
1787 document.body.clientWidth;
1792 isAncestor : function(p, c) {
1799 if (p.contains && !Roo.isSafari) {
1800 return p.contains(c);
1801 } else if (p.compareDocumentPosition) {
1802 return !!(p.compareDocumentPosition(c) & 16);
1804 var parent = c.parentNode;
1809 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1812 parent = parent.parentNode;
1818 getRegion : function(el) {
1819 return Roo.lib.Region.getRegion(el);
1822 getY : function(el) {
1823 return this.getXY(el)[1];
1826 getX : function(el) {
1827 return this.getXY(el)[0];
1830 getXY : function(el) {
1831 var p, pe, b, scroll, bd = document.body;
1832 el = Roo.getDom(el);
1833 var fly = Roo.lib.AnimBase.fly;
1834 if (el.getBoundingClientRect) {
1835 b = el.getBoundingClientRect();
1836 scroll = fly(document).getScroll();
1837 return [b.left + scroll.left, b.top + scroll.top];
1843 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1850 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1857 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1858 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1865 if (p != el && pe.getStyle('overflow') != 'visible') {
1873 if (Roo.isSafari && hasAbsolute) {
1878 if (Roo.isGecko && !hasAbsolute) {
1880 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1881 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1885 while (p && p != bd) {
1886 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1898 setXY : function(el, xy) {
1899 el = Roo.fly(el, '_setXY');
1901 var pts = el.translatePoints(xy);
1902 if (xy[0] !== false) {
1903 el.dom.style.left = pts.left + "px";
1905 if (xy[1] !== false) {
1906 el.dom.style.top = pts.top + "px";
1910 setX : function(el, x) {
1911 this.setXY(el, [x, false]);
1914 setY : function(el, y) {
1915 this.setXY(el, [false, y]);
1919 * Portions of this file are based on pieces of Yahoo User Interface Library
1920 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1921 * YUI licensed under the BSD License:
1922 * http://developer.yahoo.net/yui/license.txt
1923 * <script type="text/javascript">
1927 Roo.lib.Event = function() {
1928 var loadComplete = false;
1930 var unloadListeners = [];
1932 var onAvailStack = [];
1934 var lastError = null;
1947 startInterval: function() {
1948 if (!this._interval) {
1950 var callback = function() {
1951 self._tryPreloadAttach();
1953 this._interval = setInterval(callback, this.POLL_INTERVAL);
1958 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1959 onAvailStack.push({ id: p_id,
1962 override: p_override,
1963 checkReady: false });
1965 retryCount = this.POLL_RETRYS;
1966 this.startInterval();
1970 addListener: function(el, eventName, fn) {
1971 el = Roo.getDom(el);
1976 if ("unload" == eventName) {
1977 unloadListeners[unloadListeners.length] =
1978 [el, eventName, fn];
1982 var wrappedFn = function(e) {
1983 return fn(Roo.lib.Event.getEvent(e));
1986 var li = [el, eventName, fn, wrappedFn];
1988 var index = listeners.length;
1989 listeners[index] = li;
1991 this.doAdd(el, eventName, wrappedFn, false);
1997 removeListener: function(el, eventName, fn) {
2000 el = Roo.getDom(el);
2003 return this.purgeElement(el, false, eventName);
2007 if ("unload" == eventName) {
2009 for (i = 0,len = unloadListeners.length; i < len; i++) {
2010 var li = unloadListeners[i];
2013 li[1] == eventName &&
2015 unloadListeners.splice(i, 1);
2023 var cacheItem = null;
2026 var index = arguments[3];
2028 if ("undefined" == typeof index) {
2029 index = this._getCacheIndex(el, eventName, fn);
2033 cacheItem = listeners[index];
2036 if (!el || !cacheItem) {
2040 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2042 delete listeners[index][this.WFN];
2043 delete listeners[index][this.FN];
2044 listeners.splice(index, 1);
2051 getTarget: function(ev, resolveTextNode) {
2052 ev = ev.browserEvent || ev;
2053 var t = ev.target || ev.srcElement;
2054 return this.resolveTextNode(t);
2058 resolveTextNode: function(node) {
2059 if (Roo.isSafari && node && 3 == node.nodeType) {
2060 return node.parentNode;
2067 getPageX: function(ev) {
2068 ev = ev.browserEvent || ev;
2070 if (!x && 0 !== x) {
2071 x = ev.clientX || 0;
2074 x += this.getScroll()[1];
2082 getPageY: function(ev) {
2083 ev = ev.browserEvent || ev;
2085 if (!y && 0 !== y) {
2086 y = ev.clientY || 0;
2089 y += this.getScroll()[0];
2098 getXY: function(ev) {
2099 ev = ev.browserEvent || ev;
2100 return [this.getPageX(ev), this.getPageY(ev)];
2104 getRelatedTarget: function(ev) {
2105 ev = ev.browserEvent || ev;
2106 var t = ev.relatedTarget;
2108 if (ev.type == "mouseout") {
2110 } else if (ev.type == "mouseover") {
2115 return this.resolveTextNode(t);
2119 getTime: function(ev) {
2120 ev = ev.browserEvent || ev;
2122 var t = new Date().getTime();
2126 this.lastError = ex;
2135 stopEvent: function(ev) {
2136 this.stopPropagation(ev);
2137 this.preventDefault(ev);
2141 stopPropagation: function(ev) {
2142 ev = ev.browserEvent || ev;
2143 if (ev.stopPropagation) {
2144 ev.stopPropagation();
2146 ev.cancelBubble = true;
2151 preventDefault: function(ev) {
2152 ev = ev.browserEvent || ev;
2153 if(ev.preventDefault) {
2154 ev.preventDefault();
2156 ev.returnValue = false;
2161 getEvent: function(e) {
2162 var ev = e || window.event;
2164 var c = this.getEvent.caller;
2166 ev = c.arguments[0];
2167 if (ev && Event == ev.constructor) {
2177 getCharCode: function(ev) {
2178 ev = ev.browserEvent || ev;
2179 return ev.charCode || ev.keyCode || 0;
2183 _getCacheIndex: function(el, eventName, fn) {
2184 for (var i = 0,len = listeners.length; i < len; ++i) {
2185 var li = listeners[i];
2187 li[this.FN] == fn &&
2188 li[this.EL] == el &&
2189 li[this.TYPE] == eventName) {
2201 getEl: function(id) {
2202 return document.getElementById(id);
2206 clearCache: function() {
2210 _load: function(e) {
2211 loadComplete = true;
2212 var EU = Roo.lib.Event;
2216 EU.doRemove(window, "load", EU._load);
2221 _tryPreloadAttach: function() {
2230 var tryAgain = !loadComplete;
2232 tryAgain = (retryCount > 0);
2237 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2238 var item = onAvailStack[i];
2240 var el = this.getEl(item.id);
2243 if (!item.checkReady ||
2246 (document && document.body)) {
2249 if (item.override) {
2250 if (item.override === true) {
2253 scope = item.override;
2256 item.fn.call(scope, item.obj);
2257 onAvailStack[i] = null;
2260 notAvail.push(item);
2265 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2269 this.startInterval();
2271 clearInterval(this._interval);
2272 this._interval = null;
2275 this.locked = false;
2282 purgeElement: function(el, recurse, eventName) {
2283 var elListeners = this.getListeners(el, eventName);
2285 for (var i = 0,len = elListeners.length; i < len; ++i) {
2286 var l = elListeners[i];
2287 this.removeListener(el, l.type, l.fn);
2291 if (recurse && el && el.childNodes) {
2292 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2293 this.purgeElement(el.childNodes[i], recurse, eventName);
2299 getListeners: function(el, eventName) {
2300 var results = [], searchLists;
2302 searchLists = [listeners, unloadListeners];
2303 } else if (eventName == "unload") {
2304 searchLists = [unloadListeners];
2306 searchLists = [listeners];
2309 for (var j = 0; j < searchLists.length; ++j) {
2310 var searchList = searchLists[j];
2311 if (searchList && searchList.length > 0) {
2312 for (var i = 0,len = searchList.length; i < len; ++i) {
2313 var l = searchList[i];
2314 if (l && l[this.EL] === el &&
2315 (!eventName || eventName === l[this.TYPE])) {
2320 adjust: l[this.ADJ_SCOPE],
2328 return (results.length) ? results : null;
2332 _unload: function(e) {
2334 var EU = Roo.lib.Event, i, j, l, len, index;
2336 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2337 l = unloadListeners[i];
2340 if (l[EU.ADJ_SCOPE]) {
2341 if (l[EU.ADJ_SCOPE] === true) {
2344 scope = l[EU.ADJ_SCOPE];
2347 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2348 unloadListeners[i] = null;
2354 unloadListeners = null;
2356 if (listeners && listeners.length > 0) {
2357 j = listeners.length;
2360 l = listeners[index];
2362 EU.removeListener(l[EU.EL], l[EU.TYPE],
2372 EU.doRemove(window, "unload", EU._unload);
2377 getScroll: function() {
2378 var dd = document.documentElement, db = document.body;
2379 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2380 return [dd.scrollTop, dd.scrollLeft];
2382 return [db.scrollTop, db.scrollLeft];
2389 doAdd: function () {
2390 if (window.addEventListener) {
2391 return function(el, eventName, fn, capture) {
2392 el.addEventListener(eventName, fn, (capture));
2394 } else if (window.attachEvent) {
2395 return function(el, eventName, fn, capture) {
2396 el.attachEvent("on" + eventName, fn);
2405 doRemove: function() {
2406 if (window.removeEventListener) {
2407 return function (el, eventName, fn, capture) {
2408 el.removeEventListener(eventName, fn, (capture));
2410 } else if (window.detachEvent) {
2411 return function (el, eventName, fn) {
2412 el.detachEvent("on" + eventName, fn);
2424 var E = Roo.lib.Event;
2425 E.on = E.addListener;
2426 E.un = E.removeListener;
2428 if (document && document.body) {
2431 E.doAdd(window, "load", E._load);
2433 E.doAdd(window, "unload", E._unload);
2434 E._tryPreloadAttach();
2438 * Portions of this file are based on pieces of Yahoo User Interface Library
2439 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2440 * YUI licensed under the BSD License:
2441 * http://developer.yahoo.net/yui/license.txt
2442 * <script type="text/javascript">
2449 request : function(method, uri, cb, data, options) {
2451 var hs = options.headers;
2454 if(hs.hasOwnProperty(h)){
2455 this.initHeader(h, hs[h], false);
2459 if(options.xmlData){
2460 this.initHeader('Content-Type', 'text/xml', false);
2462 data = options.xmlData;
2466 return this.asyncRequest(method, uri, cb, data);
2469 serializeForm : function(form) {
2470 if(typeof form == 'string') {
2471 form = (document.getElementById(form) || document.forms[form]);
2474 var el, name, val, disabled, data = '', hasSubmit = false;
2475 for (var i = 0; i < form.elements.length; i++) {
2476 el = form.elements[i];
2477 disabled = form.elements[i].disabled;
2478 name = form.elements[i].name;
2479 val = form.elements[i].value;
2481 if (!disabled && name){
2485 case 'select-multiple':
2486 for (var j = 0; j < el.options.length; j++) {
2487 if (el.options[j].selected) {
2489 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2492 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2500 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2513 if(hasSubmit == false) {
2514 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2519 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2524 data = data.substr(0, data.length - 1);
2532 useDefaultHeader:true,
2534 defaultPostHeader:'application/x-www-form-urlencoded',
2536 useDefaultXhrHeader:true,
2538 defaultXhrHeader:'XMLHttpRequest',
2540 hasDefaultHeaders:true,
2552 setProgId:function(id)
2554 this.activeX.unshift(id);
2557 setDefaultPostHeader:function(b)
2559 this.useDefaultHeader = b;
2562 setDefaultXhrHeader:function(b)
2564 this.useDefaultXhrHeader = b;
2567 setPollingInterval:function(i)
2569 if (typeof i == 'number' && isFinite(i)) {
2570 this.pollInterval = i;
2574 createXhrObject:function(transactionId)
2580 http = new XMLHttpRequest();
2582 obj = { conn:http, tId:transactionId };
2586 for (var i = 0; i < this.activeX.length; ++i) {
2590 http = new ActiveXObject(this.activeX[i]);
2592 obj = { conn:http, tId:transactionId };
2605 getConnectionObject:function()
2608 var tId = this.transactionId;
2612 o = this.createXhrObject(tId);
2614 this.transactionId++;
2625 asyncRequest:function(method, uri, callback, postData)
2627 var o = this.getConnectionObject();
2633 o.conn.open(method, uri, true);
2635 if (this.useDefaultXhrHeader) {
2636 if (!this.defaultHeaders['X-Requested-With']) {
2637 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2641 if(postData && this.useDefaultHeader){
2642 this.initHeader('Content-Type', this.defaultPostHeader);
2645 if (this.hasDefaultHeaders || this.hasHeaders) {
2649 this.handleReadyState(o, callback);
2650 o.conn.send(postData || null);
2656 handleReadyState:function(o, callback)
2660 if (callback && callback.timeout) {
2661 this.timeout[o.tId] = window.setTimeout(function() {
2662 oConn.abort(o, callback, true);
2663 }, callback.timeout);
2666 this.poll[o.tId] = window.setInterval(
2668 if (o.conn && o.conn.readyState == 4) {
2669 window.clearInterval(oConn.poll[o.tId]);
2670 delete oConn.poll[o.tId];
2672 if(callback && callback.timeout) {
2673 window.clearTimeout(oConn.timeout[o.tId]);
2674 delete oConn.timeout[o.tId];
2677 oConn.handleTransactionResponse(o, callback);
2680 , this.pollInterval);
2683 handleTransactionResponse:function(o, callback, isAbort)
2687 this.releaseObject(o);
2691 var httpStatus, responseObject;
2695 if (o.conn.status !== undefined && o.conn.status != 0) {
2696 httpStatus = o.conn.status;
2708 if (httpStatus >= 200 && httpStatus < 300) {
2709 responseObject = this.createResponseObject(o, callback.argument);
2710 if (callback.success) {
2711 if (!callback.scope) {
2712 callback.success(responseObject);
2717 callback.success.apply(callback.scope, [responseObject]);
2722 switch (httpStatus) {
2730 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2731 if (callback.failure) {
2732 if (!callback.scope) {
2733 callback.failure(responseObject);
2736 callback.failure.apply(callback.scope, [responseObject]);
2741 responseObject = this.createResponseObject(o, callback.argument);
2742 if (callback.failure) {
2743 if (!callback.scope) {
2744 callback.failure(responseObject);
2747 callback.failure.apply(callback.scope, [responseObject]);
2753 this.releaseObject(o);
2754 responseObject = null;
2757 createResponseObject:function(o, callbackArg)
2764 var headerStr = o.conn.getAllResponseHeaders();
2765 var header = headerStr.split('\n');
2766 for (var i = 0; i < header.length; i++) {
2767 var delimitPos = header[i].indexOf(':');
2768 if (delimitPos != -1) {
2769 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2777 obj.status = o.conn.status;
2778 obj.statusText = o.conn.statusText;
2779 obj.getResponseHeader = headerObj;
2780 obj.getAllResponseHeaders = headerStr;
2781 obj.responseText = o.conn.responseText;
2782 obj.responseXML = o.conn.responseXML;
2784 if (typeof callbackArg !== undefined) {
2785 obj.argument = callbackArg;
2791 createExceptionObject:function(tId, callbackArg, isAbort)
2794 var COMM_ERROR = 'communication failure';
2795 var ABORT_CODE = -1;
2796 var ABORT_ERROR = 'transaction aborted';
2802 obj.status = ABORT_CODE;
2803 obj.statusText = ABORT_ERROR;
2806 obj.status = COMM_CODE;
2807 obj.statusText = COMM_ERROR;
2811 obj.argument = callbackArg;
2817 initHeader:function(label, value, isDefault)
2819 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2821 if (headerObj[label] === undefined) {
2822 headerObj[label] = value;
2827 headerObj[label] = value + "," + headerObj[label];
2831 this.hasDefaultHeaders = true;
2834 this.hasHeaders = true;
2839 setHeader:function(o)
2841 if (this.hasDefaultHeaders) {
2842 for (var prop in this.defaultHeaders) {
2843 if (this.defaultHeaders.hasOwnProperty(prop)) {
2844 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2849 if (this.hasHeaders) {
2850 for (var prop in this.headers) {
2851 if (this.headers.hasOwnProperty(prop)) {
2852 o.conn.setRequestHeader(prop, this.headers[prop]);
2856 this.hasHeaders = false;
2860 resetDefaultHeaders:function() {
2861 delete this.defaultHeaders;
2862 this.defaultHeaders = {};
2863 this.hasDefaultHeaders = false;
2866 abort:function(o, callback, isTimeout)
2868 if(this.isCallInProgress(o)) {
2870 window.clearInterval(this.poll[o.tId]);
2871 delete this.poll[o.tId];
2873 delete this.timeout[o.tId];
2876 this.handleTransactionResponse(o, callback, true);
2886 isCallInProgress:function(o)
2889 return o.conn.readyState != 4 && o.conn.readyState != 0;
2898 releaseObject:function(o)
2907 'MSXML2.XMLHTTP.3.0',
2915 * Portions of this file are based on pieces of Yahoo User Interface Library
2916 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2917 * YUI licensed under the BSD License:
2918 * http://developer.yahoo.net/yui/license.txt
2919 * <script type="text/javascript">
2923 Roo.lib.Region = function(t, r, b, l) {
2933 Roo.lib.Region.prototype = {
2934 contains : function(region) {
2935 return ( region.left >= this.left &&
2936 region.right <= this.right &&
2937 region.top >= this.top &&
2938 region.bottom <= this.bottom );
2942 getArea : function() {
2943 return ( (this.bottom - this.top) * (this.right - this.left) );
2946 intersect : function(region) {
2947 var t = Math.max(this.top, region.top);
2948 var r = Math.min(this.right, region.right);
2949 var b = Math.min(this.bottom, region.bottom);
2950 var l = Math.max(this.left, region.left);
2952 if (b >= t && r >= l) {
2953 return new Roo.lib.Region(t, r, b, l);
2958 union : function(region) {
2959 var t = Math.min(this.top, region.top);
2960 var r = Math.max(this.right, region.right);
2961 var b = Math.max(this.bottom, region.bottom);
2962 var l = Math.min(this.left, region.left);
2964 return new Roo.lib.Region(t, r, b, l);
2967 adjust : function(t, l, b, r) {
2976 Roo.lib.Region.getRegion = function(el) {
2977 var p = Roo.lib.Dom.getXY(el);
2980 var r = p[0] + el.offsetWidth;
2981 var b = p[1] + el.offsetHeight;
2984 return new Roo.lib.Region(t, r, b, l);
2987 * Portions of this file are based on pieces of Yahoo User Interface Library
2988 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2989 * YUI licensed under the BSD License:
2990 * http://developer.yahoo.net/yui/license.txt
2991 * <script type="text/javascript">
2994 //@@dep Roo.lib.Region
2997 Roo.lib.Point = function(x, y) {
2998 if (x instanceof Array) {
3002 this.x = this.right = this.left = this[0] = x;
3003 this.y = this.top = this.bottom = this[1] = y;
3006 Roo.lib.Point.prototype = new Roo.lib.Region();
3008 * Portions of this file are based on pieces of Yahoo User Interface Library
3009 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3010 * YUI licensed under the BSD License:
3011 * http://developer.yahoo.net/yui/license.txt
3012 * <script type="text/javascript">
3019 scroll : function(el, args, duration, easing, cb, scope) {
3020 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3023 motion : function(el, args, duration, easing, cb, scope) {
3024 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3027 color : function(el, args, duration, easing, cb, scope) {
3028 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3031 run : function(el, args, duration, easing, cb, scope, type) {
3032 type = type || Roo.lib.AnimBase;
3033 if (typeof easing == "string") {
3034 easing = Roo.lib.Easing[easing];
3036 var anim = new type(el, args, duration, easing);
3037 anim.animateX(function() {
3038 Roo.callback(cb, scope);
3044 * Portions of this file are based on pieces of Yahoo User Interface Library
3045 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3046 * YUI licensed under the BSD License:
3047 * http://developer.yahoo.net/yui/license.txt
3048 * <script type="text/javascript">
3056 if (!libFlyweight) {
3057 libFlyweight = new Roo.Element.Flyweight();
3059 libFlyweight.dom = el;
3060 return libFlyweight;
3063 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3067 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3069 this.init(el, attributes, duration, method);
3073 Roo.lib.AnimBase.fly = fly;
3077 Roo.lib.AnimBase.prototype = {
3079 toString: function() {
3080 var el = this.getEl();
3081 var id = el.id || el.tagName;
3082 return ("Anim " + id);
3086 noNegatives: /width|height|opacity|padding/i,
3087 offsetAttribute: /^((width|height)|(top|left))$/,
3088 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3089 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3093 doMethod: function(attr, start, end) {
3094 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3098 setAttribute: function(attr, val, unit) {
3099 if (this.patterns.noNegatives.test(attr)) {
3100 val = (val > 0) ? val : 0;
3103 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3107 getAttribute: function(attr) {
3108 var el = this.getEl();
3109 var val = fly(el).getStyle(attr);
3111 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3112 return parseFloat(val);
3115 var a = this.patterns.offsetAttribute.exec(attr) || [];
3116 var pos = !!( a[3] );
3117 var box = !!( a[2] );
3120 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3121 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3130 getDefaultUnit: function(attr) {
3131 if (this.patterns.defaultUnit.test(attr)) {
3138 animateX : function(callback, scope) {
3139 var f = function() {
3140 this.onComplete.removeListener(f);
3141 if (typeof callback == "function") {
3142 callback.call(scope || this, this);
3145 this.onComplete.addListener(f, this);
3150 setRuntimeAttribute: function(attr) {
3153 var attributes = this.attributes;
3155 this.runtimeAttributes[attr] = {};
3157 var isset = function(prop) {
3158 return (typeof prop !== 'undefined');
3161 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3165 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3168 if (isset(attributes[attr]['to'])) {
3169 end = attributes[attr]['to'];
3170 } else if (isset(attributes[attr]['by'])) {
3171 if (start.constructor == Array) {
3173 for (var i = 0, len = start.length; i < len; ++i) {
3174 end[i] = start[i] + attributes[attr]['by'][i];
3177 end = start + attributes[attr]['by'];
3181 this.runtimeAttributes[attr].start = start;
3182 this.runtimeAttributes[attr].end = end;
3185 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3189 init: function(el, attributes, duration, method) {
3191 var isAnimated = false;
3194 var startTime = null;
3197 var actualFrames = 0;
3200 el = Roo.getDom(el);
3203 this.attributes = attributes || {};
3206 this.duration = duration || 1;
3209 this.method = method || Roo.lib.Easing.easeNone;
3212 this.useSeconds = true;
3215 this.currentFrame = 0;
3218 this.totalFrames = Roo.lib.AnimMgr.fps;
3221 this.getEl = function() {
3226 this.isAnimated = function() {
3231 this.getStartTime = function() {
3235 this.runtimeAttributes = {};
3238 this.animate = function() {
3239 if (this.isAnimated()) {
3243 this.currentFrame = 0;
3245 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3247 Roo.lib.AnimMgr.registerElement(this);
3251 this.stop = function(finish) {
3253 this.currentFrame = this.totalFrames;
3254 this._onTween.fire();
3256 Roo.lib.AnimMgr.stop(this);
3259 var onStart = function() {
3260 this.onStart.fire();
3262 this.runtimeAttributes = {};
3263 for (var attr in this.attributes) {
3264 this.setRuntimeAttribute(attr);
3269 startTime = new Date();
3273 var onTween = function() {
3275 duration: new Date() - this.getStartTime(),
3276 currentFrame: this.currentFrame
3279 data.toString = function() {
3281 'duration: ' + data.duration +
3282 ', currentFrame: ' + data.currentFrame
3286 this.onTween.fire(data);
3288 var runtimeAttributes = this.runtimeAttributes;
3290 for (var attr in runtimeAttributes) {
3291 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3297 var onComplete = function() {
3298 var actual_duration = (new Date() - startTime) / 1000 ;
3301 duration: actual_duration,
3302 frames: actualFrames,
3303 fps: actualFrames / actual_duration
3306 data.toString = function() {
3308 'duration: ' + data.duration +
3309 ', frames: ' + data.frames +
3310 ', fps: ' + data.fps
3316 this.onComplete.fire(data);
3320 this._onStart = new Roo.util.Event(this);
3321 this.onStart = new Roo.util.Event(this);
3322 this.onTween = new Roo.util.Event(this);
3323 this._onTween = new Roo.util.Event(this);
3324 this.onComplete = new Roo.util.Event(this);
3325 this._onComplete = new Roo.util.Event(this);
3326 this._onStart.addListener(onStart);
3327 this._onTween.addListener(onTween);
3328 this._onComplete.addListener(onComplete);
3333 * Portions of this file are based on pieces of Yahoo User Interface Library
3334 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3335 * YUI licensed under the BSD License:
3336 * http://developer.yahoo.net/yui/license.txt
3337 * <script type="text/javascript">
3341 Roo.lib.AnimMgr = new function() {
3358 this.registerElement = function(tween) {
3359 queue[queue.length] = tween;
3361 tween._onStart.fire();
3366 this.unRegister = function(tween, index) {
3367 tween._onComplete.fire();
3368 index = index || getIndex(tween);
3370 queue.splice(index, 1);
3374 if (tweenCount <= 0) {
3380 this.start = function() {
3381 if (thread === null) {
3382 thread = setInterval(this.run, this.delay);
3387 this.stop = function(tween) {
3389 clearInterval(thread);
3391 for (var i = 0, len = queue.length; i < len; ++i) {
3392 if (queue[0].isAnimated()) {
3393 this.unRegister(queue[0], 0);
3402 this.unRegister(tween);
3407 this.run = function() {
3408 for (var i = 0, len = queue.length; i < len; ++i) {
3409 var tween = queue[i];
3410 if (!tween || !tween.isAnimated()) {
3414 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3416 tween.currentFrame += 1;
3418 if (tween.useSeconds) {
3419 correctFrame(tween);
3421 tween._onTween.fire();
3424 Roo.lib.AnimMgr.stop(tween, i);
3429 var getIndex = function(anim) {
3430 for (var i = 0, len = queue.length; i < len; ++i) {
3431 if (queue[i] == anim) {
3439 var correctFrame = function(tween) {
3440 var frames = tween.totalFrames;
3441 var frame = tween.currentFrame;
3442 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3443 var elapsed = (new Date() - tween.getStartTime());
3446 if (elapsed < tween.duration * 1000) {
3447 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3449 tweak = frames - (frame + 1);
3451 if (tweak > 0 && isFinite(tweak)) {
3452 if (tween.currentFrame + tweak >= frames) {
3453 tweak = frames - (frame + 1);
3456 tween.currentFrame += tweak;
3460 * Portions of this file are based on pieces of Yahoo User Interface Library
3461 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3462 * YUI licensed under the BSD License:
3463 * http://developer.yahoo.net/yui/license.txt
3464 * <script type="text/javascript">
3467 Roo.lib.Bezier = new function() {
3469 this.getPosition = function(points, t) {
3470 var n = points.length;
3473 for (var i = 0; i < n; ++i) {
3474 tmp[i] = [points[i][0], points[i][1]];
3477 for (var j = 1; j < n; ++j) {
3478 for (i = 0; i < n - j; ++i) {
3479 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3480 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3484 return [ tmp[0][0], tmp[0][1] ];
3488 * Portions of this file are based on pieces of Yahoo User Interface Library
3489 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3490 * YUI licensed under the BSD License:
3491 * http://developer.yahoo.net/yui/license.txt
3492 * <script type="text/javascript">
3497 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3498 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3501 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3503 var fly = Roo.lib.AnimBase.fly;
3505 var superclass = Y.ColorAnim.superclass;
3506 var proto = Y.ColorAnim.prototype;
3508 proto.toString = function() {
3509 var el = this.getEl();
3510 var id = el.id || el.tagName;
3511 return ("ColorAnim " + id);
3514 proto.patterns.color = /color$/i;
3515 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3516 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3517 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3518 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3521 proto.parseColor = function(s) {
3522 if (s.length == 3) {
3526 var c = this.patterns.hex.exec(s);
3527 if (c && c.length == 4) {
3528 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3531 c = this.patterns.rgb.exec(s);
3532 if (c && c.length == 4) {
3533 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3536 c = this.patterns.hex3.exec(s);
3537 if (c && c.length == 4) {
3538 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3543 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3544 proto.getAttribute = function(attr) {
3545 var el = this.getEl();
3546 if (this.patterns.color.test(attr)) {
3547 var val = fly(el).getStyle(attr);
3549 if (this.patterns.transparent.test(val)) {
3550 var parent = el.parentNode;
3551 val = fly(parent).getStyle(attr);
3553 while (parent && this.patterns.transparent.test(val)) {
3554 parent = parent.parentNode;
3555 val = fly(parent).getStyle(attr);
3556 if (parent.tagName.toUpperCase() == 'HTML') {
3562 val = superclass.getAttribute.call(this, attr);
3567 proto.getAttribute = function(attr) {
3568 var el = this.getEl();
3569 if (this.patterns.color.test(attr)) {
3570 var val = fly(el).getStyle(attr);
3572 if (this.patterns.transparent.test(val)) {
3573 var parent = el.parentNode;
3574 val = fly(parent).getStyle(attr);
3576 while (parent && this.patterns.transparent.test(val)) {
3577 parent = parent.parentNode;
3578 val = fly(parent).getStyle(attr);
3579 if (parent.tagName.toUpperCase() == 'HTML') {
3585 val = superclass.getAttribute.call(this, attr);
3591 proto.doMethod = function(attr, start, end) {
3594 if (this.patterns.color.test(attr)) {
3596 for (var i = 0, len = start.length; i < len; ++i) {
3597 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3600 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3603 val = superclass.doMethod.call(this, attr, start, end);
3609 proto.setRuntimeAttribute = function(attr) {
3610 superclass.setRuntimeAttribute.call(this, attr);
3612 if (this.patterns.color.test(attr)) {
3613 var attributes = this.attributes;
3614 var start = this.parseColor(this.runtimeAttributes[attr].start);
3615 var end = this.parseColor(this.runtimeAttributes[attr].end);
3617 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3618 end = this.parseColor(attributes[attr].by);
3620 for (var i = 0, len = start.length; i < len; ++i) {
3621 end[i] = start[i] + end[i];
3625 this.runtimeAttributes[attr].start = start;
3626 this.runtimeAttributes[attr].end = end;
3632 * Portions of this file are based on pieces of Yahoo User Interface Library
3633 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3634 * YUI licensed under the BSD License:
3635 * http://developer.yahoo.net/yui/license.txt
3636 * <script type="text/javascript">
3642 easeNone: function (t, b, c, d) {
3643 return c * t / d + b;
3647 easeIn: function (t, b, c, d) {
3648 return c * (t /= d) * t + b;
3652 easeOut: function (t, b, c, d) {
3653 return -c * (t /= d) * (t - 2) + b;
3657 easeBoth: function (t, b, c, d) {
3658 if ((t /= d / 2) < 1) {
3659 return c / 2 * t * t + b;
3662 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3666 easeInStrong: function (t, b, c, d) {
3667 return c * (t /= d) * t * t * t + b;
3671 easeOutStrong: function (t, b, c, d) {
3672 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3676 easeBothStrong: function (t, b, c, d) {
3677 if ((t /= d / 2) < 1) {
3678 return c / 2 * t * t * t * t + b;
3681 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3686 elasticIn: function (t, b, c, d, a, p) {
3690 if ((t /= d) == 1) {
3697 if (!a || a < Math.abs(c)) {
3702 var s = p / (2 * Math.PI) * Math.asin(c / a);
3705 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3709 elasticOut: function (t, b, c, d, a, p) {
3713 if ((t /= d) == 1) {
3720 if (!a || a < Math.abs(c)) {
3725 var s = p / (2 * Math.PI) * Math.asin(c / a);
3728 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3732 elasticBoth: function (t, b, c, d, a, p) {
3737 if ((t /= d / 2) == 2) {
3745 if (!a || a < Math.abs(c)) {
3750 var s = p / (2 * Math.PI) * Math.asin(c / a);
3754 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3755 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3757 return a * Math.pow(2, -10 * (t -= 1)) *
3758 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3763 backIn: function (t, b, c, d, s) {
3764 if (typeof s == 'undefined') {
3767 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3771 backOut: function (t, b, c, d, s) {
3772 if (typeof s == 'undefined') {
3775 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3779 backBoth: function (t, b, c, d, s) {
3780 if (typeof s == 'undefined') {
3784 if ((t /= d / 2 ) < 1) {
3785 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3787 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3791 bounceIn: function (t, b, c, d) {
3792 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3796 bounceOut: function (t, b, c, d) {
3797 if ((t /= d) < (1 / 2.75)) {
3798 return c * (7.5625 * t * t) + b;
3799 } else if (t < (2 / 2.75)) {
3800 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3801 } else if (t < (2.5 / 2.75)) {
3802 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3804 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3808 bounceBoth: function (t, b, c, d) {
3810 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3812 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3815 * Portions of this file are based on pieces of Yahoo User Interface Library
3816 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3817 * YUI licensed under the BSD License:
3818 * http://developer.yahoo.net/yui/license.txt
3819 * <script type="text/javascript">
3823 Roo.lib.Motion = function(el, attributes, duration, method) {
3825 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3829 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3833 var superclass = Y.Motion.superclass;
3834 var proto = Y.Motion.prototype;
3836 proto.toString = function() {
3837 var el = this.getEl();
3838 var id = el.id || el.tagName;
3839 return ("Motion " + id);
3842 proto.patterns.points = /^points$/i;
3844 proto.setAttribute = function(attr, val, unit) {
3845 if (this.patterns.points.test(attr)) {
3846 unit = unit || 'px';
3847 superclass.setAttribute.call(this, 'left', val[0], unit);
3848 superclass.setAttribute.call(this, 'top', val[1], unit);
3850 superclass.setAttribute.call(this, attr, val, unit);
3854 proto.getAttribute = function(attr) {
3855 if (this.patterns.points.test(attr)) {
3857 superclass.getAttribute.call(this, 'left'),
3858 superclass.getAttribute.call(this, 'top')
3861 val = superclass.getAttribute.call(this, attr);
3867 proto.doMethod = function(attr, start, end) {
3870 if (this.patterns.points.test(attr)) {
3871 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3872 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3874 val = superclass.doMethod.call(this, attr, start, end);
3879 proto.setRuntimeAttribute = function(attr) {
3880 if (this.patterns.points.test(attr)) {
3881 var el = this.getEl();
3882 var attributes = this.attributes;
3884 var control = attributes['points']['control'] || [];
3888 if (control.length > 0 && !(control[0] instanceof Array)) {
3889 control = [control];
3892 for (i = 0,len = control.length; i < len; ++i) {
3893 tmp[i] = control[i];
3898 Roo.fly(el).position();
3900 if (isset(attributes['points']['from'])) {
3901 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3904 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3907 start = this.getAttribute('points');
3910 if (isset(attributes['points']['to'])) {
3911 end = translateValues.call(this, attributes['points']['to'], start);
3913 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3914 for (i = 0,len = control.length; i < len; ++i) {
3915 control[i] = translateValues.call(this, control[i], start);
3919 } else if (isset(attributes['points']['by'])) {
3920 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3922 for (i = 0,len = control.length; i < len; ++i) {
3923 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3927 this.runtimeAttributes[attr] = [start];
3929 if (control.length > 0) {
3930 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3933 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3936 superclass.setRuntimeAttribute.call(this, attr);
3940 var translateValues = function(val, start) {
3941 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3942 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3947 var isset = function(prop) {
3948 return (typeof prop !== 'undefined');
3952 * Portions of this file are based on pieces of Yahoo User Interface Library
3953 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3954 * YUI licensed under the BSD License:
3955 * http://developer.yahoo.net/yui/license.txt
3956 * <script type="text/javascript">
3960 Roo.lib.Scroll = function(el, attributes, duration, method) {
3962 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3966 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3970 var superclass = Y.Scroll.superclass;
3971 var proto = Y.Scroll.prototype;
3973 proto.toString = function() {
3974 var el = this.getEl();
3975 var id = el.id || el.tagName;
3976 return ("Scroll " + id);
3979 proto.doMethod = function(attr, start, end) {
3982 if (attr == 'scroll') {
3984 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3985 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3989 val = superclass.doMethod.call(this, attr, start, end);
3994 proto.getAttribute = function(attr) {
3996 var el = this.getEl();
3998 if (attr == 'scroll') {
3999 val = [ el.scrollLeft, el.scrollTop ];
4001 val = superclass.getAttribute.call(this, attr);
4007 proto.setAttribute = function(attr, val, unit) {
4008 var el = this.getEl();
4010 if (attr == 'scroll') {
4011 el.scrollLeft = val[0];
4012 el.scrollTop = val[1];
4014 superclass.setAttribute.call(this, attr, val, unit);
4020 * Ext JS Library 1.1.1
4021 * Copyright(c) 2006-2007, Ext JS, LLC.
4023 * Originally Released Under LGPL - original licence link has changed is not relivant.
4026 * <script type="text/javascript">
4030 // nasty IE9 hack - what a pile of crap that is..
4033 if (typeof Range.prototype.createContextualFragment == "undefined") {
4035 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4036 >>>>>>> cba88e023db3bc6c12affc2e25a149cdac04fd17
4037 Range.prototype.createContextualFragment = function (html) {
4038 var doc = window.document;
4039 var container = doc.createElement("div");
4040 container.innerHTML = html;
4041 var frag = doc.createDocumentFragment(), n;
4042 while ((n = container.firstChild)) {
4043 frag.appendChild(n);
4050 * @class Roo.DomHelper
4051 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4052 * 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>.
4055 Roo.DomHelper = function(){
4056 var tempTableEl = null;
4057 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4058 var tableRe = /^table|tbody|tr|td$/i;
4060 // build as innerHTML where available
4062 var createHtml = function(o){
4063 if(typeof o == 'string'){
4072 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4073 if(attr == "style"){
4075 if(typeof s == "function"){
4078 if(typeof s == "string"){
4079 b += ' style="' + s + '"';
4080 }else if(typeof s == "object"){
4083 if(typeof s[key] != "function"){
4084 b += key + ":" + s[key] + ";";
4091 b += ' class="' + o["cls"] + '"';
4092 }else if(attr == "htmlFor"){
4093 b += ' for="' + o["htmlFor"] + '"';
4095 b += " " + attr + '="' + o[attr] + '"';
4099 if(emptyTags.test(o.tag)){
4103 var cn = o.children || o.cn;
4105 //http://bugs.kde.org/show_bug.cgi?id=71506
4106 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4107 for(var i = 0, len = cn.length; i < len; i++) {
4108 b += createHtml(cn[i], b);
4111 b += createHtml(cn, b);
4117 b += "</" + o.tag + ">";
4124 var createDom = function(o, parentNode){
4126 // defininition craeted..
4128 if (o.ns && o.ns != 'html') {
4130 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4131 xmlns[o.ns] = o.xmlns;
4134 if (typeof(xmlns[o.ns]) == 'undefined') {
4135 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4141 if (typeof(o) == 'string') {
4142 return parentNode.appendChild(document.createTextNode(o));
4144 o.tag = o.tag || div;
4145 if (o.ns && Roo.isIE) {
4147 o.tag = o.ns + ':' + o.tag;
4150 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4151 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4154 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4155 attr == "style" || typeof o[attr] == "function") continue;
4157 if(attr=="cls" && Roo.isIE){
4158 el.className = o["cls"];
4160 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4161 else el[attr] = o[attr];
4164 Roo.DomHelper.applyStyles(el, o.style);
4165 var cn = o.children || o.cn;
4167 //http://bugs.kde.org/show_bug.cgi?id=71506
4168 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4169 for(var i = 0, len = cn.length; i < len; i++) {
4170 createDom(cn[i], el);
4177 el.innerHTML = o.html;
4180 parentNode.appendChild(el);
4185 var ieTable = function(depth, s, h, e){
4186 tempTableEl.innerHTML = [s, h, e].join('');
4187 var i = -1, el = tempTableEl;
4194 // kill repeat to save bytes
4198 tbe = '</tbody>'+te,
4204 * Nasty code for IE's broken table implementation
4206 var insertIntoTable = function(tag, where, el, html){
4208 tempTableEl = document.createElement('div');
4213 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4216 if(where == 'beforebegin'){
4220 before = el.nextSibling;
4223 node = ieTable(4, trs, html, tre);
4225 else if(tag == 'tr'){
4226 if(where == 'beforebegin'){
4229 node = ieTable(3, tbs, html, tbe);
4230 } else if(where == 'afterend'){
4231 before = el.nextSibling;
4233 node = ieTable(3, tbs, html, tbe);
4234 } else{ // INTO a TR
4235 if(where == 'afterbegin'){
4236 before = el.firstChild;
4238 node = ieTable(4, trs, html, tre);
4240 } else if(tag == 'tbody'){
4241 if(where == 'beforebegin'){
4244 node = ieTable(2, ts, html, te);
4245 } else if(where == 'afterend'){
4246 before = el.nextSibling;
4248 node = ieTable(2, ts, html, te);
4250 if(where == 'afterbegin'){
4251 before = el.firstChild;
4253 node = ieTable(3, tbs, html, tbe);
4256 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4259 if(where == 'afterbegin'){
4260 before = el.firstChild;
4262 node = ieTable(2, ts, html, te);
4264 el.insertBefore(node, before);
4269 /** True to force the use of DOM instead of html fragments @type Boolean */
4273 * Returns the markup for the passed Element(s) config
4274 * @param {Object} o The Dom object spec (and children)
4277 markup : function(o){
4278 return createHtml(o);
4282 * Applies a style specification to an element
4283 * @param {String/HTMLElement} el The element to apply styles to
4284 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4285 * a function which returns such a specification.
4287 applyStyles : function(el, styles){
4290 if(typeof styles == "string"){
4291 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4293 while ((matches = re.exec(styles)) != null){
4294 el.setStyle(matches[1], matches[2]);
4296 }else if (typeof styles == "object"){
4297 for (var style in styles){
4298 el.setStyle(style, styles[style]);
4300 }else if (typeof styles == "function"){
4301 Roo.DomHelper.applyStyles(el, styles.call());
4307 * Inserts an HTML fragment into the Dom
4308 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4309 * @param {HTMLElement} el The context element
4310 * @param {String} html The HTML fragmenet
4311 * @return {HTMLElement} The new node
4313 insertHtml : function(where, el, html){
4314 where = where.toLowerCase();
4315 if(el.insertAdjacentHTML){
4316 if(tableRe.test(el.tagName)){
4318 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4324 el.insertAdjacentHTML('BeforeBegin', html);
4325 return el.previousSibling;
4327 el.insertAdjacentHTML('AfterBegin', html);
4328 return el.firstChild;
4330 el.insertAdjacentHTML('BeforeEnd', html);
4331 return el.lastChild;
4333 el.insertAdjacentHTML('AfterEnd', html);
4334 return el.nextSibling;
4336 throw 'Illegal insertion point -> "' + where + '"';
4338 var range = el.ownerDocument.createRange();
4342 range.setStartBefore(el);
4343 frag = range.createContextualFragment(html);
4344 el.parentNode.insertBefore(frag, el);
4345 return el.previousSibling;
4348 range.setStartBefore(el.firstChild);
4349 frag = range.createContextualFragment(html);
4350 el.insertBefore(frag, el.firstChild);
4351 return el.firstChild;
4353 el.innerHTML = html;
4354 return el.firstChild;
4358 range.setStartAfter(el.lastChild);
4359 frag = range.createContextualFragment(html);
4360 el.appendChild(frag);
4361 return el.lastChild;
4363 el.innerHTML = html;
4364 return el.lastChild;
4367 range.setStartAfter(el);
4368 frag = range.createContextualFragment(html);
4369 el.parentNode.insertBefore(frag, el.nextSibling);
4370 return el.nextSibling;
4372 throw 'Illegal insertion point -> "' + where + '"';
4376 * Creates new Dom element(s) and inserts them before el
4377 * @param {String/HTMLElement/Element} el The context element
4378 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4379 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4380 * @return {HTMLElement/Roo.Element} The new node
4382 insertBefore : function(el, o, returnElement){
4383 return this.doInsert(el, o, returnElement, "beforeBegin");
4387 * Creates new Dom element(s) and inserts them after el
4388 * @param {String/HTMLElement/Element} el The context element
4389 * @param {Object} o The Dom object spec (and children)
4390 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4391 * @return {HTMLElement/Roo.Element} The new node
4393 insertAfter : function(el, o, returnElement){
4394 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4398 * Creates new Dom element(s) and inserts them as the first child of el
4399 * @param {String/HTMLElement/Element} el The context element
4400 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4401 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4402 * @return {HTMLElement/Roo.Element} The new node
4404 insertFirst : function(el, o, returnElement){
4405 return this.doInsert(el, o, returnElement, "afterBegin");
4409 doInsert : function(el, o, returnElement, pos, sibling){
4410 el = Roo.getDom(el);
4412 if(this.useDom || o.ns){
4413 newNode = createDom(o, null);
4414 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4416 var html = createHtml(o);
4417 newNode = this.insertHtml(pos, el, html);
4419 return returnElement ? Roo.get(newNode, true) : newNode;
4423 * Creates new Dom element(s) and appends them to el
4424 * @param {String/HTMLElement/Element} el The context element
4425 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4426 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4427 * @return {HTMLElement/Roo.Element} The new node
4429 append : function(el, o, returnElement){
4430 el = Roo.getDom(el);
4432 if(this.useDom || o.ns){
4433 newNode = createDom(o, null);
4434 el.appendChild(newNode);
4436 var html = createHtml(o);
4437 newNode = this.insertHtml("beforeEnd", el, html);
4439 return returnElement ? Roo.get(newNode, true) : newNode;
4443 * Creates new Dom element(s) and overwrites the contents of el with them
4444 * @param {String/HTMLElement/Element} el The context element
4445 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4446 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4447 * @return {HTMLElement/Roo.Element} The new node
4449 overwrite : function(el, o, returnElement){
4450 el = Roo.getDom(el);
4453 while (el.childNodes.length) {
4454 el.removeChild(el.firstChild);
4458 el.innerHTML = createHtml(o);
4461 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4465 * Creates a new Roo.DomHelper.Template from the Dom object spec
4466 * @param {Object} o The Dom object spec (and children)
4467 * @return {Roo.DomHelper.Template} The new template
4469 createTemplate : function(o){
4470 var html = createHtml(o);
4471 return new Roo.Template(html);
4477 * Ext JS Library 1.1.1
4478 * Copyright(c) 2006-2007, Ext JS, LLC.
4480 * Originally Released Under LGPL - original licence link has changed is not relivant.
4483 * <script type="text/javascript">
4487 * @class Roo.Template
4488 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4489 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4492 var t = new Roo.Template({
4493 html : '<div name="{id}">' +
4494 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4496 myformat: function (value, allValues) {
4497 return 'XX' + value;
4500 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4502 * 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>.
4504 * @param {Object} cfg - Configuration object.
4506 Roo.Template = function(cfg){
4508 if(cfg instanceof Array){
4510 }else if(arguments.length > 1){
4511 cfg = Array.prototype.join.call(arguments, "");
4515 if (typeof(cfg) == 'object') {
4524 Roo.Template.prototype = {
4527 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4531 * Returns an HTML fragment of this template with the specified values applied.
4532 * @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'})
4533 * @return {String} The HTML fragment
4535 applyTemplate : function(values){
4539 return this.compiled(values);
4541 var useF = this.disableFormats !== true;
4542 var fm = Roo.util.Format, tpl = this;
4543 var fn = function(m, name, format, args){
4545 if(format.substr(0, 5) == "this."){
4546 return tpl.call(format.substr(5), values[name], values);
4549 // quoted values are required for strings in compiled templates,
4550 // but for non compiled we need to strip them
4551 // quoted reversed for jsmin
4552 var re = /^\s*['"](.*)["']\s*$/;
4553 args = args.split(',');
4554 for(var i = 0, len = args.length; i < len; i++){
4555 args[i] = args[i].replace(re, "$1");
4557 args = [values[name]].concat(args);
4559 args = [values[name]];
4561 return fm[format].apply(fm, args);
4564 return values[name] !== undefined ? values[name] : "";
4567 return this.html.replace(this.re, fn);
4576 * Sets the HTML used as the template and optionally compiles it.
4577 * @param {String} html
4578 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4579 * @return {Roo.Template} this
4581 set : function(html, compile){
4583 this.compiled = null;
4591 * True to disable format functions (defaults to false)
4594 disableFormats : false,
4597 * The regular expression used to match template variables
4601 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4604 * Compiles the template into an internal function, eliminating the RegEx overhead.
4605 * @return {Roo.Template} this
4607 compile : function(){
4608 var fm = Roo.util.Format;
4609 var useF = this.disableFormats !== true;
4610 var sep = Roo.isGecko ? "+" : ",";
4611 var fn = function(m, name, format, args){
4613 args = args ? ',' + args : "";
4614 if(format.substr(0, 5) != "this."){
4615 format = "fm." + format + '(';
4617 format = 'this.call("'+ format.substr(5) + '", ';
4621 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4623 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4626 // branched to use + in gecko and [].join() in others
4628 body = "this.compiled = function(values){ return '" +
4629 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4632 body = ["this.compiled = function(values){ return ['"];
4633 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4634 body.push("'].join('');};");
4635 body = body.join('');
4645 // private function used to call members
4646 call : function(fnName, value, allValues){
4647 return this[fnName](value, allValues);
4651 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4652 * @param {String/HTMLElement/Roo.Element} el The context element
4653 * @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'})
4654 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4655 * @return {HTMLElement/Roo.Element} The new node or Element
4657 insertFirst: function(el, values, returnElement){
4658 return this.doInsert('afterBegin', el, values, returnElement);
4662 * Applies the supplied values to the template and inserts the new node(s) before el.
4663 * @param {String/HTMLElement/Roo.Element} el The context element
4664 * @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'})
4665 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4666 * @return {HTMLElement/Roo.Element} The new node or Element
4668 insertBefore: function(el, values, returnElement){
4669 return this.doInsert('beforeBegin', el, values, returnElement);
4673 * Applies the supplied values to the template and inserts the new node(s) after el.
4674 * @param {String/HTMLElement/Roo.Element} el The context element
4675 * @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'})
4676 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4677 * @return {HTMLElement/Roo.Element} The new node or Element
4679 insertAfter : function(el, values, returnElement){
4680 return this.doInsert('afterEnd', el, values, returnElement);
4684 * Applies the supplied values to the template and appends the new node(s) to el.
4685 * @param {String/HTMLElement/Roo.Element} el The context element
4686 * @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'})
4687 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4688 * @return {HTMLElement/Roo.Element} The new node or Element
4690 append : function(el, values, returnElement){
4691 return this.doInsert('beforeEnd', el, values, returnElement);
4694 doInsert : function(where, el, values, returnEl){
4695 el = Roo.getDom(el);
4696 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4697 return returnEl ? Roo.get(newNode, true) : newNode;
4701 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4702 * @param {String/HTMLElement/Roo.Element} el The context element
4703 * @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'})
4704 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4705 * @return {HTMLElement/Roo.Element} The new node or Element
4707 overwrite : function(el, values, returnElement){
4708 el = Roo.getDom(el);
4709 el.innerHTML = this.applyTemplate(values);
4710 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4714 * Alias for {@link #applyTemplate}
4717 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4720 Roo.DomHelper.Template = Roo.Template;
4723 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4724 * @param {String/HTMLElement} el A DOM element or its id
4725 * @returns {Roo.Template} The created template
4728 Roo.Template.from = function(el){
4729 el = Roo.getDom(el);
4730 return new Roo.Template(el.value || el.innerHTML);
4733 * Ext JS Library 1.1.1
4734 * Copyright(c) 2006-2007, Ext JS, LLC.
4736 * Originally Released Under LGPL - original licence link has changed is not relivant.
4739 * <script type="text/javascript">
4744 * This is code is also distributed under MIT license for use
4745 * with jQuery and prototype JavaScript libraries.
4748 * @class Roo.DomQuery
4749 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).
4751 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>
4754 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.
4756 <h4>Element Selectors:</h4>
4758 <li> <b>*</b> any element</li>
4759 <li> <b>E</b> an element with the tag E</li>
4760 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4761 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4762 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4763 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4765 <h4>Attribute Selectors:</h4>
4766 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4768 <li> <b>E[foo]</b> has an attribute "foo"</li>
4769 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4770 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4771 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4772 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4773 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4774 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4776 <h4>Pseudo Classes:</h4>
4778 <li> <b>E:first-child</b> E is the first child of its parent</li>
4779 <li> <b>E:last-child</b> E is the last child of its parent</li>
4780 <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>
4781 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4782 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4783 <li> <b>E:only-child</b> E is the only child of its parent</li>
4784 <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>
4785 <li> <b>E:first</b> the first E in the resultset</li>
4786 <li> <b>E:last</b> the last E in the resultset</li>
4787 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4788 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4789 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4790 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4791 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4792 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4793 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4794 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4795 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4797 <h4>CSS Value Selectors:</h4>
4799 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4800 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4801 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4802 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4803 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4804 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4808 Roo.DomQuery = function(){
4809 var cache = {}, simpleCache = {}, valueCache = {};
4810 var nonSpace = /\S/;
4811 var trimRe = /^\s+|\s+$/g;
4812 var tplRe = /\{(\d+)\}/g;
4813 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4814 var tagTokenRe = /^(#)?([\w-\*]+)/;
4815 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4817 function child(p, index){
4819 var n = p.firstChild;
4821 if(n.nodeType == 1){
4832 while((n = n.nextSibling) && n.nodeType != 1);
4837 while((n = n.previousSibling) && n.nodeType != 1);
4841 function children(d){
4842 var n = d.firstChild, ni = -1;
4844 var nx = n.nextSibling;
4845 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4855 function byClassName(c, a, v){
4859 var r = [], ri = -1, cn;
4860 for(var i = 0, ci; ci = c[i]; i++){
4861 if((' '+ci.className+' ').indexOf(v) != -1){
4868 function attrValue(n, attr){
4869 if(!n.tagName && typeof n.length != "undefined"){
4878 if(attr == "class" || attr == "className"){
4881 return n.getAttribute(attr) || n[attr];
4885 function getNodes(ns, mode, tagName){
4886 var result = [], ri = -1, cs;
4890 tagName = tagName || "*";
4891 if(typeof ns.getElementsByTagName != "undefined"){
4895 for(var i = 0, ni; ni = ns[i]; i++){
4896 cs = ni.getElementsByTagName(tagName);
4897 for(var j = 0, ci; ci = cs[j]; j++){
4901 }else if(mode == "/" || mode == ">"){
4902 var utag = tagName.toUpperCase();
4903 for(var i = 0, ni, cn; ni = ns[i]; i++){
4904 cn = ni.children || ni.childNodes;
4905 for(var j = 0, cj; cj = cn[j]; j++){
4906 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4911 }else if(mode == "+"){
4912 var utag = tagName.toUpperCase();
4913 for(var i = 0, n; n = ns[i]; i++){
4914 while((n = n.nextSibling) && n.nodeType != 1);
4915 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4919 }else if(mode == "~"){
4920 for(var i = 0, n; n = ns[i]; i++){
4921 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4930 function concat(a, b){
4934 for(var i = 0, l = b.length; i < l; i++){
4940 function byTag(cs, tagName){
4941 if(cs.tagName || cs == document){
4947 var r = [], ri = -1;
4948 tagName = tagName.toLowerCase();
4949 for(var i = 0, ci; ci = cs[i]; i++){
4950 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4957 function byId(cs, attr, id){
4958 if(cs.tagName || cs == document){
4964 var r = [], ri = -1;
4965 for(var i = 0,ci; ci = cs[i]; i++){
4966 if(ci && ci.id == id){
4974 function byAttribute(cs, attr, value, op, custom){
4975 var r = [], ri = -1, st = custom=="{";
4976 var f = Roo.DomQuery.operators[op];
4977 for(var i = 0, ci; ci = cs[i]; i++){
4980 a = Roo.DomQuery.getStyle(ci, attr);
4982 else if(attr == "class" || attr == "className"){
4984 }else if(attr == "for"){
4986 }else if(attr == "href"){
4987 a = ci.getAttribute("href", 2);
4989 a = ci.getAttribute(attr);
4991 if((f && f(a, value)) || (!f && a)){
4998 function byPseudo(cs, name, value){
4999 return Roo.DomQuery.pseudos[name](cs, value);
5002 // This is for IE MSXML which does not support expandos.
5003 // IE runs the same speed using setAttribute, however FF slows way down
5004 // and Safari completely fails so they need to continue to use expandos.
5005 var isIE = window.ActiveXObject ? true : false;
5007 // this eval is stop the compressor from
5008 // renaming the variable to something shorter
5010 /** eval:var:batch */
5015 function nodupIEXml(cs){
5017 cs[0].setAttribute("_nodup", d);
5019 for(var i = 1, len = cs.length; i < len; i++){
5021 if(!c.getAttribute("_nodup") != d){
5022 c.setAttribute("_nodup", d);
5026 for(var i = 0, len = cs.length; i < len; i++){
5027 cs[i].removeAttribute("_nodup");
5036 var len = cs.length, c, i, r = cs, cj, ri = -1;
5037 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5040 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5041 return nodupIEXml(cs);
5045 for(i = 1; c = cs[i]; i++){
5050 for(var j = 0; j < i; j++){
5053 for(j = i+1; cj = cs[j]; j++){
5065 function quickDiffIEXml(c1, c2){
5067 for(var i = 0, len = c1.length; i < len; i++){
5068 c1[i].setAttribute("_qdiff", d);
5071 for(var i = 0, len = c2.length; i < len; i++){
5072 if(c2[i].getAttribute("_qdiff") != d){
5073 r[r.length] = c2[i];
5076 for(var i = 0, len = c1.length; i < len; i++){
5077 c1[i].removeAttribute("_qdiff");
5082 function quickDiff(c1, c2){
5083 var len1 = c1.length;
5087 if(isIE && c1[0].selectSingleNode){
5088 return quickDiffIEXml(c1, c2);
5091 for(var i = 0; i < len1; i++){
5095 for(var i = 0, len = c2.length; i < len; i++){
5096 if(c2[i]._qdiff != d){
5097 r[r.length] = c2[i];
5103 function quickId(ns, mode, root, id){
5105 var d = root.ownerDocument || root;
5106 return d.getElementById(id);
5108 ns = getNodes(ns, mode, "*");
5109 return byId(ns, null, id);
5113 getStyle : function(el, name){
5114 return Roo.fly(el).getStyle(name);
5117 * Compiles a selector/xpath query into a reusable function. The returned function
5118 * takes one parameter "root" (optional), which is the context node from where the query should start.
5119 * @param {String} selector The selector/xpath query
5120 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5121 * @return {Function}
5123 compile : function(path, type){
5124 type = type || "select";
5126 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5127 var q = path, mode, lq;
5128 var tk = Roo.DomQuery.matchers;
5129 var tklen = tk.length;
5132 // accept leading mode switch
5133 var lmode = q.match(modeRe);
5134 if(lmode && lmode[1]){
5135 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5136 q = q.replace(lmode[1], "");
5138 // strip leading slashes
5139 while(path.substr(0, 1)=="/"){
5140 path = path.substr(1);
5143 while(q && lq != q){
5145 var tm = q.match(tagTokenRe);
5146 if(type == "select"){
5149 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5151 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5153 q = q.replace(tm[0], "");
5154 }else if(q.substr(0, 1) != '@'){
5155 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5160 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5162 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5164 q = q.replace(tm[0], "");
5167 while(!(mm = q.match(modeRe))){
5168 var matched = false;
5169 for(var j = 0; j < tklen; j++){
5171 var m = q.match(t.re);
5173 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5176 q = q.replace(m[0], "");
5181 // prevent infinite loop on bad selector
5183 throw 'Error parsing selector, parsing failed at "' + q + '"';
5187 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5188 q = q.replace(mm[1], "");
5191 fn[fn.length] = "return nodup(n);\n}";
5194 * list of variables that need from compression as they are used by eval.
5204 * eval:var:byClassName
5206 * eval:var:byAttribute
5207 * eval:var:attrValue
5215 * Selects a group of elements.
5216 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5217 * @param {Node} root (optional) The start of the query (defaults to document).
5220 select : function(path, root, type){
5221 if(!root || root == document){
5224 if(typeof root == "string"){
5225 root = document.getElementById(root);
5227 var paths = path.split(",");
5229 for(var i = 0, len = paths.length; i < len; i++){
5230 var p = paths[i].replace(trimRe, "");
5232 cache[p] = Roo.DomQuery.compile(p);
5234 throw p + " is not a valid selector";
5237 var result = cache[p](root);
5238 if(result && result != document){
5239 results = results.concat(result);
5242 if(paths.length > 1){
5243 return nodup(results);
5249 * Selects a single element.
5250 * @param {String} selector The selector/xpath query
5251 * @param {Node} root (optional) The start of the query (defaults to document).
5254 selectNode : function(path, root){
5255 return Roo.DomQuery.select(path, root)[0];
5259 * Selects the value of a node, optionally replacing null with the defaultValue.
5260 * @param {String} selector The selector/xpath query
5261 * @param {Node} root (optional) The start of the query (defaults to document).
5262 * @param {String} defaultValue
5264 selectValue : function(path, root, defaultValue){
5265 path = path.replace(trimRe, "");
5266 if(!valueCache[path]){
5267 valueCache[path] = Roo.DomQuery.compile(path, "select");
5269 var n = valueCache[path](root);
5270 n = n[0] ? n[0] : n;
5271 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5272 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5276 * Selects the value of a node, parsing integers and floats.
5277 * @param {String} selector The selector/xpath query
5278 * @param {Node} root (optional) The start of the query (defaults to document).
5279 * @param {Number} defaultValue
5282 selectNumber : function(path, root, defaultValue){
5283 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5284 return parseFloat(v);
5288 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5289 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5290 * @param {String} selector The simple selector to test
5293 is : function(el, ss){
5294 if(typeof el == "string"){
5295 el = document.getElementById(el);
5297 var isArray = (el instanceof Array);
5298 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5299 return isArray ? (result.length == el.length) : (result.length > 0);
5303 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5304 * @param {Array} el An array of elements to filter
5305 * @param {String} selector The simple selector to test
5306 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5307 * the selector instead of the ones that match
5310 filter : function(els, ss, nonMatches){
5311 ss = ss.replace(trimRe, "");
5312 if(!simpleCache[ss]){
5313 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5315 var result = simpleCache[ss](els);
5316 return nonMatches ? quickDiff(result, els) : result;
5320 * Collection of matching regular expressions and code snippets.
5324 select: 'n = byClassName(n, null, " {1} ");'
5326 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5327 select: 'n = byPseudo(n, "{1}", "{2}");'
5329 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5330 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5333 select: 'n = byId(n, null, "{1}");'
5336 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5341 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5342 * 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, > <.
5345 "=" : function(a, v){
5348 "!=" : function(a, v){
5351 "^=" : function(a, v){
5352 return a && a.substr(0, v.length) == v;
5354 "$=" : function(a, v){
5355 return a && a.substr(a.length-v.length) == v;
5357 "*=" : function(a, v){
5358 return a && a.indexOf(v) !== -1;
5360 "%=" : function(a, v){
5361 return (a % v) == 0;
5363 "|=" : function(a, v){
5364 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5366 "~=" : function(a, v){
5367 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5372 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5373 * and the argument (if any) supplied in the selector.
5376 "first-child" : function(c){
5377 var r = [], ri = -1, n;
5378 for(var i = 0, ci; ci = n = c[i]; i++){
5379 while((n = n.previousSibling) && n.nodeType != 1);
5387 "last-child" : function(c){
5388 var r = [], ri = -1, n;
5389 for(var i = 0, ci; ci = n = c[i]; i++){
5390 while((n = n.nextSibling) && n.nodeType != 1);
5398 "nth-child" : function(c, a) {
5399 var r = [], ri = -1;
5400 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5401 var f = (m[1] || 1) - 0, l = m[2] - 0;
5402 for(var i = 0, n; n = c[i]; i++){
5403 var pn = n.parentNode;
5404 if (batch != pn._batch) {
5406 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5407 if(cn.nodeType == 1){
5414 if (l == 0 || n.nodeIndex == l){
5417 } else if ((n.nodeIndex + l) % f == 0){
5425 "only-child" : function(c){
5426 var r = [], ri = -1;;
5427 for(var i = 0, ci; ci = c[i]; i++){
5428 if(!prev(ci) && !next(ci)){
5435 "empty" : function(c){
5436 var r = [], ri = -1;
5437 for(var i = 0, ci; ci = c[i]; i++){
5438 var cns = ci.childNodes, j = 0, cn, empty = true;
5441 if(cn.nodeType == 1 || cn.nodeType == 3){
5453 "contains" : function(c, v){
5454 var r = [], ri = -1;
5455 for(var i = 0, ci; ci = c[i]; i++){
5456 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5463 "nodeValue" : function(c, v){
5464 var r = [], ri = -1;
5465 for(var i = 0, ci; ci = c[i]; i++){
5466 if(ci.firstChild && ci.firstChild.nodeValue == v){
5473 "checked" : function(c){
5474 var r = [], ri = -1;
5475 for(var i = 0, ci; ci = c[i]; i++){
5476 if(ci.checked == true){
5483 "not" : function(c, ss){
5484 return Roo.DomQuery.filter(c, ss, true);
5487 "odd" : function(c){
5488 return this["nth-child"](c, "odd");
5491 "even" : function(c){
5492 return this["nth-child"](c, "even");
5495 "nth" : function(c, a){
5496 return c[a-1] || [];
5499 "first" : function(c){
5503 "last" : function(c){
5504 return c[c.length-1] || [];
5507 "has" : function(c, ss){
5508 var s = Roo.DomQuery.select;
5509 var r = [], ri = -1;
5510 for(var i = 0, ci; ci = c[i]; i++){
5511 if(s(ss, ci).length > 0){
5518 "next" : function(c, ss){
5519 var is = Roo.DomQuery.is;
5520 var r = [], ri = -1;
5521 for(var i = 0, ci; ci = c[i]; i++){
5530 "prev" : function(c, ss){
5531 var is = Roo.DomQuery.is;
5532 var r = [], ri = -1;
5533 for(var i = 0, ci; ci = c[i]; i++){
5546 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5547 * @param {String} path The selector/xpath query
5548 * @param {Node} root (optional) The start of the query (defaults to document).
5553 Roo.query = Roo.DomQuery.select;
5556 * Ext JS Library 1.1.1
5557 * Copyright(c) 2006-2007, Ext JS, LLC.
5559 * Originally Released Under LGPL - original licence link has changed is not relivant.
5562 * <script type="text/javascript">
5566 * @class Roo.util.Observable
5567 * Base class that provides a common interface for publishing events. Subclasses are expected to
5568 * to have a property "events" with all the events defined.<br>
5571 Employee = function(name){
5578 Roo.extend(Employee, Roo.util.Observable);
5580 * @param {Object} config properties to use (incuding events / listeners)
5583 Roo.util.Observable = function(cfg){
5586 this.addEvents(cfg.events || {});
5588 delete cfg.events; // make sure
5591 Roo.apply(this, cfg);
5594 this.on(this.listeners);
5595 delete this.listeners;
5598 Roo.util.Observable.prototype = {
5600 * @cfg {Object} listeners list of events and functions to call for this object,
5604 'click' : function(e) {
5614 * Fires the specified event with the passed parameters (minus the event name).
5615 * @param {String} eventName
5616 * @param {Object...} args Variable number of parameters are passed to handlers
5617 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5619 fireEvent : function(){
5620 var ce = this.events[arguments[0].toLowerCase()];
5621 if(typeof ce == "object"){
5622 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5629 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5632 * Appends an event handler to this component
5633 * @param {String} eventName The type of event to listen for
5634 * @param {Function} handler The method the event invokes
5635 * @param {Object} scope (optional) The scope in which to execute the handler
5636 * function. The handler function's "this" context.
5637 * @param {Object} options (optional) An object containing handler configuration
5638 * properties. This may contain any of the following properties:<ul>
5639 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5640 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5641 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5642 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5643 * by the specified number of milliseconds. If the event fires again within that time, the original
5644 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5647 * <b>Combining Options</b><br>
5648 * Using the options argument, it is possible to combine different types of listeners:<br>
5650 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5652 el.on('click', this.onClick, this, {
5659 * <b>Attaching multiple handlers in 1 call</b><br>
5660 * The method also allows for a single argument to be passed which is a config object containing properties
5661 * which specify multiple handlers.
5670 fn: this.onMouseOver,
5674 fn: this.onMouseOut,
5680 * Or a shorthand syntax which passes the same scope object to all handlers:
5683 'click': this.onClick,
5684 'mouseover': this.onMouseOver,
5685 'mouseout': this.onMouseOut,
5690 addListener : function(eventName, fn, scope, o){
5691 if(typeof eventName == "object"){
5694 if(this.filterOptRe.test(e)){
5697 if(typeof o[e] == "function"){
5699 this.addListener(e, o[e], o.scope, o);
5701 // individual options
5702 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5707 o = (!o || typeof o == "boolean") ? {} : o;
5708 eventName = eventName.toLowerCase();
5709 var ce = this.events[eventName] || true;
5710 if(typeof ce == "boolean"){
5711 ce = new Roo.util.Event(this, eventName);
5712 this.events[eventName] = ce;
5714 ce.addListener(fn, scope, o);
5718 * Removes a listener
5719 * @param {String} eventName The type of event to listen for
5720 * @param {Function} handler The handler to remove
5721 * @param {Object} scope (optional) The scope (this object) for the handler
5723 removeListener : function(eventName, fn, scope){
5724 var ce = this.events[eventName.toLowerCase()];
5725 if(typeof ce == "object"){
5726 ce.removeListener(fn, scope);
5731 * Removes all listeners for this object
5733 purgeListeners : function(){
5734 for(var evt in this.events){
5735 if(typeof this.events[evt] == "object"){
5736 this.events[evt].clearListeners();
5741 relayEvents : function(o, events){
5742 var createHandler = function(ename){
5744 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5747 for(var i = 0, len = events.length; i < len; i++){
5748 var ename = events[i];
5749 if(!this.events[ename]){ this.events[ename] = true; };
5750 o.on(ename, createHandler(ename), this);
5755 * Used to define events on this Observable
5756 * @param {Object} object The object with the events defined
5758 addEvents : function(o){
5762 Roo.applyIf(this.events, o);
5766 * Checks to see if this object has any listeners for a specified event
5767 * @param {String} eventName The name of the event to check for
5768 * @return {Boolean} True if the event is being listened for, else false
5770 hasListener : function(eventName){
5771 var e = this.events[eventName];
5772 return typeof e == "object" && e.listeners.length > 0;
5776 * Appends an event handler to this element (shorthand for addListener)
5777 * @param {String} eventName The type of event to listen for
5778 * @param {Function} handler The method the event invokes
5779 * @param {Object} scope (optional) The scope in which to execute the handler
5780 * function. The handler function's "this" context.
5781 * @param {Object} options (optional)
5784 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5786 * Removes a listener (shorthand for removeListener)
5787 * @param {String} eventName The type of event to listen for
5788 * @param {Function} handler The handler to remove
5789 * @param {Object} scope (optional) The scope (this object) for the handler
5792 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5795 * Starts capture on the specified Observable. All events will be passed
5796 * to the supplied function with the event name + standard signature of the event
5797 * <b>before</b> the event is fired. If the supplied function returns false,
5798 * the event will not fire.
5799 * @param {Observable} o The Observable to capture
5800 * @param {Function} fn The function to call
5801 * @param {Object} scope (optional) The scope (this object) for the fn
5804 Roo.util.Observable.capture = function(o, fn, scope){
5805 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5809 * Removes <b>all</b> added captures from the Observable.
5810 * @param {Observable} o The Observable to release
5813 Roo.util.Observable.releaseCapture = function(o){
5814 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5819 var createBuffered = function(h, o, scope){
5820 var task = new Roo.util.DelayedTask();
5822 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5826 var createSingle = function(h, e, fn, scope){
5828 e.removeListener(fn, scope);
5829 return h.apply(scope, arguments);
5833 var createDelayed = function(h, o, scope){
5835 var args = Array.prototype.slice.call(arguments, 0);
5836 setTimeout(function(){
5837 h.apply(scope, args);
5842 Roo.util.Event = function(obj, name){
5845 this.listeners = [];
5848 Roo.util.Event.prototype = {
5849 addListener : function(fn, scope, options){
5850 var o = options || {};
5851 scope = scope || this.obj;
5852 if(!this.isListening(fn, scope)){
5853 var l = {fn: fn, scope: scope, options: o};
5856 h = createDelayed(h, o, scope);
5859 h = createSingle(h, this, fn, scope);
5862 h = createBuffered(h, o, scope);
5865 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5866 this.listeners.push(l);
5868 this.listeners = this.listeners.slice(0);
5869 this.listeners.push(l);
5874 findListener : function(fn, scope){
5875 scope = scope || this.obj;
5876 var ls = this.listeners;
5877 for(var i = 0, len = ls.length; i < len; i++){
5879 if(l.fn == fn && l.scope == scope){
5886 isListening : function(fn, scope){
5887 return this.findListener(fn, scope) != -1;
5890 removeListener : function(fn, scope){
5892 if((index = this.findListener(fn, scope)) != -1){
5894 this.listeners.splice(index, 1);
5896 this.listeners = this.listeners.slice(0);
5897 this.listeners.splice(index, 1);
5904 clearListeners : function(){
5905 this.listeners = [];
5909 var ls = this.listeners, scope, len = ls.length;
5912 var args = Array.prototype.slice.call(arguments, 0);
5913 for(var i = 0; i < len; i++){
5915 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5916 this.firing = false;
5920 this.firing = false;
5927 * Ext JS Library 1.1.1
5928 * Copyright(c) 2006-2007, Ext JS, LLC.
5930 * Originally Released Under LGPL - original licence link has changed is not relivant.
5933 * <script type="text/javascript">
5937 * @class Roo.EventManager
5938 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5939 * several useful events directly.
5940 * See {@link Roo.EventObject} for more details on normalized event objects.
5943 Roo.EventManager = function(){
5944 var docReadyEvent, docReadyProcId, docReadyState = false;
5945 var resizeEvent, resizeTask, textEvent, textSize;
5946 var E = Roo.lib.Event;
5947 var D = Roo.lib.Dom;
5950 var fireDocReady = function(){
5952 docReadyState = true;
5955 clearInterval(docReadyProcId);
5957 if(Roo.isGecko || Roo.isOpera) {
5958 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5961 var defer = document.getElementById("ie-deferred-loader");
5963 defer.onreadystatechange = null;
5964 defer.parentNode.removeChild(defer);
5968 docReadyEvent.fire();
5969 docReadyEvent.clearListeners();
5974 var initDocReady = function(){
5975 docReadyEvent = new Roo.util.Event();
5976 if(Roo.isGecko || Roo.isOpera) {
5977 document.addEventListener("DOMContentLoaded", fireDocReady, false);
5979 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5980 var defer = document.getElementById("ie-deferred-loader");
5981 defer.onreadystatechange = function(){
5982 if(this.readyState == "complete"){
5986 }else if(Roo.isSafari){
5987 docReadyProcId = setInterval(function(){
5988 var rs = document.readyState;
5989 if(rs == "complete") {
5994 // no matter what, make sure it fires on load
5995 E.on(window, "load", fireDocReady);
5998 var createBuffered = function(h, o){
5999 var task = new Roo.util.DelayedTask(h);
6001 // create new event object impl so new events don't wipe out properties
6002 e = new Roo.EventObjectImpl(e);
6003 task.delay(o.buffer, h, null, [e]);
6007 var createSingle = function(h, el, ename, fn){
6009 Roo.EventManager.removeListener(el, ename, fn);
6014 var createDelayed = function(h, o){
6016 // create new event object impl so new events don't wipe out properties
6017 e = new Roo.EventObjectImpl(e);
6018 setTimeout(function(){
6024 var listen = function(element, ename, opt, fn, scope){
6025 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6026 fn = fn || o.fn; scope = scope || o.scope;
6027 var el = Roo.getDom(element);
6029 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6031 var h = function(e){
6032 e = Roo.EventObject.setEvent(e);
6035 t = e.getTarget(o.delegate, el);
6042 if(o.stopEvent === true){
6045 if(o.preventDefault === true){
6048 if(o.stopPropagation === true){
6049 e.stopPropagation();
6052 if(o.normalized === false){
6056 fn.call(scope || el, e, t, o);
6059 h = createDelayed(h, o);
6062 h = createSingle(h, el, ename, fn);
6065 h = createBuffered(h, o);
6067 fn._handlers = fn._handlers || [];
6068 fn._handlers.push([Roo.id(el), ename, h]);
6071 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6072 el.addEventListener("DOMMouseScroll", h, false);
6073 E.on(window, 'unload', function(){
6074 el.removeEventListener("DOMMouseScroll", h, false);
6077 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6078 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6083 var stopListening = function(el, ename, fn){
6084 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6086 for(var i = 0, len = hds.length; i < len; i++){
6088 if(h[0] == id && h[1] == ename){
6095 E.un(el, ename, hd);
6096 el = Roo.getDom(el);
6097 if(ename == "mousewheel" && el.addEventListener){
6098 el.removeEventListener("DOMMouseScroll", hd, false);
6100 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6101 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6105 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6112 * @scope Roo.EventManager
6117 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6118 * object with a Roo.EventObject
6119 * @param {Function} fn The method the event invokes
6120 * @param {Object} scope An object that becomes the scope of the handler
6121 * @param {boolean} override If true, the obj passed in becomes
6122 * the execution scope of the listener
6123 * @return {Function} The wrapped function
6126 wrap : function(fn, scope, override){
6128 Roo.EventObject.setEvent(e);
6129 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6134 * Appends an event handler to an element (shorthand for addListener)
6135 * @param {String/HTMLElement} element The html element or id to assign the
6136 * @param {String} eventName The type of event to listen for
6137 * @param {Function} handler The method the event invokes
6138 * @param {Object} scope (optional) The scope in which to execute the handler
6139 * function. The handler function's "this" context.
6140 * @param {Object} options (optional) An object containing handler configuration
6141 * properties. This may contain any of the following properties:<ul>
6142 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6143 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6144 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6145 * <li>preventDefault {Boolean} True to prevent the default action</li>
6146 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6147 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6148 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6149 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6150 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6151 * by the specified number of milliseconds. If the event fires again within that time, the original
6152 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6155 * <b>Combining Options</b><br>
6156 * Using the options argument, it is possible to combine different types of listeners:<br>
6158 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6160 el.on('click', this.onClick, this, {
6167 * <b>Attaching multiple handlers in 1 call</b><br>
6168 * The method also allows for a single argument to be passed which is a config object containing properties
6169 * which specify multiple handlers.
6179 fn: this.onMouseOver
6188 * Or a shorthand syntax:<br>
6191 'click' : this.onClick,
6192 'mouseover' : this.onMouseOver,
6193 'mouseout' : this.onMouseOut
6197 addListener : function(element, eventName, fn, scope, options){
6198 if(typeof eventName == "object"){
6204 if(typeof o[e] == "function"){
6206 listen(element, e, o, o[e], o.scope);
6208 // individual options
6209 listen(element, e, o[e]);
6214 return listen(element, eventName, options, fn, scope);
6218 * Removes an event handler
6220 * @param {String/HTMLElement} element The id or html element to remove the
6222 * @param {String} eventName The type of event
6223 * @param {Function} fn
6224 * @return {Boolean} True if a listener was actually removed
6226 removeListener : function(element, eventName, fn){
6227 return stopListening(element, eventName, fn);
6231 * Fires when the document is ready (before onload and before images are loaded). Can be
6232 * accessed shorthanded Roo.onReady().
6233 * @param {Function} fn The method the event invokes
6234 * @param {Object} scope An object that becomes the scope of the handler
6235 * @param {boolean} options
6237 onDocumentReady : function(fn, scope, options){
6238 if(docReadyState){ // if it already fired
6239 docReadyEvent.addListener(fn, scope, options);
6240 docReadyEvent.fire();
6241 docReadyEvent.clearListeners();
6247 docReadyEvent.addListener(fn, scope, options);
6251 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6252 * @param {Function} fn The method the event invokes
6253 * @param {Object} scope An object that becomes the scope of the handler
6254 * @param {boolean} options
6256 onWindowResize : function(fn, scope, options){
6258 resizeEvent = new Roo.util.Event();
6259 resizeTask = new Roo.util.DelayedTask(function(){
6260 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6262 E.on(window, "resize", function(){
6264 resizeTask.delay(50);
6266 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6270 resizeEvent.addListener(fn, scope, options);
6274 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6275 * @param {Function} fn The method the event invokes
6276 * @param {Object} scope An object that becomes the scope of the handler
6277 * @param {boolean} options
6279 onTextResize : function(fn, scope, options){
6281 textEvent = new Roo.util.Event();
6282 var textEl = new Roo.Element(document.createElement('div'));
6283 textEl.dom.className = 'x-text-resize';
6284 textEl.dom.innerHTML = 'X';
6285 textEl.appendTo(document.body);
6286 textSize = textEl.dom.offsetHeight;
6287 setInterval(function(){
6288 if(textEl.dom.offsetHeight != textSize){
6289 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6291 }, this.textResizeInterval);
6293 textEvent.addListener(fn, scope, options);
6297 * Removes the passed window resize listener.
6298 * @param {Function} fn The method the event invokes
6299 * @param {Object} scope The scope of handler
6301 removeResizeListener : function(fn, scope){
6303 resizeEvent.removeListener(fn, scope);
6308 fireResize : function(){
6310 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6314 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6318 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6320 textResizeInterval : 50
6325 * @scopeAlias pub=Roo.EventManager
6329 * Appends an event handler to an element (shorthand for addListener)
6330 * @param {String/HTMLElement} element The html element or id to assign the
6331 * @param {String} eventName The type of event to listen for
6332 * @param {Function} handler The method the event invokes
6333 * @param {Object} scope (optional) The scope in which to execute the handler
6334 * function. The handler function's "this" context.
6335 * @param {Object} options (optional) An object containing handler configuration
6336 * properties. This may contain any of the following properties:<ul>
6337 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6338 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6339 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6340 * <li>preventDefault {Boolean} True to prevent the default action</li>
6341 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6342 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6343 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6344 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6345 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6346 * by the specified number of milliseconds. If the event fires again within that time, the original
6347 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6350 * <b>Combining Options</b><br>
6351 * Using the options argument, it is possible to combine different types of listeners:<br>
6353 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6355 el.on('click', this.onClick, this, {
6362 * <b>Attaching multiple handlers in 1 call</b><br>
6363 * The method also allows for a single argument to be passed which is a config object containing properties
6364 * which specify multiple handlers.
6374 fn: this.onMouseOver
6383 * Or a shorthand syntax:<br>
6386 'click' : this.onClick,
6387 'mouseover' : this.onMouseOver,
6388 'mouseout' : this.onMouseOut
6392 pub.on = pub.addListener;
6393 pub.un = pub.removeListener;
6395 pub.stoppedMouseDownEvent = new Roo.util.Event();
6399 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6400 * @param {Function} fn The method the event invokes
6401 * @param {Object} scope An object that becomes the scope of the handler
6402 * @param {boolean} override If true, the obj passed in becomes
6403 * the execution scope of the listener
6407 Roo.onReady = Roo.EventManager.onDocumentReady;
6409 Roo.onReady(function(){
6410 var bd = Roo.get(document.body);
6415 : Roo.isGecko ? "roo-gecko"
6416 : Roo.isOpera ? "roo-opera"
6417 : Roo.isSafari ? "roo-safari" : ""];
6420 cls.push("roo-mac");
6423 cls.push("roo-linux");
6425 if(Roo.isBorderBox){
6426 cls.push('roo-border-box');
6428 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6429 var p = bd.dom.parentNode;
6431 p.className += ' roo-strict';
6434 bd.addClass(cls.join(' '));
6438 * @class Roo.EventObject
6439 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6440 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6443 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6445 var target = e.getTarget();
6448 var myDiv = Roo.get("myDiv");
6449 myDiv.on("click", handleClick);
6451 Roo.EventManager.on("myDiv", 'click', handleClick);
6452 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6456 Roo.EventObject = function(){
6458 var E = Roo.lib.Event;
6460 // safari keypress events for special keys return bad keycodes
6463 63235 : 39, // right
6466 63276 : 33, // page up
6467 63277 : 34, // page down
6468 63272 : 46, // delete
6473 // normalize button clicks
6474 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6475 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6477 Roo.EventObjectImpl = function(e){
6479 this.setEvent(e.browserEvent || e);
6482 Roo.EventObjectImpl.prototype = {
6484 * Used to fix doc tools.
6485 * @scope Roo.EventObject.prototype
6491 /** The normal browser event */
6492 browserEvent : null,
6493 /** The button pressed in a mouse event */
6495 /** True if the shift key was down during the event */
6497 /** True if the control key was down during the event */
6499 /** True if the alt key was down during the event */
6558 setEvent : function(e){
6559 if(e == this || (e && e.browserEvent)){ // already wrapped
6562 this.browserEvent = e;
6564 // normalize buttons
6565 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6566 if(e.type == 'click' && this.button == -1){
6570 this.shiftKey = e.shiftKey;
6571 // mac metaKey behaves like ctrlKey
6572 this.ctrlKey = e.ctrlKey || e.metaKey;
6573 this.altKey = e.altKey;
6574 // in getKey these will be normalized for the mac
6575 this.keyCode = e.keyCode;
6576 // keyup warnings on firefox.
6577 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6578 // cache the target for the delayed and or buffered events
6579 this.target = E.getTarget(e);
6581 this.xy = E.getXY(e);
6584 this.shiftKey = false;
6585 this.ctrlKey = false;
6586 this.altKey = false;
6596 * Stop the event (preventDefault and stopPropagation)
6598 stopEvent : function(){
6599 if(this.browserEvent){
6600 if(this.browserEvent.type == 'mousedown'){
6601 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6603 E.stopEvent(this.browserEvent);
6608 * Prevents the browsers default handling of the event.
6610 preventDefault : function(){
6611 if(this.browserEvent){
6612 E.preventDefault(this.browserEvent);
6617 isNavKeyPress : function(){
6618 var k = this.keyCode;
6619 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6620 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6623 isSpecialKey : function(){
6624 var k = this.keyCode;
6625 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6626 (k == 16) || (k == 17) ||
6627 (k >= 18 && k <= 20) ||
6628 (k >= 33 && k <= 35) ||
6629 (k >= 36 && k <= 39) ||
6630 (k >= 44 && k <= 45);
6633 * Cancels bubbling of the event.
6635 stopPropagation : function(){
6636 if(this.browserEvent){
6637 if(this.type == 'mousedown'){
6638 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6640 E.stopPropagation(this.browserEvent);
6645 * Gets the key code for the event.
6648 getCharCode : function(){
6649 return this.charCode || this.keyCode;
6653 * Returns a normalized keyCode for the event.
6654 * @return {Number} The key code
6656 getKey : function(){
6657 var k = this.keyCode || this.charCode;
6658 return Roo.isSafari ? (safariKeys[k] || k) : k;
6662 * Gets the x coordinate of the event.
6665 getPageX : function(){
6670 * Gets the y coordinate of the event.
6673 getPageY : function(){
6678 * Gets the time of the event.
6681 getTime : function(){
6682 if(this.browserEvent){
6683 return E.getTime(this.browserEvent);
6689 * Gets the page coordinates of the event.
6690 * @return {Array} The xy values like [x, y]
6697 * Gets the target for the event.
6698 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6699 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6700 search as a number or element (defaults to 10 || document.body)
6701 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6702 * @return {HTMLelement}
6704 getTarget : function(selector, maxDepth, returnEl){
6705 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6708 * Gets the related target.
6709 * @return {HTMLElement}
6711 getRelatedTarget : function(){
6712 if(this.browserEvent){
6713 return E.getRelatedTarget(this.browserEvent);
6719 * Normalizes mouse wheel delta across browsers
6720 * @return {Number} The delta
6722 getWheelDelta : function(){
6723 var e = this.browserEvent;
6725 if(e.wheelDelta){ /* IE/Opera. */
6726 delta = e.wheelDelta/120;
6727 }else if(e.detail){ /* Mozilla case. */
6728 delta = -e.detail/3;
6734 * Returns true if the control, meta, shift or alt key was pressed during this event.
6737 hasModifier : function(){
6738 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6742 * Returns true if the target of this event equals el or is a child of el
6743 * @param {String/HTMLElement/Element} el
6744 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6747 within : function(el, related){
6748 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6749 return t && Roo.fly(el).contains(t);
6752 getPoint : function(){
6753 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6757 return new Roo.EventObjectImpl();
6762 * Ext JS Library 1.1.1
6763 * Copyright(c) 2006-2007, Ext JS, LLC.
6765 * Originally Released Under LGPL - original licence link has changed is not relivant.
6768 * <script type="text/javascript">
6772 // was in Composite Element!??!?!
6775 var D = Roo.lib.Dom;
6776 var E = Roo.lib.Event;
6777 var A = Roo.lib.Anim;
6779 // local style camelizing for speed
6781 var camelRe = /(-[a-z])/gi;
6782 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6783 var view = document.defaultView;
6786 * @class Roo.Element
6787 * Represents an Element in the DOM.<br><br>
6790 var el = Roo.get("my-div");
6793 var el = getEl("my-div");
6795 // or with a DOM element
6796 var el = Roo.get(myDivElement);
6798 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6799 * each call instead of constructing a new one.<br><br>
6800 * <b>Animations</b><br />
6801 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6802 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6804 Option Default Description
6805 --------- -------- ---------------------------------------------
6806 duration .35 The duration of the animation in seconds
6807 easing easeOut The YUI easing method
6808 callback none A function to execute when the anim completes
6809 scope this The scope (this) of the callback function
6811 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6812 * manipulate the animation. Here's an example:
6814 var el = Roo.get("my-div");
6819 // default animation
6820 el.setWidth(100, true);
6822 // animation with some options set
6829 // using the "anim" property to get the Anim object
6835 el.setWidth(100, opt);
6837 if(opt.anim.isAnimated()){
6841 * <b> Composite (Collections of) Elements</b><br />
6842 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6843 * @constructor Create a new Element directly.
6844 * @param {String/HTMLElement} element
6845 * @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).
6847 Roo.Element = function(element, forceNew){
6848 var dom = typeof element == "string" ?
6849 document.getElementById(element) : element;
6850 if(!dom){ // invalid id/element
6854 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6855 return Roo.Element.cache[id];
6865 * The DOM element ID
6868 this.id = id || Roo.id(dom);
6871 var El = Roo.Element;
6875 * The element's default display mode (defaults to "")
6878 originalDisplay : "",
6882 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6887 * Sets the element's visibility mode. When setVisible() is called it
6888 * will use this to determine whether to set the visibility or the display property.
6889 * @param visMode Element.VISIBILITY or Element.DISPLAY
6890 * @return {Roo.Element} this
6892 setVisibilityMode : function(visMode){
6893 this.visibilityMode = visMode;
6897 * Convenience method for setVisibilityMode(Element.DISPLAY)
6898 * @param {String} display (optional) What to set display to when visible
6899 * @return {Roo.Element} this
6901 enableDisplayMode : function(display){
6902 this.setVisibilityMode(El.DISPLAY);
6903 if(typeof display != "undefined") this.originalDisplay = display;
6908 * 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)
6909 * @param {String} selector The simple selector to test
6910 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6911 search as a number or element (defaults to 10 || document.body)
6912 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6913 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6915 findParent : function(simpleSelector, maxDepth, returnEl){
6916 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6917 maxDepth = maxDepth || 50;
6918 if(typeof maxDepth != "number"){
6919 stopEl = Roo.getDom(maxDepth);
6922 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6923 if(dq.is(p, simpleSelector)){
6924 return returnEl ? Roo.get(p) : p;
6934 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6935 * @param {String} selector The simple selector to test
6936 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6937 search as a number or element (defaults to 10 || document.body)
6938 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6939 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6941 findParentNode : function(simpleSelector, maxDepth, returnEl){
6942 var p = Roo.fly(this.dom.parentNode, '_internal');
6943 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6947 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6948 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6949 * @param {String} selector The simple selector to test
6950 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6951 search as a number or element (defaults to 10 || document.body)
6952 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6954 up : function(simpleSelector, maxDepth){
6955 return this.findParentNode(simpleSelector, maxDepth, true);
6961 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6962 * @param {String} selector The simple selector to test
6963 * @return {Boolean} True if this element matches the selector, else false
6965 is : function(simpleSelector){
6966 return Roo.DomQuery.is(this.dom, simpleSelector);
6970 * Perform animation on this element.
6971 * @param {Object} args The YUI animation control args
6972 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6973 * @param {Function} onComplete (optional) Function to call when animation completes
6974 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6975 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6976 * @return {Roo.Element} this
6978 animate : function(args, duration, onComplete, easing, animType){
6979 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6984 * @private Internal animation call
6986 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6987 animType = animType || 'run';
6989 var anim = Roo.lib.Anim[animType](
6991 (opt.duration || defaultDur) || .35,
6992 (opt.easing || defaultEase) || 'easeOut',
6994 Roo.callback(cb, this);
6995 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7003 // private legacy anim prep
7004 preanim : function(a, i){
7005 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7009 * Removes worthless text nodes
7010 * @param {Boolean} forceReclean (optional) By default the element
7011 * keeps track if it has been cleaned already so
7012 * you can call this over and over. However, if you update the element and
7013 * need to force a reclean, you can pass true.
7015 clean : function(forceReclean){
7016 if(this.isCleaned && forceReclean !== true){
7020 var d = this.dom, n = d.firstChild, ni = -1;
7022 var nx = n.nextSibling;
7023 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7030 this.isCleaned = true;
7035 calcOffsetsTo : function(el){
7038 var restorePos = false;
7039 if(el.getStyle('position') == 'static'){
7040 el.position('relative');
7045 while(op && op != d && op.tagName != 'HTML'){
7048 op = op.offsetParent;
7051 el.position('static');
7057 * Scrolls this element into view within the passed container.
7058 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7059 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7060 * @return {Roo.Element} this
7062 scrollIntoView : function(container, hscroll){
7063 var c = Roo.getDom(container) || document.body;
7066 var o = this.calcOffsetsTo(c),
7069 b = t+el.offsetHeight,
7070 r = l+el.offsetWidth;
7072 var ch = c.clientHeight;
7073 var ct = parseInt(c.scrollTop, 10);
7074 var cl = parseInt(c.scrollLeft, 10);
7076 var cr = cl + c.clientWidth;
7084 if(hscroll !== false){
7088 c.scrollLeft = r-c.clientWidth;
7095 scrollChildIntoView : function(child, hscroll){
7096 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7100 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7101 * the new height may not be available immediately.
7102 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7103 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7104 * @param {Function} onComplete (optional) Function to call when animation completes
7105 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7106 * @return {Roo.Element} this
7108 autoHeight : function(animate, duration, onComplete, easing){
7109 var oldHeight = this.getHeight();
7111 this.setHeight(1); // force clipping
7112 setTimeout(function(){
7113 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7115 this.setHeight(height);
7117 if(typeof onComplete == "function"){
7121 this.setHeight(oldHeight); // restore original height
7122 this.setHeight(height, animate, duration, function(){
7124 if(typeof onComplete == "function") onComplete();
7125 }.createDelegate(this), easing);
7127 }.createDelegate(this), 0);
7132 * Returns true if this element is an ancestor of the passed element
7133 * @param {HTMLElement/String} el The element to check
7134 * @return {Boolean} True if this element is an ancestor of el, else false
7136 contains : function(el){
7137 if(!el){return false;}
7138 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7142 * Checks whether the element is currently visible using both visibility and display properties.
7143 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7144 * @return {Boolean} True if the element is currently visible, else false
7146 isVisible : function(deep) {
7147 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7148 if(deep !== true || !vis){
7151 var p = this.dom.parentNode;
7152 while(p && p.tagName.toLowerCase() != "body"){
7153 if(!Roo.fly(p, '_isVisible').isVisible()){
7162 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7163 * @param {String} selector The CSS selector
7164 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7165 * @return {CompositeElement/CompositeElementLite} The composite element
7167 select : function(selector, unique){
7168 return El.select(selector, unique, this.dom);
7172 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7173 * @param {String} selector The CSS selector
7174 * @return {Array} An array of the matched nodes
7176 query : function(selector, unique){
7177 return Roo.DomQuery.select(selector, this.dom);
7181 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7182 * @param {String} selector The CSS selector
7183 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7184 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7186 child : function(selector, returnDom){
7187 var n = Roo.DomQuery.selectNode(selector, this.dom);
7188 return returnDom ? n : Roo.get(n);
7192 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7193 * @param {String} selector The CSS selector
7194 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7195 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7197 down : function(selector, returnDom){
7198 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7199 return returnDom ? n : Roo.get(n);
7203 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7204 * @param {String} group The group the DD object is member of
7205 * @param {Object} config The DD config object
7206 * @param {Object} overrides An object containing methods to override/implement on the DD object
7207 * @return {Roo.dd.DD} The DD object
7209 initDD : function(group, config, overrides){
7210 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7211 return Roo.apply(dd, overrides);
7215 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7216 * @param {String} group The group the DDProxy object is member of
7217 * @param {Object} config The DDProxy config object
7218 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7219 * @return {Roo.dd.DDProxy} The DDProxy object
7221 initDDProxy : function(group, config, overrides){
7222 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7223 return Roo.apply(dd, overrides);
7227 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7228 * @param {String} group The group the DDTarget object is member of
7229 * @param {Object} config The DDTarget config object
7230 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7231 * @return {Roo.dd.DDTarget} The DDTarget object
7233 initDDTarget : function(group, config, overrides){
7234 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7235 return Roo.apply(dd, overrides);
7239 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7240 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7241 * @param {Boolean} visible Whether the element is visible
7242 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7243 * @return {Roo.Element} this
7245 setVisible : function(visible, animate){
7247 if(this.visibilityMode == El.DISPLAY){
7248 this.setDisplayed(visible);
7251 this.dom.style.visibility = visible ? "visible" : "hidden";
7254 // closure for composites
7256 var visMode = this.visibilityMode;
7258 this.setOpacity(.01);
7259 this.setVisible(true);
7261 this.anim({opacity: { to: (visible?1:0) }},
7262 this.preanim(arguments, 1),
7263 null, .35, 'easeIn', function(){
7265 if(visMode == El.DISPLAY){
7266 dom.style.display = "none";
7268 dom.style.visibility = "hidden";
7270 Roo.get(dom).setOpacity(1);
7278 * Returns true if display is not "none"
7281 isDisplayed : function() {
7282 return this.getStyle("display") != "none";
7286 * Toggles the element's visibility or display, depending on visibility mode.
7287 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7288 * @return {Roo.Element} this
7290 toggle : function(animate){
7291 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7296 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7297 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7298 * @return {Roo.Element} this
7300 setDisplayed : function(value) {
7301 if(typeof value == "boolean"){
7302 value = value ? this.originalDisplay : "none";
7304 this.setStyle("display", value);
7309 * Tries to focus the element. Any exceptions are caught and ignored.
7310 * @return {Roo.Element} this
7312 focus : function() {
7320 * Tries to blur the element. Any exceptions are caught and ignored.
7321 * @return {Roo.Element} this
7331 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7332 * @param {String/Array} className The CSS class to add, or an array of classes
7333 * @return {Roo.Element} this
7335 addClass : function(className){
7336 if(className instanceof Array){
7337 for(var i = 0, len = className.length; i < len; i++) {
7338 this.addClass(className[i]);
7341 if(className && !this.hasClass(className)){
7342 this.dom.className = this.dom.className + " " + className;
7349 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7350 * @param {String/Array} className The CSS class to add, or an array of classes
7351 * @return {Roo.Element} this
7353 radioClass : function(className){
7354 var siblings = this.dom.parentNode.childNodes;
7355 for(var i = 0; i < siblings.length; i++) {
7356 var s = siblings[i];
7357 if(s.nodeType == 1){
7358 Roo.get(s).removeClass(className);
7361 this.addClass(className);
7366 * Removes one or more CSS classes from the element.
7367 * @param {String/Array} className The CSS class to remove, or an array of classes
7368 * @return {Roo.Element} this
7370 removeClass : function(className){
7371 if(!className || !this.dom.className){
7374 if(className instanceof Array){
7375 for(var i = 0, len = className.length; i < len; i++) {
7376 this.removeClass(className[i]);
7379 if(this.hasClass(className)){
7380 var re = this.classReCache[className];
7382 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7383 this.classReCache[className] = re;
7385 this.dom.className =
7386 this.dom.className.replace(re, " ");
7396 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7397 * @param {String} className The CSS class to toggle
7398 * @return {Roo.Element} this
7400 toggleClass : function(className){
7401 if(this.hasClass(className)){
7402 this.removeClass(className);
7404 this.addClass(className);
7410 * Checks if the specified CSS class exists on this element's DOM node.
7411 * @param {String} className The CSS class to check for
7412 * @return {Boolean} True if the class exists, else false
7414 hasClass : function(className){
7415 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7419 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7420 * @param {String} oldClassName The CSS class to replace
7421 * @param {String} newClassName The replacement CSS class
7422 * @return {Roo.Element} this
7424 replaceClass : function(oldClassName, newClassName){
7425 this.removeClass(oldClassName);
7426 this.addClass(newClassName);
7431 * Returns an object with properties matching the styles requested.
7432 * For example, el.getStyles('color', 'font-size', 'width') might return
7433 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7434 * @param {String} style1 A style name
7435 * @param {String} style2 A style name
7436 * @param {String} etc.
7437 * @return {Object} The style object
7439 getStyles : function(){
7440 var a = arguments, len = a.length, r = {};
7441 for(var i = 0; i < len; i++){
7442 r[a[i]] = this.getStyle(a[i]);
7448 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7449 * @param {String} property The style property whose value is returned.
7450 * @return {String} The current value of the style property for this element.
7452 getStyle : function(){
7453 return view && view.getComputedStyle ?
7455 var el = this.dom, v, cs, camel;
7456 if(prop == 'float'){
7459 if(el.style && (v = el.style[prop])){
7462 if(cs = view.getComputedStyle(el, "")){
7463 if(!(camel = propCache[prop])){
7464 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7471 var el = this.dom, v, cs, camel;
7472 if(prop == 'opacity'){
7473 if(typeof el.style.filter == 'string'){
7474 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7476 var fv = parseFloat(m[1]);
7478 return fv ? fv / 100 : 0;
7483 }else if(prop == 'float'){
7484 prop = "styleFloat";
7486 if(!(camel = propCache[prop])){
7487 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7489 if(v = el.style[camel]){
7492 if(cs = el.currentStyle){
7500 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7501 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7502 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7503 * @return {Roo.Element} this
7505 setStyle : function(prop, value){
7506 if(typeof prop == "string"){
7508 if (prop == 'float') {
7509 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7514 if(!(camel = propCache[prop])){
7515 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7518 if(camel == 'opacity') {
7519 this.setOpacity(value);
7521 this.dom.style[camel] = value;
7524 for(var style in prop){
7525 if(typeof prop[style] != "function"){
7526 this.setStyle(style, prop[style]);
7534 * More flexible version of {@link #setStyle} for setting style properties.
7535 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7536 * a function which returns such a specification.
7537 * @return {Roo.Element} this
7539 applyStyles : function(style){
7540 Roo.DomHelper.applyStyles(this.dom, style);
7545 * 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).
7546 * @return {Number} The X position of the element
7549 return D.getX(this.dom);
7553 * 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).
7554 * @return {Number} The Y position of the element
7557 return D.getY(this.dom);
7561 * 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).
7562 * @return {Array} The XY position of the element
7565 return D.getXY(this.dom);
7569 * 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).
7570 * @param {Number} The X position of the element
7571 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7572 * @return {Roo.Element} this
7574 setX : function(x, animate){
7576 D.setX(this.dom, x);
7578 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7584 * 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).
7585 * @param {Number} The Y position of the element
7586 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7587 * @return {Roo.Element} this
7589 setY : function(y, animate){
7591 D.setY(this.dom, y);
7593 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7599 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7600 * @param {String} left The left CSS property value
7601 * @return {Roo.Element} this
7603 setLeft : function(left){
7604 this.setStyle("left", this.addUnits(left));
7609 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7610 * @param {String} top The top CSS property value
7611 * @return {Roo.Element} this
7613 setTop : function(top){
7614 this.setStyle("top", this.addUnits(top));
7619 * Sets the element's CSS right style.
7620 * @param {String} right The right CSS property value
7621 * @return {Roo.Element} this
7623 setRight : function(right){
7624 this.setStyle("right", this.addUnits(right));
7629 * Sets the element's CSS bottom style.
7630 * @param {String} bottom The bottom CSS property value
7631 * @return {Roo.Element} this
7633 setBottom : function(bottom){
7634 this.setStyle("bottom", this.addUnits(bottom));
7639 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7640 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7641 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7642 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7643 * @return {Roo.Element} this
7645 setXY : function(pos, animate){
7647 D.setXY(this.dom, pos);
7649 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7655 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7656 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7657 * @param {Number} x X value for new position (coordinates are page-based)
7658 * @param {Number} y Y value for new position (coordinates are page-based)
7659 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7660 * @return {Roo.Element} this
7662 setLocation : function(x, y, animate){
7663 this.setXY([x, y], this.preanim(arguments, 2));
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 {Number} x X value for new position (coordinates are page-based)
7671 * @param {Number} y Y value for new position (coordinates are page-based)
7672 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7673 * @return {Roo.Element} this
7675 moveTo : function(x, y, animate){
7676 this.setXY([x, y], this.preanim(arguments, 2));
7681 * Returns the region of the given element.
7682 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7683 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7685 getRegion : function(){
7686 return D.getRegion(this.dom);
7690 * Returns the offset height of the element
7691 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7692 * @return {Number} The element's height
7694 getHeight : function(contentHeight){
7695 var h = this.dom.offsetHeight || 0;
7696 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7700 * Returns the offset width of the element
7701 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7702 * @return {Number} The element's width
7704 getWidth : function(contentWidth){
7705 var w = this.dom.offsetWidth || 0;
7706 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7710 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7711 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7712 * if a height has not been set using CSS.
7715 getComputedHeight : function(){
7716 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7718 h = parseInt(this.getStyle('height'), 10) || 0;
7719 if(!this.isBorderBox()){
7720 h += this.getFrameWidth('tb');
7727 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7728 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7729 * if a width has not been set using CSS.
7732 getComputedWidth : function(){
7733 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7735 w = parseInt(this.getStyle('width'), 10) || 0;
7736 if(!this.isBorderBox()){
7737 w += this.getFrameWidth('lr');
7744 * Returns the size of the element.
7745 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7746 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7748 getSize : function(contentSize){
7749 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7753 * Returns the width and height of the viewport.
7754 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7756 getViewSize : function(){
7757 var d = this.dom, doc = document, aw = 0, ah = 0;
7758 if(d == doc || d == doc.body){
7759 return {width : D.getViewWidth(), height: D.getViewHeight()};
7762 width : d.clientWidth,
7763 height: d.clientHeight
7769 * Returns the value of the "value" attribute
7770 * @param {Boolean} asNumber true to parse the value as a number
7771 * @return {String/Number}
7773 getValue : function(asNumber){
7774 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7778 adjustWidth : function(width){
7779 if(typeof width == "number"){
7780 if(this.autoBoxAdjust && !this.isBorderBox()){
7781 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7791 adjustHeight : function(height){
7792 if(typeof height == "number"){
7793 if(this.autoBoxAdjust && !this.isBorderBox()){
7794 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7804 * Set the width of the element
7805 * @param {Number} width The new width
7806 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7807 * @return {Roo.Element} this
7809 setWidth : function(width, animate){
7810 width = this.adjustWidth(width);
7812 this.dom.style.width = this.addUnits(width);
7814 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7820 * Set the height of the element
7821 * @param {Number} height The new height
7822 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7823 * @return {Roo.Element} this
7825 setHeight : function(height, animate){
7826 height = this.adjustHeight(height);
7828 this.dom.style.height = this.addUnits(height);
7830 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7836 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7837 * @param {Number} width The new width
7838 * @param {Number} height The new height
7839 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7840 * @return {Roo.Element} this
7842 setSize : function(width, height, animate){
7843 if(typeof width == "object"){ // in case of object from getSize()
7844 height = width.height; width = width.width;
7846 width = this.adjustWidth(width); height = this.adjustHeight(height);
7848 this.dom.style.width = this.addUnits(width);
7849 this.dom.style.height = this.addUnits(height);
7851 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7857 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7858 * @param {Number} x X value for new position (coordinates are page-based)
7859 * @param {Number} y Y value for new position (coordinates are page-based)
7860 * @param {Number} width The new width
7861 * @param {Number} height The new height
7862 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7863 * @return {Roo.Element} this
7865 setBounds : function(x, y, width, height, animate){
7867 this.setSize(width, height);
7868 this.setLocation(x, y);
7870 width = this.adjustWidth(width); height = this.adjustHeight(height);
7871 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7872 this.preanim(arguments, 4), 'motion');
7878 * 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.
7879 * @param {Roo.lib.Region} region The region to fill
7880 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7881 * @return {Roo.Element} this
7883 setRegion : function(region, animate){
7884 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7889 * Appends an event handler
7891 * @param {String} eventName The type of event to append
7892 * @param {Function} fn The method the event invokes
7893 * @param {Object} scope (optional) The scope (this object) of the fn
7894 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7896 addListener : function(eventName, fn, scope, options){
7898 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7903 * Removes an event handler from this element
7904 * @param {String} eventName the type of event to remove
7905 * @param {Function} fn the method the event invokes
7906 * @return {Roo.Element} this
7908 removeListener : function(eventName, fn){
7909 Roo.EventManager.removeListener(this.dom, eventName, fn);
7914 * Removes all previous added listeners from this element
7915 * @return {Roo.Element} this
7917 removeAllListeners : function(){
7918 E.purgeElement(this.dom);
7922 relayEvent : function(eventName, observable){
7923 this.on(eventName, function(e){
7924 observable.fireEvent(eventName, e);
7929 * Set the opacity of the element
7930 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7931 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7932 * @return {Roo.Element} this
7934 setOpacity : function(opacity, animate){
7936 var s = this.dom.style;
7939 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7940 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7942 s.opacity = opacity;
7945 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7951 * Gets the left X coordinate
7952 * @param {Boolean} local True to get the local css position instead of page coordinate
7955 getLeft : function(local){
7959 return parseInt(this.getStyle("left"), 10) || 0;
7964 * Gets the right X coordinate of the element (element X position + element width)
7965 * @param {Boolean} local True to get the local css position instead of page coordinate
7968 getRight : function(local){
7970 return this.getX() + this.getWidth();
7972 return (this.getLeft(true) + this.getWidth()) || 0;
7977 * Gets the top Y coordinate
7978 * @param {Boolean} local True to get the local css position instead of page coordinate
7981 getTop : function(local) {
7985 return parseInt(this.getStyle("top"), 10) || 0;
7990 * Gets the bottom Y coordinate of the element (element Y position + element height)
7991 * @param {Boolean} local True to get the local css position instead of page coordinate
7994 getBottom : function(local){
7996 return this.getY() + this.getHeight();
7998 return (this.getTop(true) + this.getHeight()) || 0;
8003 * Initializes positioning on this element. If a desired position is not passed, it will make the
8004 * the element positioned relative IF it is not already positioned.
8005 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8006 * @param {Number} zIndex (optional) The zIndex to apply
8007 * @param {Number} x (optional) Set the page X position
8008 * @param {Number} y (optional) Set the page Y position
8010 position : function(pos, zIndex, x, y){
8012 if(this.getStyle('position') == 'static'){
8013 this.setStyle('position', 'relative');
8016 this.setStyle("position", pos);
8019 this.setStyle("z-index", zIndex);
8021 if(x !== undefined && y !== undefined){
8023 }else if(x !== undefined){
8025 }else if(y !== undefined){
8031 * Clear positioning back to the default when the document was loaded
8032 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8033 * @return {Roo.Element} this
8035 clearPositioning : function(value){
8043 "position" : "static"
8049 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8050 * snapshot before performing an update and then restoring the element.
8053 getPositioning : function(){
8054 var l = this.getStyle("left");
8055 var t = this.getStyle("top");
8057 "position" : this.getStyle("position"),
8059 "right" : l ? "" : this.getStyle("right"),
8061 "bottom" : t ? "" : this.getStyle("bottom"),
8062 "z-index" : this.getStyle("z-index")
8067 * Gets the width of the border(s) for the specified side(s)
8068 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8069 * passing lr would get the border (l)eft width + the border (r)ight width.
8070 * @return {Number} The width of the sides passed added together
8072 getBorderWidth : function(side){
8073 return this.addStyles(side, El.borders);
8077 * Gets the width of the padding(s) for the specified side(s)
8078 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8079 * passing lr would get the padding (l)eft + the padding (r)ight.
8080 * @return {Number} The padding of the sides passed added together
8082 getPadding : function(side){
8083 return this.addStyles(side, El.paddings);
8087 * Set positioning with an object returned by getPositioning().
8088 * @param {Object} posCfg
8089 * @return {Roo.Element} this
8091 setPositioning : function(pc){
8092 this.applyStyles(pc);
8093 if(pc.right == "auto"){
8094 this.dom.style.right = "";
8096 if(pc.bottom == "auto"){
8097 this.dom.style.bottom = "";
8103 fixDisplay : function(){
8104 if(this.getStyle("display") == "none"){
8105 this.setStyle("visibility", "hidden");
8106 this.setStyle("display", this.originalDisplay); // first try reverting to default
8107 if(this.getStyle("display") == "none"){ // if that fails, default to block
8108 this.setStyle("display", "block");
8114 * Quick set left and top adding default units
8115 * @param {String} left The left CSS property value
8116 * @param {String} top The top CSS property value
8117 * @return {Roo.Element} this
8119 setLeftTop : function(left, top){
8120 this.dom.style.left = this.addUnits(left);
8121 this.dom.style.top = this.addUnits(top);
8126 * Move this element relative to its current position.
8127 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8128 * @param {Number} distance How far to move the element in pixels
8129 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8130 * @return {Roo.Element} this
8132 move : function(direction, distance, animate){
8133 var xy = this.getXY();
8134 direction = direction.toLowerCase();
8138 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8142 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8147 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8152 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8159 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8160 * @return {Roo.Element} this
8163 if(!this.isClipped){
8164 this.isClipped = true;
8165 this.originalClip = {
8166 "o": this.getStyle("overflow"),
8167 "x": this.getStyle("overflow-x"),
8168 "y": this.getStyle("overflow-y")
8170 this.setStyle("overflow", "hidden");
8171 this.setStyle("overflow-x", "hidden");
8172 this.setStyle("overflow-y", "hidden");
8178 * Return clipping (overflow) to original clipping before clip() was called
8179 * @return {Roo.Element} this
8181 unclip : function(){
8183 this.isClipped = false;
8184 var o = this.originalClip;
8185 if(o.o){this.setStyle("overflow", o.o);}
8186 if(o.x){this.setStyle("overflow-x", o.x);}
8187 if(o.y){this.setStyle("overflow-y", o.y);}
8194 * Gets the x,y coordinates specified by the anchor position on the element.
8195 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8196 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8197 * {width: (target width), height: (target height)} (defaults to the element's current size)
8198 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8199 * @return {Array} [x, y] An array containing the element's x and y coordinates
8201 getAnchorXY : function(anchor, local, s){
8202 //Passing a different size is useful for pre-calculating anchors,
8203 //especially for anchored animations that change the el size.
8205 var w, h, vp = false;
8208 if(d == document.body || d == document){
8210 w = D.getViewWidth(); h = D.getViewHeight();
8212 w = this.getWidth(); h = this.getHeight();
8215 w = s.width; h = s.height;
8217 var x = 0, y = 0, r = Math.round;
8218 switch((anchor || "tl").toLowerCase()){
8260 var sc = this.getScroll();
8261 return [x + sc.left, y + sc.top];
8263 //Add the element's offset xy
8264 var o = this.getXY();
8265 return [x+o[0], y+o[1]];
8269 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8270 * supported position values.
8271 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8272 * @param {String} position The position to align to.
8273 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8274 * @return {Array} [x, y]
8276 getAlignToXY : function(el, p, o){
8280 throw "Element.alignTo with an element that doesn't exist";
8282 var c = false; //constrain to viewport
8283 var p1 = "", p2 = "";
8290 }else if(p.indexOf("-") == -1){
8293 p = p.toLowerCase();
8294 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8296 throw "Element.alignTo with an invalid alignment " + p;
8298 p1 = m[1]; p2 = m[2]; c = !!m[3];
8300 //Subtract the aligned el's internal xy from the target's offset xy
8301 //plus custom offset to get the aligned el's new offset xy
8302 var a1 = this.getAnchorXY(p1, true);
8303 var a2 = el.getAnchorXY(p2, false);
8304 var x = a2[0] - a1[0] + o[0];
8305 var y = a2[1] - a1[1] + o[1];
8307 //constrain the aligned el to viewport if necessary
8308 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8309 // 5px of margin for ie
8310 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8312 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8313 //perpendicular to the vp border, allow the aligned el to slide on that border,
8314 //otherwise swap the aligned el to the opposite border of the target.
8315 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8316 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8317 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8318 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8321 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8322 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8324 if((x+w) > dw + scrollX){
8325 x = swapX ? r.left-w : dw+scrollX-w;
8328 x = swapX ? r.right : scrollX;
8330 if((y+h) > dh + scrollY){
8331 y = swapY ? r.top-h : dh+scrollY-h;
8334 y = swapY ? r.bottom : scrollY;
8341 getConstrainToXY : function(){
8342 var os = {top:0, left:0, bottom:0, right: 0};
8344 return function(el, local, offsets, proposedXY){
8346 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8348 var vw, vh, vx = 0, vy = 0;
8349 if(el.dom == document.body || el.dom == document){
8350 vw = Roo.lib.Dom.getViewWidth();
8351 vh = Roo.lib.Dom.getViewHeight();
8353 vw = el.dom.clientWidth;
8354 vh = el.dom.clientHeight;
8356 var vxy = el.getXY();
8362 var s = el.getScroll();
8364 vx += offsets.left + s.left;
8365 vy += offsets.top + s.top;
8367 vw -= offsets.right;
8368 vh -= offsets.bottom;
8373 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8374 var x = xy[0], y = xy[1];
8375 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8377 // only move it if it needs it
8380 // first validate right/bottom
8389 // then make sure top/left isn't negative
8398 return moved ? [x, y] : false;
8403 adjustForConstraints : function(xy, parent, offsets){
8404 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8408 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8409 * document it aligns it to the viewport.
8410 * The position parameter is optional, and can be specified in any one of the following formats:
8412 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8413 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8414 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8415 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8416 * <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
8417 * element's anchor point, and the second value is used as the target's anchor point.</li>
8419 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8420 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8421 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8422 * that specified in order to enforce the viewport constraints.
8423 * Following are all of the supported anchor positions:
8426 ----- -----------------------------
8427 tl The top left corner (default)
8428 t The center of the top edge
8429 tr The top right corner
8430 l The center of the left edge
8431 c In the center of the element
8432 r The center of the right edge
8433 bl The bottom left corner
8434 b The center of the bottom edge
8435 br The bottom right corner
8439 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8440 el.alignTo("other-el");
8442 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8443 el.alignTo("other-el", "tr?");
8445 // align the bottom right corner of el with the center left edge of other-el
8446 el.alignTo("other-el", "br-l?");
8448 // align the center of el with the bottom left corner of other-el and
8449 // adjust the x position by -6 pixels (and the y position by 0)
8450 el.alignTo("other-el", "c-bl", [-6, 0]);
8452 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8453 * @param {String} position The position to align to.
8454 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8455 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8456 * @return {Roo.Element} this
8458 alignTo : function(element, position, offsets, animate){
8459 var xy = this.getAlignToXY(element, position, offsets);
8460 this.setXY(xy, this.preanim(arguments, 3));
8465 * Anchors an element to another element and realigns it when the window is resized.
8466 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8467 * @param {String} position The position to align to.
8468 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8469 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8470 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8471 * is a number, it is used as the buffer delay (defaults to 50ms).
8472 * @param {Function} callback The function to call after the animation finishes
8473 * @return {Roo.Element} this
8475 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8476 var action = function(){
8477 this.alignTo(el, alignment, offsets, animate);
8478 Roo.callback(callback, this);
8480 Roo.EventManager.onWindowResize(action, this);
8481 var tm = typeof monitorScroll;
8482 if(tm != 'undefined'){
8483 Roo.EventManager.on(window, 'scroll', action, this,
8484 {buffer: tm == 'number' ? monitorScroll : 50});
8486 action.call(this); // align immediately
8490 * Clears any opacity settings from this element. Required in some cases for IE.
8491 * @return {Roo.Element} this
8493 clearOpacity : function(){
8494 if (window.ActiveXObject) {
8495 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8496 this.dom.style.filter = "";
8499 this.dom.style.opacity = "";
8500 this.dom.style["-moz-opacity"] = "";
8501 this.dom.style["-khtml-opacity"] = "";
8507 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8508 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8509 * @return {Roo.Element} this
8511 hide : function(animate){
8512 this.setVisible(false, this.preanim(arguments, 0));
8517 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8518 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8519 * @return {Roo.Element} this
8521 show : function(animate){
8522 this.setVisible(true, this.preanim(arguments, 0));
8527 * @private Test if size has a unit, otherwise appends the default
8529 addUnits : function(size){
8530 return Roo.Element.addUnits(size, this.defaultUnit);
8534 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8535 * @return {Roo.Element} this
8537 beginMeasure : function(){
8539 if(el.offsetWidth || el.offsetHeight){
8540 return this; // offsets work already
8543 var p = this.dom, b = document.body; // start with this element
8544 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8545 var pe = Roo.get(p);
8546 if(pe.getStyle('display') == 'none'){
8547 changed.push({el: p, visibility: pe.getStyle("visibility")});
8548 p.style.visibility = "hidden";
8549 p.style.display = "block";
8553 this._measureChanged = changed;
8559 * Restores displays to before beginMeasure was called
8560 * @return {Roo.Element} this
8562 endMeasure : function(){
8563 var changed = this._measureChanged;
8565 for(var i = 0, len = changed.length; i < len; i++) {
8567 r.el.style.visibility = r.visibility;
8568 r.el.style.display = "none";
8570 this._measureChanged = null;
8576 * Update the innerHTML of this element, optionally searching for and processing scripts
8577 * @param {String} html The new HTML
8578 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8579 * @param {Function} callback For async script loading you can be noticed when the update completes
8580 * @return {Roo.Element} this
8582 update : function(html, loadScripts, callback){
8583 if(typeof html == "undefined"){
8586 if(loadScripts !== true){
8587 this.dom.innerHTML = html;
8588 if(typeof callback == "function"){
8596 html += '<span id="' + id + '"></span>';
8598 E.onAvailable(id, function(){
8599 var hd = document.getElementsByTagName("head")[0];
8600 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8601 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8602 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8605 while(match = re.exec(html)){
8606 var attrs = match[1];
8607 var srcMatch = attrs ? attrs.match(srcRe) : false;
8608 if(srcMatch && srcMatch[2]){
8609 var s = document.createElement("script");
8610 s.src = srcMatch[2];
8611 var typeMatch = attrs.match(typeRe);
8612 if(typeMatch && typeMatch[2]){
8613 s.type = typeMatch[2];
8616 }else if(match[2] && match[2].length > 0){
8617 if(window.execScript) {
8618 window.execScript(match[2]);
8626 window.eval(match[2]);
8630 var el = document.getElementById(id);
8631 if(el){el.parentNode.removeChild(el);}
8632 if(typeof callback == "function"){
8636 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8641 * Direct access to the UpdateManager update() method (takes the same parameters).
8642 * @param {String/Function} url The url for this request or a function to call to get the url
8643 * @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}
8644 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8645 * @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.
8646 * @return {Roo.Element} this
8649 var um = this.getUpdateManager();
8650 um.update.apply(um, arguments);
8655 * Gets this element's UpdateManager
8656 * @return {Roo.UpdateManager} The UpdateManager
8658 getUpdateManager : function(){
8659 if(!this.updateManager){
8660 this.updateManager = new Roo.UpdateManager(this);
8662 return this.updateManager;
8666 * Disables text selection for this element (normalized across browsers)
8667 * @return {Roo.Element} this
8669 unselectable : function(){
8670 this.dom.unselectable = "on";
8671 this.swallowEvent("selectstart", true);
8672 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8673 this.addClass("x-unselectable");
8678 * Calculates the x, y to center this element on the screen
8679 * @return {Array} The x, y values [x, y]
8681 getCenterXY : function(){
8682 return this.getAlignToXY(document, 'c-c');
8686 * Centers the Element in either the viewport, or another Element.
8687 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8689 center : function(centerIn){
8690 this.alignTo(centerIn || document, 'c-c');
8695 * Tests various css rules/browsers to determine if this element uses a border box
8698 isBorderBox : function(){
8699 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8703 * Return a box {x, y, width, height} that can be used to set another elements
8704 * size/location to match this element.
8705 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8706 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8707 * @return {Object} box An object in the format {x, y, width, height}
8709 getBox : function(contentBox, local){
8714 var left = parseInt(this.getStyle("left"), 10) || 0;
8715 var top = parseInt(this.getStyle("top"), 10) || 0;
8718 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8720 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8722 var l = this.getBorderWidth("l")+this.getPadding("l");
8723 var r = this.getBorderWidth("r")+this.getPadding("r");
8724 var t = this.getBorderWidth("t")+this.getPadding("t");
8725 var b = this.getBorderWidth("b")+this.getPadding("b");
8726 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)};
8728 bx.right = bx.x + bx.width;
8729 bx.bottom = bx.y + bx.height;
8734 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8735 for more information about the sides.
8736 * @param {String} sides
8739 getFrameWidth : function(sides, onlyContentBox){
8740 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8744 * 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.
8745 * @param {Object} box The box to fill {x, y, width, height}
8746 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8747 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8748 * @return {Roo.Element} this
8750 setBox : function(box, adjust, animate){
8751 var w = box.width, h = box.height;
8752 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8753 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8754 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8756 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8761 * Forces the browser to repaint this element
8762 * @return {Roo.Element} this
8764 repaint : function(){
8766 this.addClass("x-repaint");
8767 setTimeout(function(){
8768 Roo.get(dom).removeClass("x-repaint");
8774 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8775 * then it returns the calculated width of the sides (see getPadding)
8776 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8777 * @return {Object/Number}
8779 getMargins : function(side){
8782 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8783 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8784 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8785 right: parseInt(this.getStyle("margin-right"), 10) || 0
8788 return this.addStyles(side, El.margins);
8793 addStyles : function(sides, styles){
8795 for(var i = 0, len = sides.length; i < len; i++){
8796 v = this.getStyle(styles[sides.charAt(i)]);
8798 w = parseInt(v, 10);
8806 * Creates a proxy element of this element
8807 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8808 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8809 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8810 * @return {Roo.Element} The new proxy element
8812 createProxy : function(config, renderTo, matchBox){
8814 renderTo = Roo.getDom(renderTo);
8816 renderTo = document.body;
8818 config = typeof config == "object" ?
8819 config : {tag : "div", cls: config};
8820 var proxy = Roo.DomHelper.append(renderTo, config, true);
8822 proxy.setBox(this.getBox());
8828 * Puts a mask over this element to disable user interaction. Requires core.css.
8829 * This method can only be applied to elements which accept child nodes.
8830 * @param {String} msg (optional) A message to display in the mask
8831 * @param {String} msgCls (optional) A css class to apply to the msg element
8832 * @return {Element} The mask element
8834 mask : function(msg, msgCls){
8835 if(this.getStyle("position") == "static"){
8836 this.setStyle("position", "relative");
8839 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8841 this.addClass("x-masked");
8842 this._mask.setDisplayed(true);
8843 if(typeof msg == 'string'){
8845 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8847 var mm = this._maskMsg;
8848 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8849 mm.dom.firstChild.innerHTML = msg;
8850 mm.setDisplayed(true);
8853 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8854 this._mask.setHeight(this.getHeight());
8860 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8861 * it is cached for reuse.
8863 unmask : function(removeEl){
8865 if(removeEl === true){
8866 this._mask.remove();
8869 this._maskMsg.remove();
8870 delete this._maskMsg;
8873 this._mask.setDisplayed(false);
8875 this._maskMsg.setDisplayed(false);
8879 this.removeClass("x-masked");
8883 * Returns true if this element is masked
8886 isMasked : function(){
8887 return this._mask && this._mask.isVisible();
8891 * Creates an iframe shim for this element to keep selects and other windowed objects from
8893 * @return {Roo.Element} The new shim element
8895 createShim : function(){
8896 var el = document.createElement('iframe');
8897 el.frameBorder = 'no';
8898 el.className = 'roo-shim';
8899 if(Roo.isIE && Roo.isSecure){
8900 el.src = Roo.SSL_SECURE_URL;
8902 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8903 shim.autoBoxAdjust = false;
8908 * Removes this element from the DOM and deletes it from the cache
8910 remove : function(){
8911 if(this.dom.parentNode){
8912 this.dom.parentNode.removeChild(this.dom);
8914 delete El.cache[this.dom.id];
8918 * Sets up event handlers to add and remove a css class when the mouse is over this element
8919 * @param {String} className
8920 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8921 * mouseout events for children elements
8922 * @return {Roo.Element} this
8924 addClassOnOver : function(className, preventFlicker){
8925 this.on("mouseover", function(){
8926 Roo.fly(this, '_internal').addClass(className);
8928 var removeFn = function(e){
8929 if(preventFlicker !== true || !e.within(this, true)){
8930 Roo.fly(this, '_internal').removeClass(className);
8933 this.on("mouseout", removeFn, this.dom);
8938 * Sets up event handlers to add and remove a css class when this element has the focus
8939 * @param {String} className
8940 * @return {Roo.Element} this
8942 addClassOnFocus : function(className){
8943 this.on("focus", function(){
8944 Roo.fly(this, '_internal').addClass(className);
8946 this.on("blur", function(){
8947 Roo.fly(this, '_internal').removeClass(className);
8952 * 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)
8953 * @param {String} className
8954 * @return {Roo.Element} this
8956 addClassOnClick : function(className){
8958 this.on("mousedown", function(){
8959 Roo.fly(dom, '_internal').addClass(className);
8960 var d = Roo.get(document);
8961 var fn = function(){
8962 Roo.fly(dom, '_internal').removeClass(className);
8963 d.removeListener("mouseup", fn);
8965 d.on("mouseup", fn);
8971 * Stops the specified event from bubbling and optionally prevents the default action
8972 * @param {String} eventName
8973 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8974 * @return {Roo.Element} this
8976 swallowEvent : function(eventName, preventDefault){
8977 var fn = function(e){
8978 e.stopPropagation();
8983 if(eventName instanceof Array){
8984 for(var i = 0, len = eventName.length; i < len; i++){
8985 this.on(eventName[i], fn);
8989 this.on(eventName, fn);
8996 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8999 * Sizes this element to its parent element's dimensions performing
9000 * neccessary box adjustments.
9001 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9002 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9003 * @return {Roo.Element} this
9005 fitToParent : function(monitorResize, targetParent) {
9006 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9007 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9008 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9011 var p = Roo.get(targetParent || this.dom.parentNode);
9012 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9013 if (monitorResize === true) {
9014 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9015 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9021 * Gets the next sibling, skipping text nodes
9022 * @return {HTMLElement} The next sibling or null
9024 getNextSibling : function(){
9025 var n = this.dom.nextSibling;
9026 while(n && n.nodeType != 1){
9033 * Gets the previous sibling, skipping text nodes
9034 * @return {HTMLElement} The previous sibling or null
9036 getPrevSibling : function(){
9037 var n = this.dom.previousSibling;
9038 while(n && n.nodeType != 1){
9039 n = n.previousSibling;
9046 * Appends the passed element(s) to this element
9047 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9048 * @return {Roo.Element} this
9050 appendChild: function(el){
9057 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9058 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9059 * automatically generated with the specified attributes.
9060 * @param {HTMLElement} insertBefore (optional) a child element of this element
9061 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9062 * @return {Roo.Element} The new child element
9064 createChild: function(config, insertBefore, returnDom){
9065 config = config || {tag:'div'};
9067 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9069 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9073 * Appends this element to the passed element
9074 * @param {String/HTMLElement/Element} el The new parent element
9075 * @return {Roo.Element} this
9077 appendTo: function(el){
9078 el = Roo.getDom(el);
9079 el.appendChild(this.dom);
9084 * Inserts this element before the passed element in the DOM
9085 * @param {String/HTMLElement/Element} el The element to insert before
9086 * @return {Roo.Element} this
9088 insertBefore: function(el){
9089 el = Roo.getDom(el);
9090 el.parentNode.insertBefore(this.dom, el);
9095 * Inserts this element after the passed element in the DOM
9096 * @param {String/HTMLElement/Element} el The element to insert after
9097 * @return {Roo.Element} this
9099 insertAfter: function(el){
9100 el = Roo.getDom(el);
9101 el.parentNode.insertBefore(this.dom, el.nextSibling);
9106 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9107 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9108 * @return {Roo.Element} The new child
9110 insertFirst: function(el, returnDom){
9112 if(typeof el == 'object' && !el.nodeType){ // dh config
9113 return this.createChild(el, this.dom.firstChild, returnDom);
9115 el = Roo.getDom(el);
9116 this.dom.insertBefore(el, this.dom.firstChild);
9117 return !returnDom ? Roo.get(el) : el;
9122 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9123 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9124 * @param {String} where (optional) 'before' or 'after' defaults to before
9125 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9126 * @return {Roo.Element} the inserted Element
9128 insertSibling: function(el, where, returnDom){
9129 where = where ? where.toLowerCase() : 'before';
9131 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9133 if(typeof el == 'object' && !el.nodeType){ // dh config
9134 if(where == 'after' && !this.dom.nextSibling){
9135 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9137 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9141 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9142 where == 'before' ? this.dom : this.dom.nextSibling);
9151 * Creates and wraps this element with another element
9152 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9153 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9154 * @return {HTMLElement/Element} The newly created wrapper element
9156 wrap: function(config, returnDom){
9158 config = {tag: "div"};
9160 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9161 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9166 * Replaces the passed element with this element
9167 * @param {String/HTMLElement/Element} el The element to replace
9168 * @return {Roo.Element} this
9170 replace: function(el){
9172 this.insertBefore(el);
9178 * Inserts an html fragment into this element
9179 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9180 * @param {String} html The HTML fragment
9181 * @param {Boolean} returnEl True to return an Roo.Element
9182 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9184 insertHtml : function(where, html, returnEl){
9185 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9186 return returnEl ? Roo.get(el) : el;
9190 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9191 * @param {Object} o The object with the attributes
9192 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9193 * @return {Roo.Element} this
9195 set : function(o, useSet){
9197 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9199 if(attr == "style" || typeof o[attr] == "function") continue;
9201 el.className = o["cls"];
9203 if(useSet) el.setAttribute(attr, o[attr]);
9204 else el[attr] = o[attr];
9208 Roo.DomHelper.applyStyles(el, o.style);
9214 * Convenience method for constructing a KeyMap
9215 * @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:
9216 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9217 * @param {Function} fn The function to call
9218 * @param {Object} scope (optional) The scope of the function
9219 * @return {Roo.KeyMap} The KeyMap created
9221 addKeyListener : function(key, fn, scope){
9223 if(typeof key != "object" || key instanceof Array){
9239 return new Roo.KeyMap(this, config);
9243 * Creates a KeyMap for this element
9244 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9245 * @return {Roo.KeyMap} The KeyMap created
9247 addKeyMap : function(config){
9248 return new Roo.KeyMap(this, config);
9252 * Returns true if this element is scrollable.
9255 isScrollable : function(){
9257 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9261 * 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().
9262 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9263 * @param {Number} value The new scroll value
9264 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9265 * @return {Element} this
9268 scrollTo : function(side, value, animate){
9269 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9271 this.dom[prop] = value;
9273 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9274 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9280 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9281 * within this element's scrollable range.
9282 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9283 * @param {Number} distance How far to scroll the element in pixels
9284 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9285 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9286 * was scrolled as far as it could go.
9288 scroll : function(direction, distance, animate){
9289 if(!this.isScrollable()){
9293 var l = el.scrollLeft, t = el.scrollTop;
9294 var w = el.scrollWidth, h = el.scrollHeight;
9295 var cw = el.clientWidth, ch = el.clientHeight;
9296 direction = direction.toLowerCase();
9297 var scrolled = false;
9298 var a = this.preanim(arguments, 2);
9303 var v = Math.min(l + distance, w-cw);
9304 this.scrollTo("left", v, a);
9311 var v = Math.max(l - distance, 0);
9312 this.scrollTo("left", v, a);
9320 var v = Math.max(t - distance, 0);
9321 this.scrollTo("top", v, a);
9329 var v = Math.min(t + distance, h-ch);
9330 this.scrollTo("top", v, a);
9339 * Translates the passed page coordinates into left/top css values for this element
9340 * @param {Number/Array} x The page x or an array containing [x, y]
9341 * @param {Number} y The page y
9342 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9344 translatePoints : function(x, y){
9345 if(typeof x == 'object' || x instanceof Array){
9348 var p = this.getStyle('position');
9349 var o = this.getXY();
9351 var l = parseInt(this.getStyle('left'), 10);
9352 var t = parseInt(this.getStyle('top'), 10);
9355 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9358 t = (p == "relative") ? 0 : this.dom.offsetTop;
9361 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9365 * Returns the current scroll position of the element.
9366 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9368 getScroll : function(){
9369 var d = this.dom, doc = document;
9370 if(d == doc || d == doc.body){
9371 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9372 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9373 return {left: l, top: t};
9375 return {left: d.scrollLeft, top: d.scrollTop};
9380 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9381 * are convert to standard 6 digit hex color.
9382 * @param {String} attr The css attribute
9383 * @param {String} defaultValue The default value to use when a valid color isn't found
9384 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9387 getColor : function(attr, defaultValue, prefix){
9388 var v = this.getStyle(attr);
9389 if(!v || v == "transparent" || v == "inherit") {
9390 return defaultValue;
9392 var color = typeof prefix == "undefined" ? "#" : prefix;
9393 if(v.substr(0, 4) == "rgb("){
9394 var rvs = v.slice(4, v.length -1).split(",");
9395 for(var i = 0; i < 3; i++){
9396 var h = parseInt(rvs[i]).toString(16);
9403 if(v.substr(0, 1) == "#"){
9405 for(var i = 1; i < 4; i++){
9406 var c = v.charAt(i);
9409 }else if(v.length == 7){
9410 color += v.substr(1);
9414 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9418 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9419 * gradient background, rounded corners and a 4-way shadow.
9420 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9421 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9422 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9423 * @return {Roo.Element} this
9425 boxWrap : function(cls){
9426 cls = cls || 'x-box';
9427 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9428 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9433 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9434 * @param {String} namespace The namespace in which to look for the attribute
9435 * @param {String} name The attribute name
9436 * @return {String} The attribute value
9438 getAttributeNS : Roo.isIE ? function(ns, name){
9440 var type = typeof d[ns+":"+name];
9441 if(type != 'undefined' && type != 'unknown'){
9442 return d[ns+":"+name];
9445 } : function(ns, name){
9447 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9451 var ep = El.prototype;
9454 * Appends an event handler (Shorthand for addListener)
9455 * @param {String} eventName The type of event to append
9456 * @param {Function} fn The method the event invokes
9457 * @param {Object} scope (optional) The scope (this object) of the fn
9458 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9461 ep.on = ep.addListener;
9463 ep.mon = ep.addListener;
9466 * Removes an event handler from this element (shorthand for removeListener)
9467 * @param {String} eventName the type of event to remove
9468 * @param {Function} fn the method the event invokes
9469 * @return {Roo.Element} this
9472 ep.un = ep.removeListener;
9475 * true to automatically adjust width and height settings for box-model issues (default to true)
9477 ep.autoBoxAdjust = true;
9480 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9483 El.addUnits = function(v, defaultUnit){
9484 if(v === "" || v == "auto"){
9487 if(v === undefined){
9490 if(typeof v == "number" || !El.unitPattern.test(v)){
9491 return v + (defaultUnit || 'px');
9496 // special markup used throughout Roo when box wrapping elements
9497 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>';
9499 * Visibility mode constant - Use visibility to hide element
9505 * Visibility mode constant - Use display to hide element
9511 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9512 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9513 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9525 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9526 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9527 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9528 * @return {Element} The Element object
9531 El.get = function(el){
9533 if(!el){ return null; }
9534 if(typeof el == "string"){ // element id
9535 if(!(elm = document.getElementById(el))){
9538 if(ex = El.cache[el]){
9541 ex = El.cache[el] = new El(elm);
9544 }else if(el.tagName){ // dom element
9548 if(ex = El.cache[id]){
9551 ex = El.cache[id] = new El(el);
9554 }else if(el instanceof El){
9556 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9557 // catch case where it hasn't been appended
9558 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9561 }else if(el.isComposite){
9563 }else if(el instanceof Array){
9564 return El.select(el);
9565 }else if(el == document){
9566 // create a bogus element object representing the document object
9568 var f = function(){};
9569 f.prototype = El.prototype;
9571 docEl.dom = document;
9579 El.uncache = function(el){
9580 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9582 delete El.cache[a[i].id || a[i]];
9588 // Garbage collection - uncache elements/purge listeners on orphaned elements
9589 // so we don't hold a reference and cause the browser to retain them
9590 El.garbageCollect = function(){
9591 if(!Roo.enableGarbageCollector){
9592 clearInterval(El.collectorThread);
9595 for(var eid in El.cache){
9596 var el = El.cache[eid], d = el.dom;
9597 // -------------------------------------------------------
9598 // Determining what is garbage:
9599 // -------------------------------------------------------
9601 // dom node is null, definitely garbage
9602 // -------------------------------------------------------
9604 // no parentNode == direct orphan, definitely garbage
9605 // -------------------------------------------------------
9606 // !d.offsetParent && !document.getElementById(eid)
9607 // display none elements have no offsetParent so we will
9608 // also try to look it up by it's id. However, check
9609 // offsetParent first so we don't do unneeded lookups.
9610 // This enables collection of elements that are not orphans
9611 // directly, but somewhere up the line they have an orphan
9613 // -------------------------------------------------------
9614 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9615 delete El.cache[eid];
9616 if(d && Roo.enableListenerCollection){
9622 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9626 El.Flyweight = function(dom){
9629 El.Flyweight.prototype = El.prototype;
9631 El._flyweights = {};
9633 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9634 * the dom node can be overwritten by other code.
9635 * @param {String/HTMLElement} el The dom node or id
9636 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9637 * prevent conflicts (e.g. internally Roo uses "_internal")
9639 * @return {Element} The shared Element object
9641 El.fly = function(el, named){
9642 named = named || '_global';
9643 el = Roo.getDom(el);
9647 if(!El._flyweights[named]){
9648 El._flyweights[named] = new El.Flyweight();
9650 El._flyweights[named].dom = el;
9651 return El._flyweights[named];
9655 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9656 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9657 * Shorthand of {@link Roo.Element#get}
9658 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9659 * @return {Element} The Element object
9665 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9666 * the dom node can be overwritten by other code.
9667 * Shorthand of {@link Roo.Element#fly}
9668 * @param {String/HTMLElement} el The dom node or id
9669 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9670 * prevent conflicts (e.g. internally Roo uses "_internal")
9672 * @return {Element} The shared Element object
9678 // speedy lookup for elements never to box adjust
9679 var noBoxAdjust = Roo.isStrict ? {
9682 input:1, select:1, textarea:1
9684 if(Roo.isIE || Roo.isGecko){
9685 noBoxAdjust['button'] = 1;
9689 Roo.EventManager.on(window, 'unload', function(){
9691 delete El._flyweights;
9699 Roo.Element.selectorFunction = Roo.DomQuery.select;
9702 Roo.Element.select = function(selector, unique, root){
9704 if(typeof selector == "string"){
9705 els = Roo.Element.selectorFunction(selector, root);
9706 }else if(selector.length !== undefined){
9709 throw "Invalid selector";
9711 if(unique === true){
9712 return new Roo.CompositeElement(els);
9714 return new Roo.CompositeElementLite(els);
9718 * Selects elements based on the passed CSS selector to enable working on them as 1.
9719 * @param {String/Array} selector The CSS selector or an array of elements
9720 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9721 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9722 * @return {CompositeElementLite/CompositeElement}
9726 Roo.select = Roo.Element.select;
9743 * Ext JS Library 1.1.1
9744 * Copyright(c) 2006-2007, Ext JS, LLC.
9746 * Originally Released Under LGPL - original licence link has changed is not relivant.
9749 * <script type="text/javascript">
9754 //Notifies Element that fx methods are available
9755 Roo.enableFx = true;
9759 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9760 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9761 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9762 * Element effects to work.</p><br/>
9764 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9765 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9766 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9767 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9768 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9769 * expected results and should be done with care.</p><br/>
9771 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9772 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9775 ----- -----------------------------
9776 tl The top left corner
9777 t The center of the top edge
9778 tr The top right corner
9779 l The center of the left edge
9780 r The center of the right edge
9781 bl The bottom left corner
9782 b The center of the bottom edge
9783 br The bottom right corner
9785 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9786 * below are common options that can be passed to any Fx method.</b>
9787 * @cfg {Function} callback A function called when the effect is finished
9788 * @cfg {Object} scope The scope of the effect function
9789 * @cfg {String} easing A valid Easing value for the effect
9790 * @cfg {String} afterCls A css class to apply after the effect
9791 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9792 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9793 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9794 * effects that end with the element being visually hidden, ignored otherwise)
9795 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9796 * a function which returns such a specification that will be applied to the Element after the effect finishes
9797 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9798 * @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
9799 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9803 * Slides the element into view. An anchor point can be optionally passed to set the point of
9804 * origin for the slide effect. This function automatically handles wrapping the element with
9805 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9808 // default: slide the element in from the top
9811 // custom: slide the element in from the right with a 2-second duration
9812 el.slideIn('r', { duration: 2 });
9814 // common config options shown with default values
9820 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9821 * @param {Object} options (optional) Object literal with any of the Fx config options
9822 * @return {Roo.Element} The Element
9824 slideIn : function(anchor, o){
9825 var el = this.getFxEl();
9828 el.queueFx(o, function(){
9830 anchor = anchor || "t";
9832 // fix display to visibility
9835 // restore values after effect
9836 var r = this.getFxRestore();
9837 var b = this.getBox();
9838 // fixed size for slide
9842 var wrap = this.fxWrap(r.pos, o, "hidden");
9844 var st = this.dom.style;
9845 st.visibility = "visible";
9846 st.position = "absolute";
9848 // clear out temp styles after slide and unwrap
9849 var after = function(){
9850 el.fxUnwrap(wrap, r.pos, o);
9852 st.height = r.height;
9855 // time to calc the positions
9856 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9858 switch(anchor.toLowerCase()){
9860 wrap.setSize(b.width, 0);
9861 st.left = st.bottom = "0";
9865 wrap.setSize(0, b.height);
9866 st.right = st.top = "0";
9870 wrap.setSize(0, b.height);
9872 st.left = st.top = "0";
9873 a = {width: bw, points: pt};
9876 wrap.setSize(b.width, 0);
9877 wrap.setY(b.bottom);
9878 st.left = st.top = "0";
9879 a = {height: bh, points: pt};
9883 st.right = st.bottom = "0";
9884 a = {width: bw, height: bh};
9888 wrap.setY(b.y+b.height);
9889 st.right = st.top = "0";
9890 a = {width: bw, height: bh, points: pt};
9894 wrap.setXY([b.right, b.bottom]);
9895 st.left = st.top = "0";
9896 a = {width: bw, height: bh, points: pt};
9900 wrap.setX(b.x+b.width);
9901 st.left = st.bottom = "0";
9902 a = {width: bw, height: bh, points: pt};
9905 this.dom.style.visibility = "visible";
9908 arguments.callee.anim = wrap.fxanim(a,
9918 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9919 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9920 * 'hidden') but block elements will still take up space in the document. The element must be removed
9921 * from the DOM using the 'remove' config option if desired. This function automatically handles
9922 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9925 // default: slide the element out to the top
9928 // custom: slide the element out to the right with a 2-second duration
9929 el.slideOut('r', { duration: 2 });
9931 // common config options shown with default values
9939 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9940 * @param {Object} options (optional) Object literal with any of the Fx config options
9941 * @return {Roo.Element} The Element
9943 slideOut : function(anchor, o){
9944 var el = this.getFxEl();
9947 el.queueFx(o, function(){
9949 anchor = anchor || "t";
9951 // restore values after effect
9952 var r = this.getFxRestore();
9954 var b = this.getBox();
9955 // fixed size for slide
9959 var wrap = this.fxWrap(r.pos, o, "visible");
9961 var st = this.dom.style;
9962 st.visibility = "visible";
9963 st.position = "absolute";
9967 var after = function(){
9969 el.setDisplayed(false);
9974 el.fxUnwrap(wrap, r.pos, o);
9977 st.height = r.height;
9982 var a, zero = {to: 0};
9983 switch(anchor.toLowerCase()){
9985 st.left = st.bottom = "0";
9989 st.right = st.top = "0";
9993 st.left = st.top = "0";
9994 a = {width: zero, points: {to:[b.right, b.y]}};
9997 st.left = st.top = "0";
9998 a = {height: zero, points: {to:[b.x, b.bottom]}};
10001 st.right = st.bottom = "0";
10002 a = {width: zero, height: zero};
10005 st.right = st.top = "0";
10006 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10009 st.left = st.top = "0";
10010 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10013 st.left = st.bottom = "0";
10014 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10018 arguments.callee.anim = wrap.fxanim(a,
10028 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10029 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10030 * The element must be removed from the DOM using the 'remove' config option if desired.
10036 // common config options shown with default values
10044 * @param {Object} options (optional) Object literal with any of the Fx config options
10045 * @return {Roo.Element} The Element
10047 puff : function(o){
10048 var el = this.getFxEl();
10051 el.queueFx(o, function(){
10052 this.clearOpacity();
10055 // restore values after effect
10056 var r = this.getFxRestore();
10057 var st = this.dom.style;
10059 var after = function(){
10061 el.setDisplayed(false);
10068 el.setPositioning(r.pos);
10069 st.width = r.width;
10070 st.height = r.height;
10075 var width = this.getWidth();
10076 var height = this.getHeight();
10078 arguments.callee.anim = this.fxanim({
10079 width : {to: this.adjustWidth(width * 2)},
10080 height : {to: this.adjustHeight(height * 2)},
10081 points : {by: [-(width * .5), -(height * .5)]},
10083 fontSize: {to:200, unit: "%"}
10094 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10095 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10096 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10102 // all config options shown with default values
10110 * @param {Object} options (optional) Object literal with any of the Fx config options
10111 * @return {Roo.Element} The Element
10113 switchOff : function(o){
10114 var el = this.getFxEl();
10117 el.queueFx(o, function(){
10118 this.clearOpacity();
10121 // restore values after effect
10122 var r = this.getFxRestore();
10123 var st = this.dom.style;
10125 var after = function(){
10127 el.setDisplayed(false);
10133 el.setPositioning(r.pos);
10134 st.width = r.width;
10135 st.height = r.height;
10140 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10141 this.clearOpacity();
10145 points:{by:[0, this.getHeight() * .5]}
10146 }, o, 'motion', 0.3, 'easeIn', after);
10147 }).defer(100, this);
10154 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10155 * changed using the "attr" config option) and then fading back to the original color. If no original
10156 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10159 // default: highlight background to yellow
10162 // custom: highlight foreground text to blue for 2 seconds
10163 el.highlight("0000ff", { attr: 'color', duration: 2 });
10165 // common config options shown with default values
10166 el.highlight("ffff9c", {
10167 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10168 endColor: (current color) or "ffffff",
10173 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10174 * @param {Object} options (optional) Object literal with any of the Fx config options
10175 * @return {Roo.Element} The Element
10177 highlight : function(color, o){
10178 var el = this.getFxEl();
10181 el.queueFx(o, function(){
10182 color = color || "ffff9c";
10183 attr = o.attr || "backgroundColor";
10185 this.clearOpacity();
10188 var origColor = this.getColor(attr);
10189 var restoreColor = this.dom.style[attr];
10190 endColor = (o.endColor || origColor) || "ffffff";
10192 var after = function(){
10193 el.dom.style[attr] = restoreColor;
10198 a[attr] = {from: color, to: endColor};
10199 arguments.callee.anim = this.fxanim(a,
10209 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10212 // default: a single light blue ripple
10215 // custom: 3 red ripples lasting 3 seconds total
10216 el.frame("ff0000", 3, { duration: 3 });
10218 // common config options shown with default values
10219 el.frame("C3DAF9", 1, {
10220 duration: 1 //duration of entire animation (not each individual ripple)
10221 // Note: Easing is not configurable and will be ignored if included
10224 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10225 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10226 * @param {Object} options (optional) Object literal with any of the Fx config options
10227 * @return {Roo.Element} The Element
10229 frame : function(color, count, o){
10230 var el = this.getFxEl();
10233 el.queueFx(o, function(){
10234 color = color || "#C3DAF9";
10235 if(color.length == 6){
10236 color = "#" + color;
10238 count = count || 1;
10239 duration = o.duration || 1;
10242 var b = this.getBox();
10243 var animFn = function(){
10244 var proxy = this.createProxy({
10247 visbility:"hidden",
10248 position:"absolute",
10249 "z-index":"35000", // yee haw
10250 border:"0px solid " + color
10253 var scale = Roo.isBorderBox ? 2 : 1;
10255 top:{from:b.y, to:b.y - 20},
10256 left:{from:b.x, to:b.x - 20},
10257 borderWidth:{from:0, to:10},
10258 opacity:{from:1, to:0},
10259 height:{from:b.height, to:(b.height + (20*scale))},
10260 width:{from:b.width, to:(b.width + (20*scale))}
10261 }, duration, function(){
10265 animFn.defer((duration/2)*1000, this);
10276 * Creates a pause before any subsequent queued effects begin. If there are
10277 * no effects queued after the pause it will have no effect.
10282 * @param {Number} seconds The length of time to pause (in seconds)
10283 * @return {Roo.Element} The Element
10285 pause : function(seconds){
10286 var el = this.getFxEl();
10289 el.queueFx(o, function(){
10290 setTimeout(function(){
10292 }, seconds * 1000);
10298 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10299 * using the "endOpacity" config option.
10302 // default: fade in from opacity 0 to 100%
10305 // custom: fade in from opacity 0 to 75% over 2 seconds
10306 el.fadeIn({ endOpacity: .75, duration: 2});
10308 // common config options shown with default values
10310 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10315 * @param {Object} options (optional) Object literal with any of the Fx config options
10316 * @return {Roo.Element} The Element
10318 fadeIn : function(o){
10319 var el = this.getFxEl();
10321 el.queueFx(o, function(){
10322 this.setOpacity(0);
10324 this.dom.style.visibility = 'visible';
10325 var to = o.endOpacity || 1;
10326 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10327 o, null, .5, "easeOut", function(){
10329 this.clearOpacity();
10338 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10339 * using the "endOpacity" config option.
10342 // default: fade out from the element's current opacity to 0
10345 // custom: fade out from the element's current opacity to 25% over 2 seconds
10346 el.fadeOut({ endOpacity: .25, duration: 2});
10348 // common config options shown with default values
10350 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10357 * @param {Object} options (optional) Object literal with any of the Fx config options
10358 * @return {Roo.Element} The Element
10360 fadeOut : function(o){
10361 var el = this.getFxEl();
10363 el.queueFx(o, function(){
10364 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10365 o, null, .5, "easeOut", function(){
10366 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10367 this.dom.style.display = "none";
10369 this.dom.style.visibility = "hidden";
10371 this.clearOpacity();
10379 * Animates the transition of an element's dimensions from a starting height/width
10380 * to an ending height/width.
10383 // change height and width to 100x100 pixels
10384 el.scale(100, 100);
10386 // common config options shown with default values. The height and width will default to
10387 // the element's existing values if passed as null.
10390 [element's height], {
10395 * @param {Number} width The new width (pass undefined to keep the original width)
10396 * @param {Number} height The new height (pass undefined to keep the original height)
10397 * @param {Object} options (optional) Object literal with any of the Fx config options
10398 * @return {Roo.Element} The Element
10400 scale : function(w, h, o){
10401 this.shift(Roo.apply({}, o, {
10409 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10410 * Any of these properties not specified in the config object will not be changed. This effect
10411 * requires that at least one new dimension, position or opacity setting must be passed in on
10412 * the config object in order for the function to have any effect.
10415 // slide the element horizontally to x position 200 while changing the height and opacity
10416 el.shift({ x: 200, height: 50, opacity: .8 });
10418 // common config options shown with default values.
10420 width: [element's width],
10421 height: [element's height],
10422 x: [element's x position],
10423 y: [element's y position],
10424 opacity: [element's opacity],
10429 * @param {Object} options Object literal with any of the Fx config options
10430 * @return {Roo.Element} The Element
10432 shift : function(o){
10433 var el = this.getFxEl();
10435 el.queueFx(o, function(){
10436 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10437 if(w !== undefined){
10438 a.width = {to: this.adjustWidth(w)};
10440 if(h !== undefined){
10441 a.height = {to: this.adjustHeight(h)};
10443 if(x !== undefined || y !== undefined){
10445 x !== undefined ? x : this.getX(),
10446 y !== undefined ? y : this.getY()
10449 if(op !== undefined){
10450 a.opacity = {to: op};
10452 if(o.xy !== undefined){
10453 a.points = {to: o.xy};
10455 arguments.callee.anim = this.fxanim(a,
10456 o, 'motion', .35, "easeOut", function(){
10464 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10465 * ending point of the effect.
10468 // default: slide the element downward while fading out
10471 // custom: slide the element out to the right with a 2-second duration
10472 el.ghost('r', { duration: 2 });
10474 // common config options shown with default values
10482 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10483 * @param {Object} options (optional) Object literal with any of the Fx config options
10484 * @return {Roo.Element} The Element
10486 ghost : function(anchor, o){
10487 var el = this.getFxEl();
10490 el.queueFx(o, function(){
10491 anchor = anchor || "b";
10493 // restore values after effect
10494 var r = this.getFxRestore();
10495 var w = this.getWidth(),
10496 h = this.getHeight();
10498 var st = this.dom.style;
10500 var after = function(){
10502 el.setDisplayed(false);
10508 el.setPositioning(r.pos);
10509 st.width = r.width;
10510 st.height = r.height;
10515 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10516 switch(anchor.toLowerCase()){
10543 arguments.callee.anim = this.fxanim(a,
10553 * Ensures that all effects queued after syncFx is called on the element are
10554 * run concurrently. This is the opposite of {@link #sequenceFx}.
10555 * @return {Roo.Element} The Element
10557 syncFx : function(){
10558 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10567 * Ensures that all effects queued after sequenceFx is called on the element are
10568 * run in sequence. This is the opposite of {@link #syncFx}.
10569 * @return {Roo.Element} The Element
10571 sequenceFx : function(){
10572 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10574 concurrent : false,
10581 nextFx : function(){
10582 var ef = this.fxQueue[0];
10589 * Returns true if the element has any effects actively running or queued, else returns false.
10590 * @return {Boolean} True if element has active effects, else false
10592 hasActiveFx : function(){
10593 return this.fxQueue && this.fxQueue[0];
10597 * Stops any running effects and clears the element's internal effects queue if it contains
10598 * any additional effects that haven't started yet.
10599 * @return {Roo.Element} The Element
10601 stopFx : function(){
10602 if(this.hasActiveFx()){
10603 var cur = this.fxQueue[0];
10604 if(cur && cur.anim && cur.anim.isAnimated()){
10605 this.fxQueue = [cur]; // clear out others
10606 cur.anim.stop(true);
10613 beforeFx : function(o){
10614 if(this.hasActiveFx() && !o.concurrent){
10625 * Returns true if the element is currently blocking so that no other effect can be queued
10626 * until this effect is finished, else returns false if blocking is not set. This is commonly
10627 * used to ensure that an effect initiated by a user action runs to completion prior to the
10628 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10629 * @return {Boolean} True if blocking, else false
10631 hasFxBlock : function(){
10632 var q = this.fxQueue;
10633 return q && q[0] && q[0].block;
10637 queueFx : function(o, fn){
10641 if(!this.hasFxBlock()){
10642 Roo.applyIf(o, this.fxDefaults);
10644 var run = this.beforeFx(o);
10645 fn.block = o.block;
10646 this.fxQueue.push(fn);
10658 fxWrap : function(pos, o, vis){
10660 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10663 wrapXY = this.getXY();
10665 var div = document.createElement("div");
10666 div.style.visibility = vis;
10667 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10668 wrap.setPositioning(pos);
10669 if(wrap.getStyle("position") == "static"){
10670 wrap.position("relative");
10672 this.clearPositioning('auto');
10674 wrap.dom.appendChild(this.dom);
10676 wrap.setXY(wrapXY);
10683 fxUnwrap : function(wrap, pos, o){
10684 this.clearPositioning();
10685 this.setPositioning(pos);
10687 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10693 getFxRestore : function(){
10694 var st = this.dom.style;
10695 return {pos: this.getPositioning(), width: st.width, height : st.height};
10699 afterFx : function(o){
10701 this.applyStyles(o.afterStyle);
10704 this.addClass(o.afterCls);
10706 if(o.remove === true){
10709 Roo.callback(o.callback, o.scope, [this]);
10711 this.fxQueue.shift();
10717 getFxEl : function(){ // support for composite element fx
10718 return Roo.get(this.dom);
10722 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10723 animType = animType || 'run';
10725 var anim = Roo.lib.Anim[animType](
10727 (opt.duration || defaultDur) || .35,
10728 (opt.easing || defaultEase) || 'easeOut',
10730 Roo.callback(cb, this);
10739 // backwords compat
10740 Roo.Fx.resize = Roo.Fx.scale;
10742 //When included, Roo.Fx is automatically applied to Element so that all basic
10743 //effects are available directly via the Element API
10744 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10746 * Ext JS Library 1.1.1
10747 * Copyright(c) 2006-2007, Ext JS, LLC.
10749 * Originally Released Under LGPL - original licence link has changed is not relivant.
10752 * <script type="text/javascript">
10757 * @class Roo.CompositeElement
10758 * Standard composite class. Creates a Roo.Element for every element in the collection.
10760 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10761 * actions will be performed on all the elements in this collection.</b>
10763 * All methods return <i>this</i> and can be chained.
10765 var els = Roo.select("#some-el div.some-class", true);
10766 // or select directly from an existing element
10767 var el = Roo.get('some-el');
10768 el.select('div.some-class', true);
10770 els.setWidth(100); // all elements become 100 width
10771 els.hide(true); // all elements fade out and hide
10773 els.setWidth(100).hide(true);
10776 Roo.CompositeElement = function(els){
10777 this.elements = [];
10778 this.addElements(els);
10780 Roo.CompositeElement.prototype = {
10782 addElements : function(els){
10783 if(!els) return this;
10784 if(typeof els == "string"){
10785 els = Roo.Element.selectorFunction(els);
10787 var yels = this.elements;
10788 var index = yels.length-1;
10789 for(var i = 0, len = els.length; i < len; i++) {
10790 yels[++index] = Roo.get(els[i]);
10796 * Clears this composite and adds the elements returned by the passed selector.
10797 * @param {String/Array} els A string CSS selector, an array of elements or an element
10798 * @return {CompositeElement} this
10800 fill : function(els){
10801 this.elements = [];
10807 * Filters this composite to only elements that match the passed selector.
10808 * @param {String} selector A string CSS selector
10809 * @return {CompositeElement} this
10811 filter : function(selector){
10813 this.each(function(el){
10814 if(el.is(selector)){
10815 els[els.length] = el.dom;
10822 invoke : function(fn, args){
10823 var els = this.elements;
10824 for(var i = 0, len = els.length; i < len; i++) {
10825 Roo.Element.prototype[fn].apply(els[i], args);
10830 * Adds elements to this composite.
10831 * @param {String/Array} els A string CSS selector, an array of elements or an element
10832 * @return {CompositeElement} this
10834 add : function(els){
10835 if(typeof els == "string"){
10836 this.addElements(Roo.Element.selectorFunction(els));
10837 }else if(els.length !== undefined){
10838 this.addElements(els);
10840 this.addElements([els]);
10845 * Calls the passed function passing (el, this, index) for each element in this composite.
10846 * @param {Function} fn The function to call
10847 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10848 * @return {CompositeElement} this
10850 each : function(fn, scope){
10851 var els = this.elements;
10852 for(var i = 0, len = els.length; i < len; i++){
10853 if(fn.call(scope || els[i], els[i], this, i) === false) {
10861 * Returns the Element object at the specified index
10862 * @param {Number} index
10863 * @return {Roo.Element}
10865 item : function(index){
10866 return this.elements[index] || null;
10870 * Returns the first Element
10871 * @return {Roo.Element}
10873 first : function(){
10874 return this.item(0);
10878 * Returns the last Element
10879 * @return {Roo.Element}
10882 return this.item(this.elements.length-1);
10886 * Returns the number of elements in this composite
10889 getCount : function(){
10890 return this.elements.length;
10894 * Returns true if this composite contains the passed element
10897 contains : function(el){
10898 return this.indexOf(el) !== -1;
10902 * Returns true if this composite contains the passed element
10905 indexOf : function(el){
10906 return this.elements.indexOf(Roo.get(el));
10911 * Removes the specified element(s).
10912 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10913 * or an array of any of those.
10914 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10915 * @return {CompositeElement} this
10917 removeElement : function(el, removeDom){
10918 if(el instanceof Array){
10919 for(var i = 0, len = el.length; i < len; i++){
10920 this.removeElement(el[i]);
10924 var index = typeof el == 'number' ? el : this.indexOf(el);
10927 var d = this.elements[index];
10931 d.parentNode.removeChild(d);
10934 this.elements.splice(index, 1);
10940 * Replaces the specified element with the passed element.
10941 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10943 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10944 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10945 * @return {CompositeElement} this
10947 replaceElement : function(el, replacement, domReplace){
10948 var index = typeof el == 'number' ? el : this.indexOf(el);
10951 this.elements[index].replaceWith(replacement);
10953 this.elements.splice(index, 1, Roo.get(replacement))
10960 * Removes all elements.
10962 clear : function(){
10963 this.elements = [];
10967 Roo.CompositeElement.createCall = function(proto, fnName){
10968 if(!proto[fnName]){
10969 proto[fnName] = function(){
10970 return this.invoke(fnName, arguments);
10974 for(var fnName in Roo.Element.prototype){
10975 if(typeof Roo.Element.prototype[fnName] == "function"){
10976 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10982 * Ext JS Library 1.1.1
10983 * Copyright(c) 2006-2007, Ext JS, LLC.
10985 * Originally Released Under LGPL - original licence link has changed is not relivant.
10988 * <script type="text/javascript">
10992 * @class Roo.CompositeElementLite
10993 * @extends Roo.CompositeElement
10994 * Flyweight composite class. Reuses the same Roo.Element for element operations.
10996 var els = Roo.select("#some-el div.some-class");
10997 // or select directly from an existing element
10998 var el = Roo.get('some-el');
10999 el.select('div.some-class');
11001 els.setWidth(100); // all elements become 100 width
11002 els.hide(true); // all elements fade out and hide
11004 els.setWidth(100).hide(true);
11005 </code></pre><br><br>
11006 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11007 * actions will be performed on all the elements in this collection.</b>
11009 Roo.CompositeElementLite = function(els){
11010 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11011 this.el = new Roo.Element.Flyweight();
11013 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11014 addElements : function(els){
11016 if(els instanceof Array){
11017 this.elements = this.elements.concat(els);
11019 var yels = this.elements;
11020 var index = yels.length-1;
11021 for(var i = 0, len = els.length; i < len; i++) {
11022 yels[++index] = els[i];
11028 invoke : function(fn, args){
11029 var els = this.elements;
11031 for(var i = 0, len = els.length; i < len; i++) {
11033 Roo.Element.prototype[fn].apply(el, args);
11038 * Returns a flyweight Element of the dom element object at the specified index
11039 * @param {Number} index
11040 * @return {Roo.Element}
11042 item : function(index){
11043 if(!this.elements[index]){
11046 this.el.dom = this.elements[index];
11050 // fixes scope with flyweight
11051 addListener : function(eventName, handler, scope, opt){
11052 var els = this.elements;
11053 for(var i = 0, len = els.length; i < len; i++) {
11054 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11060 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11061 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11062 * a reference to the dom node, use el.dom.</b>
11063 * @param {Function} fn The function to call
11064 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11065 * @return {CompositeElement} this
11067 each : function(fn, scope){
11068 var els = this.elements;
11070 for(var i = 0, len = els.length; i < len; i++){
11072 if(fn.call(scope || el, el, this, i) === false){
11079 indexOf : function(el){
11080 return this.elements.indexOf(Roo.getDom(el));
11083 replaceElement : function(el, replacement, domReplace){
11084 var index = typeof el == 'number' ? el : this.indexOf(el);
11086 replacement = Roo.getDom(replacement);
11088 var d = this.elements[index];
11089 d.parentNode.insertBefore(replacement, d);
11090 d.parentNode.removeChild(d);
11092 this.elements.splice(index, 1, replacement);
11097 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11101 * Ext JS Library 1.1.1
11102 * Copyright(c) 2006-2007, Ext JS, LLC.
11104 * Originally Released Under LGPL - original licence link has changed is not relivant.
11107 * <script type="text/javascript">
11113 * @class Roo.data.Connection
11114 * @extends Roo.util.Observable
11115 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11116 * either to a configured URL, or to a URL specified at request time.<br><br>
11118 * Requests made by this class are asynchronous, and will return immediately. No data from
11119 * the server will be available to the statement immediately following the {@link #request} call.
11120 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11122 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11123 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11124 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11125 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11126 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11127 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11128 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11129 * standard DOM methods.
11131 * @param {Object} config a configuration object.
11133 Roo.data.Connection = function(config){
11134 Roo.apply(this, config);
11137 * @event beforerequest
11138 * Fires before a network request is made to retrieve a data object.
11139 * @param {Connection} conn This Connection object.
11140 * @param {Object} options The options config object passed to the {@link #request} method.
11142 "beforerequest" : true,
11144 * @event requestcomplete
11145 * Fires if the request was successfully completed.
11146 * @param {Connection} conn This Connection object.
11147 * @param {Object} response The XHR object containing the response data.
11148 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11149 * @param {Object} options The options config object passed to the {@link #request} method.
11151 "requestcomplete" : true,
11153 * @event requestexception
11154 * Fires if an error HTTP status was returned from the server.
11155 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11156 * @param {Connection} conn This Connection object.
11157 * @param {Object} response The XHR object containing the response data.
11158 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11159 * @param {Object} options The options config object passed to the {@link #request} method.
11161 "requestexception" : true
11163 Roo.data.Connection.superclass.constructor.call(this);
11166 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11168 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11171 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11172 * extra parameters to each request made by this object. (defaults to undefined)
11175 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11176 * to each request made by this object. (defaults to undefined)
11179 * @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)
11182 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11186 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11192 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11195 disableCaching: true,
11198 * Sends an HTTP request to a remote server.
11199 * @param {Object} options An object which may contain the following properties:<ul>
11200 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11201 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11202 * request, a url encoded string or a function to call to get either.</li>
11203 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11204 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11205 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11206 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11207 * <li>options {Object} The parameter to the request call.</li>
11208 * <li>success {Boolean} True if the request succeeded.</li>
11209 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11211 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11212 * The callback is passed the following parameters:<ul>
11213 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11214 * <li>options {Object} The parameter to the request call.</li>
11216 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11217 * The callback is passed the following parameters:<ul>
11218 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11219 * <li>options {Object} The parameter to the request call.</li>
11221 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11222 * for the callback function. Defaults to the browser window.</li>
11223 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11224 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11225 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11226 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11227 * params for the post data. Any params will be appended to the URL.</li>
11228 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11230 * @return {Number} transactionId
11232 request : function(o){
11233 if(this.fireEvent("beforerequest", this, o) !== false){
11236 if(typeof p == "function"){
11237 p = p.call(o.scope||window, o);
11239 if(typeof p == "object"){
11240 p = Roo.urlEncode(o.params);
11242 if(this.extraParams){
11243 var extras = Roo.urlEncode(this.extraParams);
11244 p = p ? (p + '&' + extras) : extras;
11247 var url = o.url || this.url;
11248 if(typeof url == 'function'){
11249 url = url.call(o.scope||window, o);
11253 var form = Roo.getDom(o.form);
11254 url = url || form.action;
11256 var enctype = form.getAttribute("enctype");
11257 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11258 return this.doFormUpload(o, p, url);
11260 var f = Roo.lib.Ajax.serializeForm(form);
11261 p = p ? (p + '&' + f) : f;
11264 var hs = o.headers;
11265 if(this.defaultHeaders){
11266 hs = Roo.apply(hs || {}, this.defaultHeaders);
11273 success: this.handleResponse,
11274 failure: this.handleFailure,
11276 argument: {options: o},
11277 timeout : this.timeout
11280 var method = o.method||this.method||(p ? "POST" : "GET");
11282 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11283 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11286 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11290 }else if(this.autoAbort !== false){
11294 if((method == 'GET' && p) || o.xmlData){
11295 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11298 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11299 return this.transId;
11301 Roo.callback(o.callback, o.scope, [o, null, null]);
11307 * Determine whether this object has a request outstanding.
11308 * @param {Number} transactionId (Optional) defaults to the last transaction
11309 * @return {Boolean} True if there is an outstanding request.
11311 isLoading : function(transId){
11313 return Roo.lib.Ajax.isCallInProgress(transId);
11315 return this.transId ? true : false;
11320 * Aborts any outstanding request.
11321 * @param {Number} transactionId (Optional) defaults to the last transaction
11323 abort : function(transId){
11324 if(transId || this.isLoading()){
11325 Roo.lib.Ajax.abort(transId || this.transId);
11330 handleResponse : function(response){
11331 this.transId = false;
11332 var options = response.argument.options;
11333 response.argument = options ? options.argument : null;
11334 this.fireEvent("requestcomplete", this, response, options);
11335 Roo.callback(options.success, options.scope, [response, options]);
11336 Roo.callback(options.callback, options.scope, [options, true, response]);
11340 handleFailure : function(response, e){
11341 this.transId = false;
11342 var options = response.argument.options;
11343 response.argument = options ? options.argument : null;
11344 this.fireEvent("requestexception", this, response, options, e);
11345 Roo.callback(options.failure, options.scope, [response, options]);
11346 Roo.callback(options.callback, options.scope, [options, false, response]);
11350 doFormUpload : function(o, ps, url){
11352 var frame = document.createElement('iframe');
11355 frame.className = 'x-hidden';
11357 frame.src = Roo.SSL_SECURE_URL;
11359 document.body.appendChild(frame);
11362 document.frames[id].name = id;
11365 var form = Roo.getDom(o.form);
11367 form.method = 'POST';
11368 form.enctype = form.encoding = 'multipart/form-data';
11374 if(ps){ // add dynamic params
11376 ps = Roo.urlDecode(ps, false);
11378 if(ps.hasOwnProperty(k)){
11379 hd = document.createElement('input');
11380 hd.type = 'hidden';
11383 form.appendChild(hd);
11390 var r = { // bogus response object
11395 r.argument = o ? o.argument : null;
11400 doc = frame.contentWindow.document;
11402 doc = (frame.contentDocument || window.frames[id].document);
11404 if(doc && doc.body){
11405 r.responseText = doc.body.innerHTML;
11407 if(doc && doc.XMLDocument){
11408 r.responseXML = doc.XMLDocument;
11410 r.responseXML = doc;
11417 Roo.EventManager.removeListener(frame, 'load', cb, this);
11419 this.fireEvent("requestcomplete", this, r, o);
11420 Roo.callback(o.success, o.scope, [r, o]);
11421 Roo.callback(o.callback, o.scope, [o, true, r]);
11423 setTimeout(function(){document.body.removeChild(frame);}, 100);
11426 Roo.EventManager.on(frame, 'load', cb, this);
11429 if(hiddens){ // remove dynamic params
11430 for(var i = 0, len = hiddens.length; i < len; i++){
11431 form.removeChild(hiddens[i]);
11439 * @extends Roo.data.Connection
11440 * Global Ajax request class.
11444 Roo.Ajax = new Roo.data.Connection({
11447 * @cfg {String} url @hide
11450 * @cfg {Object} extraParams @hide
11453 * @cfg {Object} defaultHeaders @hide
11456 * @cfg {String} method (Optional) @hide
11459 * @cfg {Number} timeout (Optional) @hide
11462 * @cfg {Boolean} autoAbort (Optional) @hide
11466 * @cfg {Boolean} disableCaching (Optional) @hide
11470 * @property disableCaching
11471 * True to add a unique cache-buster param to GET requests. (defaults to true)
11476 * The default URL to be used for requests to the server. (defaults to undefined)
11480 * @property extraParams
11481 * An object containing properties which are used as
11482 * extra parameters to each request made by this object. (defaults to undefined)
11486 * @property defaultHeaders
11487 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11492 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11496 * @property timeout
11497 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11502 * @property autoAbort
11503 * Whether a new request should abort any pending requests. (defaults to false)
11509 * Serialize the passed form into a url encoded string
11510 * @param {String/HTMLElement} form
11513 serializeForm : function(form){
11514 return Roo.lib.Ajax.serializeForm(form);
11518 * Ext JS Library 1.1.1
11519 * Copyright(c) 2006-2007, Ext JS, LLC.
11521 * Originally Released Under LGPL - original licence link has changed is not relivant.
11524 * <script type="text/javascript">
11529 * @extends Roo.data.Connection
11530 * Global Ajax request class.
11532 * @instanceOf Roo.data.Connection
11534 Roo.Ajax = new Roo.data.Connection({
11543 * @cfg {String} url @hide
11546 * @cfg {Object} extraParams @hide
11549 * @cfg {Object} defaultHeaders @hide
11552 * @cfg {String} method (Optional) @hide
11555 * @cfg {Number} timeout (Optional) @hide
11558 * @cfg {Boolean} autoAbort (Optional) @hide
11562 * @cfg {Boolean} disableCaching (Optional) @hide
11566 * @property disableCaching
11567 * True to add a unique cache-buster param to GET requests. (defaults to true)
11572 * The default URL to be used for requests to the server. (defaults to undefined)
11576 * @property extraParams
11577 * An object containing properties which are used as
11578 * extra parameters to each request made by this object. (defaults to undefined)
11582 * @property defaultHeaders
11583 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11588 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11592 * @property timeout
11593 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11598 * @property autoAbort
11599 * Whether a new request should abort any pending requests. (defaults to false)
11605 * Serialize the passed form into a url encoded string
11606 * @param {String/HTMLElement} form
11609 serializeForm : function(form){
11610 return Roo.lib.Ajax.serializeForm(form);
11614 * Ext JS Library 1.1.1
11615 * Copyright(c) 2006-2007, Ext JS, LLC.
11617 * Originally Released Under LGPL - original licence link has changed is not relivant.
11620 * <script type="text/javascript">
11625 * @class Roo.UpdateManager
11626 * @extends Roo.util.Observable
11627 * Provides AJAX-style update for Element object.<br><br>
11630 * // Get it from a Roo.Element object
11631 * var el = Roo.get("foo");
11632 * var mgr = el.getUpdateManager();
11633 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11635 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11637 * // or directly (returns the same UpdateManager instance)
11638 * var mgr = new Roo.UpdateManager("myElementId");
11639 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11640 * mgr.on("update", myFcnNeedsToKnow);
11642 // short handed call directly from the element object
11643 Roo.get("foo").load({
11647 text: "Loading Foo..."
11651 * Create new UpdateManager directly.
11652 * @param {String/HTMLElement/Roo.Element} el The element to update
11653 * @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).
11655 Roo.UpdateManager = function(el, forceNew){
11657 if(!forceNew && el.updateManager){
11658 return el.updateManager;
11661 * The Element object
11662 * @type Roo.Element
11666 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11669 this.defaultUrl = null;
11673 * @event beforeupdate
11674 * Fired before an update is made, return false from your handler and the update is cancelled.
11675 * @param {Roo.Element} el
11676 * @param {String/Object/Function} url
11677 * @param {String/Object} params
11679 "beforeupdate": true,
11682 * Fired after successful update is made.
11683 * @param {Roo.Element} el
11684 * @param {Object} oResponseObject The response Object
11689 * Fired on update failure.
11690 * @param {Roo.Element} el
11691 * @param {Object} oResponseObject The response Object
11695 var d = Roo.UpdateManager.defaults;
11697 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11700 this.sslBlankUrl = d.sslBlankUrl;
11702 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11705 this.disableCaching = d.disableCaching;
11707 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11710 this.indicatorText = d.indicatorText;
11712 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11715 this.showLoadIndicator = d.showLoadIndicator;
11717 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11720 this.timeout = d.timeout;
11723 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11726 this.loadScripts = d.loadScripts;
11729 * Transaction object of current executing transaction
11731 this.transaction = null;
11736 this.autoRefreshProcId = null;
11738 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11741 this.refreshDelegate = this.refresh.createDelegate(this);
11743 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11746 this.updateDelegate = this.update.createDelegate(this);
11748 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11751 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11755 this.successDelegate = this.processSuccess.createDelegate(this);
11759 this.failureDelegate = this.processFailure.createDelegate(this);
11761 if(!this.renderer){
11763 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11765 this.renderer = new Roo.UpdateManager.BasicRenderer();
11768 Roo.UpdateManager.superclass.constructor.call(this);
11771 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11773 * Get the Element this UpdateManager is bound to
11774 * @return {Roo.Element} The element
11776 getEl : function(){
11780 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11781 * @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:
11784 url: "your-url.php",<br/>
11785 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11786 callback: yourFunction,<br/>
11787 scope: yourObject, //(optional scope) <br/>
11788 discardUrl: false, <br/>
11789 nocache: false,<br/>
11790 text: "Loading...",<br/>
11792 scripts: false<br/>
11795 * The only required property is url. The optional properties nocache, text and scripts
11796 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11797 * @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}
11798 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11799 * @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.
11801 update : function(url, params, callback, discardUrl){
11802 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11803 var method = this.method, cfg;
11804 if(typeof url == "object"){ // must be config object
11807 params = params || cfg.params;
11808 callback = callback || cfg.callback;
11809 discardUrl = discardUrl || cfg.discardUrl;
11810 if(callback && cfg.scope){
11811 callback = callback.createDelegate(cfg.scope);
11813 if(typeof cfg.method != "undefined"){method = cfg.method;};
11814 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11815 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11816 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11817 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11819 this.showLoading();
11821 this.defaultUrl = url;
11823 if(typeof url == "function"){
11824 url = url.call(this);
11827 method = method || (params ? "POST" : "GET");
11828 if(method == "GET"){
11829 url = this.prepareUrl(url);
11832 var o = Roo.apply(cfg ||{}, {
11835 success: this.successDelegate,
11836 failure: this.failureDelegate,
11837 callback: undefined,
11838 timeout: (this.timeout*1000),
11839 argument: {"url": url, "form": null, "callback": callback, "params": params}
11842 this.transaction = Roo.Ajax.request(o);
11847 * 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.
11848 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11849 * @param {String/HTMLElement} form The form Id or form element
11850 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11851 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11852 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11854 formUpdate : function(form, url, reset, callback){
11855 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11856 if(typeof url == "function"){
11857 url = url.call(this);
11859 form = Roo.getDom(form);
11860 this.transaction = Roo.Ajax.request({
11863 success: this.successDelegate,
11864 failure: this.failureDelegate,
11865 timeout: (this.timeout*1000),
11866 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11868 this.showLoading.defer(1, this);
11873 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11874 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11876 refresh : function(callback){
11877 if(this.defaultUrl == null){
11880 this.update(this.defaultUrl, null, callback, true);
11884 * Set this element to auto refresh.
11885 * @param {Number} interval How often to update (in seconds).
11886 * @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)
11887 * @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}
11888 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11889 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11891 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11893 this.update(url || this.defaultUrl, params, callback, true);
11895 if(this.autoRefreshProcId){
11896 clearInterval(this.autoRefreshProcId);
11898 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11902 * Stop auto refresh on this element.
11904 stopAutoRefresh : function(){
11905 if(this.autoRefreshProcId){
11906 clearInterval(this.autoRefreshProcId);
11907 delete this.autoRefreshProcId;
11911 isAutoRefreshing : function(){
11912 return this.autoRefreshProcId ? true : false;
11915 * Called to update the element to "Loading" state. Override to perform custom action.
11917 showLoading : function(){
11918 if(this.showLoadIndicator){
11919 this.el.update(this.indicatorText);
11924 * Adds unique parameter to query string if disableCaching = true
11927 prepareUrl : function(url){
11928 if(this.disableCaching){
11929 var append = "_dc=" + (new Date().getTime());
11930 if(url.indexOf("?") !== -1){
11931 url += "&" + append;
11933 url += "?" + append;
11942 processSuccess : function(response){
11943 this.transaction = null;
11944 if(response.argument.form && response.argument.reset){
11945 try{ // put in try/catch since some older FF releases had problems with this
11946 response.argument.form.reset();
11949 if(this.loadScripts){
11950 this.renderer.render(this.el, response, this,
11951 this.updateComplete.createDelegate(this, [response]));
11953 this.renderer.render(this.el, response, this);
11954 this.updateComplete(response);
11958 updateComplete : function(response){
11959 this.fireEvent("update", this.el, response);
11960 if(typeof response.argument.callback == "function"){
11961 response.argument.callback(this.el, true, response);
11968 processFailure : function(response){
11969 this.transaction = null;
11970 this.fireEvent("failure", this.el, response);
11971 if(typeof response.argument.callback == "function"){
11972 response.argument.callback(this.el, false, response);
11977 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11978 * @param {Object} renderer The object implementing the render() method
11980 setRenderer : function(renderer){
11981 this.renderer = renderer;
11984 getRenderer : function(){
11985 return this.renderer;
11989 * Set the defaultUrl used for updates
11990 * @param {String/Function} defaultUrl The url or a function to call to get the url
11992 setDefaultUrl : function(defaultUrl){
11993 this.defaultUrl = defaultUrl;
11997 * Aborts the executing transaction
11999 abort : function(){
12000 if(this.transaction){
12001 Roo.Ajax.abort(this.transaction);
12006 * Returns true if an update is in progress
12007 * @return {Boolean}
12009 isUpdating : function(){
12010 if(this.transaction){
12011 return Roo.Ajax.isLoading(this.transaction);
12018 * @class Roo.UpdateManager.defaults
12019 * @static (not really - but it helps the doc tool)
12020 * The defaults collection enables customizing the default properties of UpdateManager
12022 Roo.UpdateManager.defaults = {
12024 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12030 * True to process scripts by default (Defaults to false).
12033 loadScripts : false,
12036 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12039 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12041 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12044 disableCaching : false,
12046 * Whether to show indicatorText when loading (Defaults to true).
12049 showLoadIndicator : true,
12051 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12054 indicatorText : '<div class="loading-indicator">Loading...</div>'
12058 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12060 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12061 * @param {String/HTMLElement/Roo.Element} el The element to update
12062 * @param {String} url The url
12063 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12064 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12067 * @member Roo.UpdateManager
12069 Roo.UpdateManager.updateElement = function(el, url, params, options){
12070 var um = Roo.get(el, true).getUpdateManager();
12071 Roo.apply(um, options);
12072 um.update(url, params, options ? options.callback : null);
12074 // alias for backwards compat
12075 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12077 * @class Roo.UpdateManager.BasicRenderer
12078 * Default Content renderer. Updates the elements innerHTML with the responseText.
12080 Roo.UpdateManager.BasicRenderer = function(){};
12082 Roo.UpdateManager.BasicRenderer.prototype = {
12084 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12085 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12086 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12087 * @param {Roo.Element} el The element being rendered
12088 * @param {Object} response The YUI Connect response object
12089 * @param {UpdateManager} updateManager The calling update manager
12090 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12092 render : function(el, response, updateManager, callback){
12093 el.update(response.responseText, updateManager.loadScripts, callback);
12098 * Ext JS Library 1.1.1
12099 * Copyright(c) 2006-2007, Ext JS, LLC.
12101 * Originally Released Under LGPL - original licence link has changed is not relivant.
12104 * <script type="text/javascript">
12108 * @class Roo.util.DelayedTask
12109 * Provides a convenient method of performing setTimeout where a new
12110 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12111 * You can use this class to buffer
12112 * the keypress events for a certain number of milliseconds, and perform only if they stop
12113 * for that amount of time.
12114 * @constructor The parameters to this constructor serve as defaults and are not required.
12115 * @param {Function} fn (optional) The default function to timeout
12116 * @param {Object} scope (optional) The default scope of that timeout
12117 * @param {Array} args (optional) The default Array of arguments
12119 Roo.util.DelayedTask = function(fn, scope, args){
12120 var id = null, d, t;
12122 var call = function(){
12123 var now = new Date().getTime();
12127 fn.apply(scope, args || []);
12131 * Cancels any pending timeout and queues a new one
12132 * @param {Number} delay The milliseconds to delay
12133 * @param {Function} newFn (optional) Overrides function passed to constructor
12134 * @param {Object} newScope (optional) Overrides scope passed to constructor
12135 * @param {Array} newArgs (optional) Overrides args passed to constructor
12137 this.delay = function(delay, newFn, newScope, newArgs){
12138 if(id && delay != d){
12142 t = new Date().getTime();
12144 scope = newScope || scope;
12145 args = newArgs || args;
12147 id = setInterval(call, d);
12152 * Cancel the last queued timeout
12154 this.cancel = function(){
12162 * Ext JS Library 1.1.1
12163 * Copyright(c) 2006-2007, Ext JS, LLC.
12165 * Originally Released Under LGPL - original licence link has changed is not relivant.
12168 * <script type="text/javascript">
12172 Roo.util.TaskRunner = function(interval){
12173 interval = interval || 10;
12174 var tasks = [], removeQueue = [];
12176 var running = false;
12178 var stopThread = function(){
12184 var startThread = function(){
12187 id = setInterval(runTasks, interval);
12191 var removeTask = function(task){
12192 removeQueue.push(task);
12198 var runTasks = function(){
12199 if(removeQueue.length > 0){
12200 for(var i = 0, len = removeQueue.length; i < len; i++){
12201 tasks.remove(removeQueue[i]);
12204 if(tasks.length < 1){
12209 var now = new Date().getTime();
12210 for(var i = 0, len = tasks.length; i < len; ++i){
12212 var itime = now - t.taskRunTime;
12213 if(t.interval <= itime){
12214 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12215 t.taskRunTime = now;
12216 if(rt === false || t.taskRunCount === t.repeat){
12221 if(t.duration && t.duration <= (now - t.taskStartTime)){
12228 * Queues a new task.
12229 * @param {Object} task
12231 this.start = function(task){
12233 task.taskStartTime = new Date().getTime();
12234 task.taskRunTime = 0;
12235 task.taskRunCount = 0;
12240 this.stop = function(task){
12245 this.stopAll = function(){
12247 for(var i = 0, len = tasks.length; i < len; i++){
12248 if(tasks[i].onStop){
12257 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12259 * Ext JS Library 1.1.1
12260 * Copyright(c) 2006-2007, Ext JS, LLC.
12262 * Originally Released Under LGPL - original licence link has changed is not relivant.
12265 * <script type="text/javascript">
12270 * @class Roo.util.MixedCollection
12271 * @extends Roo.util.Observable
12272 * A Collection class that maintains both numeric indexes and keys and exposes events.
12274 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12275 * collection (defaults to false)
12276 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12277 * and return the key value for that item. This is used when available to look up the key on items that
12278 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12279 * equivalent to providing an implementation for the {@link #getKey} method.
12281 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12289 * Fires when the collection is cleared.
12294 * Fires when an item is added to the collection.
12295 * @param {Number} index The index at which the item was added.
12296 * @param {Object} o The item added.
12297 * @param {String} key The key associated with the added item.
12302 * Fires when an item is replaced in the collection.
12303 * @param {String} key he key associated with the new added.
12304 * @param {Object} old The item being replaced.
12305 * @param {Object} new The new item.
12310 * Fires when an item is removed from the collection.
12311 * @param {Object} o The item being removed.
12312 * @param {String} key (optional) The key associated with the removed item.
12317 this.allowFunctions = allowFunctions === true;
12319 this.getKey = keyFn;
12321 Roo.util.MixedCollection.superclass.constructor.call(this);
12324 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12325 allowFunctions : false,
12328 * Adds an item to the collection.
12329 * @param {String} key The key to associate with the item
12330 * @param {Object} o The item to add.
12331 * @return {Object} The item added.
12333 add : function(key, o){
12334 if(arguments.length == 1){
12336 key = this.getKey(o);
12338 if(typeof key == "undefined" || key === null){
12340 this.items.push(o);
12341 this.keys.push(null);
12343 var old = this.map[key];
12345 return this.replace(key, o);
12348 this.items.push(o);
12350 this.keys.push(key);
12352 this.fireEvent("add", this.length-1, o, key);
12357 * MixedCollection has a generic way to fetch keys if you implement getKey.
12360 var mc = new Roo.util.MixedCollection();
12361 mc.add(someEl.dom.id, someEl);
12362 mc.add(otherEl.dom.id, otherEl);
12366 var mc = new Roo.util.MixedCollection();
12367 mc.getKey = function(el){
12373 // or via the constructor
12374 var mc = new Roo.util.MixedCollection(false, function(el){
12380 * @param o {Object} The item for which to find the key.
12381 * @return {Object} The key for the passed item.
12383 getKey : function(o){
12388 * Replaces an item in the collection.
12389 * @param {String} key The key associated with the item to replace, or the item to replace.
12390 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12391 * @return {Object} The new item.
12393 replace : function(key, o){
12394 if(arguments.length == 1){
12396 key = this.getKey(o);
12398 var old = this.item(key);
12399 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12400 return this.add(key, o);
12402 var index = this.indexOfKey(key);
12403 this.items[index] = o;
12405 this.fireEvent("replace", key, old, o);
12410 * Adds all elements of an Array or an Object to the collection.
12411 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12412 * an Array of values, each of which are added to the collection.
12414 addAll : function(objs){
12415 if(arguments.length > 1 || objs instanceof Array){
12416 var args = arguments.length > 1 ? arguments : objs;
12417 for(var i = 0, len = args.length; i < len; i++){
12421 for(var key in objs){
12422 if(this.allowFunctions || typeof objs[key] != "function"){
12423 this.add(key, objs[key]);
12430 * Executes the specified function once for every item in the collection, passing each
12431 * item as the first and only parameter. returning false from the function will stop the iteration.
12432 * @param {Function} fn The function to execute for each item.
12433 * @param {Object} scope (optional) The scope in which to execute the function.
12435 each : function(fn, scope){
12436 var items = [].concat(this.items); // each safe for removal
12437 for(var i = 0, len = items.length; i < len; i++){
12438 if(fn.call(scope || items[i], items[i], i, len) === false){
12445 * Executes the specified function once for every key in the collection, passing each
12446 * key, and its associated item as the first two parameters.
12447 * @param {Function} fn The function to execute for each item.
12448 * @param {Object} scope (optional) The scope in which to execute the function.
12450 eachKey : function(fn, scope){
12451 for(var i = 0, len = this.keys.length; i < len; i++){
12452 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12457 * Returns the first item in the collection which elicits a true return value from the
12458 * passed selection function.
12459 * @param {Function} fn The selection function to execute for each item.
12460 * @param {Object} scope (optional) The scope in which to execute the function.
12461 * @return {Object} The first item in the collection which returned true from the selection function.
12463 find : function(fn, scope){
12464 for(var i = 0, len = this.items.length; i < len; i++){
12465 if(fn.call(scope || window, this.items[i], this.keys[i])){
12466 return this.items[i];
12473 * Inserts an item at the specified index in the collection.
12474 * @param {Number} index The index to insert the item at.
12475 * @param {String} key The key to associate with the new item, or the item itself.
12476 * @param {Object} o (optional) If the second parameter was a key, the new item.
12477 * @return {Object} The item inserted.
12479 insert : function(index, key, o){
12480 if(arguments.length == 2){
12482 key = this.getKey(o);
12484 if(index >= this.length){
12485 return this.add(key, o);
12488 this.items.splice(index, 0, o);
12489 if(typeof key != "undefined" && key != null){
12492 this.keys.splice(index, 0, key);
12493 this.fireEvent("add", index, o, key);
12498 * Removed an item from the collection.
12499 * @param {Object} o The item to remove.
12500 * @return {Object} The item removed.
12502 remove : function(o){
12503 return this.removeAt(this.indexOf(o));
12507 * Remove an item from a specified index in the collection.
12508 * @param {Number} index The index within the collection of the item to remove.
12510 removeAt : function(index){
12511 if(index < this.length && index >= 0){
12513 var o = this.items[index];
12514 this.items.splice(index, 1);
12515 var key = this.keys[index];
12516 if(typeof key != "undefined"){
12517 delete this.map[key];
12519 this.keys.splice(index, 1);
12520 this.fireEvent("remove", o, key);
12525 * Removed an item associated with the passed key fom the collection.
12526 * @param {String} key The key of the item to remove.
12528 removeKey : function(key){
12529 return this.removeAt(this.indexOfKey(key));
12533 * Returns the number of items in the collection.
12534 * @return {Number} the number of items in the collection.
12536 getCount : function(){
12537 return this.length;
12541 * Returns index within the collection of the passed Object.
12542 * @param {Object} o The item to find the index of.
12543 * @return {Number} index of the item.
12545 indexOf : function(o){
12546 if(!this.items.indexOf){
12547 for(var i = 0, len = this.items.length; i < len; i++){
12548 if(this.items[i] == o) return i;
12552 return this.items.indexOf(o);
12557 * Returns index within the collection of the passed key.
12558 * @param {String} key The key to find the index of.
12559 * @return {Number} index of the key.
12561 indexOfKey : function(key){
12562 if(!this.keys.indexOf){
12563 for(var i = 0, len = this.keys.length; i < len; i++){
12564 if(this.keys[i] == key) return i;
12568 return this.keys.indexOf(key);
12573 * Returns the item associated with the passed key OR index. Key has priority over index.
12574 * @param {String/Number} key The key or index of the item.
12575 * @return {Object} The item associated with the passed key.
12577 item : function(key){
12578 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12579 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12583 * Returns the item at the specified index.
12584 * @param {Number} index The index of the item.
12587 itemAt : function(index){
12588 return this.items[index];
12592 * Returns the item associated with the passed key.
12593 * @param {String/Number} key The key of the item.
12594 * @return {Object} The item associated with the passed key.
12596 key : function(key){
12597 return this.map[key];
12601 * Returns true if the collection contains the passed Object as an item.
12602 * @param {Object} o The Object to look for in the collection.
12603 * @return {Boolean} True if the collection contains the Object as an item.
12605 contains : function(o){
12606 return this.indexOf(o) != -1;
12610 * Returns true if the collection contains the passed Object as a key.
12611 * @param {String} key The key to look for in the collection.
12612 * @return {Boolean} True if the collection contains the Object as a key.
12614 containsKey : function(key){
12615 return typeof this.map[key] != "undefined";
12619 * Removes all items from the collection.
12621 clear : function(){
12626 this.fireEvent("clear");
12630 * Returns the first item in the collection.
12631 * @return {Object} the first item in the collection..
12633 first : function(){
12634 return this.items[0];
12638 * Returns the last item in the collection.
12639 * @return {Object} the last item in the collection..
12642 return this.items[this.length-1];
12645 _sort : function(property, dir, fn){
12646 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12647 fn = fn || function(a, b){
12650 var c = [], k = this.keys, items = this.items;
12651 for(var i = 0, len = items.length; i < len; i++){
12652 c[c.length] = {key: k[i], value: items[i], index: i};
12654 c.sort(function(a, b){
12655 var v = fn(a[property], b[property]) * dsc;
12657 v = (a.index < b.index ? -1 : 1);
12661 for(var i = 0, len = c.length; i < len; i++){
12662 items[i] = c[i].value;
12665 this.fireEvent("sort", this);
12669 * Sorts this collection with the passed comparison function
12670 * @param {String} direction (optional) "ASC" or "DESC"
12671 * @param {Function} fn (optional) comparison function
12673 sort : function(dir, fn){
12674 this._sort("value", dir, fn);
12678 * Sorts this collection by keys
12679 * @param {String} direction (optional) "ASC" or "DESC"
12680 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12682 keySort : function(dir, fn){
12683 this._sort("key", dir, fn || function(a, b){
12684 return String(a).toUpperCase()-String(b).toUpperCase();
12689 * Returns a range of items in this collection
12690 * @param {Number} startIndex (optional) defaults to 0
12691 * @param {Number} endIndex (optional) default to the last item
12692 * @return {Array} An array of items
12694 getRange : function(start, end){
12695 var items = this.items;
12696 if(items.length < 1){
12699 start = start || 0;
12700 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12703 for(var i = start; i <= end; i++) {
12704 r[r.length] = items[i];
12707 for(var i = start; i >= end; i--) {
12708 r[r.length] = items[i];
12715 * Filter the <i>objects</i> in this collection by a specific property.
12716 * Returns a new collection that has been filtered.
12717 * @param {String} property A property on your objects
12718 * @param {String/RegExp} value Either string that the property values
12719 * should start with or a RegExp to test against the property
12720 * @return {MixedCollection} The new filtered collection
12722 filter : function(property, value){
12723 if(!value.exec){ // not a regex
12724 value = String(value);
12725 if(value.length == 0){
12726 return this.clone();
12728 value = new RegExp("^" + Roo.escapeRe(value), "i");
12730 return this.filterBy(function(o){
12731 return o && value.test(o[property]);
12736 * Filter by a function. * Returns a new collection that has been filtered.
12737 * The passed function will be called with each
12738 * object in the collection. If the function returns true, the value is included
12739 * otherwise it is filtered.
12740 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12741 * @param {Object} scope (optional) The scope of the function (defaults to this)
12742 * @return {MixedCollection} The new filtered collection
12744 filterBy : function(fn, scope){
12745 var r = new Roo.util.MixedCollection();
12746 r.getKey = this.getKey;
12747 var k = this.keys, it = this.items;
12748 for(var i = 0, len = it.length; i < len; i++){
12749 if(fn.call(scope||this, it[i], k[i])){
12750 r.add(k[i], it[i]);
12757 * Creates a duplicate of this collection
12758 * @return {MixedCollection}
12760 clone : function(){
12761 var r = new Roo.util.MixedCollection();
12762 var k = this.keys, it = this.items;
12763 for(var i = 0, len = it.length; i < len; i++){
12764 r.add(k[i], it[i]);
12766 r.getKey = this.getKey;
12771 * Returns the item associated with the passed key or index.
12773 * @param {String/Number} key The key or index of the item.
12774 * @return {Object} The item associated with the passed key.
12776 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12778 * Ext JS Library 1.1.1
12779 * Copyright(c) 2006-2007, Ext JS, LLC.
12781 * Originally Released Under LGPL - original licence link has changed is not relivant.
12784 * <script type="text/javascript">
12787 * @class Roo.util.JSON
12788 * Modified version of Douglas Crockford"s json.js that doesn"t
12789 * mess with the Object prototype
12790 * http://www.json.org/js.html
12793 Roo.util.JSON = new (function(){
12794 var useHasOwn = {}.hasOwnProperty ? true : false;
12796 // crashes Safari in some instances
12797 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12799 var pad = function(n) {
12800 return n < 10 ? "0" + n : n;
12813 var encodeString = function(s){
12814 if (/["\\\x00-\x1f]/.test(s)) {
12815 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12820 c = b.charCodeAt();
12822 Math.floor(c / 16).toString(16) +
12823 (c % 16).toString(16);
12826 return '"' + s + '"';
12829 var encodeArray = function(o){
12830 var a = ["["], b, i, l = o.length, v;
12831 for (i = 0; i < l; i += 1) {
12833 switch (typeof v) {
12842 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12850 var encodeDate = function(o){
12851 return '"' + o.getFullYear() + "-" +
12852 pad(o.getMonth() + 1) + "-" +
12853 pad(o.getDate()) + "T" +
12854 pad(o.getHours()) + ":" +
12855 pad(o.getMinutes()) + ":" +
12856 pad(o.getSeconds()) + '"';
12860 * Encodes an Object, Array or other value
12861 * @param {Mixed} o The variable to encode
12862 * @return {String} The JSON string
12864 this.encode = function(o)
12866 // should this be extended to fully wrap stringify..
12868 if(typeof o == "undefined" || o === null){
12870 }else if(o instanceof Array){
12871 return encodeArray(o);
12872 }else if(o instanceof Date){
12873 return encodeDate(o);
12874 }else if(typeof o == "string"){
12875 return encodeString(o);
12876 }else if(typeof o == "number"){
12877 return isFinite(o) ? String(o) : "null";
12878 }else if(typeof o == "boolean"){
12881 var a = ["{"], b, i, v;
12883 if(!useHasOwn || o.hasOwnProperty(i)) {
12885 switch (typeof v) {
12894 a.push(this.encode(i), ":",
12895 v === null ? "null" : this.encode(v));
12906 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12907 * @param {String} json The JSON string
12908 * @return {Object} The resulting object
12910 this.decode = function(json){
12912 return /** eval:var:json */ eval("(" + json + ')');
12916 * Shorthand for {@link Roo.util.JSON#encode}
12917 * @member Roo encode
12919 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12921 * Shorthand for {@link Roo.util.JSON#decode}
12922 * @member Roo decode
12924 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12927 * Ext JS Library 1.1.1
12928 * Copyright(c) 2006-2007, Ext JS, LLC.
12930 * Originally Released Under LGPL - original licence link has changed is not relivant.
12933 * <script type="text/javascript">
12937 * @class Roo.util.Format
12938 * Reusable data formatting functions
12941 Roo.util.Format = function(){
12942 var trimRe = /^\s+|\s+$/g;
12945 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12946 * @param {String} value The string to truncate
12947 * @param {Number} length The maximum length to allow before truncating
12948 * @return {String} The converted text
12950 ellipsis : function(value, len){
12951 if(value && value.length > len){
12952 return value.substr(0, len-3)+"...";
12958 * Checks a reference and converts it to empty string if it is undefined
12959 * @param {Mixed} value Reference to check
12960 * @return {Mixed} Empty string if converted, otherwise the original value
12962 undef : function(value){
12963 return typeof value != "undefined" ? value : "";
12967 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12968 * @param {String} value The string to encode
12969 * @return {String} The encoded text
12971 htmlEncode : function(value){
12972 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12976 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12977 * @param {String} value The string to decode
12978 * @return {String} The decoded text
12980 htmlDecode : function(value){
12981 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12985 * Trims any whitespace from either side of a string
12986 * @param {String} value The text to trim
12987 * @return {String} The trimmed text
12989 trim : function(value){
12990 return String(value).replace(trimRe, "");
12994 * Returns a substring from within an original string
12995 * @param {String} value The original text
12996 * @param {Number} start The start index of the substring
12997 * @param {Number} length The length of the substring
12998 * @return {String} The substring
13000 substr : function(value, start, length){
13001 return String(value).substr(start, length);
13005 * Converts a string to all lower case letters
13006 * @param {String} value The text to convert
13007 * @return {String} The converted text
13009 lowercase : function(value){
13010 return String(value).toLowerCase();
13014 * Converts a string to all upper case letters
13015 * @param {String} value The text to convert
13016 * @return {String} The converted text
13018 uppercase : function(value){
13019 return String(value).toUpperCase();
13023 * Converts the first character only of a string to upper case
13024 * @param {String} value The text to convert
13025 * @return {String} The converted text
13027 capitalize : function(value){
13028 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13032 call : function(value, fn){
13033 if(arguments.length > 2){
13034 var args = Array.prototype.slice.call(arguments, 2);
13035 args.unshift(value);
13037 return /** eval:var:value */ eval(fn).apply(window, args);
13039 /** eval:var:value */
13040 return /** eval:var:value */ eval(fn).call(window, value);
13046 * safer version of Math.toFixed..??/
13047 * @param {Number/String} value The numeric value to format
13048 * @param {Number/String} value Decimal places
13049 * @return {String} The formatted currency string
13051 toFixed : function(v, n)
13053 // why not use to fixed - precision is buggered???
13055 return Math.round(v-0);
13057 var fact = Math.pow(10,n+1);
13058 v = (Math.round((v-0)*fact))/fact;
13059 var z = (''+fact).substring(2);
13060 if (v == Math.floor(v)) {
13061 return Math.floor(v) + '.' + z;
13064 // now just padd decimals..
13065 var ps = String(v).split('.');
13066 var fd = (ps[1] + z);
13067 var r = fd.substring(0,n);
13068 var rm = fd.substring(n);
13070 return ps[0] + '.' + r;
13072 r*=1; // turn it into a number;
13074 if (String(r).length != n) {
13077 r = String(r).substring(1); // chop the end off.
13080 return ps[0] + '.' + r;
13085 * Format a number as US currency
13086 * @param {Number/String} value The numeric value to format
13087 * @return {String} The formatted currency string
13089 usMoney : function(v){
13090 v = (Math.round((v-0)*100))/100;
13091 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13093 var ps = v.split('.');
13095 var sub = ps[1] ? '.'+ ps[1] : '.00';
13096 var r = /(\d+)(\d{3})/;
13097 while (r.test(whole)) {
13098 whole = whole.replace(r, '$1' + ',' + '$2');
13100 return "$" + whole + sub ;
13104 * Parse a value into a formatted date using the specified format pattern.
13105 * @param {Mixed} value The value to format
13106 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13107 * @return {String} The formatted date string
13109 date : function(v, format){
13113 if(!(v instanceof Date)){
13114 v = new Date(Date.parse(v));
13116 return v.dateFormat(format || "m/d/Y");
13120 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13121 * @param {String} format Any valid date format string
13122 * @return {Function} The date formatting function
13124 dateRenderer : function(format){
13125 return function(v){
13126 return Roo.util.Format.date(v, format);
13131 stripTagsRE : /<\/?[^>]+>/gi,
13134 * Strips all HTML tags
13135 * @param {Mixed} value The text from which to strip tags
13136 * @return {String} The stripped text
13138 stripTags : function(v){
13139 return !v ? v : String(v).replace(this.stripTagsRE, "");
13144 * Ext JS Library 1.1.1
13145 * Copyright(c) 2006-2007, Ext JS, LLC.
13147 * Originally Released Under LGPL - original licence link has changed is not relivant.
13150 * <script type="text/javascript">
13157 * @class Roo.MasterTemplate
13158 * @extends Roo.Template
13159 * Provides a template that can have child templates. The syntax is:
13161 var t = new Roo.MasterTemplate(
13162 '<select name="{name}">',
13163 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13166 t.add('options', {value: 'foo', text: 'bar'});
13167 // or you can add multiple child elements in one shot
13168 t.addAll('options', [
13169 {value: 'foo', text: 'bar'},
13170 {value: 'foo2', text: 'bar2'},
13171 {value: 'foo3', text: 'bar3'}
13173 // then append, applying the master template values
13174 t.append('my-form', {name: 'my-select'});
13176 * A name attribute for the child template is not required if you have only one child
13177 * template or you want to refer to them by index.
13179 Roo.MasterTemplate = function(){
13180 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13181 this.originalHtml = this.html;
13183 var m, re = this.subTemplateRe;
13186 while(m = re.exec(this.html)){
13187 var name = m[1], content = m[2];
13192 tpl : new Roo.Template(content)
13195 st[name] = st[subIndex];
13197 st[subIndex].tpl.compile();
13198 st[subIndex].tpl.call = this.call.createDelegate(this);
13201 this.subCount = subIndex;
13204 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13206 * The regular expression used to match sub templates
13210 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13213 * Applies the passed values to a child template.
13214 * @param {String/Number} name (optional) The name or index of the child template
13215 * @param {Array/Object} values The values to be applied to the template
13216 * @return {MasterTemplate} this
13218 add : function(name, values){
13219 if(arguments.length == 1){
13220 values = arguments[0];
13223 var s = this.subs[name];
13224 s.buffer[s.buffer.length] = s.tpl.apply(values);
13229 * Applies all the passed values to a child template.
13230 * @param {String/Number} name (optional) The name or index of the child template
13231 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13232 * @param {Boolean} reset (optional) True to reset the template first
13233 * @return {MasterTemplate} this
13235 fill : function(name, values, reset){
13237 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13245 for(var i = 0, len = values.length; i < len; i++){
13246 this.add(name, values[i]);
13252 * Resets the template for reuse
13253 * @return {MasterTemplate} this
13255 reset : function(){
13257 for(var i = 0; i < this.subCount; i++){
13263 applyTemplate : function(values){
13265 var replaceIndex = -1;
13266 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13267 return s[++replaceIndex].buffer.join("");
13269 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13272 apply : function(){
13273 return this.applyTemplate.apply(this, arguments);
13276 compile : function(){return this;}
13280 * Alias for fill().
13283 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13285 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13286 * var tpl = Roo.MasterTemplate.from('element-id');
13287 * @param {String/HTMLElement} el
13288 * @param {Object} config
13291 Roo.MasterTemplate.from = function(el, config){
13292 el = Roo.getDom(el);
13293 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13296 * Ext JS Library 1.1.1
13297 * Copyright(c) 2006-2007, Ext JS, LLC.
13299 * Originally Released Under LGPL - original licence link has changed is not relivant.
13302 * <script type="text/javascript">
13307 * @class Roo.util.CSS
13308 * Utility class for manipulating CSS rules
13311 Roo.util.CSS = function(){
13313 var doc = document;
13315 var camelRe = /(-[a-z])/gi;
13316 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13320 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13321 * tag and appended to the HEAD of the document.
13322 * @param {String|Object} cssText The text containing the css rules
13323 * @param {String} id An id to add to the stylesheet for later removal
13324 * @return {StyleSheet}
13326 createStyleSheet : function(cssText, id){
13328 var head = doc.getElementsByTagName("head")[0];
13329 var nrules = doc.createElement("style");
13330 nrules.setAttribute("type", "text/css");
13332 nrules.setAttribute("id", id);
13334 if (typeof(cssText) != 'string') {
13335 // support object maps..
13336 // not sure if this a good idea..
13337 // perhaps it should be merged with the general css handling
13338 // and handle js style props.
13339 var cssTextNew = [];
13340 for(var n in cssText) {
13342 for(var k in cssText[n]) {
13343 citems.push( k + ' : ' +cssText[n][k] + ';' );
13345 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13348 cssText = cssTextNew.join("\n");
13354 head.appendChild(nrules);
13355 ss = nrules.styleSheet;
13356 ss.cssText = cssText;
13359 nrules.appendChild(doc.createTextNode(cssText));
13361 nrules.cssText = cssText;
13363 head.appendChild(nrules);
13364 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13366 this.cacheStyleSheet(ss);
13371 * Removes a style or link tag by id
13372 * @param {String} id The id of the tag
13374 removeStyleSheet : function(id){
13375 var existing = doc.getElementById(id);
13377 existing.parentNode.removeChild(existing);
13382 * Dynamically swaps an existing stylesheet reference for a new one
13383 * @param {String} id The id of an existing link tag to remove
13384 * @param {String} url The href of the new stylesheet to include
13386 swapStyleSheet : function(id, url){
13387 this.removeStyleSheet(id);
13388 var ss = doc.createElement("link");
13389 ss.setAttribute("rel", "stylesheet");
13390 ss.setAttribute("type", "text/css");
13391 ss.setAttribute("id", id);
13392 ss.setAttribute("href", url);
13393 doc.getElementsByTagName("head")[0].appendChild(ss);
13397 * Refresh the rule cache if you have dynamically added stylesheets
13398 * @return {Object} An object (hash) of rules indexed by selector
13400 refreshCache : function(){
13401 return this.getRules(true);
13405 cacheStyleSheet : function(stylesheet){
13409 try{// try catch for cross domain access issue
13410 var ssRules = stylesheet.cssRules || stylesheet.rules;
13411 for(var j = ssRules.length-1; j >= 0; --j){
13412 rules[ssRules[j].selectorText] = ssRules[j];
13418 * Gets all css rules for the document
13419 * @param {Boolean} refreshCache true to refresh the internal cache
13420 * @return {Object} An object (hash) of rules indexed by selector
13422 getRules : function(refreshCache){
13423 if(rules == null || refreshCache){
13425 var ds = doc.styleSheets;
13426 for(var i =0, len = ds.length; i < len; i++){
13428 this.cacheStyleSheet(ds[i]);
13436 * Gets an an individual CSS rule by selector(s)
13437 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13438 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13439 * @return {CSSRule} The CSS rule or null if one is not found
13441 getRule : function(selector, refreshCache){
13442 var rs = this.getRules(refreshCache);
13443 if(!(selector instanceof Array)){
13444 return rs[selector];
13446 for(var i = 0; i < selector.length; i++){
13447 if(rs[selector[i]]){
13448 return rs[selector[i]];
13456 * Updates a rule property
13457 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13458 * @param {String} property The css property
13459 * @param {String} value The new value for the property
13460 * @return {Boolean} true If a rule was found and updated
13462 updateRule : function(selector, property, value){
13463 if(!(selector instanceof Array)){
13464 var rule = this.getRule(selector);
13466 rule.style[property.replace(camelRe, camelFn)] = value;
13470 for(var i = 0; i < selector.length; i++){
13471 if(this.updateRule(selector[i], property, value)){
13481 * Ext JS Library 1.1.1
13482 * Copyright(c) 2006-2007, Ext JS, LLC.
13484 * Originally Released Under LGPL - original licence link has changed is not relivant.
13487 * <script type="text/javascript">
13493 * @class Roo.util.ClickRepeater
13494 * @extends Roo.util.Observable
13496 * A wrapper class which can be applied to any element. Fires a "click" event while the
13497 * mouse is pressed. The interval between firings may be specified in the config but
13498 * defaults to 10 milliseconds.
13500 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13502 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13503 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13504 * Similar to an autorepeat key delay.
13505 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13506 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13507 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13508 * "interval" and "delay" are ignored. "immediate" is honored.
13509 * @cfg {Boolean} preventDefault True to prevent the default click event
13510 * @cfg {Boolean} stopDefault True to stop the default click event
13513 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13514 * 2007-02-02 jvs Renamed to ClickRepeater
13515 * 2007-02-03 jvs Modifications for FF Mac and Safari
13518 * @param {String/HTMLElement/Element} el The element to listen on
13519 * @param {Object} config
13521 Roo.util.ClickRepeater = function(el, config)
13523 this.el = Roo.get(el);
13524 this.el.unselectable();
13526 Roo.apply(this, config);
13531 * Fires when the mouse button is depressed.
13532 * @param {Roo.util.ClickRepeater} this
13534 "mousedown" : true,
13537 * Fires on a specified interval during the time the element is pressed.
13538 * @param {Roo.util.ClickRepeater} this
13543 * Fires when the mouse key is released.
13544 * @param {Roo.util.ClickRepeater} this
13549 this.el.on("mousedown", this.handleMouseDown, this);
13550 if(this.preventDefault || this.stopDefault){
13551 this.el.on("click", function(e){
13552 if(this.preventDefault){
13553 e.preventDefault();
13555 if(this.stopDefault){
13561 // allow inline handler
13563 this.on("click", this.handler, this.scope || this);
13566 Roo.util.ClickRepeater.superclass.constructor.call(this);
13569 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13572 preventDefault : true,
13573 stopDefault : false,
13577 handleMouseDown : function(){
13578 clearTimeout(this.timer);
13580 if(this.pressClass){
13581 this.el.addClass(this.pressClass);
13583 this.mousedownTime = new Date();
13585 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13586 this.el.on("mouseout", this.handleMouseOut, this);
13588 this.fireEvent("mousedown", this);
13589 this.fireEvent("click", this);
13591 this.timer = this.click.defer(this.delay || this.interval, this);
13595 click : function(){
13596 this.fireEvent("click", this);
13597 this.timer = this.click.defer(this.getInterval(), this);
13601 getInterval: function(){
13602 if(!this.accelerate){
13603 return this.interval;
13605 var pressTime = this.mousedownTime.getElapsed();
13606 if(pressTime < 500){
13608 }else if(pressTime < 1700){
13610 }else if(pressTime < 2600){
13612 }else if(pressTime < 3500){
13614 }else if(pressTime < 4400){
13616 }else if(pressTime < 5300){
13618 }else if(pressTime < 6200){
13626 handleMouseOut : function(){
13627 clearTimeout(this.timer);
13628 if(this.pressClass){
13629 this.el.removeClass(this.pressClass);
13631 this.el.on("mouseover", this.handleMouseReturn, this);
13635 handleMouseReturn : function(){
13636 this.el.un("mouseover", this.handleMouseReturn);
13637 if(this.pressClass){
13638 this.el.addClass(this.pressClass);
13644 handleMouseUp : function(){
13645 clearTimeout(this.timer);
13646 this.el.un("mouseover", this.handleMouseReturn);
13647 this.el.un("mouseout", this.handleMouseOut);
13648 Roo.get(document).un("mouseup", this.handleMouseUp);
13649 this.el.removeClass(this.pressClass);
13650 this.fireEvent("mouseup", this);
13654 * Ext JS Library 1.1.1
13655 * Copyright(c) 2006-2007, Ext JS, LLC.
13657 * Originally Released Under LGPL - original licence link has changed is not relivant.
13660 * <script type="text/javascript">
13665 * @class Roo.KeyNav
13666 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13667 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13668 * way to implement custom navigation schemes for any UI component.</p>
13669 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13670 * pageUp, pageDown, del, home, end. Usage:</p>
13672 var nav = new Roo.KeyNav("my-element", {
13673 "left" : function(e){
13674 this.moveLeft(e.ctrlKey);
13676 "right" : function(e){
13677 this.moveRight(e.ctrlKey);
13679 "enter" : function(e){
13686 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13687 * @param {Object} config The config
13689 Roo.KeyNav = function(el, config){
13690 this.el = Roo.get(el);
13691 Roo.apply(this, config);
13692 if(!this.disabled){
13693 this.disabled = true;
13698 Roo.KeyNav.prototype = {
13700 * @cfg {Boolean} disabled
13701 * True to disable this KeyNav instance (defaults to false)
13705 * @cfg {String} defaultEventAction
13706 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13707 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13708 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13710 defaultEventAction: "stopEvent",
13712 * @cfg {Boolean} forceKeyDown
13713 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13714 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13715 * handle keydown instead of keypress.
13717 forceKeyDown : false,
13720 prepareEvent : function(e){
13721 var k = e.getKey();
13722 var h = this.keyToHandler[k];
13723 //if(h && this[h]){
13724 // e.stopPropagation();
13726 if(Roo.isSafari && h && k >= 37 && k <= 40){
13732 relay : function(e){
13733 var k = e.getKey();
13734 var h = this.keyToHandler[k];
13736 if(this.doRelay(e, this[h], h) !== true){
13737 e[this.defaultEventAction]();
13743 doRelay : function(e, h, hname){
13744 return h.call(this.scope || this, e);
13747 // possible handlers
13761 // quick lookup hash
13778 * Enable this KeyNav
13780 enable: function(){
13782 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13783 // the EventObject will normalize Safari automatically
13784 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13785 this.el.on("keydown", this.relay, this);
13787 this.el.on("keydown", this.prepareEvent, this);
13788 this.el.on("keypress", this.relay, this);
13790 this.disabled = false;
13795 * Disable this KeyNav
13797 disable: function(){
13798 if(!this.disabled){
13799 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13800 this.el.un("keydown", this.relay);
13802 this.el.un("keydown", this.prepareEvent);
13803 this.el.un("keypress", this.relay);
13805 this.disabled = true;
13810 * Ext JS Library 1.1.1
13811 * Copyright(c) 2006-2007, Ext JS, LLC.
13813 * Originally Released Under LGPL - original licence link has changed is not relivant.
13816 * <script type="text/javascript">
13821 * @class Roo.KeyMap
13822 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13823 * The constructor accepts the same config object as defined by {@link #addBinding}.
13824 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13825 * combination it will call the function with this signature (if the match is a multi-key
13826 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13827 * A KeyMap can also handle a string representation of keys.<br />
13830 // map one key by key code
13831 var map = new Roo.KeyMap("my-element", {
13832 key: 13, // or Roo.EventObject.ENTER
13837 // map multiple keys to one action by string
13838 var map = new Roo.KeyMap("my-element", {
13844 // map multiple keys to multiple actions by strings and array of codes
13845 var map = new Roo.KeyMap("my-element", [
13848 fn: function(){ alert("Return was pressed"); }
13851 fn: function(){ alert('a, b or c was pressed'); }
13856 fn: function(){ alert('Control + shift + tab was pressed.'); }
13860 * <b>Note: A KeyMap starts enabled</b>
13862 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13863 * @param {Object} config The config (see {@link #addBinding})
13864 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13866 Roo.KeyMap = function(el, config, eventName){
13867 this.el = Roo.get(el);
13868 this.eventName = eventName || "keydown";
13869 this.bindings = [];
13871 this.addBinding(config);
13876 Roo.KeyMap.prototype = {
13878 * True to stop the event from bubbling and prevent the default browser action if the
13879 * key was handled by the KeyMap (defaults to false)
13885 * Add a new binding to this KeyMap. The following config object properties are supported:
13887 Property Type Description
13888 ---------- --------------- ----------------------------------------------------------------------
13889 key String/Array A single keycode or an array of keycodes to handle
13890 shift Boolean True to handle key only when shift is pressed (defaults to false)
13891 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13892 alt Boolean True to handle key only when alt is pressed (defaults to false)
13893 fn Function The function to call when KeyMap finds the expected key combination
13894 scope Object The scope of the callback function
13900 var map = new Roo.KeyMap(document, {
13901 key: Roo.EventObject.ENTER,
13906 //Add a new binding to the existing KeyMap later
13914 * @param {Object/Array} config A single KeyMap config or an array of configs
13916 addBinding : function(config){
13917 if(config instanceof Array){
13918 for(var i = 0, len = config.length; i < len; i++){
13919 this.addBinding(config[i]);
13923 var keyCode = config.key,
13924 shift = config.shift,
13925 ctrl = config.ctrl,
13928 scope = config.scope;
13929 if(typeof keyCode == "string"){
13931 var keyString = keyCode.toUpperCase();
13932 for(var j = 0, len = keyString.length; j < len; j++){
13933 ks.push(keyString.charCodeAt(j));
13937 var keyArray = keyCode instanceof Array;
13938 var handler = function(e){
13939 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13940 var k = e.getKey();
13942 for(var i = 0, len = keyCode.length; i < len; i++){
13943 if(keyCode[i] == k){
13944 if(this.stopEvent){
13947 fn.call(scope || window, k, e);
13953 if(this.stopEvent){
13956 fn.call(scope || window, k, e);
13961 this.bindings.push(handler);
13965 * Shorthand for adding a single key listener
13966 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13967 * following options:
13968 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13969 * @param {Function} fn The function to call
13970 * @param {Object} scope (optional) The scope of the function
13972 on : function(key, fn, scope){
13973 var keyCode, shift, ctrl, alt;
13974 if(typeof key == "object" && !(key instanceof Array)){
13993 handleKeyDown : function(e){
13994 if(this.enabled){ //just in case
13995 var b = this.bindings;
13996 for(var i = 0, len = b.length; i < len; i++){
13997 b[i].call(this, e);
14003 * Returns true if this KeyMap is enabled
14004 * @return {Boolean}
14006 isEnabled : function(){
14007 return this.enabled;
14011 * Enables this KeyMap
14013 enable: function(){
14015 this.el.on(this.eventName, this.handleKeyDown, this);
14016 this.enabled = true;
14021 * Disable this KeyMap
14023 disable: function(){
14025 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14026 this.enabled = false;
14031 * Ext JS Library 1.1.1
14032 * Copyright(c) 2006-2007, Ext JS, LLC.
14034 * Originally Released Under LGPL - original licence link has changed is not relivant.
14037 * <script type="text/javascript">
14042 * @class Roo.util.TextMetrics
14043 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14044 * wide, in pixels, a given block of text will be.
14047 Roo.util.TextMetrics = function(){
14051 * Measures the size of the specified text
14052 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14053 * that can affect the size of the rendered text
14054 * @param {String} text The text to measure
14055 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14056 * in order to accurately measure the text height
14057 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14059 measure : function(el, text, fixedWidth){
14061 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14064 shared.setFixedWidth(fixedWidth || 'auto');
14065 return shared.getSize(text);
14069 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14070 * the overhead of multiple calls to initialize the style properties on each measurement.
14071 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14072 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14073 * in order to accurately measure the text height
14074 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14076 createInstance : function(el, fixedWidth){
14077 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14084 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14085 var ml = new Roo.Element(document.createElement('div'));
14086 document.body.appendChild(ml.dom);
14087 ml.position('absolute');
14088 ml.setLeftTop(-1000, -1000);
14092 ml.setWidth(fixedWidth);
14097 * Returns the size of the specified text based on the internal element's style and width properties
14098 * @memberOf Roo.util.TextMetrics.Instance#
14099 * @param {String} text The text to measure
14100 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14102 getSize : function(text){
14104 var s = ml.getSize();
14110 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14111 * that can affect the size of the rendered text
14112 * @memberOf Roo.util.TextMetrics.Instance#
14113 * @param {String/HTMLElement} el The element, dom node or id
14115 bind : function(el){
14117 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14122 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14123 * to set a fixed width in order to accurately measure the text height.
14124 * @memberOf Roo.util.TextMetrics.Instance#
14125 * @param {Number} width The width to set on the element
14127 setFixedWidth : function(width){
14128 ml.setWidth(width);
14132 * Returns the measured width of the specified text
14133 * @memberOf Roo.util.TextMetrics.Instance#
14134 * @param {String} text The text to measure
14135 * @return {Number} width The width in pixels
14137 getWidth : function(text){
14138 ml.dom.style.width = 'auto';
14139 return this.getSize(text).width;
14143 * Returns the measured height of the specified text. For multiline text, be sure to call
14144 * {@link #setFixedWidth} if necessary.
14145 * @memberOf Roo.util.TextMetrics.Instance#
14146 * @param {String} text The text to measure
14147 * @return {Number} height The height in pixels
14149 getHeight : function(text){
14150 return this.getSize(text).height;
14154 instance.bind(bindTo);
14159 // backwards compat
14160 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14162 * Ext JS Library 1.1.1
14163 * Copyright(c) 2006-2007, Ext JS, LLC.
14165 * Originally Released Under LGPL - original licence link has changed is not relivant.
14168 * <script type="text/javascript">
14172 * @class Roo.state.Provider
14173 * Abstract base class for state provider implementations. This class provides methods
14174 * for encoding and decoding <b>typed</b> variables including dates and defines the
14175 * Provider interface.
14177 Roo.state.Provider = function(){
14179 * @event statechange
14180 * Fires when a state change occurs.
14181 * @param {Provider} this This state provider
14182 * @param {String} key The state key which was changed
14183 * @param {String} value The encoded value for the state
14186 "statechange": true
14189 Roo.state.Provider.superclass.constructor.call(this);
14191 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14193 * Returns the current value for a key
14194 * @param {String} name The key name
14195 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14196 * @return {Mixed} The state data
14198 get : function(name, defaultValue){
14199 return typeof this.state[name] == "undefined" ?
14200 defaultValue : this.state[name];
14204 * Clears a value from the state
14205 * @param {String} name The key name
14207 clear : function(name){
14208 delete this.state[name];
14209 this.fireEvent("statechange", this, name, null);
14213 * Sets the value for a key
14214 * @param {String} name The key name
14215 * @param {Mixed} value The value to set
14217 set : function(name, value){
14218 this.state[name] = value;
14219 this.fireEvent("statechange", this, name, value);
14223 * Decodes a string previously encoded with {@link #encodeValue}.
14224 * @param {String} value The value to decode
14225 * @return {Mixed} The decoded value
14227 decodeValue : function(cookie){
14228 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14229 var matches = re.exec(unescape(cookie));
14230 if(!matches || !matches[1]) return; // non state cookie
14231 var type = matches[1];
14232 var v = matches[2];
14235 return parseFloat(v);
14237 return new Date(Date.parse(v));
14242 var values = v.split("^");
14243 for(var i = 0, len = values.length; i < len; i++){
14244 all.push(this.decodeValue(values[i]));
14249 var values = v.split("^");
14250 for(var i = 0, len = values.length; i < len; i++){
14251 var kv = values[i].split("=");
14252 all[kv[0]] = this.decodeValue(kv[1]);
14261 * Encodes a value including type information. Decode with {@link #decodeValue}.
14262 * @param {Mixed} value The value to encode
14263 * @return {String} The encoded value
14265 encodeValue : function(v){
14267 if(typeof v == "number"){
14269 }else if(typeof v == "boolean"){
14270 enc = "b:" + (v ? "1" : "0");
14271 }else if(v instanceof Date){
14272 enc = "d:" + v.toGMTString();
14273 }else if(v instanceof Array){
14275 for(var i = 0, len = v.length; i < len; i++){
14276 flat += this.encodeValue(v[i]);
14277 if(i != len-1) flat += "^";
14280 }else if(typeof v == "object"){
14283 if(typeof v[key] != "function"){
14284 flat += key + "=" + this.encodeValue(v[key]) + "^";
14287 enc = "o:" + flat.substring(0, flat.length-1);
14291 return escape(enc);
14297 * Ext JS Library 1.1.1
14298 * Copyright(c) 2006-2007, Ext JS, LLC.
14300 * Originally Released Under LGPL - original licence link has changed is not relivant.
14303 * <script type="text/javascript">
14306 * @class Roo.state.Manager
14307 * This is the global state manager. By default all components that are "state aware" check this class
14308 * for state information if you don't pass them a custom state provider. In order for this class
14309 * to be useful, it must be initialized with a provider when your application initializes.
14311 // in your initialization function
14313 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14315 // supposed you have a {@link Roo.BorderLayout}
14316 var layout = new Roo.BorderLayout(...);
14317 layout.restoreState();
14318 // or a {Roo.BasicDialog}
14319 var dialog = new Roo.BasicDialog(...);
14320 dialog.restoreState();
14324 Roo.state.Manager = function(){
14325 var provider = new Roo.state.Provider();
14329 * Configures the default state provider for your application
14330 * @param {Provider} stateProvider The state provider to set
14332 setProvider : function(stateProvider){
14333 provider = stateProvider;
14337 * Returns the current value for a key
14338 * @param {String} name The key name
14339 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14340 * @return {Mixed} The state data
14342 get : function(key, defaultValue){
14343 return provider.get(key, defaultValue);
14347 * Sets the value for a key
14348 * @param {String} name The key name
14349 * @param {Mixed} value The state data
14351 set : function(key, value){
14352 provider.set(key, value);
14356 * Clears a value from the state
14357 * @param {String} name The key name
14359 clear : function(key){
14360 provider.clear(key);
14364 * Gets the currently configured state provider
14365 * @return {Provider} The state provider
14367 getProvider : function(){
14374 * Ext JS Library 1.1.1
14375 * Copyright(c) 2006-2007, Ext JS, LLC.
14377 * Originally Released Under LGPL - original licence link has changed is not relivant.
14380 * <script type="text/javascript">
14383 * @class Roo.state.CookieProvider
14384 * @extends Roo.state.Provider
14385 * The default Provider implementation which saves state via cookies.
14388 var cp = new Roo.state.CookieProvider({
14390 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14391 domain: "roojs.com"
14393 Roo.state.Manager.setProvider(cp);
14395 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14396 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14397 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14398 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14399 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14400 * domain the page is running on including the 'www' like 'www.roojs.com')
14401 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14403 * Create a new CookieProvider
14404 * @param {Object} config The configuration object
14406 Roo.state.CookieProvider = function(config){
14407 Roo.state.CookieProvider.superclass.constructor.call(this);
14409 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14410 this.domain = null;
14411 this.secure = false;
14412 Roo.apply(this, config);
14413 this.state = this.readCookies();
14416 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14418 set : function(name, value){
14419 if(typeof value == "undefined" || value === null){
14423 this.setCookie(name, value);
14424 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14428 clear : function(name){
14429 this.clearCookie(name);
14430 Roo.state.CookieProvider.superclass.clear.call(this, name);
14434 readCookies : function(){
14436 var c = document.cookie + ";";
14437 var re = /\s?(.*?)=(.*?);/g;
14439 while((matches = re.exec(c)) != null){
14440 var name = matches[1];
14441 var value = matches[2];
14442 if(name && name.substring(0,3) == "ys-"){
14443 cookies[name.substr(3)] = this.decodeValue(value);
14450 setCookie : function(name, value){
14451 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14452 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14453 ((this.path == null) ? "" : ("; path=" + this.path)) +
14454 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14455 ((this.secure == true) ? "; secure" : "");
14459 clearCookie : function(name){
14460 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14461 ((this.path == null) ? "" : ("; path=" + this.path)) +
14462 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14463 ((this.secure == true) ? "; secure" : "");
14467 * Ext JS Library 1.1.1
14468 * Copyright(c) 2006-2007, Ext JS, LLC.
14470 * Originally Released Under LGPL - original licence link has changed is not relivant.
14473 * <script type="text/javascript">
14479 * These classes are derivatives of the similarly named classes in the YUI Library.
14480 * The original license:
14481 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14482 * Code licensed under the BSD License:
14483 * http://developer.yahoo.net/yui/license.txt
14488 var Event=Roo.EventManager;
14489 var Dom=Roo.lib.Dom;
14492 * @class Roo.dd.DragDrop
14493 * @extends Roo.util.Observable
14494 * Defines the interface and base operation of items that that can be
14495 * dragged or can be drop targets. It was designed to be extended, overriding
14496 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14497 * Up to three html elements can be associated with a DragDrop instance:
14499 * <li>linked element: the element that is passed into the constructor.
14500 * This is the element which defines the boundaries for interaction with
14501 * other DragDrop objects.</li>
14502 * <li>handle element(s): The drag operation only occurs if the element that
14503 * was clicked matches a handle element. By default this is the linked
14504 * element, but there are times that you will want only a portion of the
14505 * linked element to initiate the drag operation, and the setHandleElId()
14506 * method provides a way to define this.</li>
14507 * <li>drag element: this represents the element that would be moved along
14508 * with the cursor during a drag operation. By default, this is the linked
14509 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14510 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14513 * This class should not be instantiated until the onload event to ensure that
14514 * the associated elements are available.
14515 * The following would define a DragDrop obj that would interact with any
14516 * other DragDrop obj in the "group1" group:
14518 * dd = new Roo.dd.DragDrop("div1", "group1");
14520 * Since none of the event handlers have been implemented, nothing would
14521 * actually happen if you were to run the code above. Normally you would
14522 * override this class or one of the default implementations, but you can
14523 * also override the methods you want on an instance of the class...
14525 * dd.onDragDrop = function(e, id) {
14526 * alert("dd was dropped on " + id);
14530 * @param {String} id of the element that is linked to this instance
14531 * @param {String} sGroup the group of related DragDrop objects
14532 * @param {object} config an object containing configurable attributes
14533 * Valid properties for DragDrop:
14534 * padding, isTarget, maintainOffset, primaryButtonOnly
14536 Roo.dd.DragDrop = function(id, sGroup, config) {
14538 this.init(id, sGroup, config);
14543 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
14546 * The id of the element associated with this object. This is what we
14547 * refer to as the "linked element" because the size and position of
14548 * this element is used to determine when the drag and drop objects have
14556 * Configuration attributes passed into the constructor
14563 * The id of the element that will be dragged. By default this is same
14564 * as the linked element , but could be changed to another element. Ex:
14566 * @property dragElId
14573 * the id of the element that initiates the drag operation. By default
14574 * this is the linked element, but could be changed to be a child of this
14575 * element. This lets us do things like only starting the drag when the
14576 * header element within the linked html element is clicked.
14577 * @property handleElId
14584 * An associative array of HTML tags that will be ignored if clicked.
14585 * @property invalidHandleTypes
14586 * @type {string: string}
14588 invalidHandleTypes: null,
14591 * An associative array of ids for elements that will be ignored if clicked
14592 * @property invalidHandleIds
14593 * @type {string: string}
14595 invalidHandleIds: null,
14598 * An indexted array of css class names for elements that will be ignored
14600 * @property invalidHandleClasses
14603 invalidHandleClasses: null,
14606 * The linked element's absolute X position at the time the drag was
14608 * @property startPageX
14615 * The linked element's absolute X position at the time the drag was
14617 * @property startPageY
14624 * The group defines a logical collection of DragDrop objects that are
14625 * related. Instances only get events when interacting with other
14626 * DragDrop object in the same group. This lets us define multiple
14627 * groups using a single DragDrop subclass if we want.
14629 * @type {string: string}
14634 * Individual drag/drop instances can be locked. This will prevent
14635 * onmousedown start drag.
14643 * Lock this instance
14646 lock: function() { this.locked = true; },
14649 * Unlock this instace
14652 unlock: function() { this.locked = false; },
14655 * By default, all insances can be a drop target. This can be disabled by
14656 * setting isTarget to false.
14663 * The padding configured for this drag and drop object for calculating
14664 * the drop zone intersection with this object.
14671 * Cached reference to the linked element
14672 * @property _domRef
14678 * Internal typeof flag
14679 * @property __ygDragDrop
14682 __ygDragDrop: true,
14685 * Set to true when horizontal contraints are applied
14686 * @property constrainX
14693 * Set to true when vertical contraints are applied
14694 * @property constrainY
14701 * The left constraint
14709 * The right constraint
14717 * The up constraint
14726 * The down constraint
14734 * Maintain offsets when we resetconstraints. Set to true when you want
14735 * the position of the element relative to its parent to stay the same
14736 * when the page changes
14738 * @property maintainOffset
14741 maintainOffset: false,
14744 * Array of pixel locations the element will snap to if we specified a
14745 * horizontal graduation/interval. This array is generated automatically
14746 * when you define a tick interval.
14753 * Array of pixel locations the element will snap to if we specified a
14754 * vertical graduation/interval. This array is generated automatically
14755 * when you define a tick interval.
14762 * By default the drag and drop instance will only respond to the primary
14763 * button click (left button for a right-handed mouse). Set to true to
14764 * allow drag and drop to start with any mouse click that is propogated
14766 * @property primaryButtonOnly
14769 primaryButtonOnly: true,
14772 * The availabe property is false until the linked dom element is accessible.
14773 * @property available
14779 * By default, drags can only be initiated if the mousedown occurs in the
14780 * region the linked element is. This is done in part to work around a
14781 * bug in some browsers that mis-report the mousedown if the previous
14782 * mouseup happened outside of the window. This property is set to true
14783 * if outer handles are defined.
14785 * @property hasOuterHandles
14789 hasOuterHandles: false,
14792 * Code that executes immediately before the startDrag event
14793 * @method b4StartDrag
14796 b4StartDrag: function(x, y) { },
14799 * Abstract method called after a drag/drop object is clicked
14800 * and the drag or mousedown time thresholds have beeen met.
14801 * @method startDrag
14802 * @param {int} X click location
14803 * @param {int} Y click location
14805 startDrag: function(x, y) { /* override this */ },
14808 * Code that executes immediately before the onDrag event
14812 b4Drag: function(e) { },
14815 * Abstract method called during the onMouseMove event while dragging an
14818 * @param {Event} e the mousemove event
14820 onDrag: function(e) { /* override this */ },
14823 * Abstract method called when this element fist begins hovering over
14824 * another DragDrop obj
14825 * @method onDragEnter
14826 * @param {Event} e the mousemove event
14827 * @param {String|DragDrop[]} id In POINT mode, the element
14828 * id this is hovering over. In INTERSECT mode, an array of one or more
14829 * dragdrop items being hovered over.
14831 onDragEnter: function(e, id) { /* override this */ },
14834 * Code that executes immediately before the onDragOver event
14835 * @method b4DragOver
14838 b4DragOver: function(e) { },
14841 * Abstract method called when this element is hovering over another
14843 * @method onDragOver
14844 * @param {Event} e the mousemove event
14845 * @param {String|DragDrop[]} id In POINT mode, the element
14846 * id this is hovering over. In INTERSECT mode, an array of dd items
14847 * being hovered over.
14849 onDragOver: function(e, id) { /* override this */ },
14852 * Code that executes immediately before the onDragOut event
14853 * @method b4DragOut
14856 b4DragOut: function(e) { },
14859 * Abstract method called when we are no longer hovering over an element
14860 * @method onDragOut
14861 * @param {Event} e the mousemove event
14862 * @param {String|DragDrop[]} id In POINT mode, the element
14863 * id this was hovering over. In INTERSECT mode, an array of dd items
14864 * that the mouse is no longer over.
14866 onDragOut: function(e, id) { /* override this */ },
14869 * Code that executes immediately before the onDragDrop event
14870 * @method b4DragDrop
14873 b4DragDrop: function(e) { },
14876 * Abstract method called when this item is dropped on another DragDrop
14878 * @method onDragDrop
14879 * @param {Event} e the mouseup event
14880 * @param {String|DragDrop[]} id In POINT mode, the element
14881 * id this was dropped on. In INTERSECT mode, an array of dd items this
14884 onDragDrop: function(e, id) { /* override this */ },
14887 * Abstract method called when this item is dropped on an area with no
14889 * @method onInvalidDrop
14890 * @param {Event} e the mouseup event
14892 onInvalidDrop: function(e) { /* override this */ },
14895 * Code that executes immediately before the endDrag event
14896 * @method b4EndDrag
14899 b4EndDrag: function(e) { },
14902 * Fired when we are done dragging the object
14904 * @param {Event} e the mouseup event
14906 endDrag: function(e) { /* override this */ },
14909 * Code executed immediately before the onMouseDown event
14910 * @method b4MouseDown
14911 * @param {Event} e the mousedown event
14914 b4MouseDown: function(e) { },
14917 * Event handler that fires when a drag/drop obj gets a mousedown
14918 * @method onMouseDown
14919 * @param {Event} e the mousedown event
14921 onMouseDown: function(e) { /* override this */ },
14924 * Event handler that fires when a drag/drop obj gets a mouseup
14925 * @method onMouseUp
14926 * @param {Event} e the mouseup event
14928 onMouseUp: function(e) { /* override this */ },
14931 * Override the onAvailable method to do what is needed after the initial
14932 * position was determined.
14933 * @method onAvailable
14935 onAvailable: function () {
14939 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14942 defaultPadding : {left:0, right:0, top:0, bottom:0},
14945 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14949 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14950 { dragElId: "existingProxyDiv" });
14951 dd.startDrag = function(){
14952 this.constrainTo("parent-id");
14955 * Or you can initalize it using the {@link Roo.Element} object:
14957 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14958 startDrag : function(){
14959 this.constrainTo("parent-id");
14963 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14964 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14965 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14966 * an object containing the sides to pad. For example: {right:10, bottom:10}
14967 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14969 constrainTo : function(constrainTo, pad, inContent){
14970 if(typeof pad == "number"){
14971 pad = {left: pad, right:pad, top:pad, bottom:pad};
14973 pad = pad || this.defaultPadding;
14974 var b = Roo.get(this.getEl()).getBox();
14975 var ce = Roo.get(constrainTo);
14976 var s = ce.getScroll();
14977 var c, cd = ce.dom;
14978 if(cd == document.body){
14979 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14982 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14986 var topSpace = b.y - c.y;
14987 var leftSpace = b.x - c.x;
14989 this.resetConstraints();
14990 this.setXConstraint(leftSpace - (pad.left||0), // left
14991 c.width - leftSpace - b.width - (pad.right||0) //right
14993 this.setYConstraint(topSpace - (pad.top||0), //top
14994 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14999 * Returns a reference to the linked element
15001 * @return {HTMLElement} the html element
15003 getEl: function() {
15004 if (!this._domRef) {
15005 this._domRef = Roo.getDom(this.id);
15008 return this._domRef;
15012 * Returns a reference to the actual element to drag. By default this is
15013 * the same as the html element, but it can be assigned to another
15014 * element. An example of this can be found in Roo.dd.DDProxy
15015 * @method getDragEl
15016 * @return {HTMLElement} the html element
15018 getDragEl: function() {
15019 return Roo.getDom(this.dragElId);
15023 * Sets up the DragDrop object. Must be called in the constructor of any
15024 * Roo.dd.DragDrop subclass
15026 * @param id the id of the linked element
15027 * @param {String} sGroup the group of related items
15028 * @param {object} config configuration attributes
15030 init: function(id, sGroup, config) {
15031 this.initTarget(id, sGroup, config);
15032 Event.on(this.id, "mousedown", this.handleMouseDown, this);
15033 // Event.on(this.id, "selectstart", Event.preventDefault);
15037 * Initializes Targeting functionality only... the object does not
15038 * get a mousedown handler.
15039 * @method initTarget
15040 * @param id the id of the linked element
15041 * @param {String} sGroup the group of related items
15042 * @param {object} config configuration attributes
15044 initTarget: function(id, sGroup, config) {
15046 // configuration attributes
15047 this.config = config || {};
15049 // create a local reference to the drag and drop manager
15050 this.DDM = Roo.dd.DDM;
15051 // initialize the groups array
15054 // assume that we have an element reference instead of an id if the
15055 // parameter is not a string
15056 if (typeof id !== "string") {
15063 // add to an interaction group
15064 this.addToGroup((sGroup) ? sGroup : "default");
15066 // We don't want to register this as the handle with the manager
15067 // so we just set the id rather than calling the setter.
15068 this.handleElId = id;
15070 // the linked element is the element that gets dragged by default
15071 this.setDragElId(id);
15073 // by default, clicked anchors will not start drag operations.
15074 this.invalidHandleTypes = { A: "A" };
15075 this.invalidHandleIds = {};
15076 this.invalidHandleClasses = [];
15078 this.applyConfig();
15080 this.handleOnAvailable();
15084 * Applies the configuration parameters that were passed into the constructor.
15085 * This is supposed to happen at each level through the inheritance chain. So
15086 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15087 * DragDrop in order to get all of the parameters that are available in
15089 * @method applyConfig
15091 applyConfig: function() {
15093 // configurable properties:
15094 // padding, isTarget, maintainOffset, primaryButtonOnly
15095 this.padding = this.config.padding || [0, 0, 0, 0];
15096 this.isTarget = (this.config.isTarget !== false);
15097 this.maintainOffset = (this.config.maintainOffset);
15098 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15103 * Executed when the linked element is available
15104 * @method handleOnAvailable
15107 handleOnAvailable: function() {
15108 this.available = true;
15109 this.resetConstraints();
15110 this.onAvailable();
15114 * Configures the padding for the target zone in px. Effectively expands
15115 * (or reduces) the virtual object size for targeting calculations.
15116 * Supports css-style shorthand; if only one parameter is passed, all sides
15117 * will have that padding, and if only two are passed, the top and bottom
15118 * will have the first param, the left and right the second.
15119 * @method setPadding
15120 * @param {int} iTop Top pad
15121 * @param {int} iRight Right pad
15122 * @param {int} iBot Bot pad
15123 * @param {int} iLeft Left pad
15125 setPadding: function(iTop, iRight, iBot, iLeft) {
15126 // this.padding = [iLeft, iRight, iTop, iBot];
15127 if (!iRight && 0 !== iRight) {
15128 this.padding = [iTop, iTop, iTop, iTop];
15129 } else if (!iBot && 0 !== iBot) {
15130 this.padding = [iTop, iRight, iTop, iRight];
15132 this.padding = [iTop, iRight, iBot, iLeft];
15137 * Stores the initial placement of the linked element.
15138 * @method setInitialPosition
15139 * @param {int} diffX the X offset, default 0
15140 * @param {int} diffY the Y offset, default 0
15142 setInitPosition: function(diffX, diffY) {
15143 var el = this.getEl();
15145 if (!this.DDM.verifyEl(el)) {
15149 var dx = diffX || 0;
15150 var dy = diffY || 0;
15152 var p = Dom.getXY( el );
15154 this.initPageX = p[0] - dx;
15155 this.initPageY = p[1] - dy;
15157 this.lastPageX = p[0];
15158 this.lastPageY = p[1];
15161 this.setStartPosition(p);
15165 * Sets the start position of the element. This is set when the obj
15166 * is initialized, the reset when a drag is started.
15167 * @method setStartPosition
15168 * @param pos current position (from previous lookup)
15171 setStartPosition: function(pos) {
15172 var p = pos || Dom.getXY( this.getEl() );
15173 this.deltaSetXY = null;
15175 this.startPageX = p[0];
15176 this.startPageY = p[1];
15180 * Add this instance to a group of related drag/drop objects. All
15181 * instances belong to at least one group, and can belong to as many
15182 * groups as needed.
15183 * @method addToGroup
15184 * @param sGroup {string} the name of the group
15186 addToGroup: function(sGroup) {
15187 this.groups[sGroup] = true;
15188 this.DDM.regDragDrop(this, sGroup);
15192 * Remove's this instance from the supplied interaction group
15193 * @method removeFromGroup
15194 * @param {string} sGroup The group to drop
15196 removeFromGroup: function(sGroup) {
15197 if (this.groups[sGroup]) {
15198 delete this.groups[sGroup];
15201 this.DDM.removeDDFromGroup(this, sGroup);
15205 * Allows you to specify that an element other than the linked element
15206 * will be moved with the cursor during a drag
15207 * @method setDragElId
15208 * @param id {string} the id of the element that will be used to initiate the drag
15210 setDragElId: function(id) {
15211 this.dragElId = id;
15215 * Allows you to specify a child of the linked element that should be
15216 * used to initiate the drag operation. An example of this would be if
15217 * you have a content div with text and links. Clicking anywhere in the
15218 * content area would normally start the drag operation. Use this method
15219 * to specify that an element inside of the content div is the element
15220 * that starts the drag operation.
15221 * @method setHandleElId
15222 * @param id {string} the id of the element that will be used to
15223 * initiate the drag.
15225 setHandleElId: function(id) {
15226 if (typeof id !== "string") {
15229 this.handleElId = id;
15230 this.DDM.regHandle(this.id, id);
15234 * Allows you to set an element outside of the linked element as a drag
15236 * @method setOuterHandleElId
15237 * @param id the id of the element that will be used to initiate the drag
15239 setOuterHandleElId: function(id) {
15240 if (typeof id !== "string") {
15243 Event.on(id, "mousedown",
15244 this.handleMouseDown, this);
15245 this.setHandleElId(id);
15247 this.hasOuterHandles = true;
15251 * Remove all drag and drop hooks for this element
15254 unreg: function() {
15255 Event.un(this.id, "mousedown",
15256 this.handleMouseDown);
15257 this._domRef = null;
15258 this.DDM._remove(this);
15261 destroy : function(){
15266 * Returns true if this instance is locked, or the drag drop mgr is locked
15267 * (meaning that all drag/drop is disabled on the page.)
15269 * @return {boolean} true if this obj or all drag/drop is locked, else
15272 isLocked: function() {
15273 return (this.DDM.isLocked() || this.locked);
15277 * Fired when this object is clicked
15278 * @method handleMouseDown
15280 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15283 handleMouseDown: function(e, oDD){
15284 if (this.primaryButtonOnly && e.button != 0) {
15288 if (this.isLocked()) {
15292 this.DDM.refreshCache(this.groups);
15294 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15295 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15297 if (this.clickValidator(e)) {
15299 // set the initial element position
15300 this.setStartPosition();
15303 this.b4MouseDown(e);
15304 this.onMouseDown(e);
15306 this.DDM.handleMouseDown(e, this);
15308 this.DDM.stopEvent(e);
15316 clickValidator: function(e) {
15317 var target = e.getTarget();
15318 return ( this.isValidHandleChild(target) &&
15319 (this.id == this.handleElId ||
15320 this.DDM.handleWasClicked(target, this.id)) );
15324 * Allows you to specify a tag name that should not start a drag operation
15325 * when clicked. This is designed to facilitate embedding links within a
15326 * drag handle that do something other than start the drag.
15327 * @method addInvalidHandleType
15328 * @param {string} tagName the type of element to exclude
15330 addInvalidHandleType: function(tagName) {
15331 var type = tagName.toUpperCase();
15332 this.invalidHandleTypes[type] = type;
15336 * Lets you to specify an element id for a child of a drag handle
15337 * that should not initiate a drag
15338 * @method addInvalidHandleId
15339 * @param {string} id the element id of the element you wish to ignore
15341 addInvalidHandleId: function(id) {
15342 if (typeof id !== "string") {
15345 this.invalidHandleIds[id] = id;
15349 * Lets you specify a css class of elements that will not initiate a drag
15350 * @method addInvalidHandleClass
15351 * @param {string} cssClass the class of the elements you wish to ignore
15353 addInvalidHandleClass: function(cssClass) {
15354 this.invalidHandleClasses.push(cssClass);
15358 * Unsets an excluded tag name set by addInvalidHandleType
15359 * @method removeInvalidHandleType
15360 * @param {string} tagName the type of element to unexclude
15362 removeInvalidHandleType: function(tagName) {
15363 var type = tagName.toUpperCase();
15364 // this.invalidHandleTypes[type] = null;
15365 delete this.invalidHandleTypes[type];
15369 * Unsets an invalid handle id
15370 * @method removeInvalidHandleId
15371 * @param {string} id the id of the element to re-enable
15373 removeInvalidHandleId: function(id) {
15374 if (typeof id !== "string") {
15377 delete this.invalidHandleIds[id];
15381 * Unsets an invalid css class
15382 * @method removeInvalidHandleClass
15383 * @param {string} cssClass the class of the element(s) you wish to
15386 removeInvalidHandleClass: function(cssClass) {
15387 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15388 if (this.invalidHandleClasses[i] == cssClass) {
15389 delete this.invalidHandleClasses[i];
15395 * Checks the tag exclusion list to see if this click should be ignored
15396 * @method isValidHandleChild
15397 * @param {HTMLElement} node the HTMLElement to evaluate
15398 * @return {boolean} true if this is a valid tag type, false if not
15400 isValidHandleChild: function(node) {
15403 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15406 nodeName = node.nodeName.toUpperCase();
15408 nodeName = node.nodeName;
15410 valid = valid && !this.invalidHandleTypes[nodeName];
15411 valid = valid && !this.invalidHandleIds[node.id];
15413 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15414 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15423 * Create the array of horizontal tick marks if an interval was specified
15424 * in setXConstraint().
15425 * @method setXTicks
15428 setXTicks: function(iStartX, iTickSize) {
15430 this.xTickSize = iTickSize;
15434 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15436 this.xTicks[this.xTicks.length] = i;
15441 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15443 this.xTicks[this.xTicks.length] = i;
15448 this.xTicks.sort(this.DDM.numericSort) ;
15452 * Create the array of vertical tick marks if an interval was specified in
15453 * setYConstraint().
15454 * @method setYTicks
15457 setYTicks: function(iStartY, iTickSize) {
15459 this.yTickSize = iTickSize;
15463 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15465 this.yTicks[this.yTicks.length] = i;
15470 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15472 this.yTicks[this.yTicks.length] = i;
15477 this.yTicks.sort(this.DDM.numericSort) ;
15481 * By default, the element can be dragged any place on the screen. Use
15482 * this method to limit the horizontal travel of the element. Pass in
15483 * 0,0 for the parameters if you want to lock the drag to the y axis.
15484 * @method setXConstraint
15485 * @param {int} iLeft the number of pixels the element can move to the left
15486 * @param {int} iRight the number of pixels the element can move to the
15488 * @param {int} iTickSize optional parameter for specifying that the
15490 * should move iTickSize pixels at a time.
15492 setXConstraint: function(iLeft, iRight, iTickSize) {
15493 this.leftConstraint = iLeft;
15494 this.rightConstraint = iRight;
15496 this.minX = this.initPageX - iLeft;
15497 this.maxX = this.initPageX + iRight;
15498 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15500 this.constrainX = true;
15504 * Clears any constraints applied to this instance. Also clears ticks
15505 * since they can't exist independent of a constraint at this time.
15506 * @method clearConstraints
15508 clearConstraints: function() {
15509 this.constrainX = false;
15510 this.constrainY = false;
15515 * Clears any tick interval defined for this instance
15516 * @method clearTicks
15518 clearTicks: function() {
15519 this.xTicks = null;
15520 this.yTicks = null;
15521 this.xTickSize = 0;
15522 this.yTickSize = 0;
15526 * By default, the element can be dragged any place on the screen. Set
15527 * this to limit the vertical travel of the element. Pass in 0,0 for the
15528 * parameters if you want to lock the drag to the x axis.
15529 * @method setYConstraint
15530 * @param {int} iUp the number of pixels the element can move up
15531 * @param {int} iDown the number of pixels the element can move down
15532 * @param {int} iTickSize optional parameter for specifying that the
15533 * element should move iTickSize pixels at a time.
15535 setYConstraint: function(iUp, iDown, iTickSize) {
15536 this.topConstraint = iUp;
15537 this.bottomConstraint = iDown;
15539 this.minY = this.initPageY - iUp;
15540 this.maxY = this.initPageY + iDown;
15541 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15543 this.constrainY = true;
15548 * resetConstraints must be called if you manually reposition a dd element.
15549 * @method resetConstraints
15550 * @param {boolean} maintainOffset
15552 resetConstraints: function() {
15555 // Maintain offsets if necessary
15556 if (this.initPageX || this.initPageX === 0) {
15557 // figure out how much this thing has moved
15558 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15559 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15561 this.setInitPosition(dx, dy);
15563 // This is the first time we have detected the element's position
15565 this.setInitPosition();
15568 if (this.constrainX) {
15569 this.setXConstraint( this.leftConstraint,
15570 this.rightConstraint,
15574 if (this.constrainY) {
15575 this.setYConstraint( this.topConstraint,
15576 this.bottomConstraint,
15582 * Normally the drag element is moved pixel by pixel, but we can specify
15583 * that it move a number of pixels at a time. This method resolves the
15584 * location when we have it set up like this.
15586 * @param {int} val where we want to place the object
15587 * @param {int[]} tickArray sorted array of valid points
15588 * @return {int} the closest tick
15591 getTick: function(val, tickArray) {
15594 // If tick interval is not defined, it is effectively 1 pixel,
15595 // so we return the value passed to us.
15597 } else if (tickArray[0] >= val) {
15598 // The value is lower than the first tick, so we return the first
15600 return tickArray[0];
15602 for (var i=0, len=tickArray.length; i<len; ++i) {
15604 if (tickArray[next] && tickArray[next] >= val) {
15605 var diff1 = val - tickArray[i];
15606 var diff2 = tickArray[next] - val;
15607 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15611 // The value is larger than the last tick, so we return the last
15613 return tickArray[tickArray.length - 1];
15620 * @return {string} string representation of the dd obj
15622 toString: function() {
15623 return ("DragDrop " + this.id);
15631 * Ext JS Library 1.1.1
15632 * Copyright(c) 2006-2007, Ext JS, LLC.
15634 * Originally Released Under LGPL - original licence link has changed is not relivant.
15637 * <script type="text/javascript">
15642 * The drag and drop utility provides a framework for building drag and drop
15643 * applications. In addition to enabling drag and drop for specific elements,
15644 * the drag and drop elements are tracked by the manager class, and the
15645 * interactions between the various elements are tracked during the drag and
15646 * the implementing code is notified about these important moments.
15649 // Only load the library once. Rewriting the manager class would orphan
15650 // existing drag and drop instances.
15651 if (!Roo.dd.DragDropMgr) {
15654 * @class Roo.dd.DragDropMgr
15655 * DragDropMgr is a singleton that tracks the element interaction for
15656 * all DragDrop items in the window. Generally, you will not call
15657 * this class directly, but it does have helper methods that could
15658 * be useful in your DragDrop implementations.
15661 Roo.dd.DragDropMgr = function() {
15663 var Event = Roo.EventManager;
15668 * Two dimensional Array of registered DragDrop objects. The first
15669 * dimension is the DragDrop item group, the second the DragDrop
15672 * @type {string: string}
15679 * Array of element ids defined as drag handles. Used to determine
15680 * if the element that generated the mousedown event is actually the
15681 * handle and not the html element itself.
15682 * @property handleIds
15683 * @type {string: string}
15690 * the DragDrop object that is currently being dragged
15691 * @property dragCurrent
15699 * the DragDrop object(s) that are being hovered over
15700 * @property dragOvers
15708 * the X distance between the cursor and the object being dragged
15717 * the Y distance between the cursor and the object being dragged
15726 * Flag to determine if we should prevent the default behavior of the
15727 * events we define. By default this is true, but this can be set to
15728 * false if you need the default behavior (not recommended)
15729 * @property preventDefault
15733 preventDefault: true,
15736 * Flag to determine if we should stop the propagation of the events
15737 * we generate. This is true by default but you may want to set it to
15738 * false if the html element contains other features that require the
15740 * @property stopPropagation
15744 stopPropagation: true,
15747 * Internal flag that is set to true when drag and drop has been
15749 * @property initialized
15756 * All drag and drop can be disabled.
15764 * Called the first time an element is registered.
15770 this.initialized = true;
15774 * In point mode, drag and drop interaction is defined by the
15775 * location of the cursor during the drag/drop
15783 * In intersect mode, drag and drop interactio nis defined by the
15784 * overlap of two or more drag and drop objects.
15785 * @property INTERSECT
15792 * The current drag and drop mode. Default: POINT
15800 * Runs method on all drag and drop objects
15801 * @method _execOnAll
15805 _execOnAll: function(sMethod, args) {
15806 for (var i in this.ids) {
15807 for (var j in this.ids[i]) {
15808 var oDD = this.ids[i][j];
15809 if (! this.isTypeOfDD(oDD)) {
15812 oDD[sMethod].apply(oDD, args);
15818 * Drag and drop initialization. Sets up the global event handlers
15823 _onLoad: function() {
15828 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15829 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15830 Event.on(window, "unload", this._onUnload, this, true);
15831 Event.on(window, "resize", this._onResize, this, true);
15832 // Event.on(window, "mouseout", this._test);
15837 * Reset constraints on all drag and drop objs
15838 * @method _onResize
15842 _onResize: function(e) {
15843 this._execOnAll("resetConstraints", []);
15847 * Lock all drag and drop functionality
15851 lock: function() { this.locked = true; },
15854 * Unlock all drag and drop functionality
15858 unlock: function() { this.locked = false; },
15861 * Is drag and drop locked?
15863 * @return {boolean} True if drag and drop is locked, false otherwise.
15866 isLocked: function() { return this.locked; },
15869 * Location cache that is set for all drag drop objects when a drag is
15870 * initiated, cleared when the drag is finished.
15871 * @property locationCache
15878 * Set useCache to false if you want to force object the lookup of each
15879 * drag and drop linked element constantly during a drag.
15880 * @property useCache
15887 * The number of pixels that the mouse needs to move after the
15888 * mousedown before the drag is initiated. Default=3;
15889 * @property clickPixelThresh
15893 clickPixelThresh: 3,
15896 * The number of milliseconds after the mousedown event to initiate the
15897 * drag if we don't get a mouseup event. Default=1000
15898 * @property clickTimeThresh
15902 clickTimeThresh: 350,
15905 * Flag that indicates that either the drag pixel threshold or the
15906 * mousdown time threshold has been met
15907 * @property dragThreshMet
15912 dragThreshMet: false,
15915 * Timeout used for the click time threshold
15916 * @property clickTimeout
15921 clickTimeout: null,
15924 * The X position of the mousedown event stored for later use when a
15925 * drag threshold is met.
15934 * The Y position of the mousedown event stored for later use when a
15935 * drag threshold is met.
15944 * Each DragDrop instance must be registered with the DragDropMgr.
15945 * This is executed in DragDrop.init()
15946 * @method regDragDrop
15947 * @param {DragDrop} oDD the DragDrop object to register
15948 * @param {String} sGroup the name of the group this element belongs to
15951 regDragDrop: function(oDD, sGroup) {
15952 if (!this.initialized) { this.init(); }
15954 if (!this.ids[sGroup]) {
15955 this.ids[sGroup] = {};
15957 this.ids[sGroup][oDD.id] = oDD;
15961 * Removes the supplied dd instance from the supplied group. Executed
15962 * by DragDrop.removeFromGroup, so don't call this function directly.
15963 * @method removeDDFromGroup
15967 removeDDFromGroup: function(oDD, sGroup) {
15968 if (!this.ids[sGroup]) {
15969 this.ids[sGroup] = {};
15972 var obj = this.ids[sGroup];
15973 if (obj && obj[oDD.id]) {
15974 delete obj[oDD.id];
15979 * Unregisters a drag and drop item. This is executed in
15980 * DragDrop.unreg, use that method instead of calling this directly.
15985 _remove: function(oDD) {
15986 for (var g in oDD.groups) {
15987 if (g && this.ids[g][oDD.id]) {
15988 delete this.ids[g][oDD.id];
15991 delete this.handleIds[oDD.id];
15995 * Each DragDrop handle element must be registered. This is done
15996 * automatically when executing DragDrop.setHandleElId()
15997 * @method regHandle
15998 * @param {String} sDDId the DragDrop id this element is a handle for
15999 * @param {String} sHandleId the id of the element that is the drag
16003 regHandle: function(sDDId, sHandleId) {
16004 if (!this.handleIds[sDDId]) {
16005 this.handleIds[sDDId] = {};
16007 this.handleIds[sDDId][sHandleId] = sHandleId;
16011 * Utility function to determine if a given element has been
16012 * registered as a drag drop item.
16013 * @method isDragDrop
16014 * @param {String} id the element id to check
16015 * @return {boolean} true if this element is a DragDrop item,
16019 isDragDrop: function(id) {
16020 return ( this.getDDById(id) ) ? true : false;
16024 * Returns the drag and drop instances that are in all groups the
16025 * passed in instance belongs to.
16026 * @method getRelated
16027 * @param {DragDrop} p_oDD the obj to get related data for
16028 * @param {boolean} bTargetsOnly if true, only return targetable objs
16029 * @return {DragDrop[]} the related instances
16032 getRelated: function(p_oDD, bTargetsOnly) {
16034 for (var i in p_oDD.groups) {
16035 for (j in this.ids[i]) {
16036 var dd = this.ids[i][j];
16037 if (! this.isTypeOfDD(dd)) {
16040 if (!bTargetsOnly || dd.isTarget) {
16041 oDDs[oDDs.length] = dd;
16050 * Returns true if the specified dd target is a legal target for
16051 * the specifice drag obj
16052 * @method isLegalTarget
16053 * @param {DragDrop} the drag obj
16054 * @param {DragDrop} the target
16055 * @return {boolean} true if the target is a legal target for the
16059 isLegalTarget: function (oDD, oTargetDD) {
16060 var targets = this.getRelated(oDD, true);
16061 for (var i=0, len=targets.length;i<len;++i) {
16062 if (targets[i].id == oTargetDD.id) {
16071 * My goal is to be able to transparently determine if an object is
16072 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16073 * returns "object", oDD.constructor.toString() always returns
16074 * "DragDrop" and not the name of the subclass. So for now it just
16075 * evaluates a well-known variable in DragDrop.
16076 * @method isTypeOfDD
16077 * @param {Object} the object to evaluate
16078 * @return {boolean} true if typeof oDD = DragDrop
16081 isTypeOfDD: function (oDD) {
16082 return (oDD && oDD.__ygDragDrop);
16086 * Utility function to determine if a given element has been
16087 * registered as a drag drop handle for the given Drag Drop object.
16089 * @param {String} id the element id to check
16090 * @return {boolean} true if this element is a DragDrop handle, false
16094 isHandle: function(sDDId, sHandleId) {
16095 return ( this.handleIds[sDDId] &&
16096 this.handleIds[sDDId][sHandleId] );
16100 * Returns the DragDrop instance for a given id
16101 * @method getDDById
16102 * @param {String} id the id of the DragDrop object
16103 * @return {DragDrop} the drag drop object, null if it is not found
16106 getDDById: function(id) {
16107 for (var i in this.ids) {
16108 if (this.ids[i][id]) {
16109 return this.ids[i][id];
16116 * Fired after a registered DragDrop object gets the mousedown event.
16117 * Sets up the events required to track the object being dragged
16118 * @method handleMouseDown
16119 * @param {Event} e the event
16120 * @param oDD the DragDrop object being dragged
16124 handleMouseDown: function(e, oDD) {
16126 Roo.QuickTips.disable();
16128 this.currentTarget = e.getTarget();
16130 this.dragCurrent = oDD;
16132 var el = oDD.getEl();
16134 // track start position
16135 this.startX = e.getPageX();
16136 this.startY = e.getPageY();
16138 this.deltaX = this.startX - el.offsetLeft;
16139 this.deltaY = this.startY - el.offsetTop;
16141 this.dragThreshMet = false;
16143 this.clickTimeout = setTimeout(
16145 var DDM = Roo.dd.DDM;
16146 DDM.startDrag(DDM.startX, DDM.startY);
16148 this.clickTimeThresh );
16152 * Fired when either the drag pixel threshol or the mousedown hold
16153 * time threshold has been met.
16154 * @method startDrag
16155 * @param x {int} the X position of the original mousedown
16156 * @param y {int} the Y position of the original mousedown
16159 startDrag: function(x, y) {
16160 clearTimeout(this.clickTimeout);
16161 if (this.dragCurrent) {
16162 this.dragCurrent.b4StartDrag(x, y);
16163 this.dragCurrent.startDrag(x, y);
16165 this.dragThreshMet = true;
16169 * Internal function to handle the mouseup event. Will be invoked
16170 * from the context of the document.
16171 * @method handleMouseUp
16172 * @param {Event} e the event
16176 handleMouseUp: function(e) {
16179 Roo.QuickTips.enable();
16181 if (! this.dragCurrent) {
16185 clearTimeout(this.clickTimeout);
16187 if (this.dragThreshMet) {
16188 this.fireEvents(e, true);
16198 * Utility to stop event propagation and event default, if these
16199 * features are turned on.
16200 * @method stopEvent
16201 * @param {Event} e the event as returned by this.getEvent()
16204 stopEvent: function(e){
16205 if(this.stopPropagation) {
16206 e.stopPropagation();
16209 if (this.preventDefault) {
16210 e.preventDefault();
16215 * Internal function to clean up event handlers after the drag
16216 * operation is complete
16218 * @param {Event} e the event
16222 stopDrag: function(e) {
16223 // Fire the drag end event for the item that was dragged
16224 if (this.dragCurrent) {
16225 if (this.dragThreshMet) {
16226 this.dragCurrent.b4EndDrag(e);
16227 this.dragCurrent.endDrag(e);
16230 this.dragCurrent.onMouseUp(e);
16233 this.dragCurrent = null;
16234 this.dragOvers = {};
16238 * Internal function to handle the mousemove event. Will be invoked
16239 * from the context of the html element.
16241 * @TODO figure out what we can do about mouse events lost when the
16242 * user drags objects beyond the window boundary. Currently we can
16243 * detect this in internet explorer by verifying that the mouse is
16244 * down during the mousemove event. Firefox doesn't give us the
16245 * button state on the mousemove event.
16246 * @method handleMouseMove
16247 * @param {Event} e the event
16251 handleMouseMove: function(e) {
16252 if (! this.dragCurrent) {
16256 // var button = e.which || e.button;
16258 // check for IE mouseup outside of page boundary
16259 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16261 return this.handleMouseUp(e);
16264 if (!this.dragThreshMet) {
16265 var diffX = Math.abs(this.startX - e.getPageX());
16266 var diffY = Math.abs(this.startY - e.getPageY());
16267 if (diffX > this.clickPixelThresh ||
16268 diffY > this.clickPixelThresh) {
16269 this.startDrag(this.startX, this.startY);
16273 if (this.dragThreshMet) {
16274 this.dragCurrent.b4Drag(e);
16275 this.dragCurrent.onDrag(e);
16276 if(!this.dragCurrent.moveOnly){
16277 this.fireEvents(e, false);
16287 * Iterates over all of the DragDrop elements to find ones we are
16288 * hovering over or dropping on
16289 * @method fireEvents
16290 * @param {Event} e the event
16291 * @param {boolean} isDrop is this a drop op or a mouseover op?
16295 fireEvents: function(e, isDrop) {
16296 var dc = this.dragCurrent;
16298 // If the user did the mouse up outside of the window, we could
16299 // get here even though we have ended the drag.
16300 if (!dc || dc.isLocked()) {
16304 var pt = e.getPoint();
16306 // cache the previous dragOver array
16312 var enterEvts = [];
16314 // Check to see if the object(s) we were hovering over is no longer
16315 // being hovered over so we can fire the onDragOut event
16316 for (var i in this.dragOvers) {
16318 var ddo = this.dragOvers[i];
16320 if (! this.isTypeOfDD(ddo)) {
16324 if (! this.isOverTarget(pt, ddo, this.mode)) {
16325 outEvts.push( ddo );
16328 oldOvers[i] = true;
16329 delete this.dragOvers[i];
16332 for (var sGroup in dc.groups) {
16334 if ("string" != typeof sGroup) {
16338 for (i in this.ids[sGroup]) {
16339 var oDD = this.ids[sGroup][i];
16340 if (! this.isTypeOfDD(oDD)) {
16344 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16345 if (this.isOverTarget(pt, oDD, this.mode)) {
16346 // look for drop interactions
16348 dropEvts.push( oDD );
16349 // look for drag enter and drag over interactions
16352 // initial drag over: dragEnter fires
16353 if (!oldOvers[oDD.id]) {
16354 enterEvts.push( oDD );
16355 // subsequent drag overs: dragOver fires
16357 overEvts.push( oDD );
16360 this.dragOvers[oDD.id] = oDD;
16368 if (outEvts.length) {
16369 dc.b4DragOut(e, outEvts);
16370 dc.onDragOut(e, outEvts);
16373 if (enterEvts.length) {
16374 dc.onDragEnter(e, enterEvts);
16377 if (overEvts.length) {
16378 dc.b4DragOver(e, overEvts);
16379 dc.onDragOver(e, overEvts);
16382 if (dropEvts.length) {
16383 dc.b4DragDrop(e, dropEvts);
16384 dc.onDragDrop(e, dropEvts);
16388 // fire dragout events
16390 for (i=0, len=outEvts.length; i<len; ++i) {
16391 dc.b4DragOut(e, outEvts[i].id);
16392 dc.onDragOut(e, outEvts[i].id);
16395 // fire enter events
16396 for (i=0,len=enterEvts.length; i<len; ++i) {
16397 // dc.b4DragEnter(e, oDD.id);
16398 dc.onDragEnter(e, enterEvts[i].id);
16401 // fire over events
16402 for (i=0,len=overEvts.length; i<len; ++i) {
16403 dc.b4DragOver(e, overEvts[i].id);
16404 dc.onDragOver(e, overEvts[i].id);
16407 // fire drop events
16408 for (i=0, len=dropEvts.length; i<len; ++i) {
16409 dc.b4DragDrop(e, dropEvts[i].id);
16410 dc.onDragDrop(e, dropEvts[i].id);
16415 // notify about a drop that did not find a target
16416 if (isDrop && !dropEvts.length) {
16417 dc.onInvalidDrop(e);
16423 * Helper function for getting the best match from the list of drag
16424 * and drop objects returned by the drag and drop events when we are
16425 * in INTERSECT mode. It returns either the first object that the
16426 * cursor is over, or the object that has the greatest overlap with
16427 * the dragged element.
16428 * @method getBestMatch
16429 * @param {DragDrop[]} dds The array of drag and drop objects
16431 * @return {DragDrop} The best single match
16434 getBestMatch: function(dds) {
16436 // Return null if the input is not what we expect
16437 //if (!dds || !dds.length || dds.length == 0) {
16439 // If there is only one item, it wins
16440 //} else if (dds.length == 1) {
16442 var len = dds.length;
16447 // Loop through the targeted items
16448 for (var i=0; i<len; ++i) {
16450 // If the cursor is over the object, it wins. If the
16451 // cursor is over multiple matches, the first one we come
16453 if (dd.cursorIsOver) {
16456 // Otherwise the object with the most overlap wins
16459 winner.overlap.getArea() < dd.overlap.getArea()) {
16470 * Refreshes the cache of the top-left and bottom-right points of the
16471 * drag and drop objects in the specified group(s). This is in the
16472 * format that is stored in the drag and drop instance, so typical
16475 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16479 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16481 * @TODO this really should be an indexed array. Alternatively this
16482 * method could accept both.
16483 * @method refreshCache
16484 * @param {Object} groups an associative array of groups to refresh
16487 refreshCache: function(groups) {
16488 for (var sGroup in groups) {
16489 if ("string" != typeof sGroup) {
16492 for (var i in this.ids[sGroup]) {
16493 var oDD = this.ids[sGroup][i];
16495 if (this.isTypeOfDD(oDD)) {
16496 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16497 var loc = this.getLocation(oDD);
16499 this.locationCache[oDD.id] = loc;
16501 delete this.locationCache[oDD.id];
16502 // this will unregister the drag and drop object if
16503 // the element is not in a usable state
16512 * This checks to make sure an element exists and is in the DOM. The
16513 * main purpose is to handle cases where innerHTML is used to remove
16514 * drag and drop objects from the DOM. IE provides an 'unspecified
16515 * error' when trying to access the offsetParent of such an element
16517 * @param {HTMLElement} el the element to check
16518 * @return {boolean} true if the element looks usable
16521 verifyEl: function(el) {
16526 parent = el.offsetParent;
16529 parent = el.offsetParent;
16540 * Returns a Region object containing the drag and drop element's position
16541 * and size, including the padding configured for it
16542 * @method getLocation
16543 * @param {DragDrop} oDD the drag and drop object to get the
16545 * @return {Roo.lib.Region} a Region object representing the total area
16546 * the element occupies, including any padding
16547 * the instance is configured for.
16550 getLocation: function(oDD) {
16551 if (! this.isTypeOfDD(oDD)) {
16555 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16558 pos= Roo.lib.Dom.getXY(el);
16566 x2 = x1 + el.offsetWidth;
16568 y2 = y1 + el.offsetHeight;
16570 t = y1 - oDD.padding[0];
16571 r = x2 + oDD.padding[1];
16572 b = y2 + oDD.padding[2];
16573 l = x1 - oDD.padding[3];
16575 return new Roo.lib.Region( t, r, b, l );
16579 * Checks the cursor location to see if it over the target
16580 * @method isOverTarget
16581 * @param {Roo.lib.Point} pt The point to evaluate
16582 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16583 * @return {boolean} true if the mouse is over the target
16587 isOverTarget: function(pt, oTarget, intersect) {
16588 // use cache if available
16589 var loc = this.locationCache[oTarget.id];
16590 if (!loc || !this.useCache) {
16591 loc = this.getLocation(oTarget);
16592 this.locationCache[oTarget.id] = loc;
16600 oTarget.cursorIsOver = loc.contains( pt );
16602 // DragDrop is using this as a sanity check for the initial mousedown
16603 // in this case we are done. In POINT mode, if the drag obj has no
16604 // contraints, we are also done. Otherwise we need to evaluate the
16605 // location of the target as related to the actual location of the
16606 // dragged element.
16607 var dc = this.dragCurrent;
16608 if (!dc || !dc.getTargetCoord ||
16609 (!intersect && !dc.constrainX && !dc.constrainY)) {
16610 return oTarget.cursorIsOver;
16613 oTarget.overlap = null;
16615 // Get the current location of the drag element, this is the
16616 // location of the mouse event less the delta that represents
16617 // where the original mousedown happened on the element. We
16618 // need to consider constraints and ticks as well.
16619 var pos = dc.getTargetCoord(pt.x, pt.y);
16621 var el = dc.getDragEl();
16622 var curRegion = new Roo.lib.Region( pos.y,
16623 pos.x + el.offsetWidth,
16624 pos.y + el.offsetHeight,
16627 var overlap = curRegion.intersect(loc);
16630 oTarget.overlap = overlap;
16631 return (intersect) ? true : oTarget.cursorIsOver;
16638 * unload event handler
16639 * @method _onUnload
16643 _onUnload: function(e, me) {
16644 Roo.dd.DragDropMgr.unregAll();
16648 * Cleans up the drag and drop events and objects.
16653 unregAll: function() {
16655 if (this.dragCurrent) {
16657 this.dragCurrent = null;
16660 this._execOnAll("unreg", []);
16662 for (i in this.elementCache) {
16663 delete this.elementCache[i];
16666 this.elementCache = {};
16671 * A cache of DOM elements
16672 * @property elementCache
16679 * Get the wrapper for the DOM element specified
16680 * @method getElWrapper
16681 * @param {String} id the id of the element to get
16682 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16684 * @deprecated This wrapper isn't that useful
16687 getElWrapper: function(id) {
16688 var oWrapper = this.elementCache[id];
16689 if (!oWrapper || !oWrapper.el) {
16690 oWrapper = this.elementCache[id] =
16691 new this.ElementWrapper(Roo.getDom(id));
16697 * Returns the actual DOM element
16698 * @method getElement
16699 * @param {String} id the id of the elment to get
16700 * @return {Object} The element
16701 * @deprecated use Roo.getDom instead
16704 getElement: function(id) {
16705 return Roo.getDom(id);
16709 * Returns the style property for the DOM element (i.e.,
16710 * document.getElById(id).style)
16712 * @param {String} id the id of the elment to get
16713 * @return {Object} The style property of the element
16714 * @deprecated use Roo.getDom instead
16717 getCss: function(id) {
16718 var el = Roo.getDom(id);
16719 return (el) ? el.style : null;
16723 * Inner class for cached elements
16724 * @class DragDropMgr.ElementWrapper
16729 ElementWrapper: function(el) {
16734 this.el = el || null;
16739 this.id = this.el && el.id;
16741 * A reference to the style property
16744 this.css = this.el && el.style;
16748 * Returns the X position of an html element
16750 * @param el the element for which to get the position
16751 * @return {int} the X coordinate
16753 * @deprecated use Roo.lib.Dom.getX instead
16756 getPosX: function(el) {
16757 return Roo.lib.Dom.getX(el);
16761 * Returns the Y position of an html element
16763 * @param el the element for which to get the position
16764 * @return {int} the Y coordinate
16765 * @deprecated use Roo.lib.Dom.getY instead
16768 getPosY: function(el) {
16769 return Roo.lib.Dom.getY(el);
16773 * Swap two nodes. In IE, we use the native method, for others we
16774 * emulate the IE behavior
16776 * @param n1 the first node to swap
16777 * @param n2 the other node to swap
16780 swapNode: function(n1, n2) {
16784 var p = n2.parentNode;
16785 var s = n2.nextSibling;
16788 p.insertBefore(n1, n2);
16789 } else if (n2 == n1.nextSibling) {
16790 p.insertBefore(n2, n1);
16792 n1.parentNode.replaceChild(n2, n1);
16793 p.insertBefore(n1, s);
16799 * Returns the current scroll position
16800 * @method getScroll
16804 getScroll: function () {
16805 var t, l, dde=document.documentElement, db=document.body;
16806 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16808 l = dde.scrollLeft;
16815 return { top: t, left: l };
16819 * Returns the specified element style property
16821 * @param {HTMLElement} el the element
16822 * @param {string} styleProp the style property
16823 * @return {string} The value of the style property
16824 * @deprecated use Roo.lib.Dom.getStyle
16827 getStyle: function(el, styleProp) {
16828 return Roo.fly(el).getStyle(styleProp);
16832 * Gets the scrollTop
16833 * @method getScrollTop
16834 * @return {int} the document's scrollTop
16837 getScrollTop: function () { return this.getScroll().top; },
16840 * Gets the scrollLeft
16841 * @method getScrollLeft
16842 * @return {int} the document's scrollTop
16845 getScrollLeft: function () { return this.getScroll().left; },
16848 * Sets the x/y position of an element to the location of the
16851 * @param {HTMLElement} moveEl The element to move
16852 * @param {HTMLElement} targetEl The position reference element
16855 moveToEl: function (moveEl, targetEl) {
16856 var aCoord = Roo.lib.Dom.getXY(targetEl);
16857 Roo.lib.Dom.setXY(moveEl, aCoord);
16861 * Numeric array sort function
16862 * @method numericSort
16865 numericSort: function(a, b) { return (a - b); },
16869 * @property _timeoutCount
16876 * Trying to make the load order less important. Without this we get
16877 * an error if this file is loaded before the Event Utility.
16878 * @method _addListeners
16882 _addListeners: function() {
16883 var DDM = Roo.dd.DDM;
16884 if ( Roo.lib.Event && document ) {
16887 if (DDM._timeoutCount > 2000) {
16889 setTimeout(DDM._addListeners, 10);
16890 if (document && document.body) {
16891 DDM._timeoutCount += 1;
16898 * Recursively searches the immediate parent and all child nodes for
16899 * the handle element in order to determine wheter or not it was
16901 * @method handleWasClicked
16902 * @param node the html element to inspect
16905 handleWasClicked: function(node, id) {
16906 if (this.isHandle(id, node.id)) {
16909 // check to see if this is a text node child of the one we want
16910 var p = node.parentNode;
16913 if (this.isHandle(id, p.id)) {
16928 // shorter alias, save a few bytes
16929 Roo.dd.DDM = Roo.dd.DragDropMgr;
16930 Roo.dd.DDM._addListeners();
16934 * Ext JS Library 1.1.1
16935 * Copyright(c) 2006-2007, Ext JS, LLC.
16937 * Originally Released Under LGPL - original licence link has changed is not relivant.
16940 * <script type="text/javascript">
16945 * A DragDrop implementation where the linked element follows the
16946 * mouse cursor during a drag.
16947 * @extends Roo.dd.DragDrop
16949 * @param {String} id the id of the linked element
16950 * @param {String} sGroup the group of related DragDrop items
16951 * @param {object} config an object containing configurable attributes
16952 * Valid properties for DD:
16955 Roo.dd.DD = function(id, sGroup, config) {
16957 this.init(id, sGroup, config);
16961 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16964 * When set to true, the utility automatically tries to scroll the browser
16965 * window wehn a drag and drop element is dragged near the viewport boundary.
16966 * Defaults to true.
16973 * Sets the pointer offset to the distance between the linked element's top
16974 * left corner and the location the element was clicked
16975 * @method autoOffset
16976 * @param {int} iPageX the X coordinate of the click
16977 * @param {int} iPageY the Y coordinate of the click
16979 autoOffset: function(iPageX, iPageY) {
16980 var x = iPageX - this.startPageX;
16981 var y = iPageY - this.startPageY;
16982 this.setDelta(x, y);
16986 * Sets the pointer offset. You can call this directly to force the
16987 * offset to be in a particular location (e.g., pass in 0,0 to set it
16988 * to the center of the object)
16990 * @param {int} iDeltaX the distance from the left
16991 * @param {int} iDeltaY the distance from the top
16993 setDelta: function(iDeltaX, iDeltaY) {
16994 this.deltaX = iDeltaX;
16995 this.deltaY = iDeltaY;
16999 * Sets the drag element to the location of the mousedown or click event,
17000 * maintaining the cursor location relative to the location on the element
17001 * that was clicked. Override this if you want to place the element in a
17002 * location other than where the cursor is.
17003 * @method setDragElPos
17004 * @param {int} iPageX the X coordinate of the mousedown or drag event
17005 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17007 setDragElPos: function(iPageX, iPageY) {
17008 // the first time we do this, we are going to check to make sure
17009 // the element has css positioning
17011 var el = this.getDragEl();
17012 this.alignElWithMouse(el, iPageX, iPageY);
17016 * Sets the element to the location of the mousedown or click event,
17017 * maintaining the cursor location relative to the location on the element
17018 * that was clicked. Override this if you want to place the element in a
17019 * location other than where the cursor is.
17020 * @method alignElWithMouse
17021 * @param {HTMLElement} el the element to move
17022 * @param {int} iPageX the X coordinate of the mousedown or drag event
17023 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17025 alignElWithMouse: function(el, iPageX, iPageY) {
17026 var oCoord = this.getTargetCoord(iPageX, iPageY);
17027 var fly = el.dom ? el : Roo.fly(el);
17028 if (!this.deltaSetXY) {
17029 var aCoord = [oCoord.x, oCoord.y];
17031 var newLeft = fly.getLeft(true);
17032 var newTop = fly.getTop(true);
17033 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
17035 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
17038 this.cachePosition(oCoord.x, oCoord.y);
17039 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
17044 * Saves the most recent position so that we can reset the constraints and
17045 * tick marks on-demand. We need to know this so that we can calculate the
17046 * number of pixels the element is offset from its original position.
17047 * @method cachePosition
17048 * @param iPageX the current x position (optional, this just makes it so we
17049 * don't have to look it up again)
17050 * @param iPageY the current y position (optional, this just makes it so we
17051 * don't have to look it up again)
17053 cachePosition: function(iPageX, iPageY) {
17055 this.lastPageX = iPageX;
17056 this.lastPageY = iPageY;
17058 var aCoord = Roo.lib.Dom.getXY(this.getEl());
17059 this.lastPageX = aCoord[0];
17060 this.lastPageY = aCoord[1];
17065 * Auto-scroll the window if the dragged object has been moved beyond the
17066 * visible window boundary.
17067 * @method autoScroll
17068 * @param {int} x the drag element's x position
17069 * @param {int} y the drag element's y position
17070 * @param {int} h the height of the drag element
17071 * @param {int} w the width of the drag element
17074 autoScroll: function(x, y, h, w) {
17077 // The client height
17078 var clientH = Roo.lib.Dom.getViewWidth();
17080 // The client width
17081 var clientW = Roo.lib.Dom.getViewHeight();
17083 // The amt scrolled down
17084 var st = this.DDM.getScrollTop();
17086 // The amt scrolled right
17087 var sl = this.DDM.getScrollLeft();
17089 // Location of the bottom of the element
17092 // Location of the right of the element
17095 // The distance from the cursor to the bottom of the visible area,
17096 // adjusted so that we don't scroll if the cursor is beyond the
17097 // element drag constraints
17098 var toBot = (clientH + st - y - this.deltaY);
17100 // The distance from the cursor to the right of the visible area
17101 var toRight = (clientW + sl - x - this.deltaX);
17104 // How close to the edge the cursor must be before we scroll
17105 // var thresh = (document.all) ? 100 : 40;
17108 // How many pixels to scroll per autoscroll op. This helps to reduce
17109 // clunky scrolling. IE is more sensitive about this ... it needs this
17110 // value to be higher.
17111 var scrAmt = (document.all) ? 80 : 30;
17113 // Scroll down if we are near the bottom of the visible page and the
17114 // obj extends below the crease
17115 if ( bot > clientH && toBot < thresh ) {
17116 window.scrollTo(sl, st + scrAmt);
17119 // Scroll up if the window is scrolled down and the top of the object
17120 // goes above the top border
17121 if ( y < st && st > 0 && y - st < thresh ) {
17122 window.scrollTo(sl, st - scrAmt);
17125 // Scroll right if the obj is beyond the right border and the cursor is
17126 // near the border.
17127 if ( right > clientW && toRight < thresh ) {
17128 window.scrollTo(sl + scrAmt, st);
17131 // Scroll left if the window has been scrolled to the right and the obj
17132 // extends past the left border
17133 if ( x < sl && sl > 0 && x - sl < thresh ) {
17134 window.scrollTo(sl - scrAmt, st);
17140 * Finds the location the element should be placed if we want to move
17141 * it to where the mouse location less the click offset would place us.
17142 * @method getTargetCoord
17143 * @param {int} iPageX the X coordinate of the click
17144 * @param {int} iPageY the Y coordinate of the click
17145 * @return an object that contains the coordinates (Object.x and Object.y)
17148 getTargetCoord: function(iPageX, iPageY) {
17151 var x = iPageX - this.deltaX;
17152 var y = iPageY - this.deltaY;
17154 if (this.constrainX) {
17155 if (x < this.minX) { x = this.minX; }
17156 if (x > this.maxX) { x = this.maxX; }
17159 if (this.constrainY) {
17160 if (y < this.minY) { y = this.minY; }
17161 if (y > this.maxY) { y = this.maxY; }
17164 x = this.getTick(x, this.xTicks);
17165 y = this.getTick(y, this.yTicks);
17172 * Sets up config options specific to this class. Overrides
17173 * Roo.dd.DragDrop, but all versions of this method through the
17174 * inheritance chain are called
17176 applyConfig: function() {
17177 Roo.dd.DD.superclass.applyConfig.call(this);
17178 this.scroll = (this.config.scroll !== false);
17182 * Event that fires prior to the onMouseDown event. Overrides
17185 b4MouseDown: function(e) {
17186 // this.resetConstraints();
17187 this.autoOffset(e.getPageX(),
17192 * Event that fires prior to the onDrag event. Overrides
17195 b4Drag: function(e) {
17196 this.setDragElPos(e.getPageX(),
17200 toString: function() {
17201 return ("DD " + this.id);
17204 //////////////////////////////////////////////////////////////////////////
17205 // Debugging ygDragDrop events that can be overridden
17206 //////////////////////////////////////////////////////////////////////////
17208 startDrag: function(x, y) {
17211 onDrag: function(e) {
17214 onDragEnter: function(e, id) {
17217 onDragOver: function(e, id) {
17220 onDragOut: function(e, id) {
17223 onDragDrop: function(e, id) {
17226 endDrag: function(e) {
17233 * Ext JS Library 1.1.1
17234 * Copyright(c) 2006-2007, Ext JS, LLC.
17236 * Originally Released Under LGPL - original licence link has changed is not relivant.
17239 * <script type="text/javascript">
17243 * @class Roo.dd.DDProxy
17244 * A DragDrop implementation that inserts an empty, bordered div into
17245 * the document that follows the cursor during drag operations. At the time of
17246 * the click, the frame div is resized to the dimensions of the linked html
17247 * element, and moved to the exact location of the linked element.
17249 * References to the "frame" element refer to the single proxy element that
17250 * was created to be dragged in place of all DDProxy elements on the
17253 * @extends Roo.dd.DD
17255 * @param {String} id the id of the linked html element
17256 * @param {String} sGroup the group of related DragDrop objects
17257 * @param {object} config an object containing configurable attributes
17258 * Valid properties for DDProxy in addition to those in DragDrop:
17259 * resizeFrame, centerFrame, dragElId
17261 Roo.dd.DDProxy = function(id, sGroup, config) {
17263 this.init(id, sGroup, config);
17269 * The default drag frame div id
17270 * @property Roo.dd.DDProxy.dragElId
17274 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17276 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17279 * By default we resize the drag frame to be the same size as the element
17280 * we want to drag (this is to get the frame effect). We can turn it off
17281 * if we want a different behavior.
17282 * @property resizeFrame
17288 * By default the frame is positioned exactly where the drag element is, so
17289 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17290 * you do not have constraints on the obj is to have the drag frame centered
17291 * around the cursor. Set centerFrame to true for this effect.
17292 * @property centerFrame
17295 centerFrame: false,
17298 * Creates the proxy element if it does not yet exist
17299 * @method createFrame
17301 createFrame: function() {
17303 var body = document.body;
17305 if (!body || !body.firstChild) {
17306 setTimeout( function() { self.createFrame(); }, 50 );
17310 var div = this.getDragEl();
17313 div = document.createElement("div");
17314 div.id = this.dragElId;
17317 s.position = "absolute";
17318 s.visibility = "hidden";
17320 s.border = "2px solid #aaa";
17323 // appendChild can blow up IE if invoked prior to the window load event
17324 // while rendering a table. It is possible there are other scenarios
17325 // that would cause this to happen as well.
17326 body.insertBefore(div, body.firstChild);
17331 * Initialization for the drag frame element. Must be called in the
17332 * constructor of all subclasses
17333 * @method initFrame
17335 initFrame: function() {
17336 this.createFrame();
17339 applyConfig: function() {
17340 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17342 this.resizeFrame = (this.config.resizeFrame !== false);
17343 this.centerFrame = (this.config.centerFrame);
17344 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17348 * Resizes the drag frame to the dimensions of the clicked object, positions
17349 * it over the object, and finally displays it
17350 * @method showFrame
17351 * @param {int} iPageX X click position
17352 * @param {int} iPageY Y click position
17355 showFrame: function(iPageX, iPageY) {
17356 var el = this.getEl();
17357 var dragEl = this.getDragEl();
17358 var s = dragEl.style;
17360 this._resizeProxy();
17362 if (this.centerFrame) {
17363 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17364 Math.round(parseInt(s.height, 10)/2) );
17367 this.setDragElPos(iPageX, iPageY);
17369 Roo.fly(dragEl).show();
17373 * The proxy is automatically resized to the dimensions of the linked
17374 * element when a drag is initiated, unless resizeFrame is set to false
17375 * @method _resizeProxy
17378 _resizeProxy: function() {
17379 if (this.resizeFrame) {
17380 var el = this.getEl();
17381 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17385 // overrides Roo.dd.DragDrop
17386 b4MouseDown: function(e) {
17387 var x = e.getPageX();
17388 var y = e.getPageY();
17389 this.autoOffset(x, y);
17390 this.setDragElPos(x, y);
17393 // overrides Roo.dd.DragDrop
17394 b4StartDrag: function(x, y) {
17395 // show the drag frame
17396 this.showFrame(x, y);
17399 // overrides Roo.dd.DragDrop
17400 b4EndDrag: function(e) {
17401 Roo.fly(this.getDragEl()).hide();
17404 // overrides Roo.dd.DragDrop
17405 // By default we try to move the element to the last location of the frame.
17406 // This is so that the default behavior mirrors that of Roo.dd.DD.
17407 endDrag: function(e) {
17409 var lel = this.getEl();
17410 var del = this.getDragEl();
17412 // Show the drag frame briefly so we can get its position
17413 del.style.visibility = "";
17416 // Hide the linked element before the move to get around a Safari
17418 lel.style.visibility = "hidden";
17419 Roo.dd.DDM.moveToEl(lel, del);
17420 del.style.visibility = "hidden";
17421 lel.style.visibility = "";
17426 beforeMove : function(){
17430 afterDrag : function(){
17434 toString: function() {
17435 return ("DDProxy " + this.id);
17441 * Ext JS Library 1.1.1
17442 * Copyright(c) 2006-2007, Ext JS, LLC.
17444 * Originally Released Under LGPL - original licence link has changed is not relivant.
17447 * <script type="text/javascript">
17451 * @class Roo.dd.DDTarget
17452 * A DragDrop implementation that does not move, but can be a drop
17453 * target. You would get the same result by simply omitting implementation
17454 * for the event callbacks, but this way we reduce the processing cost of the
17455 * event listener and the callbacks.
17456 * @extends Roo.dd.DragDrop
17458 * @param {String} id the id of the element that is a drop target
17459 * @param {String} sGroup the group of related DragDrop objects
17460 * @param {object} config an object containing configurable attributes
17461 * Valid properties for DDTarget in addition to those in
17465 Roo.dd.DDTarget = function(id, sGroup, config) {
17467 this.initTarget(id, sGroup, config);
17469 if (config.listeners || config.events) {
17470 Roo.dd.DragDrop.superclass.constructor.call(this, {
17471 listeners : config.listeners || {},
17472 events : config.events || {}
17477 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17478 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17479 toString: function() {
17480 return ("DDTarget " + this.id);
17485 * Ext JS Library 1.1.1
17486 * Copyright(c) 2006-2007, Ext JS, LLC.
17488 * Originally Released Under LGPL - original licence link has changed is not relivant.
17491 * <script type="text/javascript">
17496 * @class Roo.dd.ScrollManager
17497 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17498 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17501 Roo.dd.ScrollManager = function(){
17502 var ddm = Roo.dd.DragDropMgr;
17507 var onStop = function(e){
17512 var triggerRefresh = function(){
17513 if(ddm.dragCurrent){
17514 ddm.refreshCache(ddm.dragCurrent.groups);
17518 var doScroll = function(){
17519 if(ddm.dragCurrent){
17520 var dds = Roo.dd.ScrollManager;
17522 if(proc.el.scroll(proc.dir, dds.increment)){
17526 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17531 var clearProc = function(){
17533 clearInterval(proc.id);
17540 var startProc = function(el, dir){
17544 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17547 var onFire = function(e, isDrop){
17548 if(isDrop || !ddm.dragCurrent){ return; }
17549 var dds = Roo.dd.ScrollManager;
17550 if(!dragEl || dragEl != ddm.dragCurrent){
17551 dragEl = ddm.dragCurrent;
17552 // refresh regions on drag start
17553 dds.refreshCache();
17556 var xy = Roo.lib.Event.getXY(e);
17557 var pt = new Roo.lib.Point(xy[0], xy[1]);
17558 for(var id in els){
17559 var el = els[id], r = el._region;
17560 if(r && r.contains(pt) && el.isScrollable()){
17561 if(r.bottom - pt.y <= dds.thresh){
17563 startProc(el, "down");
17566 }else if(r.right - pt.x <= dds.thresh){
17568 startProc(el, "left");
17571 }else if(pt.y - r.top <= dds.thresh){
17573 startProc(el, "up");
17576 }else if(pt.x - r.left <= dds.thresh){
17578 startProc(el, "right");
17587 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17588 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17592 * Registers new overflow element(s) to auto scroll
17593 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17595 register : function(el){
17596 if(el instanceof Array){
17597 for(var i = 0, len = el.length; i < len; i++) {
17598 this.register(el[i]);
17607 * Unregisters overflow element(s) so they are no longer scrolled
17608 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17610 unregister : function(el){
17611 if(el instanceof Array){
17612 for(var i = 0, len = el.length; i < len; i++) {
17613 this.unregister(el[i]);
17622 * The number of pixels from the edge of a container the pointer needs to be to
17623 * trigger scrolling (defaults to 25)
17629 * The number of pixels to scroll in each scroll increment (defaults to 50)
17635 * The frequency of scrolls in milliseconds (defaults to 500)
17641 * True to animate the scroll (defaults to true)
17647 * The animation duration in seconds -
17648 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17654 * Manually trigger a cache refresh.
17656 refreshCache : function(){
17657 for(var id in els){
17658 if(typeof els[id] == 'object'){ // for people extending the object prototype
17659 els[id]._region = els[id].getRegion();
17666 * Ext JS Library 1.1.1
17667 * Copyright(c) 2006-2007, Ext JS, LLC.
17669 * Originally Released Under LGPL - original licence link has changed is not relivant.
17672 * <script type="text/javascript">
17677 * @class Roo.dd.Registry
17678 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17679 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17682 Roo.dd.Registry = function(){
17685 var autoIdSeed = 0;
17687 var getId = function(el, autogen){
17688 if(typeof el == "string"){
17692 if(!id && autogen !== false){
17693 id = "roodd-" + (++autoIdSeed);
17701 * Register a drag drop element
17702 * @param {String|HTMLElement} element The id or DOM node to register
17703 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17704 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17705 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17706 * populated in the data object (if applicable):
17708 Value Description<br />
17709 --------- ------------------------------------------<br />
17710 handles Array of DOM nodes that trigger dragging<br />
17711 for the element being registered<br />
17712 isHandle True if the element passed in triggers<br />
17713 dragging itself, else false
17716 register : function(el, data){
17718 if(typeof el == "string"){
17719 el = document.getElementById(el);
17722 elements[getId(el)] = data;
17723 if(data.isHandle !== false){
17724 handles[data.ddel.id] = data;
17727 var hs = data.handles;
17728 for(var i = 0, len = hs.length; i < len; i++){
17729 handles[getId(hs[i])] = data;
17735 * Unregister a drag drop element
17736 * @param {String|HTMLElement} element The id or DOM node to unregister
17738 unregister : function(el){
17739 var id = getId(el, false);
17740 var data = elements[id];
17742 delete elements[id];
17744 var hs = data.handles;
17745 for(var i = 0, len = hs.length; i < len; i++){
17746 delete handles[getId(hs[i], false)];
17753 * Returns the handle registered for a DOM Node by id
17754 * @param {String|HTMLElement} id The DOM node or id to look up
17755 * @return {Object} handle The custom handle data
17757 getHandle : function(id){
17758 if(typeof id != "string"){ // must be element?
17761 return handles[id];
17765 * Returns the handle that is registered for the DOM node that is the target of the event
17766 * @param {Event} e The event
17767 * @return {Object} handle The custom handle data
17769 getHandleFromEvent : function(e){
17770 var t = Roo.lib.Event.getTarget(e);
17771 return t ? handles[t.id] : null;
17775 * Returns a custom data object that is registered for a DOM node by id
17776 * @param {String|HTMLElement} id The DOM node or id to look up
17777 * @return {Object} data The custom data
17779 getTarget : function(id){
17780 if(typeof id != "string"){ // must be element?
17783 return elements[id];
17787 * Returns a custom data object that is registered for the DOM node that is the target of the event
17788 * @param {Event} e The event
17789 * @return {Object} data The custom data
17791 getTargetFromEvent : function(e){
17792 var t = Roo.lib.Event.getTarget(e);
17793 return t ? elements[t.id] || handles[t.id] : null;
17798 * Ext JS Library 1.1.1
17799 * Copyright(c) 2006-2007, Ext JS, LLC.
17801 * Originally Released Under LGPL - original licence link has changed is not relivant.
17804 * <script type="text/javascript">
17809 * @class Roo.dd.StatusProxy
17810 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17811 * default drag proxy used by all Roo.dd components.
17813 * @param {Object} config
17815 Roo.dd.StatusProxy = function(config){
17816 Roo.apply(this, config);
17817 this.id = this.id || Roo.id();
17818 this.el = new Roo.Layer({
17820 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17821 {tag: "div", cls: "x-dd-drop-icon"},
17822 {tag: "div", cls: "x-dd-drag-ghost"}
17825 shadow: !config || config.shadow !== false
17827 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17828 this.dropStatus = this.dropNotAllowed;
17831 Roo.dd.StatusProxy.prototype = {
17833 * @cfg {String} dropAllowed
17834 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17836 dropAllowed : "x-dd-drop-ok",
17838 * @cfg {String} dropNotAllowed
17839 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17841 dropNotAllowed : "x-dd-drop-nodrop",
17844 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17845 * over the current target element.
17846 * @param {String} cssClass The css class for the new drop status indicator image
17848 setStatus : function(cssClass){
17849 cssClass = cssClass || this.dropNotAllowed;
17850 if(this.dropStatus != cssClass){
17851 this.el.replaceClass(this.dropStatus, cssClass);
17852 this.dropStatus = cssClass;
17857 * Resets the status indicator to the default dropNotAllowed value
17858 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17860 reset : function(clearGhost){
17861 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17862 this.dropStatus = this.dropNotAllowed;
17864 this.ghost.update("");
17869 * Updates the contents of the ghost element
17870 * @param {String} html The html that will replace the current innerHTML of the ghost element
17872 update : function(html){
17873 if(typeof html == "string"){
17874 this.ghost.update(html);
17876 this.ghost.update("");
17877 html.style.margin = "0";
17878 this.ghost.dom.appendChild(html);
17880 // ensure float = none set?? cant remember why though.
17881 var el = this.ghost.dom.firstChild;
17883 Roo.fly(el).setStyle('float', 'none');
17888 * Returns the underlying proxy {@link Roo.Layer}
17889 * @return {Roo.Layer} el
17891 getEl : function(){
17896 * Returns the ghost element
17897 * @return {Roo.Element} el
17899 getGhost : function(){
17905 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17907 hide : function(clear){
17915 * Stops the repair animation if it's currently running
17918 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17924 * Displays this proxy
17931 * Force the Layer to sync its shadow and shim positions to the element
17938 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17939 * invalid drop operation by the item being dragged.
17940 * @param {Array} xy The XY position of the element ([x, y])
17941 * @param {Function} callback The function to call after the repair is complete
17942 * @param {Object} scope The scope in which to execute the callback
17944 repair : function(xy, callback, scope){
17945 this.callback = callback;
17946 this.scope = scope;
17947 if(xy && this.animRepair !== false){
17948 this.el.addClass("x-dd-drag-repair");
17949 this.el.hideUnders(true);
17950 this.anim = this.el.shift({
17951 duration: this.repairDuration || .5,
17955 callback: this.afterRepair,
17959 this.afterRepair();
17964 afterRepair : function(){
17966 if(typeof this.callback == "function"){
17967 this.callback.call(this.scope || this);
17969 this.callback = null;
17974 * Ext JS Library 1.1.1
17975 * Copyright(c) 2006-2007, Ext JS, LLC.
17977 * Originally Released Under LGPL - original licence link has changed is not relivant.
17980 * <script type="text/javascript">
17984 * @class Roo.dd.DragSource
17985 * @extends Roo.dd.DDProxy
17986 * A simple class that provides the basic implementation needed to make any element draggable.
17988 * @param {String/HTMLElement/Element} el The container element
17989 * @param {Object} config
17991 Roo.dd.DragSource = function(el, config){
17992 this.el = Roo.get(el);
17993 this.dragData = {};
17995 Roo.apply(this, config);
17998 this.proxy = new Roo.dd.StatusProxy();
18001 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18002 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
18004 this.dragging = false;
18007 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
18009 * @cfg {String} dropAllowed
18010 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18012 dropAllowed : "x-dd-drop-ok",
18014 * @cfg {String} dropNotAllowed
18015 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18017 dropNotAllowed : "x-dd-drop-nodrop",
18020 * Returns the data object associated with this drag source
18021 * @return {Object} data An object containing arbitrary data
18023 getDragData : function(e){
18024 return this.dragData;
18028 onDragEnter : function(e, id){
18029 var target = Roo.dd.DragDropMgr.getDDById(id);
18030 this.cachedTarget = target;
18031 if(this.beforeDragEnter(target, e, id) !== false){
18032 if(target.isNotifyTarget){
18033 var status = target.notifyEnter(this, e, this.dragData);
18034 this.proxy.setStatus(status);
18036 this.proxy.setStatus(this.dropAllowed);
18039 if(this.afterDragEnter){
18041 * An empty function by default, but provided so that you can perform a custom action
18042 * when the dragged item enters the drop target by providing an implementation.
18043 * @param {Roo.dd.DragDrop} target The drop target
18044 * @param {Event} e The event object
18045 * @param {String} id The id of the dragged element
18046 * @method afterDragEnter
18048 this.afterDragEnter(target, e, id);
18054 * An empty function by default, but provided so that you can perform a custom action
18055 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
18056 * @param {Roo.dd.DragDrop} target The drop target
18057 * @param {Event} e The event object
18058 * @param {String} id The id of the dragged element
18059 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18061 beforeDragEnter : function(target, e, id){
18066 alignElWithMouse: function() {
18067 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18072 onDragOver : function(e, id){
18073 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18074 if(this.beforeDragOver(target, e, id) !== false){
18075 if(target.isNotifyTarget){
18076 var status = target.notifyOver(this, e, this.dragData);
18077 this.proxy.setStatus(status);
18080 if(this.afterDragOver){
18082 * An empty function by default, but provided so that you can perform a custom action
18083 * while the dragged item is over the drop target by providing an implementation.
18084 * @param {Roo.dd.DragDrop} target The drop target
18085 * @param {Event} e The event object
18086 * @param {String} id The id of the dragged element
18087 * @method afterDragOver
18089 this.afterDragOver(target, e, id);
18095 * An empty function by default, but provided so that you can perform a custom action
18096 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18097 * @param {Roo.dd.DragDrop} target The drop target
18098 * @param {Event} e The event object
18099 * @param {String} id The id of the dragged element
18100 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18102 beforeDragOver : function(target, e, id){
18107 onDragOut : function(e, id){
18108 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18109 if(this.beforeDragOut(target, e, id) !== false){
18110 if(target.isNotifyTarget){
18111 target.notifyOut(this, e, this.dragData);
18113 this.proxy.reset();
18114 if(this.afterDragOut){
18116 * An empty function by default, but provided so that you can perform a custom action
18117 * after the dragged item is dragged out of the target without dropping.
18118 * @param {Roo.dd.DragDrop} target The drop target
18119 * @param {Event} e The event object
18120 * @param {String} id The id of the dragged element
18121 * @method afterDragOut
18123 this.afterDragOut(target, e, id);
18126 this.cachedTarget = null;
18130 * An empty function by default, but provided so that you can perform a custom action before the dragged
18131 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18132 * @param {Roo.dd.DragDrop} target The drop target
18133 * @param {Event} e The event object
18134 * @param {String} id The id of the dragged element
18135 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18137 beforeDragOut : function(target, e, id){
18142 onDragDrop : function(e, id){
18143 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18144 if(this.beforeDragDrop(target, e, id) !== false){
18145 if(target.isNotifyTarget){
18146 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18147 this.onValidDrop(target, e, id);
18149 this.onInvalidDrop(target, e, id);
18152 this.onValidDrop(target, e, id);
18155 if(this.afterDragDrop){
18157 * An empty function by default, but provided so that you can perform a custom action
18158 * after a valid drag drop has occurred by providing an implementation.
18159 * @param {Roo.dd.DragDrop} target The drop target
18160 * @param {Event} e The event object
18161 * @param {String} id The id of the dropped element
18162 * @method afterDragDrop
18164 this.afterDragDrop(target, e, id);
18167 delete this.cachedTarget;
18171 * An empty function by default, but provided so that you can perform a custom action before the dragged
18172 * item is dropped onto the target and optionally cancel the onDragDrop.
18173 * @param {Roo.dd.DragDrop} target The drop target
18174 * @param {Event} e The event object
18175 * @param {String} id The id of the dragged element
18176 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18178 beforeDragDrop : function(target, e, id){
18183 onValidDrop : function(target, e, id){
18185 if(this.afterValidDrop){
18187 * An empty function by default, but provided so that you can perform a custom action
18188 * after a valid drop has occurred by providing an implementation.
18189 * @param {Object} target The target DD
18190 * @param {Event} e The event object
18191 * @param {String} id The id of the dropped element
18192 * @method afterInvalidDrop
18194 this.afterValidDrop(target, e, id);
18199 getRepairXY : function(e, data){
18200 return this.el.getXY();
18204 onInvalidDrop : function(target, e, id){
18205 this.beforeInvalidDrop(target, e, id);
18206 if(this.cachedTarget){
18207 if(this.cachedTarget.isNotifyTarget){
18208 this.cachedTarget.notifyOut(this, e, this.dragData);
18210 this.cacheTarget = null;
18212 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18214 if(this.afterInvalidDrop){
18216 * An empty function by default, but provided so that you can perform a custom action
18217 * after an invalid drop has occurred by providing an implementation.
18218 * @param {Event} e The event object
18219 * @param {String} id The id of the dropped element
18220 * @method afterInvalidDrop
18222 this.afterInvalidDrop(e, id);
18227 afterRepair : function(){
18229 this.el.highlight(this.hlColor || "c3daf9");
18231 this.dragging = false;
18235 * An empty function by default, but provided so that you can perform a custom action after an invalid
18236 * drop has occurred.
18237 * @param {Roo.dd.DragDrop} target The drop target
18238 * @param {Event} e The event object
18239 * @param {String} id The id of the dragged element
18240 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18242 beforeInvalidDrop : function(target, e, id){
18247 handleMouseDown : function(e){
18248 if(this.dragging) {
18251 var data = this.getDragData(e);
18252 if(data && this.onBeforeDrag(data, e) !== false){
18253 this.dragData = data;
18255 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18260 * An empty function by default, but provided so that you can perform a custom action before the initial
18261 * drag event begins and optionally cancel it.
18262 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18263 * @param {Event} e The event object
18264 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18266 onBeforeDrag : function(data, e){
18271 * An empty function by default, but provided so that you can perform a custom action once the initial
18272 * drag event has begun. The drag cannot be canceled from this function.
18273 * @param {Number} x The x position of the click on the dragged object
18274 * @param {Number} y The y position of the click on the dragged object
18276 onStartDrag : Roo.emptyFn,
18278 // private - YUI override
18279 startDrag : function(x, y){
18280 this.proxy.reset();
18281 this.dragging = true;
18282 this.proxy.update("");
18283 this.onInitDrag(x, y);
18288 onInitDrag : function(x, y){
18289 var clone = this.el.dom.cloneNode(true);
18290 clone.id = Roo.id(); // prevent duplicate ids
18291 this.proxy.update(clone);
18292 this.onStartDrag(x, y);
18297 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18298 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18300 getProxy : function(){
18305 * Hides the drag source's {@link Roo.dd.StatusProxy}
18307 hideProxy : function(){
18309 this.proxy.reset(true);
18310 this.dragging = false;
18314 triggerCacheRefresh : function(){
18315 Roo.dd.DDM.refreshCache(this.groups);
18318 // private - override to prevent hiding
18319 b4EndDrag: function(e) {
18322 // private - override to prevent moving
18323 endDrag : function(e){
18324 this.onEndDrag(this.dragData, e);
18328 onEndDrag : function(data, e){
18331 // private - pin to cursor
18332 autoOffset : function(x, y) {
18333 this.setDelta(-12, -20);
18337 * Ext JS Library 1.1.1
18338 * Copyright(c) 2006-2007, Ext JS, LLC.
18340 * Originally Released Under LGPL - original licence link has changed is not relivant.
18343 * <script type="text/javascript">
18348 * @class Roo.dd.DropTarget
18349 * @extends Roo.dd.DDTarget
18350 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18351 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18353 * @param {String/HTMLElement/Element} el The container element
18354 * @param {Object} config
18356 Roo.dd.DropTarget = function(el, config){
18357 this.el = Roo.get(el);
18359 var listeners = false; ;
18360 if (config && config.listeners) {
18361 listeners= config.listeners;
18362 delete config.listeners;
18364 Roo.apply(this, config);
18366 if(this.containerScroll){
18367 Roo.dd.ScrollManager.register(this.el);
18371 * @scope Roo.dd.DropTarget
18376 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18377 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18378 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18380 * IMPORTANT : it should set this.overClass and this.dropAllowed
18382 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18383 * @param {Event} e The event
18384 * @param {Object} data An object containing arbitrary data supplied by the drag source
18390 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18391 * This method will be called on every mouse movement while the drag source is over the drop target.
18392 * This default implementation simply returns the dropAllowed config value.
18394 * IMPORTANT : it should set this.dropAllowed
18396 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18397 * @param {Event} e The event
18398 * @param {Object} data An object containing arbitrary data supplied by the drag source
18404 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18405 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18406 * overClass (if any) from the drop element.
18407 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18408 * @param {Event} e The event
18409 * @param {Object} data An object containing arbitrary data supplied by the drag source
18415 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18416 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18417 * implementation that does something to process the drop event and returns true so that the drag source's
18418 * repair action does not run.
18420 * IMPORTANT : it should set this.success
18422 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18423 * @param {Event} e The event
18424 * @param {Object} data An object containing arbitrary data supplied by the drag source
18430 Roo.dd.DropTarget.superclass.constructor.call( this,
18432 this.ddGroup || this.group,
18435 listeners : listeners || {}
18443 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18445 * @cfg {String} overClass
18446 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18449 * @cfg {String} ddGroup
18450 * The drag drop group to handle drop events for
18454 * @cfg {String} dropAllowed
18455 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18457 dropAllowed : "x-dd-drop-ok",
18459 * @cfg {String} dropNotAllowed
18460 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18462 dropNotAllowed : "x-dd-drop-nodrop",
18464 * @cfg {boolean} success
18465 * set this after drop listener..
18469 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
18470 * if the drop point is valid for over/enter..
18477 isNotifyTarget : true,
18482 notifyEnter : function(dd, e, data)
18485 this.fireEvent('enter', dd, e, data);
18486 if(this.overClass){
18487 this.el.addClass(this.overClass);
18489 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18490 this.valid ? this.dropAllowed : this.dropNotAllowed
18497 notifyOver : function(dd, e, data)
18500 this.fireEvent('over', dd, e, data);
18501 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18502 this.valid ? this.dropAllowed : this.dropNotAllowed
18509 notifyOut : function(dd, e, data)
18511 this.fireEvent('out', dd, e, data);
18512 if(this.overClass){
18513 this.el.removeClass(this.overClass);
18520 notifyDrop : function(dd, e, data)
18522 this.success = false;
18523 this.fireEvent('drop', dd, e, data);
18524 return this.success;
18528 * Ext JS Library 1.1.1
18529 * Copyright(c) 2006-2007, Ext JS, LLC.
18531 * Originally Released Under LGPL - original licence link has changed is not relivant.
18534 * <script type="text/javascript">
18539 * @class Roo.dd.DragZone
18540 * @extends Roo.dd.DragSource
18541 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18542 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18544 * @param {String/HTMLElement/Element} el The container element
18545 * @param {Object} config
18547 Roo.dd.DragZone = function(el, config){
18548 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18549 if(this.containerScroll){
18550 Roo.dd.ScrollManager.register(this.el);
18554 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18556 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18557 * for auto scrolling during drag operations.
18560 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18561 * method after a failed drop (defaults to "c3daf9" - light blue)
18565 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18566 * for a valid target to drag based on the mouse down. Override this method
18567 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18568 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18569 * @param {EventObject} e The mouse down event
18570 * @return {Object} The dragData
18572 getDragData : function(e){
18573 return Roo.dd.Registry.getHandleFromEvent(e);
18577 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18578 * this.dragData.ddel
18579 * @param {Number} x The x position of the click on the dragged object
18580 * @param {Number} y The y position of the click on the dragged object
18581 * @return {Boolean} true to continue the drag, false to cancel
18583 onInitDrag : function(x, y){
18584 this.proxy.update(this.dragData.ddel.cloneNode(true));
18585 this.onStartDrag(x, y);
18590 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18592 afterRepair : function(){
18594 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18596 this.dragging = false;
18600 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18601 * the XY of this.dragData.ddel
18602 * @param {EventObject} e The mouse up event
18603 * @return {Array} The xy location (e.g. [100, 200])
18605 getRepairXY : function(e){
18606 return Roo.Element.fly(this.dragData.ddel).getXY();
18610 * Ext JS Library 1.1.1
18611 * Copyright(c) 2006-2007, Ext JS, LLC.
18613 * Originally Released Under LGPL - original licence link has changed is not relivant.
18616 * <script type="text/javascript">
18619 * @class Roo.dd.DropZone
18620 * @extends Roo.dd.DropTarget
18621 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18622 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18624 * @param {String/HTMLElement/Element} el The container element
18625 * @param {Object} config
18627 Roo.dd.DropZone = function(el, config){
18628 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18631 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18633 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18634 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18635 * provide your own custom lookup.
18636 * @param {Event} e The event
18637 * @return {Object} data The custom data
18639 getTargetFromEvent : function(e){
18640 return Roo.dd.Registry.getTargetFromEvent(e);
18644 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18645 * that it has registered. This method has no default implementation and should be overridden to provide
18646 * node-specific processing if necessary.
18647 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18648 * {@link #getTargetFromEvent} for this node)
18649 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18650 * @param {Event} e The event
18651 * @param {Object} data An object containing arbitrary data supplied by the drag source
18653 onNodeEnter : function(n, dd, e, data){
18658 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18659 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18660 * overridden to provide the proper feedback.
18661 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18662 * {@link #getTargetFromEvent} for this node)
18663 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18664 * @param {Event} e The event
18665 * @param {Object} data An object containing arbitrary data supplied by the drag source
18666 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18667 * underlying {@link Roo.dd.StatusProxy} can be updated
18669 onNodeOver : function(n, dd, e, data){
18670 return this.dropAllowed;
18674 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18675 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18676 * node-specific processing if necessary.
18677 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18678 * {@link #getTargetFromEvent} for this node)
18679 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18680 * @param {Event} e The event
18681 * @param {Object} data An object containing arbitrary data supplied by the drag source
18683 onNodeOut : function(n, dd, e, data){
18688 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18689 * the drop node. The default implementation returns false, so it should be overridden to provide the
18690 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18691 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18692 * {@link #getTargetFromEvent} for this node)
18693 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18694 * @param {Event} e The event
18695 * @param {Object} data An object containing arbitrary data supplied by the drag source
18696 * @return {Boolean} True if the drop was valid, else false
18698 onNodeDrop : function(n, dd, e, data){
18703 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18704 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18705 * it should be overridden to provide the proper feedback if necessary.
18706 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18707 * @param {Event} e The event
18708 * @param {Object} data An object containing arbitrary data supplied by the drag source
18709 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18710 * underlying {@link Roo.dd.StatusProxy} can be updated
18712 onContainerOver : function(dd, e, data){
18713 return this.dropNotAllowed;
18717 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18718 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18719 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18720 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18721 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18722 * @param {Event} e The event
18723 * @param {Object} data An object containing arbitrary data supplied by the drag source
18724 * @return {Boolean} True if the drop was valid, else false
18726 onContainerDrop : function(dd, e, data){
18731 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18732 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18733 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18734 * you should override this method and provide a custom implementation.
18735 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18736 * @param {Event} e The event
18737 * @param {Object} data An object containing arbitrary data supplied by the drag source
18738 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18739 * underlying {@link Roo.dd.StatusProxy} can be updated
18741 notifyEnter : function(dd, e, data){
18742 return this.dropNotAllowed;
18746 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18747 * This method will be called on every mouse movement while the drag source is over the drop zone.
18748 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18749 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18750 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18751 * registered node, it will call {@link #onContainerOver}.
18752 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18753 * @param {Event} e The event
18754 * @param {Object} data An object containing arbitrary data supplied by the drag source
18755 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18756 * underlying {@link Roo.dd.StatusProxy} can be updated
18758 notifyOver : function(dd, e, data){
18759 var n = this.getTargetFromEvent(e);
18760 if(!n){ // not over valid drop target
18761 if(this.lastOverNode){
18762 this.onNodeOut(this.lastOverNode, dd, e, data);
18763 this.lastOverNode = null;
18765 return this.onContainerOver(dd, e, data);
18767 if(this.lastOverNode != n){
18768 if(this.lastOverNode){
18769 this.onNodeOut(this.lastOverNode, dd, e, data);
18771 this.onNodeEnter(n, dd, e, data);
18772 this.lastOverNode = n;
18774 return this.onNodeOver(n, dd, e, data);
18778 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18779 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18780 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18781 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18782 * @param {Event} e The event
18783 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18785 notifyOut : function(dd, e, data){
18786 if(this.lastOverNode){
18787 this.onNodeOut(this.lastOverNode, dd, e, data);
18788 this.lastOverNode = null;
18793 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18794 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18795 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18796 * otherwise it will call {@link #onContainerDrop}.
18797 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18798 * @param {Event} e The event
18799 * @param {Object} data An object containing arbitrary data supplied by the drag source
18800 * @return {Boolean} True if the drop was valid, else false
18802 notifyDrop : function(dd, e, data){
18803 if(this.lastOverNode){
18804 this.onNodeOut(this.lastOverNode, dd, e, data);
18805 this.lastOverNode = null;
18807 var n = this.getTargetFromEvent(e);
18809 this.onNodeDrop(n, dd, e, data) :
18810 this.onContainerDrop(dd, e, data);
18814 triggerCacheRefresh : function(){
18815 Roo.dd.DDM.refreshCache(this.groups);
18819 * Ext JS Library 1.1.1
18820 * Copyright(c) 2006-2007, Ext JS, LLC.
18822 * Originally Released Under LGPL - original licence link has changed is not relivant.
18825 * <script type="text/javascript">
18830 * @class Roo.data.SortTypes
18832 * Defines the default sorting (casting?) comparison functions used when sorting data.
18834 Roo.data.SortTypes = {
18836 * Default sort that does nothing
18837 * @param {Mixed} s The value being converted
18838 * @return {Mixed} The comparison value
18840 none : function(s){
18845 * The regular expression used to strip tags
18849 stripTagsRE : /<\/?[^>]+>/gi,
18852 * Strips all HTML tags to sort on text only
18853 * @param {Mixed} s The value being converted
18854 * @return {String} The comparison value
18856 asText : function(s){
18857 return String(s).replace(this.stripTagsRE, "");
18861 * Strips all HTML tags to sort on text only - Case insensitive
18862 * @param {Mixed} s The value being converted
18863 * @return {String} The comparison value
18865 asUCText : function(s){
18866 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18870 * Case insensitive string
18871 * @param {Mixed} s The value being converted
18872 * @return {String} The comparison value
18874 asUCString : function(s) {
18875 return String(s).toUpperCase();
18880 * @param {Mixed} s The value being converted
18881 * @return {Number} The comparison value
18883 asDate : function(s) {
18887 if(s instanceof Date){
18888 return s.getTime();
18890 return Date.parse(String(s));
18895 * @param {Mixed} s The value being converted
18896 * @return {Float} The comparison value
18898 asFloat : function(s) {
18899 var val = parseFloat(String(s).replace(/,/g, ""));
18900 if(isNaN(val)) val = 0;
18906 * @param {Mixed} s The value being converted
18907 * @return {Number} The comparison value
18909 asInt : function(s) {
18910 var val = parseInt(String(s).replace(/,/g, ""));
18911 if(isNaN(val)) val = 0;
18916 * Ext JS Library 1.1.1
18917 * Copyright(c) 2006-2007, Ext JS, LLC.
18919 * Originally Released Under LGPL - original licence link has changed is not relivant.
18922 * <script type="text/javascript">
18926 * @class Roo.data.Record
18927 * Instances of this class encapsulate both record <em>definition</em> information, and record
18928 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18929 * to access Records cached in an {@link Roo.data.Store} object.<br>
18931 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18932 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18935 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18937 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18938 * {@link #create}. The parameters are the same.
18939 * @param {Array} data An associative Array of data values keyed by the field name.
18940 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18941 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18942 * not specified an integer id is generated.
18944 Roo.data.Record = function(data, id){
18945 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18950 * Generate a constructor for a specific record layout.
18951 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18952 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18953 * Each field definition object may contain the following properties: <ul>
18954 * <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,
18955 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18956 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18957 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18958 * is being used, then this is a string containing the javascript expression to reference the data relative to
18959 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18960 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18961 * this may be omitted.</p></li>
18962 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18963 * <ul><li>auto (Default, implies no conversion)</li>
18968 * <li>date</li></ul></p></li>
18969 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18970 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18971 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18972 * by the Reader into an object that will be stored in the Record. It is passed the
18973 * following parameters:<ul>
18974 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18976 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18978 * <br>usage:<br><pre><code>
18979 var TopicRecord = Roo.data.Record.create(
18980 {name: 'title', mapping: 'topic_title'},
18981 {name: 'author', mapping: 'username'},
18982 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18983 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18984 {name: 'lastPoster', mapping: 'user2'},
18985 {name: 'excerpt', mapping: 'post_text'}
18988 var myNewRecord = new TopicRecord({
18989 title: 'Do my job please',
18992 lastPost: new Date(),
18993 lastPoster: 'Animal',
18994 excerpt: 'No way dude!'
18996 myStore.add(myNewRecord);
19001 Roo.data.Record.create = function(o){
19002 var f = function(){
19003 f.superclass.constructor.apply(this, arguments);
19005 Roo.extend(f, Roo.data.Record);
19006 var p = f.prototype;
19007 p.fields = new Roo.util.MixedCollection(false, function(field){
19010 for(var i = 0, len = o.length; i < len; i++){
19011 p.fields.add(new Roo.data.Field(o[i]));
19013 f.getField = function(name){
19014 return p.fields.get(name);
19019 Roo.data.Record.AUTO_ID = 1000;
19020 Roo.data.Record.EDIT = 'edit';
19021 Roo.data.Record.REJECT = 'reject';
19022 Roo.data.Record.COMMIT = 'commit';
19024 Roo.data.Record.prototype = {
19026 * Readonly flag - true if this record has been modified.
19035 join : function(store){
19036 this.store = store;
19040 * Set the named field to the specified value.
19041 * @param {String} name The name of the field to set.
19042 * @param {Object} value The value to set the field to.
19044 set : function(name, value){
19045 if(this.data[name] == value){
19049 if(!this.modified){
19050 this.modified = {};
19052 if(typeof this.modified[name] == 'undefined'){
19053 this.modified[name] = this.data[name];
19055 this.data[name] = value;
19057 this.store.afterEdit(this);
19062 * Get the value of the named field.
19063 * @param {String} name The name of the field to get the value of.
19064 * @return {Object} The value of the field.
19066 get : function(name){
19067 return this.data[name];
19071 beginEdit : function(){
19072 this.editing = true;
19073 this.modified = {};
19077 cancelEdit : function(){
19078 this.editing = false;
19079 delete this.modified;
19083 endEdit : function(){
19084 this.editing = false;
19085 if(this.dirty && this.store){
19086 this.store.afterEdit(this);
19091 * Usually called by the {@link Roo.data.Store} which owns the Record.
19092 * Rejects all changes made to the Record since either creation, or the last commit operation.
19093 * Modified fields are reverted to their original values.
19095 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19096 * of reject operations.
19098 reject : function(){
19099 var m = this.modified;
19101 if(typeof m[n] != "function"){
19102 this.data[n] = m[n];
19105 this.dirty = false;
19106 delete this.modified;
19107 this.editing = false;
19109 this.store.afterReject(this);
19114 * Usually called by the {@link Roo.data.Store} which owns the Record.
19115 * Commits all changes made to the Record since either creation, or the last commit operation.
19117 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19118 * of commit operations.
19120 commit : function(){
19121 this.dirty = false;
19122 delete this.modified;
19123 this.editing = false;
19125 this.store.afterCommit(this);
19130 hasError : function(){
19131 return this.error != null;
19135 clearError : function(){
19140 * Creates a copy of this record.
19141 * @param {String} id (optional) A new record id if you don't want to use this record's id
19144 copy : function(newId) {
19145 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19149 * Ext JS Library 1.1.1
19150 * Copyright(c) 2006-2007, Ext JS, LLC.
19152 * Originally Released Under LGPL - original licence link has changed is not relivant.
19155 * <script type="text/javascript">
19161 * @class Roo.data.Store
19162 * @extends Roo.util.Observable
19163 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19164 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19166 * 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
19167 * has no knowledge of the format of the data returned by the Proxy.<br>
19169 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19170 * instances from the data object. These records are cached and made available through accessor functions.
19172 * Creates a new Store.
19173 * @param {Object} config A config object containing the objects needed for the Store to access data,
19174 * and read the data into Records.
19176 Roo.data.Store = function(config){
19177 this.data = new Roo.util.MixedCollection(false);
19178 this.data.getKey = function(o){
19181 this.baseParams = {};
19183 this.paramNames = {
19188 "multisort" : "_multisort"
19191 if(config && config.data){
19192 this.inlineData = config.data;
19193 delete config.data;
19196 Roo.apply(this, config);
19198 if(this.reader){ // reader passed
19199 this.reader = Roo.factory(this.reader, Roo.data);
19200 this.reader.xmodule = this.xmodule || false;
19201 if(!this.recordType){
19202 this.recordType = this.reader.recordType;
19204 if(this.reader.onMetaChange){
19205 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19209 if(this.recordType){
19210 this.fields = this.recordType.prototype.fields;
19212 this.modified = [];
19216 * @event datachanged
19217 * Fires when the data cache has changed, and a widget which is using this Store
19218 * as a Record cache should refresh its view.
19219 * @param {Store} this
19221 datachanged : true,
19223 * @event metachange
19224 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19225 * @param {Store} this
19226 * @param {Object} meta The JSON metadata
19231 * Fires when Records have been added to the Store
19232 * @param {Store} this
19233 * @param {Roo.data.Record[]} records The array of Records added
19234 * @param {Number} index The index at which the record(s) were added
19239 * Fires when a Record has been removed from the Store
19240 * @param {Store} this
19241 * @param {Roo.data.Record} record The Record that was removed
19242 * @param {Number} index The index at which the record was removed
19247 * Fires when a Record has been updated
19248 * @param {Store} this
19249 * @param {Roo.data.Record} record The Record that was updated
19250 * @param {String} operation The update operation being performed. Value may be one of:
19252 Roo.data.Record.EDIT
19253 Roo.data.Record.REJECT
19254 Roo.data.Record.COMMIT
19260 * Fires when the data cache has been cleared.
19261 * @param {Store} this
19265 * @event beforeload
19266 * Fires before a request is made for a new data object. If the beforeload handler returns false
19267 * the load action will be canceled.
19268 * @param {Store} this
19269 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19274 * Fires after a new set of Records has been loaded.
19275 * @param {Store} this
19276 * @param {Roo.data.Record[]} records The Records that were loaded
19277 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19281 * @event loadexception
19282 * Fires if an exception occurs in the Proxy during loading.
19283 * Called with the signature of the Proxy's "loadexception" event.
19284 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19287 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19288 * @param {Object} load options
19289 * @param {Object} jsonData from your request (normally this contains the Exception)
19291 loadexception : true
19295 this.proxy = Roo.factory(this.proxy, Roo.data);
19296 this.proxy.xmodule = this.xmodule || false;
19297 this.relayEvents(this.proxy, ["loadexception"]);
19299 this.sortToggle = {};
19300 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
19302 Roo.data.Store.superclass.constructor.call(this);
19304 if(this.inlineData){
19305 this.loadData(this.inlineData);
19306 delete this.inlineData;
19309 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19311 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19312 * without a remote query - used by combo/forms at present.
19316 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19319 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19322 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19323 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19326 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19327 * on any HTTP request
19330 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19333 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
19337 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19338 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19340 remoteSort : false,
19343 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19344 * loaded or when a record is removed. (defaults to false).
19346 pruneModifiedRecords : false,
19349 lastOptions : null,
19352 * Add Records to the Store and fires the add event.
19353 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19355 add : function(records){
19356 records = [].concat(records);
19357 for(var i = 0, len = records.length; i < len; i++){
19358 records[i].join(this);
19360 var index = this.data.length;
19361 this.data.addAll(records);
19362 this.fireEvent("add", this, records, index);
19366 * Remove a Record from the Store and fires the remove event.
19367 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19369 remove : function(record){
19370 var index = this.data.indexOf(record);
19371 this.data.removeAt(index);
19372 if(this.pruneModifiedRecords){
19373 this.modified.remove(record);
19375 this.fireEvent("remove", this, record, index);
19379 * Remove all Records from the Store and fires the clear event.
19381 removeAll : function(){
19383 if(this.pruneModifiedRecords){
19384 this.modified = [];
19386 this.fireEvent("clear", this);
19390 * Inserts Records to the Store at the given index and fires the add event.
19391 * @param {Number} index The start index at which to insert the passed Records.
19392 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19394 insert : function(index, records){
19395 records = [].concat(records);
19396 for(var i = 0, len = records.length; i < len; i++){
19397 this.data.insert(index, records[i]);
19398 records[i].join(this);
19400 this.fireEvent("add", this, records, index);
19404 * Get the index within the cache of the passed Record.
19405 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19406 * @return {Number} The index of the passed Record. Returns -1 if not found.
19408 indexOf : function(record){
19409 return this.data.indexOf(record);
19413 * Get the index within the cache of the Record with the passed id.
19414 * @param {String} id The id of the Record to find.
19415 * @return {Number} The index of the Record. Returns -1 if not found.
19417 indexOfId : function(id){
19418 return this.data.indexOfKey(id);
19422 * Get the Record with the specified id.
19423 * @param {String} id The id of the Record to find.
19424 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19426 getById : function(id){
19427 return this.data.key(id);
19431 * Get the Record at the specified index.
19432 * @param {Number} index The index of the Record to find.
19433 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19435 getAt : function(index){
19436 return this.data.itemAt(index);
19440 * Returns a range of Records between specified indices.
19441 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19442 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19443 * @return {Roo.data.Record[]} An array of Records
19445 getRange : function(start, end){
19446 return this.data.getRange(start, end);
19450 storeOptions : function(o){
19451 o = Roo.apply({}, o);
19454 this.lastOptions = o;
19458 * Loads the Record cache from the configured Proxy using the configured Reader.
19460 * If using remote paging, then the first load call must specify the <em>start</em>
19461 * and <em>limit</em> properties in the options.params property to establish the initial
19462 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19464 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19465 * and this call will return before the new data has been loaded. Perform any post-processing
19466 * in a callback function, or in a "load" event handler.</strong>
19468 * @param {Object} options An object containing properties which control loading options:<ul>
19469 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19470 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19471 * passed the following arguments:<ul>
19472 * <li>r : Roo.data.Record[]</li>
19473 * <li>options: Options object from the load call</li>
19474 * <li>success: Boolean success indicator</li></ul></li>
19475 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19476 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19479 load : function(options){
19480 options = options || {};
19481 if(this.fireEvent("beforeload", this, options) !== false){
19482 this.storeOptions(options);
19483 var p = Roo.apply(options.params || {}, this.baseParams);
19484 // if meta was not loaded from remote source.. try requesting it.
19485 if (!this.reader.metaFromRemote) {
19486 p._requestMeta = 1;
19488 if(this.sortInfo && this.remoteSort){
19489 var pn = this.paramNames;
19490 p[pn["sort"]] = this.sortInfo.field;
19491 p[pn["dir"]] = this.sortInfo.direction;
19493 if (this.multiSort) {
19494 var pn = this.paramNames;
19495 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
19498 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19503 * Reloads the Record cache from the configured Proxy using the configured Reader and
19504 * the options from the last load operation performed.
19505 * @param {Object} options (optional) An object containing properties which may override the options
19506 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19507 * the most recently used options are reused).
19509 reload : function(options){
19510 this.load(Roo.applyIf(options||{}, this.lastOptions));
19514 // Called as a callback by the Reader during a load operation.
19515 loadRecords : function(o, options, success){
19516 if(!o || success === false){
19517 if(success !== false){
19518 this.fireEvent("load", this, [], options);
19520 if(options.callback){
19521 options.callback.call(options.scope || this, [], options, false);
19525 // if data returned failure - throw an exception.
19526 if (o.success === false) {
19527 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19530 var r = o.records, t = o.totalRecords || r.length;
19531 if(!options || options.add !== true){
19532 if(this.pruneModifiedRecords){
19533 this.modified = [];
19535 for(var i = 0, len = r.length; i < len; i++){
19539 this.data = this.snapshot;
19540 delete this.snapshot;
19543 this.data.addAll(r);
19544 this.totalLength = t;
19546 this.fireEvent("datachanged", this);
19548 this.totalLength = Math.max(t, this.data.length+r.length);
19551 this.fireEvent("load", this, r, options);
19552 if(options.callback){
19553 options.callback.call(options.scope || this, r, options, true);
19558 * Loads data from a passed data block. A Reader which understands the format of the data
19559 * must have been configured in the constructor.
19560 * @param {Object} data The data block from which to read the Records. The format of the data expected
19561 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19562 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19564 loadData : function(o, append){
19565 var r = this.reader.readRecords(o);
19566 this.loadRecords(r, {add: append}, true);
19570 * Gets the number of cached records.
19572 * <em>If using paging, this may not be the total size of the dataset. If the data object
19573 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19574 * the data set size</em>
19576 getCount : function(){
19577 return this.data.length || 0;
19581 * Gets the total number of records in the dataset as returned by the server.
19583 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19584 * the dataset size</em>
19586 getTotalCount : function(){
19587 return this.totalLength || 0;
19591 * Returns the sort state of the Store as an object with two properties:
19593 field {String} The name of the field by which the Records are sorted
19594 direction {String} The sort order, "ASC" or "DESC"
19597 getSortState : function(){
19598 return this.sortInfo;
19602 applySort : function(){
19603 if(this.sortInfo && !this.remoteSort){
19604 var s = this.sortInfo, f = s.field;
19605 var st = this.fields.get(f).sortType;
19606 var fn = function(r1, r2){
19607 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19608 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19610 this.data.sort(s.direction, fn);
19611 if(this.snapshot && this.snapshot != this.data){
19612 this.snapshot.sort(s.direction, fn);
19618 * Sets the default sort column and order to be used by the next load operation.
19619 * @param {String} fieldName The name of the field to sort by.
19620 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19622 setDefaultSort : function(field, dir){
19623 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19627 * Sort the Records.
19628 * If remote sorting is used, the sort is performed on the server, and the cache is
19629 * reloaded. If local sorting is used, the cache is sorted internally.
19630 * @param {String} fieldName The name of the field to sort by.
19631 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19633 sort : function(fieldName, dir){
19634 var f = this.fields.get(fieldName);
19636 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
19638 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
19639 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19644 this.sortToggle[f.name] = dir;
19645 this.sortInfo = {field: f.name, direction: dir};
19646 if(!this.remoteSort){
19648 this.fireEvent("datachanged", this);
19650 this.load(this.lastOptions);
19655 * Calls the specified function for each of the Records in the cache.
19656 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19657 * Returning <em>false</em> aborts and exits the iteration.
19658 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19660 each : function(fn, scope){
19661 this.data.each(fn, scope);
19665 * Gets all records modified since the last commit. Modified records are persisted across load operations
19666 * (e.g., during paging).
19667 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19669 getModifiedRecords : function(){
19670 return this.modified;
19674 createFilterFn : function(property, value, anyMatch){
19675 if(!value.exec){ // not a regex
19676 value = String(value);
19677 if(value.length == 0){
19680 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19682 return function(r){
19683 return value.test(r.data[property]);
19688 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19689 * @param {String} property A field on your records
19690 * @param {Number} start The record index to start at (defaults to 0)
19691 * @param {Number} end The last record index to include (defaults to length - 1)
19692 * @return {Number} The sum
19694 sum : function(property, start, end){
19695 var rs = this.data.items, v = 0;
19696 start = start || 0;
19697 end = (end || end === 0) ? end : rs.length-1;
19699 for(var i = start; i <= end; i++){
19700 v += (rs[i].data[property] || 0);
19706 * Filter the records by a specified property.
19707 * @param {String} field A field on your records
19708 * @param {String/RegExp} value Either a string that the field
19709 * should start with or a RegExp to test against the field
19710 * @param {Boolean} anyMatch True to match any part not just the beginning
19712 filter : function(property, value, anyMatch){
19713 var fn = this.createFilterFn(property, value, anyMatch);
19714 return fn ? this.filterBy(fn) : this.clearFilter();
19718 * Filter by a function. The specified function will be called with each
19719 * record in this data source. If the function returns true the record is included,
19720 * otherwise it is filtered.
19721 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19722 * @param {Object} scope (optional) The scope of the function (defaults to this)
19724 filterBy : function(fn, scope){
19725 this.snapshot = this.snapshot || this.data;
19726 this.data = this.queryBy(fn, scope||this);
19727 this.fireEvent("datachanged", this);
19731 * Query the records by a specified property.
19732 * @param {String} field A field on your records
19733 * @param {String/RegExp} value Either a string that the field
19734 * should start with or a RegExp to test against the field
19735 * @param {Boolean} anyMatch True to match any part not just the beginning
19736 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19738 query : function(property, value, anyMatch){
19739 var fn = this.createFilterFn(property, value, anyMatch);
19740 return fn ? this.queryBy(fn) : this.data.clone();
19744 * Query by a function. The specified function will be called with each
19745 * record in this data source. If the function returns true the record is included
19747 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19748 * @param {Object} scope (optional) The scope of the function (defaults to this)
19749 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19751 queryBy : function(fn, scope){
19752 var data = this.snapshot || this.data;
19753 return data.filterBy(fn, scope||this);
19757 * Collects unique values for a particular dataIndex from this store.
19758 * @param {String} dataIndex The property to collect
19759 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19760 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19761 * @return {Array} An array of the unique values
19763 collect : function(dataIndex, allowNull, bypassFilter){
19764 var d = (bypassFilter === true && this.snapshot) ?
19765 this.snapshot.items : this.data.items;
19766 var v, sv, r = [], l = {};
19767 for(var i = 0, len = d.length; i < len; i++){
19768 v = d[i].data[dataIndex];
19770 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19779 * Revert to a view of the Record cache with no filtering applied.
19780 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19782 clearFilter : function(suppressEvent){
19783 if(this.snapshot && this.snapshot != this.data){
19784 this.data = this.snapshot;
19785 delete this.snapshot;
19786 if(suppressEvent !== true){
19787 this.fireEvent("datachanged", this);
19793 afterEdit : function(record){
19794 if(this.modified.indexOf(record) == -1){
19795 this.modified.push(record);
19797 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19801 afterReject : function(record){
19802 this.modified.remove(record);
19803 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19807 afterCommit : function(record){
19808 this.modified.remove(record);
19809 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19813 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19814 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19816 commitChanges : function(){
19817 var m = this.modified.slice(0);
19818 this.modified = [];
19819 for(var i = 0, len = m.length; i < len; i++){
19825 * Cancel outstanding changes on all changed records.
19827 rejectChanges : function(){
19828 var m = this.modified.slice(0);
19829 this.modified = [];
19830 for(var i = 0, len = m.length; i < len; i++){
19835 onMetaChange : function(meta, rtype, o){
19836 this.recordType = rtype;
19837 this.fields = rtype.prototype.fields;
19838 delete this.snapshot;
19839 this.sortInfo = meta.sortInfo || this.sortInfo;
19840 this.modified = [];
19841 this.fireEvent('metachange', this, this.reader.meta);
19845 * Ext JS Library 1.1.1
19846 * Copyright(c) 2006-2007, Ext JS, LLC.
19848 * Originally Released Under LGPL - original licence link has changed is not relivant.
19851 * <script type="text/javascript">
19855 * @class Roo.data.SimpleStore
19856 * @extends Roo.data.Store
19857 * Small helper class to make creating Stores from Array data easier.
19858 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19859 * @cfg {Array} fields An array of field definition objects, or field name strings.
19860 * @cfg {Array} data The multi-dimensional array of data
19862 * @param {Object} config
19864 Roo.data.SimpleStore = function(config){
19865 Roo.data.SimpleStore.superclass.constructor.call(this, {
19867 reader: new Roo.data.ArrayReader({
19870 Roo.data.Record.create(config.fields)
19872 proxy : new Roo.data.MemoryProxy(config.data)
19876 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19878 * Ext JS Library 1.1.1
19879 * Copyright(c) 2006-2007, Ext JS, LLC.
19881 * Originally Released Under LGPL - original licence link has changed is not relivant.
19884 * <script type="text/javascript">
19889 * @extends Roo.data.Store
19890 * @class Roo.data.JsonStore
19891 * Small helper class to make creating Stores for JSON data easier. <br/>
19893 var store = new Roo.data.JsonStore({
19894 url: 'get-images.php',
19896 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19899 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19900 * JsonReader and HttpProxy (unless inline data is provided).</b>
19901 * @cfg {Array} fields An array of field definition objects, or field name strings.
19903 * @param {Object} config
19905 Roo.data.JsonStore = function(c){
19906 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19907 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19908 reader: new Roo.data.JsonReader(c, c.fields)
19911 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19913 * Ext JS Library 1.1.1
19914 * Copyright(c) 2006-2007, Ext JS, LLC.
19916 * Originally Released Under LGPL - original licence link has changed is not relivant.
19919 * <script type="text/javascript">
19923 Roo.data.Field = function(config){
19924 if(typeof config == "string"){
19925 config = {name: config};
19927 Roo.apply(this, config);
19930 this.type = "auto";
19933 var st = Roo.data.SortTypes;
19934 // named sortTypes are supported, here we look them up
19935 if(typeof this.sortType == "string"){
19936 this.sortType = st[this.sortType];
19939 // set default sortType for strings and dates
19940 if(!this.sortType){
19943 this.sortType = st.asUCString;
19946 this.sortType = st.asDate;
19949 this.sortType = st.none;
19954 var stripRe = /[\$,%]/g;
19956 // prebuilt conversion function for this field, instead of
19957 // switching every time we're reading a value
19959 var cv, dateFormat = this.dateFormat;
19964 cv = function(v){ return v; };
19967 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19971 return v !== undefined && v !== null && v !== '' ?
19972 parseInt(String(v).replace(stripRe, ""), 10) : '';
19977 return v !== undefined && v !== null && v !== '' ?
19978 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19983 cv = function(v){ return v === true || v === "true" || v == 1; };
19990 if(v instanceof Date){
19994 if(dateFormat == "timestamp"){
19995 return new Date(v*1000);
19997 return Date.parseDate(v, dateFormat);
19999 var parsed = Date.parse(v);
20000 return parsed ? new Date(parsed) : null;
20009 Roo.data.Field.prototype = {
20017 * Ext JS Library 1.1.1
20018 * Copyright(c) 2006-2007, Ext JS, LLC.
20020 * Originally Released Under LGPL - original licence link has changed is not relivant.
20023 * <script type="text/javascript">
20026 // Base class for reading structured data from a data source. This class is intended to be
20027 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20030 * @class Roo.data.DataReader
20031 * Base class for reading structured data from a data source. This class is intended to be
20032 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20035 Roo.data.DataReader = function(meta, recordType){
20039 this.recordType = recordType instanceof Array ?
20040 Roo.data.Record.create(recordType) : recordType;
20043 Roo.data.DataReader.prototype = {
20045 * Create an empty record
20046 * @param {Object} data (optional) - overlay some values
20047 * @return {Roo.data.Record} record created.
20049 newRow : function(d) {
20051 this.recordType.prototype.fields.each(function(c) {
20053 case 'int' : da[c.name] = 0; break;
20054 case 'date' : da[c.name] = new Date(); break;
20055 case 'float' : da[c.name] = 0.0; break;
20056 case 'boolean' : da[c.name] = false; break;
20057 default : da[c.name] = ""; break;
20061 return new this.recordType(Roo.apply(da, d));
20066 * Ext JS Library 1.1.1
20067 * Copyright(c) 2006-2007, Ext JS, LLC.
20069 * Originally Released Under LGPL - original licence link has changed is not relivant.
20072 * <script type="text/javascript">
20076 * @class Roo.data.DataProxy
20077 * @extends Roo.data.Observable
20078 * This class is an abstract base class for implementations which provide retrieval of
20079 * unformatted data objects.<br>
20081 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20082 * (of the appropriate type which knows how to parse the data object) to provide a block of
20083 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20085 * Custom implementations must implement the load method as described in
20086 * {@link Roo.data.HttpProxy#load}.
20088 Roo.data.DataProxy = function(){
20091 * @event beforeload
20092 * Fires before a network request is made to retrieve a data object.
20093 * @param {Object} This DataProxy object.
20094 * @param {Object} params The params parameter to the load function.
20099 * Fires before the load method's callback is called.
20100 * @param {Object} This DataProxy object.
20101 * @param {Object} o The data object.
20102 * @param {Object} arg The callback argument object passed to the load function.
20106 * @event loadexception
20107 * Fires if an Exception occurs during data retrieval.
20108 * @param {Object} This DataProxy object.
20109 * @param {Object} o The data object.
20110 * @param {Object} arg The callback argument object passed to the load function.
20111 * @param {Object} e The Exception.
20113 loadexception : true
20115 Roo.data.DataProxy.superclass.constructor.call(this);
20118 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20121 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20125 * Ext JS Library 1.1.1
20126 * Copyright(c) 2006-2007, Ext JS, LLC.
20128 * Originally Released Under LGPL - original licence link has changed is not relivant.
20131 * <script type="text/javascript">
20134 * @class Roo.data.MemoryProxy
20135 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20136 * to the Reader when its load method is called.
20138 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20140 Roo.data.MemoryProxy = function(data){
20144 Roo.data.MemoryProxy.superclass.constructor.call(this);
20148 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20150 * Load data from the requested source (in this case an in-memory
20151 * data object passed to the constructor), read the data object into
20152 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20153 * process that block using the passed callback.
20154 * @param {Object} params This parameter is not used by the MemoryProxy class.
20155 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20156 * object into a block of Roo.data.Records.
20157 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20158 * The function must be passed <ul>
20159 * <li>The Record block object</li>
20160 * <li>The "arg" argument from the load function</li>
20161 * <li>A boolean success indicator</li>
20163 * @param {Object} scope The scope in which to call the callback
20164 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20166 load : function(params, reader, callback, scope, arg){
20167 params = params || {};
20170 result = reader.readRecords(this.data);
20172 this.fireEvent("loadexception", this, arg, null, e);
20173 callback.call(scope, null, arg, false);
20176 callback.call(scope, result, arg, true);
20180 update : function(params, records){
20185 * Ext JS Library 1.1.1
20186 * Copyright(c) 2006-2007, Ext JS, LLC.
20188 * Originally Released Under LGPL - original licence link has changed is not relivant.
20191 * <script type="text/javascript">
20194 * @class Roo.data.HttpProxy
20195 * @extends Roo.data.DataProxy
20196 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20197 * configured to reference a certain URL.<br><br>
20199 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20200 * from which the running page was served.<br><br>
20202 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20204 * Be aware that to enable the browser to parse an XML document, the server must set
20205 * the Content-Type header in the HTTP response to "text/xml".
20207 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20208 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20209 * will be used to make the request.
20211 Roo.data.HttpProxy = function(conn){
20212 Roo.data.HttpProxy.superclass.constructor.call(this);
20213 // is conn a conn config or a real conn?
20215 this.useAjax = !conn || !conn.events;
20219 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20220 // thse are take from connection...
20223 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20226 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20227 * extra parameters to each request made by this object. (defaults to undefined)
20230 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20231 * to each request made by this object. (defaults to undefined)
20234 * @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)
20237 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20240 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20246 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20250 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20251 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20252 * a finer-grained basis than the DataProxy events.
20254 getConnection : function(){
20255 return this.useAjax ? Roo.Ajax : this.conn;
20259 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20260 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20261 * process that block using the passed callback.
20262 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20263 * for the request to the remote server.
20264 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20265 * object into a block of Roo.data.Records.
20266 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20267 * The function must be passed <ul>
20268 * <li>The Record block object</li>
20269 * <li>The "arg" argument from the load function</li>
20270 * <li>A boolean success indicator</li>
20272 * @param {Object} scope The scope in which to call the callback
20273 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20275 load : function(params, reader, callback, scope, arg){
20276 if(this.fireEvent("beforeload", this, params) !== false){
20278 params : params || {},
20280 callback : callback,
20285 callback : this.loadResponse,
20289 Roo.applyIf(o, this.conn);
20290 if(this.activeRequest){
20291 Roo.Ajax.abort(this.activeRequest);
20293 this.activeRequest = Roo.Ajax.request(o);
20295 this.conn.request(o);
20298 callback.call(scope||this, null, arg, false);
20303 loadResponse : function(o, success, response){
20304 delete this.activeRequest;
20306 this.fireEvent("loadexception", this, o, response);
20307 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20312 result = o.reader.read(response);
20314 this.fireEvent("loadexception", this, o, response, e);
20315 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20319 this.fireEvent("load", this, o, o.request.arg);
20320 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20324 update : function(dataSet){
20329 updateResponse : function(dataSet){
20334 * Ext JS Library 1.1.1
20335 * Copyright(c) 2006-2007, Ext JS, LLC.
20337 * Originally Released Under LGPL - original licence link has changed is not relivant.
20340 * <script type="text/javascript">
20344 * @class Roo.data.ScriptTagProxy
20345 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20346 * other than the originating domain of the running page.<br><br>
20348 * <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
20349 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20351 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20352 * source code that is used as the source inside a <script> tag.<br><br>
20354 * In order for the browser to process the returned data, the server must wrap the data object
20355 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20356 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20357 * depending on whether the callback name was passed:
20360 boolean scriptTag = false;
20361 String cb = request.getParameter("callback");
20364 response.setContentType("text/javascript");
20366 response.setContentType("application/x-json");
20368 Writer out = response.getWriter();
20370 out.write(cb + "(");
20372 out.print(dataBlock.toJsonString());
20379 * @param {Object} config A configuration object.
20381 Roo.data.ScriptTagProxy = function(config){
20382 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20383 Roo.apply(this, config);
20384 this.head = document.getElementsByTagName("head")[0];
20387 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20389 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20391 * @cfg {String} url The URL from which to request the data object.
20394 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20398 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20399 * the server the name of the callback function set up by the load call to process the returned data object.
20400 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20401 * javascript output which calls this named function passing the data object as its only parameter.
20403 callbackParam : "callback",
20405 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20406 * name to the request.
20411 * Load data from the configured URL, read the data object into
20412 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20413 * process that block using the passed callback.
20414 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20415 * for the request to the remote server.
20416 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20417 * object into a block of Roo.data.Records.
20418 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20419 * The function must be passed <ul>
20420 * <li>The Record block object</li>
20421 * <li>The "arg" argument from the load function</li>
20422 * <li>A boolean success indicator</li>
20424 * @param {Object} scope The scope in which to call the callback
20425 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20427 load : function(params, reader, callback, scope, arg){
20428 if(this.fireEvent("beforeload", this, params) !== false){
20430 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20432 var url = this.url;
20433 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20435 url += "&_dc=" + (new Date().getTime());
20437 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20440 cb : "stcCallback"+transId,
20441 scriptId : "stcScript"+transId,
20445 callback : callback,
20451 window[trans.cb] = function(o){
20452 conn.handleResponse(o, trans);
20455 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20457 if(this.autoAbort !== false){
20461 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20463 var script = document.createElement("script");
20464 script.setAttribute("src", url);
20465 script.setAttribute("type", "text/javascript");
20466 script.setAttribute("id", trans.scriptId);
20467 this.head.appendChild(script);
20469 this.trans = trans;
20471 callback.call(scope||this, null, arg, false);
20476 isLoading : function(){
20477 return this.trans ? true : false;
20481 * Abort the current server request.
20483 abort : function(){
20484 if(this.isLoading()){
20485 this.destroyTrans(this.trans);
20490 destroyTrans : function(trans, isLoaded){
20491 this.head.removeChild(document.getElementById(trans.scriptId));
20492 clearTimeout(trans.timeoutId);
20494 window[trans.cb] = undefined;
20496 delete window[trans.cb];
20499 // if hasn't been loaded, wait for load to remove it to prevent script error
20500 window[trans.cb] = function(){
20501 window[trans.cb] = undefined;
20503 delete window[trans.cb];
20510 handleResponse : function(o, trans){
20511 this.trans = false;
20512 this.destroyTrans(trans, true);
20515 result = trans.reader.readRecords(o);
20517 this.fireEvent("loadexception", this, o, trans.arg, e);
20518 trans.callback.call(trans.scope||window, null, trans.arg, false);
20521 this.fireEvent("load", this, o, trans.arg);
20522 trans.callback.call(trans.scope||window, result, trans.arg, true);
20526 handleFailure : function(trans){
20527 this.trans = false;
20528 this.destroyTrans(trans, false);
20529 this.fireEvent("loadexception", this, null, trans.arg);
20530 trans.callback.call(trans.scope||window, null, trans.arg, false);
20534 * Ext JS Library 1.1.1
20535 * Copyright(c) 2006-2007, Ext JS, LLC.
20537 * Originally Released Under LGPL - original licence link has changed is not relivant.
20540 * <script type="text/javascript">
20544 * @class Roo.data.JsonReader
20545 * @extends Roo.data.DataReader
20546 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20547 * based on mappings in a provided Roo.data.Record constructor.
20549 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
20550 * in the reply previously.
20555 var RecordDef = Roo.data.Record.create([
20556 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20557 {name: 'occupation'} // This field will use "occupation" as the mapping.
20559 var myReader = new Roo.data.JsonReader({
20560 totalProperty: "results", // The property which contains the total dataset size (optional)
20561 root: "rows", // The property which contains an Array of row objects
20562 id: "id" // The property within each row object that provides an ID for the record (optional)
20566 * This would consume a JSON file like this:
20568 { 'results': 2, 'rows': [
20569 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20570 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20573 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20574 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20575 * paged from the remote server.
20576 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20577 * @cfg {String} root name of the property which contains the Array of row objects.
20578 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20580 * Create a new JsonReader
20581 * @param {Object} meta Metadata configuration options
20582 * @param {Object} recordType Either an Array of field definition objects,
20583 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20585 Roo.data.JsonReader = function(meta, recordType){
20588 // set some defaults:
20589 Roo.applyIf(meta, {
20590 totalProperty: 'total',
20591 successProperty : 'success',
20596 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20598 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20601 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
20602 * Used by Store query builder to append _requestMeta to params.
20605 metaFromRemote : false,
20607 * This method is only used by a DataProxy which has retrieved data from a remote server.
20608 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20609 * @return {Object} data A data block which is used by an Roo.data.Store object as
20610 * a cache of Roo.data.Records.
20612 read : function(response){
20613 var json = response.responseText;
20615 var o = /* eval:var:o */ eval("("+json+")");
20617 throw {message: "JsonReader.read: Json object not found"};
20623 this.metaFromRemote = true;
20624 this.meta = o.metaData;
20625 this.recordType = Roo.data.Record.create(o.metaData.fields);
20626 this.onMetaChange(this.meta, this.recordType, o);
20628 return this.readRecords(o);
20631 // private function a store will implement
20632 onMetaChange : function(meta, recordType, o){
20639 simpleAccess: function(obj, subsc) {
20646 getJsonAccessor: function(){
20648 return function(expr) {
20650 return(re.test(expr))
20651 ? new Function("obj", "return obj." + expr)
20656 return Roo.emptyFn;
20661 * Create a data block containing Roo.data.Records from an XML document.
20662 * @param {Object} o An object which contains an Array of row objects in the property specified
20663 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20664 * which contains the total size of the dataset.
20665 * @return {Object} data A data block which is used by an Roo.data.Store object as
20666 * a cache of Roo.data.Records.
20668 readRecords : function(o){
20670 * After any data loads, the raw JSON data is available for further custom processing.
20674 var s = this.meta, Record = this.recordType,
20675 f = Record.prototype.fields, fi = f.items, fl = f.length;
20677 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20679 if(s.totalProperty) {
20680 this.getTotal = this.getJsonAccessor(s.totalProperty);
20682 if(s.successProperty) {
20683 this.getSuccess = this.getJsonAccessor(s.successProperty);
20685 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20687 var g = this.getJsonAccessor(s.id);
20688 this.getId = function(rec) {
20690 return (r === undefined || r === "") ? null : r;
20693 this.getId = function(){return null;};
20696 for(var jj = 0; jj < fl; jj++){
20698 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20699 this.ef[jj] = this.getJsonAccessor(map);
20703 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20704 if(s.totalProperty){
20705 var vt = parseInt(this.getTotal(o), 10);
20710 if(s.successProperty){
20711 var vs = this.getSuccess(o);
20712 if(vs === false || vs === 'false'){
20717 for(var i = 0; i < c; i++){
20720 var id = this.getId(n);
20721 for(var j = 0; j < fl; j++){
20723 var v = this.ef[j](n);
20725 Roo.log('missing convert for ' + f.name);
20729 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20731 var record = new Record(values, id);
20733 records[i] = record;
20738 totalRecords : totalRecords
20743 * Ext JS Library 1.1.1
20744 * Copyright(c) 2006-2007, Ext JS, LLC.
20746 * Originally Released Under LGPL - original licence link has changed is not relivant.
20749 * <script type="text/javascript">
20753 * @class Roo.data.XmlReader
20754 * @extends Roo.data.DataReader
20755 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20756 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20758 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20759 * header in the HTTP response must be set to "text/xml".</em>
20763 var RecordDef = Roo.data.Record.create([
20764 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20765 {name: 'occupation'} // This field will use "occupation" as the mapping.
20767 var myReader = new Roo.data.XmlReader({
20768 totalRecords: "results", // The element which contains the total dataset size (optional)
20769 record: "row", // The repeated element which contains row information
20770 id: "id" // The element within the row that provides an ID for the record (optional)
20774 * This would consume an XML file like this:
20778 <results>2</results>
20781 <name>Bill</name>
20782 <occupation>Gardener</occupation>
20786 <name>Ben</name>
20787 <occupation>Horticulturalist</occupation>
20791 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20792 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20793 * paged from the remote server.
20794 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20795 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20796 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20797 * a record identifier value.
20799 * Create a new XmlReader
20800 * @param {Object} meta Metadata configuration options
20801 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20802 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20803 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20805 Roo.data.XmlReader = function(meta, recordType){
20807 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20809 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20811 * This method is only used by a DataProxy which has retrieved data from a remote server.
20812 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20813 * to contain a method called 'responseXML' that returns an XML document object.
20814 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20815 * a cache of Roo.data.Records.
20817 read : function(response){
20818 var doc = response.responseXML;
20820 throw {message: "XmlReader.read: XML Document not available"};
20822 return this.readRecords(doc);
20826 * Create a data block containing Roo.data.Records from an XML document.
20827 * @param {Object} doc A parsed XML document.
20828 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20829 * a cache of Roo.data.Records.
20831 readRecords : function(doc){
20833 * After any data loads/reads, the raw XML Document is available for further custom processing.
20834 * @type XMLDocument
20836 this.xmlData = doc;
20837 var root = doc.documentElement || doc;
20838 var q = Roo.DomQuery;
20839 var recordType = this.recordType, fields = recordType.prototype.fields;
20840 var sid = this.meta.id;
20841 var totalRecords = 0, success = true;
20842 if(this.meta.totalRecords){
20843 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20846 if(this.meta.success){
20847 var sv = q.selectValue(this.meta.success, root, true);
20848 success = sv !== false && sv !== 'false';
20851 var ns = q.select(this.meta.record, root);
20852 for(var i = 0, len = ns.length; i < len; i++) {
20855 var id = sid ? q.selectValue(sid, n) : undefined;
20856 for(var j = 0, jlen = fields.length; j < jlen; j++){
20857 var f = fields.items[j];
20858 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20860 values[f.name] = v;
20862 var record = new recordType(values, id);
20864 records[records.length] = record;
20870 totalRecords : totalRecords || records.length
20875 * Ext JS Library 1.1.1
20876 * Copyright(c) 2006-2007, Ext JS, LLC.
20878 * Originally Released Under LGPL - original licence link has changed is not relivant.
20881 * <script type="text/javascript">
20885 * @class Roo.data.ArrayReader
20886 * @extends Roo.data.DataReader
20887 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20888 * Each element of that Array represents a row of data fields. The
20889 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20890 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20894 var RecordDef = Roo.data.Record.create([
20895 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20896 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20898 var myReader = new Roo.data.ArrayReader({
20899 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20903 * This would consume an Array like this:
20905 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20907 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20909 * Create a new JsonReader
20910 * @param {Object} meta Metadata configuration options.
20911 * @param {Object} recordType Either an Array of field definition objects
20912 * as specified to {@link Roo.data.Record#create},
20913 * or an {@link Roo.data.Record} object
20914 * created using {@link Roo.data.Record#create}.
20916 Roo.data.ArrayReader = function(meta, recordType){
20917 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20920 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20922 * Create a data block containing Roo.data.Records from an XML document.
20923 * @param {Object} o An Array of row objects which represents the dataset.
20924 * @return {Object} data A data block which is used by an Roo.data.Store object as
20925 * a cache of Roo.data.Records.
20927 readRecords : function(o){
20928 var sid = this.meta ? this.meta.id : null;
20929 var recordType = this.recordType, fields = recordType.prototype.fields;
20932 for(var i = 0; i < root.length; i++){
20935 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20936 for(var j = 0, jlen = fields.length; j < jlen; j++){
20937 var f = fields.items[j];
20938 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20939 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20941 values[f.name] = v;
20943 var record = new recordType(values, id);
20945 records[records.length] = record;
20949 totalRecords : records.length
20954 * Ext JS Library 1.1.1
20955 * Copyright(c) 2006-2007, Ext JS, LLC.
20957 * Originally Released Under LGPL - original licence link has changed is not relivant.
20960 * <script type="text/javascript">
20965 * @class Roo.data.Tree
20966 * @extends Roo.util.Observable
20967 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20968 * in the tree have most standard DOM functionality.
20970 * @param {Node} root (optional) The root node
20972 Roo.data.Tree = function(root){
20973 this.nodeHash = {};
20975 * The root node for this tree
20980 this.setRootNode(root);
20985 * Fires when a new child node is appended to a node in this tree.
20986 * @param {Tree} tree The owner tree
20987 * @param {Node} parent The parent node
20988 * @param {Node} node The newly appended node
20989 * @param {Number} index The index of the newly appended node
20994 * Fires when a child node is removed from a node in this tree.
20995 * @param {Tree} tree The owner tree
20996 * @param {Node} parent The parent node
20997 * @param {Node} node The child node removed
21002 * Fires when a node is moved to a new location in the tree
21003 * @param {Tree} tree The owner tree
21004 * @param {Node} node The node moved
21005 * @param {Node} oldParent The old parent of this node
21006 * @param {Node} newParent The new parent of this node
21007 * @param {Number} index The index it was moved to
21012 * Fires when a new child node is inserted in a node in this tree.
21013 * @param {Tree} tree The owner tree
21014 * @param {Node} parent The parent node
21015 * @param {Node} node The child node inserted
21016 * @param {Node} refNode The child node the node was inserted before
21020 * @event beforeappend
21021 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21022 * @param {Tree} tree The owner tree
21023 * @param {Node} parent The parent node
21024 * @param {Node} node The child node to be appended
21026 "beforeappend" : true,
21028 * @event beforeremove
21029 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21030 * @param {Tree} tree The owner tree
21031 * @param {Node} parent The parent node
21032 * @param {Node} node The child node to be removed
21034 "beforeremove" : true,
21036 * @event beforemove
21037 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21038 * @param {Tree} tree The owner tree
21039 * @param {Node} node The node being moved
21040 * @param {Node} oldParent The parent of the node
21041 * @param {Node} newParent The new parent the node is moving to
21042 * @param {Number} index The index it is being moved to
21044 "beforemove" : true,
21046 * @event beforeinsert
21047 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21048 * @param {Tree} tree The owner tree
21049 * @param {Node} parent The parent node
21050 * @param {Node} node The child node to be inserted
21051 * @param {Node} refNode The child node the node is being inserted before
21053 "beforeinsert" : true
21056 Roo.data.Tree.superclass.constructor.call(this);
21059 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21060 pathSeparator: "/",
21062 proxyNodeEvent : function(){
21063 return this.fireEvent.apply(this, arguments);
21067 * Returns the root node for this tree.
21070 getRootNode : function(){
21075 * Sets the root node for this tree.
21076 * @param {Node} node
21079 setRootNode : function(node){
21081 node.ownerTree = this;
21082 node.isRoot = true;
21083 this.registerNode(node);
21088 * Gets a node in this tree by its id.
21089 * @param {String} id
21092 getNodeById : function(id){
21093 return this.nodeHash[id];
21096 registerNode : function(node){
21097 this.nodeHash[node.id] = node;
21100 unregisterNode : function(node){
21101 delete this.nodeHash[node.id];
21104 toString : function(){
21105 return "[Tree"+(this.id?" "+this.id:"")+"]";
21110 * @class Roo.data.Node
21111 * @extends Roo.util.Observable
21112 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21113 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21115 * @param {Object} attributes The attributes/config for the node
21117 Roo.data.Node = function(attributes){
21119 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21122 this.attributes = attributes || {};
21123 this.leaf = this.attributes.leaf;
21125 * The node id. @type String
21127 this.id = this.attributes.id;
21129 this.id = Roo.id(null, "ynode-");
21130 this.attributes.id = this.id;
21133 * All child nodes of this node. @type Array
21135 this.childNodes = [];
21136 if(!this.childNodes.indexOf){ // indexOf is a must
21137 this.childNodes.indexOf = function(o){
21138 for(var i = 0, len = this.length; i < len; i++){
21147 * The parent node for this node. @type Node
21149 this.parentNode = null;
21151 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21153 this.firstChild = null;
21155 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21157 this.lastChild = null;
21159 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21161 this.previousSibling = null;
21163 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21165 this.nextSibling = null;
21170 * Fires when a new child node is appended
21171 * @param {Tree} tree The owner tree
21172 * @param {Node} this This node
21173 * @param {Node} node The newly appended node
21174 * @param {Number} index The index of the newly appended node
21179 * Fires when a child node is removed
21180 * @param {Tree} tree The owner tree
21181 * @param {Node} this This node
21182 * @param {Node} node The removed node
21187 * Fires when this node is moved to a new location in the tree
21188 * @param {Tree} tree The owner tree
21189 * @param {Node} this This node
21190 * @param {Node} oldParent The old parent of this node
21191 * @param {Node} newParent The new parent of this node
21192 * @param {Number} index The index it was moved to
21197 * Fires when a new child node is inserted.
21198 * @param {Tree} tree The owner tree
21199 * @param {Node} this This node
21200 * @param {Node} node The child node inserted
21201 * @param {Node} refNode The child node the node was inserted before
21205 * @event beforeappend
21206 * Fires before a new child is appended, return false to cancel the append.
21207 * @param {Tree} tree The owner tree
21208 * @param {Node} this This node
21209 * @param {Node} node The child node to be appended
21211 "beforeappend" : true,
21213 * @event beforeremove
21214 * Fires before a child is removed, return false to cancel the remove.
21215 * @param {Tree} tree The owner tree
21216 * @param {Node} this This node
21217 * @param {Node} node The child node to be removed
21219 "beforeremove" : true,
21221 * @event beforemove
21222 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21223 * @param {Tree} tree The owner tree
21224 * @param {Node} this This node
21225 * @param {Node} oldParent The parent of this node
21226 * @param {Node} newParent The new parent this node is moving to
21227 * @param {Number} index The index it is being moved to
21229 "beforemove" : true,
21231 * @event beforeinsert
21232 * Fires before a new child is inserted, return false to cancel the insert.
21233 * @param {Tree} tree The owner tree
21234 * @param {Node} this This node
21235 * @param {Node} node The child node to be inserted
21236 * @param {Node} refNode The child node the node is being inserted before
21238 "beforeinsert" : true
21240 this.listeners = this.attributes.listeners;
21241 Roo.data.Node.superclass.constructor.call(this);
21244 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21245 fireEvent : function(evtName){
21246 // first do standard event for this node
21247 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21250 // then bubble it up to the tree if the event wasn't cancelled
21251 var ot = this.getOwnerTree();
21253 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21261 * Returns true if this node is a leaf
21262 * @return {Boolean}
21264 isLeaf : function(){
21265 return this.leaf === true;
21269 setFirstChild : function(node){
21270 this.firstChild = node;
21274 setLastChild : function(node){
21275 this.lastChild = node;
21280 * Returns true if this node is the last child of its parent
21281 * @return {Boolean}
21283 isLast : function(){
21284 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21288 * Returns true if this node is the first child of its parent
21289 * @return {Boolean}
21291 isFirst : function(){
21292 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21295 hasChildNodes : function(){
21296 return !this.isLeaf() && this.childNodes.length > 0;
21300 * Insert node(s) as the last child node of this node.
21301 * @param {Node/Array} node The node or Array of nodes to append
21302 * @return {Node} The appended node if single append, or null if an array was passed
21304 appendChild : function(node){
21306 if(node instanceof Array){
21308 }else if(arguments.length > 1){
21311 // if passed an array or multiple args do them one by one
21313 for(var i = 0, len = multi.length; i < len; i++) {
21314 this.appendChild(multi[i]);
21317 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21320 var index = this.childNodes.length;
21321 var oldParent = node.parentNode;
21322 // it's a move, make sure we move it cleanly
21324 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21327 oldParent.removeChild(node);
21329 index = this.childNodes.length;
21331 this.setFirstChild(node);
21333 this.childNodes.push(node);
21334 node.parentNode = this;
21335 var ps = this.childNodes[index-1];
21337 node.previousSibling = ps;
21338 ps.nextSibling = node;
21340 node.previousSibling = null;
21342 node.nextSibling = null;
21343 this.setLastChild(node);
21344 node.setOwnerTree(this.getOwnerTree());
21345 this.fireEvent("append", this.ownerTree, this, node, index);
21347 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21354 * Removes a child node from this node.
21355 * @param {Node} node The node to remove
21356 * @return {Node} The removed node
21358 removeChild : function(node){
21359 var index = this.childNodes.indexOf(node);
21363 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21367 // remove it from childNodes collection
21368 this.childNodes.splice(index, 1);
21371 if(node.previousSibling){
21372 node.previousSibling.nextSibling = node.nextSibling;
21374 if(node.nextSibling){
21375 node.nextSibling.previousSibling = node.previousSibling;
21378 // update child refs
21379 if(this.firstChild == node){
21380 this.setFirstChild(node.nextSibling);
21382 if(this.lastChild == node){
21383 this.setLastChild(node.previousSibling);
21386 node.setOwnerTree(null);
21387 // clear any references from the node
21388 node.parentNode = null;
21389 node.previousSibling = null;
21390 node.nextSibling = null;
21391 this.fireEvent("remove", this.ownerTree, this, node);
21396 * Inserts the first node before the second node in this nodes childNodes collection.
21397 * @param {Node} node The node to insert
21398 * @param {Node} refNode The node to insert before (if null the node is appended)
21399 * @return {Node} The inserted node
21401 insertBefore : function(node, refNode){
21402 if(!refNode){ // like standard Dom, refNode can be null for append
21403 return this.appendChild(node);
21406 if(node == refNode){
21410 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21413 var index = this.childNodes.indexOf(refNode);
21414 var oldParent = node.parentNode;
21415 var refIndex = index;
21417 // when moving internally, indexes will change after remove
21418 if(oldParent == this && this.childNodes.indexOf(node) < index){
21422 // it's a move, make sure we move it cleanly
21424 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21427 oldParent.removeChild(node);
21430 this.setFirstChild(node);
21432 this.childNodes.splice(refIndex, 0, node);
21433 node.parentNode = this;
21434 var ps = this.childNodes[refIndex-1];
21436 node.previousSibling = ps;
21437 ps.nextSibling = node;
21439 node.previousSibling = null;
21441 node.nextSibling = refNode;
21442 refNode.previousSibling = node;
21443 node.setOwnerTree(this.getOwnerTree());
21444 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21446 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21452 * Returns the child node at the specified index.
21453 * @param {Number} index
21456 item : function(index){
21457 return this.childNodes[index];
21461 * Replaces one child node in this node with another.
21462 * @param {Node} newChild The replacement node
21463 * @param {Node} oldChild The node to replace
21464 * @return {Node} The replaced node
21466 replaceChild : function(newChild, oldChild){
21467 this.insertBefore(newChild, oldChild);
21468 this.removeChild(oldChild);
21473 * Returns the index of a child node
21474 * @param {Node} node
21475 * @return {Number} The index of the node or -1 if it was not found
21477 indexOf : function(child){
21478 return this.childNodes.indexOf(child);
21482 * Returns the tree this node is in.
21485 getOwnerTree : function(){
21486 // if it doesn't have one, look for one
21487 if(!this.ownerTree){
21491 this.ownerTree = p.ownerTree;
21497 return this.ownerTree;
21501 * Returns depth of this node (the root node has a depth of 0)
21504 getDepth : function(){
21507 while(p.parentNode){
21515 setOwnerTree : function(tree){
21516 // if it's move, we need to update everyone
21517 if(tree != this.ownerTree){
21518 if(this.ownerTree){
21519 this.ownerTree.unregisterNode(this);
21521 this.ownerTree = tree;
21522 var cs = this.childNodes;
21523 for(var i = 0, len = cs.length; i < len; i++) {
21524 cs[i].setOwnerTree(tree);
21527 tree.registerNode(this);
21533 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21534 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21535 * @return {String} The path
21537 getPath : function(attr){
21538 attr = attr || "id";
21539 var p = this.parentNode;
21540 var b = [this.attributes[attr]];
21542 b.unshift(p.attributes[attr]);
21545 var sep = this.getOwnerTree().pathSeparator;
21546 return sep + b.join(sep);
21550 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21551 * function call will be the scope provided or the current node. The arguments to the function
21552 * will be the args provided or the current node. If the function returns false at any point,
21553 * the bubble is stopped.
21554 * @param {Function} fn The function to call
21555 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21556 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21558 bubble : function(fn, scope, args){
21561 if(fn.call(scope || p, args || p) === false){
21569 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21570 * function call will be the scope provided or the current node. The arguments to the function
21571 * will be the args provided or the current node. If the function returns false at any point,
21572 * the cascade is stopped on that branch.
21573 * @param {Function} fn The function to call
21574 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21575 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21577 cascade : function(fn, scope, args){
21578 if(fn.call(scope || this, args || this) !== false){
21579 var cs = this.childNodes;
21580 for(var i = 0, len = cs.length; i < len; i++) {
21581 cs[i].cascade(fn, scope, args);
21587 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21588 * function call will be the scope provided or the current node. The arguments to the function
21589 * will be the args provided or the current node. If the function returns false at any point,
21590 * the iteration stops.
21591 * @param {Function} fn The function to call
21592 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21593 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21595 eachChild : function(fn, scope, args){
21596 var cs = this.childNodes;
21597 for(var i = 0, len = cs.length; i < len; i++) {
21598 if(fn.call(scope || this, args || cs[i]) === false){
21605 * Finds the first child that has the attribute with the specified value.
21606 * @param {String} attribute The attribute name
21607 * @param {Mixed} value The value to search for
21608 * @return {Node} The found child or null if none was found
21610 findChild : function(attribute, value){
21611 var cs = this.childNodes;
21612 for(var i = 0, len = cs.length; i < len; i++) {
21613 if(cs[i].attributes[attribute] == value){
21621 * Finds the first child by a custom function. The child matches if the function passed
21623 * @param {Function} fn
21624 * @param {Object} scope (optional)
21625 * @return {Node} The found child or null if none was found
21627 findChildBy : function(fn, scope){
21628 var cs = this.childNodes;
21629 for(var i = 0, len = cs.length; i < len; i++) {
21630 if(fn.call(scope||cs[i], cs[i]) === true){
21638 * Sorts this nodes children using the supplied sort function
21639 * @param {Function} fn
21640 * @param {Object} scope (optional)
21642 sort : function(fn, scope){
21643 var cs = this.childNodes;
21644 var len = cs.length;
21646 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21648 for(var i = 0; i < len; i++){
21650 n.previousSibling = cs[i-1];
21651 n.nextSibling = cs[i+1];
21653 this.setFirstChild(n);
21656 this.setLastChild(n);
21663 * Returns true if this node is an ancestor (at any point) of the passed node.
21664 * @param {Node} node
21665 * @return {Boolean}
21667 contains : function(node){
21668 return node.isAncestor(this);
21672 * Returns true if the passed node is an ancestor (at any point) of this node.
21673 * @param {Node} node
21674 * @return {Boolean}
21676 isAncestor : function(node){
21677 var p = this.parentNode;
21687 toString : function(){
21688 return "[Node"+(this.id?" "+this.id:"")+"]";
21692 * Ext JS Library 1.1.1
21693 * Copyright(c) 2006-2007, Ext JS, LLC.
21695 * Originally Released Under LGPL - original licence link has changed is not relivant.
21698 * <script type="text/javascript">
21703 * @class Roo.ComponentMgr
21704 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21707 Roo.ComponentMgr = function(){
21708 var all = new Roo.util.MixedCollection();
21712 * Registers a component.
21713 * @param {Roo.Component} c The component
21715 register : function(c){
21720 * Unregisters a component.
21721 * @param {Roo.Component} c The component
21723 unregister : function(c){
21728 * Returns a component by id
21729 * @param {String} id The component id
21731 get : function(id){
21732 return all.get(id);
21736 * Registers a function that will be called when a specified component is added to ComponentMgr
21737 * @param {String} id The component id
21738 * @param {Funtction} fn The callback function
21739 * @param {Object} scope The scope of the callback
21741 onAvailable : function(id, fn, scope){
21742 all.on("add", function(index, o){
21744 fn.call(scope || o, o);
21745 all.un("add", fn, scope);
21752 * Ext JS Library 1.1.1
21753 * Copyright(c) 2006-2007, Ext JS, LLC.
21755 * Originally Released Under LGPL - original licence link has changed is not relivant.
21758 * <script type="text/javascript">
21762 * @class Roo.Component
21763 * @extends Roo.util.Observable
21764 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21765 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21766 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21767 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21768 * All visual components (widgets) that require rendering into a layout should subclass Component.
21770 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21771 * 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
21772 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21774 Roo.Component = function(config){
21775 config = config || {};
21776 if(config.tagName || config.dom || typeof config == "string"){ // element object
21777 config = {el: config, id: config.id || config};
21779 this.initialConfig = config;
21781 Roo.apply(this, config);
21785 * Fires after the component is disabled.
21786 * @param {Roo.Component} this
21791 * Fires after the component is enabled.
21792 * @param {Roo.Component} this
21796 * @event beforeshow
21797 * Fires before the component is shown. Return false to stop the show.
21798 * @param {Roo.Component} this
21803 * Fires after the component is shown.
21804 * @param {Roo.Component} this
21808 * @event beforehide
21809 * Fires before the component is hidden. Return false to stop the hide.
21810 * @param {Roo.Component} this
21815 * Fires after the component is hidden.
21816 * @param {Roo.Component} this
21820 * @event beforerender
21821 * Fires before the component is rendered. Return false to stop the render.
21822 * @param {Roo.Component} this
21824 beforerender : true,
21827 * Fires after the component is rendered.
21828 * @param {Roo.Component} this
21832 * @event beforedestroy
21833 * Fires before the component is destroyed. Return false to stop the destroy.
21834 * @param {Roo.Component} this
21836 beforedestroy : true,
21839 * Fires after the component is destroyed.
21840 * @param {Roo.Component} this
21845 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21847 Roo.ComponentMgr.register(this);
21848 Roo.Component.superclass.constructor.call(this);
21849 this.initComponent();
21850 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21851 this.render(this.renderTo);
21852 delete this.renderTo;
21857 Roo.Component.AUTO_ID = 1000;
21859 Roo.extend(Roo.Component, Roo.util.Observable, {
21861 * @property {Boolean} hidden
21862 * true if this component is hidden. Read-only.
21866 * true if this component is disabled. Read-only.
21870 * true if this component has been rendered. Read-only.
21874 /** @cfg {String} disableClass
21875 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21877 disabledClass : "x-item-disabled",
21878 /** @cfg {Boolean} allowDomMove
21879 * Whether the component can move the Dom node when rendering (defaults to true).
21881 allowDomMove : true,
21882 /** @cfg {String} hideMode
21883 * How this component should hidden. Supported values are
21884 * "visibility" (css visibility), "offsets" (negative offset position) and
21885 * "display" (css display) - defaults to "display".
21887 hideMode: 'display',
21890 ctype : "Roo.Component",
21892 /** @cfg {String} actionMode
21893 * which property holds the element that used for hide() / show() / disable() / enable()
21899 getActionEl : function(){
21900 return this[this.actionMode];
21903 initComponent : Roo.emptyFn,
21905 * If this is a lazy rendering component, render it to its container element.
21906 * @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.
21908 render : function(container, position){
21909 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21910 if(!container && this.el){
21911 this.el = Roo.get(this.el);
21912 container = this.el.dom.parentNode;
21913 this.allowDomMove = false;
21915 this.container = Roo.get(container);
21916 this.rendered = true;
21917 if(position !== undefined){
21918 if(typeof position == 'number'){
21919 position = this.container.dom.childNodes[position];
21921 position = Roo.getDom(position);
21924 this.onRender(this.container, position || null);
21926 this.el.addClass(this.cls);
21930 this.el.applyStyles(this.style);
21933 this.fireEvent("render", this);
21934 this.afterRender(this.container);
21946 // default function is not really useful
21947 onRender : function(ct, position){
21949 this.el = Roo.get(this.el);
21950 if(this.allowDomMove !== false){
21951 ct.dom.insertBefore(this.el.dom, position);
21957 getAutoCreate : function(){
21958 var cfg = typeof this.autoCreate == "object" ?
21959 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21960 if(this.id && !cfg.id){
21967 afterRender : Roo.emptyFn,
21970 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21971 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21973 destroy : function(){
21974 if(this.fireEvent("beforedestroy", this) !== false){
21975 this.purgeListeners();
21976 this.beforeDestroy();
21978 this.el.removeAllListeners();
21980 if(this.actionMode == "container"){
21981 this.container.remove();
21985 Roo.ComponentMgr.unregister(this);
21986 this.fireEvent("destroy", this);
21991 beforeDestroy : function(){
21996 onDestroy : function(){
22001 * Returns the underlying {@link Roo.Element}.
22002 * @return {Roo.Element} The element
22004 getEl : function(){
22009 * Returns the id of this component.
22012 getId : function(){
22017 * Try to focus this component.
22018 * @param {Boolean} selectText True to also select the text in this component (if applicable)
22019 * @return {Roo.Component} this
22021 focus : function(selectText){
22024 if(selectText === true){
22025 this.el.dom.select();
22040 * Disable this component.
22041 * @return {Roo.Component} this
22043 disable : function(){
22047 this.disabled = true;
22048 this.fireEvent("disable", this);
22053 onDisable : function(){
22054 this.getActionEl().addClass(this.disabledClass);
22055 this.el.dom.disabled = true;
22059 * Enable this component.
22060 * @return {Roo.Component} this
22062 enable : function(){
22066 this.disabled = false;
22067 this.fireEvent("enable", this);
22072 onEnable : function(){
22073 this.getActionEl().removeClass(this.disabledClass);
22074 this.el.dom.disabled = false;
22078 * Convenience function for setting disabled/enabled by boolean.
22079 * @param {Boolean} disabled
22081 setDisabled : function(disabled){
22082 this[disabled ? "disable" : "enable"]();
22086 * Show this component.
22087 * @return {Roo.Component} this
22090 if(this.fireEvent("beforeshow", this) !== false){
22091 this.hidden = false;
22095 this.fireEvent("show", this);
22101 onShow : function(){
22102 var ae = this.getActionEl();
22103 if(this.hideMode == 'visibility'){
22104 ae.dom.style.visibility = "visible";
22105 }else if(this.hideMode == 'offsets'){
22106 ae.removeClass('x-hidden');
22108 ae.dom.style.display = "";
22113 * Hide this component.
22114 * @return {Roo.Component} this
22117 if(this.fireEvent("beforehide", this) !== false){
22118 this.hidden = true;
22122 this.fireEvent("hide", this);
22128 onHide : function(){
22129 var ae = this.getActionEl();
22130 if(this.hideMode == 'visibility'){
22131 ae.dom.style.visibility = "hidden";
22132 }else if(this.hideMode == 'offsets'){
22133 ae.addClass('x-hidden');
22135 ae.dom.style.display = "none";
22140 * Convenience function to hide or show this component by boolean.
22141 * @param {Boolean} visible True to show, false to hide
22142 * @return {Roo.Component} this
22144 setVisible: function(visible){
22154 * Returns true if this component is visible.
22156 isVisible : function(){
22157 return this.getActionEl().isVisible();
22160 cloneConfig : function(overrides){
22161 overrides = overrides || {};
22162 var id = overrides.id || Roo.id();
22163 var cfg = Roo.applyIf(overrides, this.initialConfig);
22164 cfg.id = id; // prevent dup id
22165 return new this.constructor(cfg);
22169 * Ext JS Library 1.1.1
22170 * Copyright(c) 2006-2007, Ext JS, LLC.
22172 * Originally Released Under LGPL - original licence link has changed is not relivant.
22175 * <script type="text/javascript">
22180 * @extends Roo.Element
22181 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22182 * automatic maintaining of shadow/shim positions.
22183 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22184 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22185 * you can pass a string with a CSS class name. False turns off the shadow.
22186 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22187 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22188 * @cfg {String} cls CSS class to add to the element
22189 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22190 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22192 * @param {Object} config An object with config options.
22193 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22196 Roo.Layer = function(config, existingEl){
22197 config = config || {};
22198 var dh = Roo.DomHelper;
22199 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22201 this.dom = Roo.getDom(existingEl);
22204 var o = config.dh || {tag: "div", cls: "x-layer"};
22205 this.dom = dh.append(pel, o);
22208 this.addClass(config.cls);
22210 this.constrain = config.constrain !== false;
22211 this.visibilityMode = Roo.Element.VISIBILITY;
22213 this.id = this.dom.id = config.id;
22215 this.id = Roo.id(this.dom);
22217 this.zindex = config.zindex || this.getZIndex();
22218 this.position("absolute", this.zindex);
22220 this.shadowOffset = config.shadowOffset || 4;
22221 this.shadow = new Roo.Shadow({
22222 offset : this.shadowOffset,
22223 mode : config.shadow
22226 this.shadowOffset = 0;
22228 this.useShim = config.shim !== false && Roo.useShims;
22229 this.useDisplay = config.useDisplay;
22233 var supr = Roo.Element.prototype;
22235 // shims are shared among layer to keep from having 100 iframes
22238 Roo.extend(Roo.Layer, Roo.Element, {
22240 getZIndex : function(){
22241 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22244 getShim : function(){
22251 var shim = shims.shift();
22253 shim = this.createShim();
22254 shim.enableDisplayMode('block');
22255 shim.dom.style.display = 'none';
22256 shim.dom.style.visibility = 'visible';
22258 var pn = this.dom.parentNode;
22259 if(shim.dom.parentNode != pn){
22260 pn.insertBefore(shim.dom, this.dom);
22262 shim.setStyle('z-index', this.getZIndex()-2);
22267 hideShim : function(){
22269 this.shim.setDisplayed(false);
22270 shims.push(this.shim);
22275 disableShadow : function(){
22277 this.shadowDisabled = true;
22278 this.shadow.hide();
22279 this.lastShadowOffset = this.shadowOffset;
22280 this.shadowOffset = 0;
22284 enableShadow : function(show){
22286 this.shadowDisabled = false;
22287 this.shadowOffset = this.lastShadowOffset;
22288 delete this.lastShadowOffset;
22296 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22297 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22298 sync : function(doShow){
22299 var sw = this.shadow;
22300 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22301 var sh = this.getShim();
22303 var w = this.getWidth(),
22304 h = this.getHeight();
22306 var l = this.getLeft(true),
22307 t = this.getTop(true);
22309 if(sw && !this.shadowDisabled){
22310 if(doShow && !sw.isVisible()){
22313 sw.realign(l, t, w, h);
22319 // fit the shim behind the shadow, so it is shimmed too
22320 var a = sw.adjusts, s = sh.dom.style;
22321 s.left = (Math.min(l, l+a.l))+"px";
22322 s.top = (Math.min(t, t+a.t))+"px";
22323 s.width = (w+a.w)+"px";
22324 s.height = (h+a.h)+"px";
22331 sh.setLeftTop(l, t);
22338 destroy : function(){
22341 this.shadow.hide();
22343 this.removeAllListeners();
22344 var pn = this.dom.parentNode;
22346 pn.removeChild(this.dom);
22348 Roo.Element.uncache(this.id);
22351 remove : function(){
22356 beginUpdate : function(){
22357 this.updating = true;
22361 endUpdate : function(){
22362 this.updating = false;
22367 hideUnders : function(negOffset){
22369 this.shadow.hide();
22375 constrainXY : function(){
22376 if(this.constrain){
22377 var vw = Roo.lib.Dom.getViewWidth(),
22378 vh = Roo.lib.Dom.getViewHeight();
22379 var s = Roo.get(document).getScroll();
22381 var xy = this.getXY();
22382 var x = xy[0], y = xy[1];
22383 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22384 // only move it if it needs it
22386 // first validate right/bottom
22387 if((x + w) > vw+s.left){
22388 x = vw - w - this.shadowOffset;
22391 if((y + h) > vh+s.top){
22392 y = vh - h - this.shadowOffset;
22395 // then make sure top/left isn't negative
22406 var ay = this.avoidY;
22407 if(y <= ay && (y+h) >= ay){
22413 supr.setXY.call(this, xy);
22419 isVisible : function(){
22420 return this.visible;
22424 showAction : function(){
22425 this.visible = true; // track visibility to prevent getStyle calls
22426 if(this.useDisplay === true){
22427 this.setDisplayed("");
22428 }else if(this.lastXY){
22429 supr.setXY.call(this, this.lastXY);
22430 }else if(this.lastLT){
22431 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22436 hideAction : function(){
22437 this.visible = false;
22438 if(this.useDisplay === true){
22439 this.setDisplayed(false);
22441 this.setLeftTop(-10000,-10000);
22445 // overridden Element method
22446 setVisible : function(v, a, d, c, e){
22451 var cb = function(){
22456 }.createDelegate(this);
22457 supr.setVisible.call(this, true, true, d, cb, e);
22460 this.hideUnders(true);
22469 }.createDelegate(this);
22471 supr.setVisible.call(this, v, a, d, cb, e);
22480 storeXY : function(xy){
22481 delete this.lastLT;
22485 storeLeftTop : function(left, top){
22486 delete this.lastXY;
22487 this.lastLT = [left, top];
22491 beforeFx : function(){
22492 this.beforeAction();
22493 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22497 afterFx : function(){
22498 Roo.Layer.superclass.afterFx.apply(this, arguments);
22499 this.sync(this.isVisible());
22503 beforeAction : function(){
22504 if(!this.updating && this.shadow){
22505 this.shadow.hide();
22509 // overridden Element method
22510 setLeft : function(left){
22511 this.storeLeftTop(left, this.getTop(true));
22512 supr.setLeft.apply(this, arguments);
22516 setTop : function(top){
22517 this.storeLeftTop(this.getLeft(true), top);
22518 supr.setTop.apply(this, arguments);
22522 setLeftTop : function(left, top){
22523 this.storeLeftTop(left, top);
22524 supr.setLeftTop.apply(this, arguments);
22528 setXY : function(xy, a, d, c, e){
22530 this.beforeAction();
22532 var cb = this.createCB(c);
22533 supr.setXY.call(this, xy, a, d, cb, e);
22540 createCB : function(c){
22551 // overridden Element method
22552 setX : function(x, a, d, c, e){
22553 this.setXY([x, this.getY()], a, d, c, e);
22556 // overridden Element method
22557 setY : function(y, a, d, c, e){
22558 this.setXY([this.getX(), y], a, d, c, e);
22561 // overridden Element method
22562 setSize : function(w, h, a, d, c, e){
22563 this.beforeAction();
22564 var cb = this.createCB(c);
22565 supr.setSize.call(this, w, h, a, d, cb, e);
22571 // overridden Element method
22572 setWidth : function(w, a, d, c, e){
22573 this.beforeAction();
22574 var cb = this.createCB(c);
22575 supr.setWidth.call(this, w, a, d, cb, e);
22581 // overridden Element method
22582 setHeight : function(h, a, d, c, e){
22583 this.beforeAction();
22584 var cb = this.createCB(c);
22585 supr.setHeight.call(this, h, a, d, cb, e);
22591 // overridden Element method
22592 setBounds : function(x, y, w, h, a, d, c, e){
22593 this.beforeAction();
22594 var cb = this.createCB(c);
22596 this.storeXY([x, y]);
22597 supr.setXY.call(this, [x, y]);
22598 supr.setSize.call(this, w, h, a, d, cb, e);
22601 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22607 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22608 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22609 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22610 * @param {Number} zindex The new z-index to set
22611 * @return {this} The Layer
22613 setZIndex : function(zindex){
22614 this.zindex = zindex;
22615 this.setStyle("z-index", zindex + 2);
22617 this.shadow.setZIndex(zindex + 1);
22620 this.shim.setStyle("z-index", zindex);
22626 * Ext JS Library 1.1.1
22627 * Copyright(c) 2006-2007, Ext JS, LLC.
22629 * Originally Released Under LGPL - original licence link has changed is not relivant.
22632 * <script type="text/javascript">
22637 * @class Roo.Shadow
22638 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22639 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22640 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22642 * Create a new Shadow
22643 * @param {Object} config The config object
22645 Roo.Shadow = function(config){
22646 Roo.apply(this, config);
22647 if(typeof this.mode != "string"){
22648 this.mode = this.defaultMode;
22650 var o = this.offset, a = {h: 0};
22651 var rad = Math.floor(this.offset/2);
22652 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22658 a.l -= this.offset + rad;
22659 a.t -= this.offset + rad;
22670 a.l -= (this.offset - rad);
22671 a.t -= this.offset + rad;
22673 a.w -= (this.offset - rad)*2;
22684 a.l -= (this.offset - rad);
22685 a.t -= (this.offset - rad);
22687 a.w -= (this.offset + rad + 1);
22688 a.h -= (this.offset + rad);
22697 Roo.Shadow.prototype = {
22699 * @cfg {String} mode
22700 * The shadow display mode. Supports the following options:<br />
22701 * sides: Shadow displays on both sides and bottom only<br />
22702 * frame: Shadow displays equally on all four sides<br />
22703 * drop: Traditional bottom-right drop shadow (default)
22706 * @cfg {String} offset
22707 * The number of pixels to offset the shadow from the element (defaults to 4)
22712 defaultMode: "drop",
22715 * Displays the shadow under the target element
22716 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22718 show : function(target){
22719 target = Roo.get(target);
22721 this.el = Roo.Shadow.Pool.pull();
22722 if(this.el.dom.nextSibling != target.dom){
22723 this.el.insertBefore(target);
22726 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22728 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22731 target.getLeft(true),
22732 target.getTop(true),
22736 this.el.dom.style.display = "block";
22740 * Returns true if the shadow is visible, else false
22742 isVisible : function(){
22743 return this.el ? true : false;
22747 * Direct alignment when values are already available. Show must be called at least once before
22748 * calling this method to ensure it is initialized.
22749 * @param {Number} left The target element left position
22750 * @param {Number} top The target element top position
22751 * @param {Number} width The target element width
22752 * @param {Number} height The target element height
22754 realign : function(l, t, w, h){
22758 var a = this.adjusts, d = this.el.dom, s = d.style;
22760 s.left = (l+a.l)+"px";
22761 s.top = (t+a.t)+"px";
22762 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22764 if(s.width != sws || s.height != shs){
22768 var cn = d.childNodes;
22769 var sww = Math.max(0, (sw-12))+"px";
22770 cn[0].childNodes[1].style.width = sww;
22771 cn[1].childNodes[1].style.width = sww;
22772 cn[2].childNodes[1].style.width = sww;
22773 cn[1].style.height = Math.max(0, (sh-12))+"px";
22779 * Hides this shadow
22783 this.el.dom.style.display = "none";
22784 Roo.Shadow.Pool.push(this.el);
22790 * Adjust the z-index of this shadow
22791 * @param {Number} zindex The new z-index
22793 setZIndex : function(z){
22796 this.el.setStyle("z-index", z);
22801 // Private utility class that manages the internal Shadow cache
22802 Roo.Shadow.Pool = function(){
22804 var markup = Roo.isIE ?
22805 '<div class="x-ie-shadow"></div>' :
22806 '<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>';
22809 var sh = p.shift();
22811 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22812 sh.autoBoxAdjust = false;
22817 push : function(sh){
22823 * Ext JS Library 1.1.1
22824 * Copyright(c) 2006-2007, Ext JS, LLC.
22826 * Originally Released Under LGPL - original licence link has changed is not relivant.
22829 * <script type="text/javascript">
22833 * @class Roo.BoxComponent
22834 * @extends Roo.Component
22835 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22836 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22837 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22838 * layout containers.
22840 * @param {Roo.Element/String/Object} config The configuration options.
22842 Roo.BoxComponent = function(config){
22843 Roo.Component.call(this, config);
22847 * Fires after the component is resized.
22848 * @param {Roo.Component} this
22849 * @param {Number} adjWidth The box-adjusted width that was set
22850 * @param {Number} adjHeight The box-adjusted height that was set
22851 * @param {Number} rawWidth The width that was originally specified
22852 * @param {Number} rawHeight The height that was originally specified
22857 * Fires after the component is moved.
22858 * @param {Roo.Component} this
22859 * @param {Number} x The new x position
22860 * @param {Number} y The new y position
22866 Roo.extend(Roo.BoxComponent, Roo.Component, {
22867 // private, set in afterRender to signify that the component has been rendered
22869 // private, used to defer height settings to subclasses
22870 deferHeight: false,
22871 /** @cfg {Number} width
22872 * width (optional) size of component
22874 /** @cfg {Number} height
22875 * height (optional) size of component
22879 * Sets the width and height of the component. This method fires the resize event. This method can accept
22880 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22881 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22882 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22883 * @return {Roo.BoxComponent} this
22885 setSize : function(w, h){
22886 // support for standard size objects
22887 if(typeof w == 'object'){
22892 if(!this.boxReady){
22898 // prevent recalcs when not needed
22899 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22902 this.lastSize = {width: w, height: h};
22904 var adj = this.adjustSize(w, h);
22905 var aw = adj.width, ah = adj.height;
22906 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22907 var rz = this.getResizeEl();
22908 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22909 rz.setSize(aw, ah);
22910 }else if(!this.deferHeight && ah !== undefined){
22912 }else if(aw !== undefined){
22915 this.onResize(aw, ah, w, h);
22916 this.fireEvent('resize', this, aw, ah, w, h);
22922 * Gets the current size of the component's underlying element.
22923 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22925 getSize : function(){
22926 return this.el.getSize();
22930 * Gets the current XY position of the component's underlying element.
22931 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22932 * @return {Array} The XY position of the element (e.g., [100, 200])
22934 getPosition : function(local){
22935 if(local === true){
22936 return [this.el.getLeft(true), this.el.getTop(true)];
22938 return this.xy || this.el.getXY();
22942 * Gets the current box measurements of the component's underlying element.
22943 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22944 * @returns {Object} box An object in the format {x, y, width, height}
22946 getBox : function(local){
22947 var s = this.el.getSize();
22949 s.x = this.el.getLeft(true);
22950 s.y = this.el.getTop(true);
22952 var xy = this.xy || this.el.getXY();
22960 * Sets the current box measurements of the component's underlying element.
22961 * @param {Object} box An object in the format {x, y, width, height}
22962 * @returns {Roo.BoxComponent} this
22964 updateBox : function(box){
22965 this.setSize(box.width, box.height);
22966 this.setPagePosition(box.x, box.y);
22971 getResizeEl : function(){
22972 return this.resizeEl || this.el;
22976 getPositionEl : function(){
22977 return this.positionEl || this.el;
22981 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22982 * This method fires the move event.
22983 * @param {Number} left The new left
22984 * @param {Number} top The new top
22985 * @returns {Roo.BoxComponent} this
22987 setPosition : function(x, y){
22990 if(!this.boxReady){
22993 var adj = this.adjustPosition(x, y);
22994 var ax = adj.x, ay = adj.y;
22996 var el = this.getPositionEl();
22997 if(ax !== undefined || ay !== undefined){
22998 if(ax !== undefined && ay !== undefined){
22999 el.setLeftTop(ax, ay);
23000 }else if(ax !== undefined){
23002 }else if(ay !== undefined){
23005 this.onPosition(ax, ay);
23006 this.fireEvent('move', this, ax, ay);
23012 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
23013 * This method fires the move event.
23014 * @param {Number} x The new x position
23015 * @param {Number} y The new y position
23016 * @returns {Roo.BoxComponent} this
23018 setPagePosition : function(x, y){
23021 if(!this.boxReady){
23024 if(x === undefined || y === undefined){ // cannot translate undefined points
23027 var p = this.el.translatePoints(x, y);
23028 this.setPosition(p.left, p.top);
23033 onRender : function(ct, position){
23034 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23036 this.resizeEl = Roo.get(this.resizeEl);
23038 if(this.positionEl){
23039 this.positionEl = Roo.get(this.positionEl);
23044 afterRender : function(){
23045 Roo.BoxComponent.superclass.afterRender.call(this);
23046 this.boxReady = true;
23047 this.setSize(this.width, this.height);
23048 if(this.x || this.y){
23049 this.setPosition(this.x, this.y);
23051 if(this.pageX || this.pageY){
23052 this.setPagePosition(this.pageX, this.pageY);
23057 * Force the component's size to recalculate based on the underlying element's current height and width.
23058 * @returns {Roo.BoxComponent} this
23060 syncSize : function(){
23061 delete this.lastSize;
23062 this.setSize(this.el.getWidth(), this.el.getHeight());
23067 * Called after the component is resized, this method is empty by default but can be implemented by any
23068 * subclass that needs to perform custom logic after a resize occurs.
23069 * @param {Number} adjWidth The box-adjusted width that was set
23070 * @param {Number} adjHeight The box-adjusted height that was set
23071 * @param {Number} rawWidth The width that was originally specified
23072 * @param {Number} rawHeight The height that was originally specified
23074 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23079 * Called after the component is moved, this method is empty by default but can be implemented by any
23080 * subclass that needs to perform custom logic after a move occurs.
23081 * @param {Number} x The new x position
23082 * @param {Number} y The new y position
23084 onPosition : function(x, y){
23089 adjustSize : function(w, h){
23090 if(this.autoWidth){
23093 if(this.autoHeight){
23096 return {width : w, height: h};
23100 adjustPosition : function(x, y){
23101 return {x : x, y: y};
23105 * Ext JS Library 1.1.1
23106 * Copyright(c) 2006-2007, Ext JS, LLC.
23108 * Originally Released Under LGPL - original licence link has changed is not relivant.
23111 * <script type="text/javascript">
23116 * @class Roo.SplitBar
23117 * @extends Roo.util.Observable
23118 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23122 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23123 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23124 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23125 split.minSize = 100;
23126 split.maxSize = 600;
23127 split.animate = true;
23128 split.on('moved', splitterMoved);
23131 * Create a new SplitBar
23132 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23133 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23134 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23135 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23136 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23137 position of the SplitBar).
23139 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23142 this.el = Roo.get(dragElement, true);
23143 this.el.dom.unselectable = "on";
23145 this.resizingEl = Roo.get(resizingElement, true);
23149 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23150 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23153 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23156 * The minimum size of the resizing element. (Defaults to 0)
23162 * The maximum size of the resizing element. (Defaults to 2000)
23165 this.maxSize = 2000;
23168 * Whether to animate the transition to the new size
23171 this.animate = false;
23174 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23177 this.useShim = false;
23182 if(!existingProxy){
23184 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23186 this.proxy = Roo.get(existingProxy).dom;
23189 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23192 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23195 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23198 this.dragSpecs = {};
23201 * @private The adapter to use to positon and resize elements
23203 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23204 this.adapter.init(this);
23206 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23208 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23209 this.el.addClass("x-splitbar-h");
23212 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23213 this.el.addClass("x-splitbar-v");
23219 * Fires when the splitter is moved (alias for {@link #event-moved})
23220 * @param {Roo.SplitBar} this
23221 * @param {Number} newSize the new width or height
23226 * Fires when the splitter is moved
23227 * @param {Roo.SplitBar} this
23228 * @param {Number} newSize the new width or height
23232 * @event beforeresize
23233 * Fires before the splitter is dragged
23234 * @param {Roo.SplitBar} this
23236 "beforeresize" : true,
23238 "beforeapply" : true
23241 Roo.util.Observable.call(this);
23244 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23245 onStartProxyDrag : function(x, y){
23246 this.fireEvent("beforeresize", this);
23248 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23250 o.enableDisplayMode("block");
23251 // all splitbars share the same overlay
23252 Roo.SplitBar.prototype.overlay = o;
23254 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23255 this.overlay.show();
23256 Roo.get(this.proxy).setDisplayed("block");
23257 var size = this.adapter.getElementSize(this);
23258 this.activeMinSize = this.getMinimumSize();;
23259 this.activeMaxSize = this.getMaximumSize();;
23260 var c1 = size - this.activeMinSize;
23261 var c2 = Math.max(this.activeMaxSize - size, 0);
23262 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23263 this.dd.resetConstraints();
23264 this.dd.setXConstraint(
23265 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23266 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23268 this.dd.setYConstraint(0, 0);
23270 this.dd.resetConstraints();
23271 this.dd.setXConstraint(0, 0);
23272 this.dd.setYConstraint(
23273 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23274 this.placement == Roo.SplitBar.TOP ? c2 : c1
23277 this.dragSpecs.startSize = size;
23278 this.dragSpecs.startPoint = [x, y];
23279 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23283 * @private Called after the drag operation by the DDProxy
23285 onEndProxyDrag : function(e){
23286 Roo.get(this.proxy).setDisplayed(false);
23287 var endPoint = Roo.lib.Event.getXY(e);
23289 this.overlay.hide();
23292 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23293 newSize = this.dragSpecs.startSize +
23294 (this.placement == Roo.SplitBar.LEFT ?
23295 endPoint[0] - this.dragSpecs.startPoint[0] :
23296 this.dragSpecs.startPoint[0] - endPoint[0]
23299 newSize = this.dragSpecs.startSize +
23300 (this.placement == Roo.SplitBar.TOP ?
23301 endPoint[1] - this.dragSpecs.startPoint[1] :
23302 this.dragSpecs.startPoint[1] - endPoint[1]
23305 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23306 if(newSize != this.dragSpecs.startSize){
23307 if(this.fireEvent('beforeapply', this, newSize) !== false){
23308 this.adapter.setElementSize(this, newSize);
23309 this.fireEvent("moved", this, newSize);
23310 this.fireEvent("resize", this, newSize);
23316 * Get the adapter this SplitBar uses
23317 * @return The adapter object
23319 getAdapter : function(){
23320 return this.adapter;
23324 * Set the adapter this SplitBar uses
23325 * @param {Object} adapter A SplitBar adapter object
23327 setAdapter : function(adapter){
23328 this.adapter = adapter;
23329 this.adapter.init(this);
23333 * Gets the minimum size for the resizing element
23334 * @return {Number} The minimum size
23336 getMinimumSize : function(){
23337 return this.minSize;
23341 * Sets the minimum size for the resizing element
23342 * @param {Number} minSize The minimum size
23344 setMinimumSize : function(minSize){
23345 this.minSize = minSize;
23349 * Gets the maximum size for the resizing element
23350 * @return {Number} The maximum size
23352 getMaximumSize : function(){
23353 return this.maxSize;
23357 * Sets the maximum size for the resizing element
23358 * @param {Number} maxSize The maximum size
23360 setMaximumSize : function(maxSize){
23361 this.maxSize = maxSize;
23365 * Sets the initialize size for the resizing element
23366 * @param {Number} size The initial size
23368 setCurrentSize : function(size){
23369 var oldAnimate = this.animate;
23370 this.animate = false;
23371 this.adapter.setElementSize(this, size);
23372 this.animate = oldAnimate;
23376 * Destroy this splitbar.
23377 * @param {Boolean} removeEl True to remove the element
23379 destroy : function(removeEl){
23381 this.shim.remove();
23384 this.proxy.parentNode.removeChild(this.proxy);
23392 * @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.
23394 Roo.SplitBar.createProxy = function(dir){
23395 var proxy = new Roo.Element(document.createElement("div"));
23396 proxy.unselectable();
23397 var cls = 'x-splitbar-proxy';
23398 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23399 document.body.appendChild(proxy.dom);
23404 * @class Roo.SplitBar.BasicLayoutAdapter
23405 * Default Adapter. It assumes the splitter and resizing element are not positioned
23406 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23408 Roo.SplitBar.BasicLayoutAdapter = function(){
23411 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23412 // do nothing for now
23413 init : function(s){
23417 * Called before drag operations to get the current size of the resizing element.
23418 * @param {Roo.SplitBar} s The SplitBar using this adapter
23420 getElementSize : function(s){
23421 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23422 return s.resizingEl.getWidth();
23424 return s.resizingEl.getHeight();
23429 * Called after drag operations to set the size of the resizing element.
23430 * @param {Roo.SplitBar} s The SplitBar using this adapter
23431 * @param {Number} newSize The new size to set
23432 * @param {Function} onComplete A function to be invoked when resizing is complete
23434 setElementSize : function(s, newSize, onComplete){
23435 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23437 s.resizingEl.setWidth(newSize);
23439 onComplete(s, newSize);
23442 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23447 s.resizingEl.setHeight(newSize);
23449 onComplete(s, newSize);
23452 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23459 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23460 * @extends Roo.SplitBar.BasicLayoutAdapter
23461 * Adapter that moves the splitter element to align with the resized sizing element.
23462 * Used with an absolute positioned SplitBar.
23463 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23464 * document.body, make sure you assign an id to the body element.
23466 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23467 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23468 this.container = Roo.get(container);
23471 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23472 init : function(s){
23473 this.basic.init(s);
23476 getElementSize : function(s){
23477 return this.basic.getElementSize(s);
23480 setElementSize : function(s, newSize, onComplete){
23481 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23484 moveSplitter : function(s){
23485 var yes = Roo.SplitBar;
23486 switch(s.placement){
23488 s.el.setX(s.resizingEl.getRight());
23491 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23494 s.el.setY(s.resizingEl.getBottom());
23497 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23504 * Orientation constant - Create a vertical SplitBar
23508 Roo.SplitBar.VERTICAL = 1;
23511 * Orientation constant - Create a horizontal SplitBar
23515 Roo.SplitBar.HORIZONTAL = 2;
23518 * Placement constant - The resizing element is to the left of the splitter element
23522 Roo.SplitBar.LEFT = 1;
23525 * Placement constant - The resizing element is to the right of the splitter element
23529 Roo.SplitBar.RIGHT = 2;
23532 * Placement constant - The resizing element is positioned above the splitter element
23536 Roo.SplitBar.TOP = 3;
23539 * Placement constant - The resizing element is positioned under splitter element
23543 Roo.SplitBar.BOTTOM = 4;
23546 * Ext JS Library 1.1.1
23547 * Copyright(c) 2006-2007, Ext JS, LLC.
23549 * Originally Released Under LGPL - original licence link has changed is not relivant.
23552 * <script type="text/javascript">
23557 * @extends Roo.util.Observable
23558 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23559 * This class also supports single and multi selection modes. <br>
23560 * Create a data model bound view:
23562 var store = new Roo.data.Store(...);
23564 var view = new Roo.View({
23566 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
23568 singleSelect: true,
23569 selectedClass: "ydataview-selected",
23573 // listen for node click?
23574 view.on("click", function(vw, index, node, e){
23575 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23579 dataModel.load("foobar.xml");
23581 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23583 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23584 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23586 * Note: old style constructor is still suported (container, template, config)
23589 * Create a new View
23590 * @param {Object} config The config object
23593 Roo.View = function(config, depreciated_tpl, depreciated_config){
23595 if (typeof(depreciated_tpl) == 'undefined') {
23596 // new way.. - universal constructor.
23597 Roo.apply(this, config);
23598 this.el = Roo.get(this.el);
23601 this.el = Roo.get(config);
23602 this.tpl = depreciated_tpl;
23603 Roo.apply(this, depreciated_config);
23607 if(typeof(this.tpl) == "string"){
23608 this.tpl = new Roo.Template(this.tpl);
23610 // support xtype ctors..
23611 this.tpl = new Roo.factory(this.tpl, Roo);
23615 this.tpl.compile();
23622 * @event beforeclick
23623 * Fires before a click is processed. Returns false to cancel the default action.
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
23629 "beforeclick" : true,
23632 * Fires when a template node is 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
23641 * Fires when a template node is double 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
23649 * @event contextmenu
23650 * Fires when a template node is right clicked.
23651 * @param {Roo.View} this
23652 * @param {Number} index The index of the target node
23653 * @param {HTMLElement} node The target node
23654 * @param {Roo.EventObject} e The raw event object
23656 "contextmenu" : true,
23658 * @event selectionchange
23659 * Fires when the selected nodes change.
23660 * @param {Roo.View} this
23661 * @param {Array} selections Array of the selected nodes
23663 "selectionchange" : true,
23666 * @event beforeselect
23667 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23668 * @param {Roo.View} this
23669 * @param {HTMLElement} node The node to be selected
23670 * @param {Array} selections Array of currently selected nodes
23672 "beforeselect" : true
23676 "click": this.onClick,
23677 "dblclick": this.onDblClick,
23678 "contextmenu": this.onContextMenu,
23682 this.selections = [];
23684 this.cmp = new Roo.CompositeElementLite([]);
23686 this.store = Roo.factory(this.store, Roo.data);
23687 this.setStore(this.store, true);
23689 Roo.View.superclass.constructor.call(this);
23692 Roo.extend(Roo.View, Roo.util.Observable, {
23695 * @cfg {Roo.data.Store} store Data store to load data from.
23700 * @cfg {String|Roo.Element} el The container element.
23705 * @cfg {String|Roo.Template} tpl The template used by this View
23710 * @cfg {String} selectedClass The css class to add to selected nodes
23712 selectedClass : "x-view-selected",
23714 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23718 * @cfg {Boolean} multiSelect Allow multiple selection
23721 multiSelect : false,
23723 * @cfg {Boolean} singleSelect Allow single selection
23725 singleSelect: false,
23728 * Returns the element this view is bound to.
23729 * @return {Roo.Element}
23731 getEl : function(){
23736 * Refreshes the view.
23738 refresh : function(){
23740 this.clearSelections();
23741 this.el.update("");
23743 var records = this.store.getRange();
23744 if(records.length < 1){
23745 this.el.update(this.emptyText);
23748 for(var i = 0, len = records.length; i < len; i++){
23749 var data = this.prepareData(records[i].data, i, records[i]);
23750 html[html.length] = t.apply(data);
23752 this.el.update(html.join(""));
23753 this.nodes = this.el.dom.childNodes;
23754 this.updateIndexes(0);
23758 * Function to override to reformat the data that is sent to
23759 * the template for each node.
23760 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23761 * a JSON object for an UpdateManager bound view).
23763 prepareData : function(data){
23767 onUpdate : function(ds, record){
23768 this.clearSelections();
23769 var index = this.store.indexOf(record);
23770 var n = this.nodes[index];
23771 this.tpl.insertBefore(n, this.prepareData(record.data));
23772 n.parentNode.removeChild(n);
23773 this.updateIndexes(index, index);
23776 onAdd : function(ds, records, index){
23777 this.clearSelections();
23778 if(this.nodes.length == 0){
23782 var n = this.nodes[index];
23783 for(var i = 0, len = records.length; i < len; i++){
23784 var d = this.prepareData(records[i].data);
23786 this.tpl.insertBefore(n, d);
23788 this.tpl.append(this.el, d);
23791 this.updateIndexes(index);
23794 onRemove : function(ds, record, index){
23795 this.clearSelections();
23796 this.el.dom.removeChild(this.nodes[index]);
23797 this.updateIndexes(index);
23801 * Refresh an individual node.
23802 * @param {Number} index
23804 refreshNode : function(index){
23805 this.onUpdate(this.store, this.store.getAt(index));
23808 updateIndexes : function(startIndex, endIndex){
23809 var ns = this.nodes;
23810 startIndex = startIndex || 0;
23811 endIndex = endIndex || ns.length - 1;
23812 for(var i = startIndex; i <= endIndex; i++){
23813 ns[i].nodeIndex = i;
23818 * Changes the data store this view uses and refresh the view.
23819 * @param {Store} store
23821 setStore : function(store, initial){
23822 if(!initial && this.store){
23823 this.store.un("datachanged", this.refresh);
23824 this.store.un("add", this.onAdd);
23825 this.store.un("remove", this.onRemove);
23826 this.store.un("update", this.onUpdate);
23827 this.store.un("clear", this.refresh);
23831 store.on("datachanged", this.refresh, this);
23832 store.on("add", this.onAdd, this);
23833 store.on("remove", this.onRemove, this);
23834 store.on("update", this.onUpdate, this);
23835 store.on("clear", this.refresh, this);
23844 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23845 * @param {HTMLElement} node
23846 * @return {HTMLElement} The template node
23848 findItemFromChild : function(node){
23849 var el = this.el.dom;
23850 if(!node || node.parentNode == el){
23853 var p = node.parentNode;
23854 while(p && p != el){
23855 if(p.parentNode == el){
23864 onClick : function(e){
23865 var item = this.findItemFromChild(e.getTarget());
23867 var index = this.indexOf(item);
23868 if(this.onItemClick(item, index, e) !== false){
23869 this.fireEvent("click", this, index, item, e);
23872 this.clearSelections();
23877 onContextMenu : function(e){
23878 var item = this.findItemFromChild(e.getTarget());
23880 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23885 onDblClick : function(e){
23886 var item = this.findItemFromChild(e.getTarget());
23888 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23892 onItemClick : function(item, index, e){
23893 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23896 if(this.multiSelect || this.singleSelect){
23897 if(this.multiSelect && e.shiftKey && this.lastSelection){
23898 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23900 this.select(item, this.multiSelect && e.ctrlKey);
23901 this.lastSelection = item;
23903 e.preventDefault();
23909 * Get the number of selected nodes.
23912 getSelectionCount : function(){
23913 return this.selections.length;
23917 * Get the currently selected nodes.
23918 * @return {Array} An array of HTMLElements
23920 getSelectedNodes : function(){
23921 return this.selections;
23925 * Get the indexes of the selected nodes.
23928 getSelectedIndexes : function(){
23929 var indexes = [], s = this.selections;
23930 for(var i = 0, len = s.length; i < len; i++){
23931 indexes.push(s[i].nodeIndex);
23937 * Clear all selections
23938 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23940 clearSelections : function(suppressEvent){
23941 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23942 this.cmp.elements = this.selections;
23943 this.cmp.removeClass(this.selectedClass);
23944 this.selections = [];
23945 if(!suppressEvent){
23946 this.fireEvent("selectionchange", this, this.selections);
23952 * Returns true if the passed node is selected
23953 * @param {HTMLElement/Number} node The node or node index
23954 * @return {Boolean}
23956 isSelected : function(node){
23957 var s = this.selections;
23961 node = this.getNode(node);
23962 return s.indexOf(node) !== -1;
23967 * @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
23968 * @param {Boolean} keepExisting (optional) true to keep existing selections
23969 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23971 select : function(nodeInfo, keepExisting, suppressEvent){
23972 if(nodeInfo instanceof Array){
23974 this.clearSelections(true);
23976 for(var i = 0, len = nodeInfo.length; i < len; i++){
23977 this.select(nodeInfo[i], true, true);
23980 var node = this.getNode(nodeInfo);
23981 if(node && !this.isSelected(node)){
23983 this.clearSelections(true);
23985 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23986 Roo.fly(node).addClass(this.selectedClass);
23987 this.selections.push(node);
23988 if(!suppressEvent){
23989 this.fireEvent("selectionchange", this, this.selections);
23997 * Gets a template node.
23998 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23999 * @return {HTMLElement} The node or null if it wasn't found
24001 getNode : function(nodeInfo){
24002 if(typeof nodeInfo == "string"){
24003 return document.getElementById(nodeInfo);
24004 }else if(typeof nodeInfo == "number"){
24005 return this.nodes[nodeInfo];
24011 * Gets a range template nodes.
24012 * @param {Number} startIndex
24013 * @param {Number} endIndex
24014 * @return {Array} An array of nodes
24016 getNodes : function(start, end){
24017 var ns = this.nodes;
24018 start = start || 0;
24019 end = typeof end == "undefined" ? ns.length - 1 : end;
24022 for(var i = start; i <= end; i++){
24026 for(var i = start; i >= end; i--){
24034 * Finds the index of the passed node
24035 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24036 * @return {Number} The index of the node or -1
24038 indexOf : function(node){
24039 node = this.getNode(node);
24040 if(typeof node.nodeIndex == "number"){
24041 return node.nodeIndex;
24043 var ns = this.nodes;
24044 for(var i = 0, len = ns.length; i < len; i++){
24054 * Ext JS Library 1.1.1
24055 * Copyright(c) 2006-2007, Ext JS, LLC.
24057 * Originally Released Under LGPL - original licence link has changed is not relivant.
24060 * <script type="text/javascript">
24064 * @class Roo.JsonView
24065 * @extends Roo.View
24066 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24068 var view = new Roo.JsonView({
24069 container: "my-element",
24070 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24075 // listen for node click?
24076 view.on("click", function(vw, index, node, e){
24077 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24080 // direct load of JSON data
24081 view.load("foobar.php");
24083 // Example from my blog list
24084 var tpl = new Roo.Template(
24085 '<div class="entry">' +
24086 '<a class="entry-title" href="{link}">{title}</a>' +
24087 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24088 "</div><hr />"
24091 var moreView = new Roo.JsonView({
24092 container : "entry-list",
24096 moreView.on("beforerender", this.sortEntries, this);
24098 url: "/blog/get-posts.php",
24099 params: "allposts=true",
24100 text: "Loading Blog Entries..."
24104 * Note: old code is supported with arguments : (container, template, config)
24108 * Create a new JsonView
24110 * @param {Object} config The config object
24113 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24116 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24118 var um = this.el.getUpdateManager();
24119 um.setRenderer(this);
24120 um.on("update", this.onLoad, this);
24121 um.on("failure", this.onLoadException, this);
24124 * @event beforerender
24125 * Fires before rendering of the downloaded JSON data.
24126 * @param {Roo.JsonView} this
24127 * @param {Object} data The JSON data loaded
24131 * Fires when data is loaded.
24132 * @param {Roo.JsonView} this
24133 * @param {Object} data The JSON data loaded
24134 * @param {Object} response The raw Connect response object
24137 * @event loadexception
24138 * Fires when loading fails.
24139 * @param {Roo.JsonView} this
24140 * @param {Object} response The raw Connect response object
24143 'beforerender' : true,
24145 'loadexception' : true
24148 Roo.extend(Roo.JsonView, Roo.View, {
24150 * @type {String} The root property in the loaded JSON object that contains the data
24155 * Refreshes the view.
24157 refresh : function(){
24158 this.clearSelections();
24159 this.el.update("");
24161 var o = this.jsonData;
24162 if(o && o.length > 0){
24163 for(var i = 0, len = o.length; i < len; i++){
24164 var data = this.prepareData(o[i], i, o);
24165 html[html.length] = this.tpl.apply(data);
24168 html.push(this.emptyText);
24170 this.el.update(html.join(""));
24171 this.nodes = this.el.dom.childNodes;
24172 this.updateIndexes(0);
24176 * 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.
24177 * @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:
24180 url: "your-url.php",
24181 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24182 callback: yourFunction,
24183 scope: yourObject, //(optional scope)
24186 text: "Loading...",
24191 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24192 * 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.
24193 * @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}
24194 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24195 * @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.
24198 var um = this.el.getUpdateManager();
24199 um.update.apply(um, arguments);
24202 render : function(el, response){
24203 this.clearSelections();
24204 this.el.update("");
24207 o = Roo.util.JSON.decode(response.responseText);
24210 o = o[this.jsonRoot];
24215 * The current JSON data or null
24218 this.beforeRender();
24223 * Get the number of records in the current JSON dataset
24226 getCount : function(){
24227 return this.jsonData ? this.jsonData.length : 0;
24231 * Returns the JSON object for the specified node(s)
24232 * @param {HTMLElement/Array} node The node or an array of nodes
24233 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24234 * you get the JSON object for the node
24236 getNodeData : function(node){
24237 if(node instanceof Array){
24239 for(var i = 0, len = node.length; i < len; i++){
24240 data.push(this.getNodeData(node[i]));
24244 return this.jsonData[this.indexOf(node)] || null;
24247 beforeRender : function(){
24248 this.snapshot = this.jsonData;
24250 this.sort.apply(this, this.sortInfo);
24252 this.fireEvent("beforerender", this, this.jsonData);
24255 onLoad : function(el, o){
24256 this.fireEvent("load", this, this.jsonData, o);
24259 onLoadException : function(el, o){
24260 this.fireEvent("loadexception", this, o);
24264 * Filter the data by a specific property.
24265 * @param {String} property A property on your JSON objects
24266 * @param {String/RegExp} value Either string that the property values
24267 * should start with, or a RegExp to test against the property
24269 filter : function(property, value){
24272 var ss = this.snapshot;
24273 if(typeof value == "string"){
24274 var vlen = value.length;
24276 this.clearFilter();
24279 value = value.toLowerCase();
24280 for(var i = 0, len = ss.length; i < len; i++){
24282 if(o[property].substr(0, vlen).toLowerCase() == value){
24286 } else if(value.exec){ // regex?
24287 for(var i = 0, len = ss.length; i < len; i++){
24289 if(value.test(o[property])){
24296 this.jsonData = data;
24302 * Filter by a function. The passed function will be called with each
24303 * object in the current dataset. If the function returns true the value is kept,
24304 * otherwise it is filtered.
24305 * @param {Function} fn
24306 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24308 filterBy : function(fn, scope){
24311 var ss = this.snapshot;
24312 for(var i = 0, len = ss.length; i < len; i++){
24314 if(fn.call(scope || this, o)){
24318 this.jsonData = data;
24324 * Clears the current filter.
24326 clearFilter : function(){
24327 if(this.snapshot && this.jsonData != this.snapshot){
24328 this.jsonData = this.snapshot;
24335 * Sorts the data for this view and refreshes it.
24336 * @param {String} property A property on your JSON objects to sort on
24337 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24338 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24340 sort : function(property, dir, sortType){
24341 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24344 var dsc = dir && dir.toLowerCase() == "desc";
24345 var f = function(o1, o2){
24346 var v1 = sortType ? sortType(o1[p]) : o1[p];
24347 var v2 = sortType ? sortType(o2[p]) : o2[p];
24350 return dsc ? +1 : -1;
24351 } else if(v1 > v2){
24352 return dsc ? -1 : +1;
24357 this.jsonData.sort(f);
24359 if(this.jsonData != this.snapshot){
24360 this.snapshot.sort(f);
24366 * Ext JS Library 1.1.1
24367 * Copyright(c) 2006-2007, Ext JS, LLC.
24369 * Originally Released Under LGPL - original licence link has changed is not relivant.
24372 * <script type="text/javascript">
24377 * @class Roo.ColorPalette
24378 * @extends Roo.Component
24379 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24380 * Here's an example of typical usage:
24382 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24383 cp.render('my-div');
24385 cp.on('select', function(palette, selColor){
24386 // do something with selColor
24390 * Create a new ColorPalette
24391 * @param {Object} config The config object
24393 Roo.ColorPalette = function(config){
24394 Roo.ColorPalette.superclass.constructor.call(this, config);
24398 * Fires when a color is selected
24399 * @param {ColorPalette} this
24400 * @param {String} color The 6-digit color hex code (without the # symbol)
24406 this.on("select", this.handler, this.scope, true);
24409 Roo.extend(Roo.ColorPalette, Roo.Component, {
24411 * @cfg {String} itemCls
24412 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24414 itemCls : "x-color-palette",
24416 * @cfg {String} value
24417 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24418 * the hex codes are case-sensitive.
24421 clickEvent:'click',
24423 ctype: "Roo.ColorPalette",
24426 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24428 allowReselect : false,
24431 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24432 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24433 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24434 * of colors with the width setting until the box is symmetrical.</p>
24435 * <p>You can override individual colors if needed:</p>
24437 var cp = new Roo.ColorPalette();
24438 cp.colors[0] = "FF0000"; // change the first box to red
24441 Or you can provide a custom array of your own for complete control:
24443 var cp = new Roo.ColorPalette();
24444 cp.colors = ["000000", "993300", "333300"];
24449 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24450 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24451 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24452 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24453 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24457 onRender : function(container, position){
24458 var t = new Roo.MasterTemplate(
24459 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24461 var c = this.colors;
24462 for(var i = 0, len = c.length; i < len; i++){
24465 var el = document.createElement("div");
24466 el.className = this.itemCls;
24468 container.dom.insertBefore(el, position);
24469 this.el = Roo.get(el);
24470 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24471 if(this.clickEvent != 'click'){
24472 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24477 afterRender : function(){
24478 Roo.ColorPalette.superclass.afterRender.call(this);
24480 var s = this.value;
24487 handleClick : function(e, t){
24488 e.preventDefault();
24489 if(!this.disabled){
24490 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24491 this.select(c.toUpperCase());
24496 * Selects the specified color in the palette (fires the select event)
24497 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24499 select : function(color){
24500 color = color.replace("#", "");
24501 if(color != this.value || this.allowReselect){
24504 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24506 el.child("a.color-"+color).addClass("x-color-palette-sel");
24507 this.value = color;
24508 this.fireEvent("select", this, color);
24513 * Ext JS Library 1.1.1
24514 * Copyright(c) 2006-2007, Ext JS, LLC.
24516 * Originally Released Under LGPL - original licence link has changed is not relivant.
24519 * <script type="text/javascript">
24523 * @class Roo.DatePicker
24524 * @extends Roo.Component
24525 * Simple date picker class.
24527 * Create a new DatePicker
24528 * @param {Object} config The config object
24530 Roo.DatePicker = function(config){
24531 Roo.DatePicker.superclass.constructor.call(this, config);
24533 this.value = config && config.value ?
24534 config.value.clearTime() : new Date().clearTime();
24539 * Fires when a date is selected
24540 * @param {DatePicker} this
24541 * @param {Date} date The selected date
24547 this.on("select", this.handler, this.scope || this);
24549 // build the disabledDatesRE
24550 if(!this.disabledDatesRE && this.disabledDates){
24551 var dd = this.disabledDates;
24553 for(var i = 0; i < dd.length; i++){
24555 if(i != dd.length-1) re += "|";
24557 this.disabledDatesRE = new RegExp(re + ")");
24561 Roo.extend(Roo.DatePicker, Roo.Component, {
24563 * @cfg {String} todayText
24564 * The text to display on the button that selects the current date (defaults to "Today")
24566 todayText : "Today",
24568 * @cfg {String} okText
24569 * The text to display on the ok button
24571 okText : " OK ", //   to give the user extra clicking room
24573 * @cfg {String} cancelText
24574 * The text to display on the cancel button
24576 cancelText : "Cancel",
24578 * @cfg {String} todayTip
24579 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24581 todayTip : "{0} (Spacebar)",
24583 * @cfg {Date} minDate
24584 * Minimum allowable date (JavaScript date object, defaults to null)
24588 * @cfg {Date} maxDate
24589 * Maximum allowable date (JavaScript date object, defaults to null)
24593 * @cfg {String} minText
24594 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24596 minText : "This date is before the minimum date",
24598 * @cfg {String} maxText
24599 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24601 maxText : "This date is after the maximum date",
24603 * @cfg {String} format
24604 * The default date format string which can be overriden for localization support. The format must be
24605 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24609 * @cfg {Array} disabledDays
24610 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24612 disabledDays : null,
24614 * @cfg {String} disabledDaysText
24615 * The tooltip to display when the date falls on a disabled day (defaults to "")
24617 disabledDaysText : "",
24619 * @cfg {RegExp} disabledDatesRE
24620 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24622 disabledDatesRE : null,
24624 * @cfg {String} disabledDatesText
24625 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24627 disabledDatesText : "",
24629 * @cfg {Boolean} constrainToViewport
24630 * True to constrain the date picker to the viewport (defaults to true)
24632 constrainToViewport : true,
24634 * @cfg {Array} monthNames
24635 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24637 monthNames : Date.monthNames,
24639 * @cfg {Array} dayNames
24640 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24642 dayNames : Date.dayNames,
24644 * @cfg {String} nextText
24645 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24647 nextText: 'Next Month (Control+Right)',
24649 * @cfg {String} prevText
24650 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24652 prevText: 'Previous Month (Control+Left)',
24654 * @cfg {String} monthYearText
24655 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24657 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24659 * @cfg {Number} startDay
24660 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24664 * @cfg {Bool} showClear
24665 * Show a clear button (usefull for date form elements that can be blank.)
24671 * Sets the value of the date field
24672 * @param {Date} value The date to set
24674 setValue : function(value){
24675 var old = this.value;
24676 this.value = value.clearTime(true);
24678 this.update(this.value);
24683 * Gets the current selected value of the date field
24684 * @return {Date} The selected date
24686 getValue : function(){
24691 focus : function(){
24693 this.update(this.activeDate);
24698 onRender : function(container, position){
24700 '<table cellspacing="0">',
24701 '<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>',
24702 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24703 var dn = this.dayNames;
24704 for(var i = 0; i < 7; i++){
24705 var d = this.startDay+i;
24709 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24711 m[m.length] = "</tr></thead><tbody><tr>";
24712 for(var i = 0; i < 42; i++) {
24713 if(i % 7 == 0 && i != 0){
24714 m[m.length] = "</tr><tr>";
24716 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24718 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24719 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24721 var el = document.createElement("div");
24722 el.className = "x-date-picker";
24723 el.innerHTML = m.join("");
24725 container.dom.insertBefore(el, position);
24727 this.el = Roo.get(el);
24728 this.eventEl = Roo.get(el.firstChild);
24730 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24731 handler: this.showPrevMonth,
24733 preventDefault:true,
24737 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24738 handler: this.showNextMonth,
24740 preventDefault:true,
24744 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24746 this.monthPicker = this.el.down('div.x-date-mp');
24747 this.monthPicker.enableDisplayMode('block');
24749 var kn = new Roo.KeyNav(this.eventEl, {
24750 "left" : function(e){
24752 this.showPrevMonth() :
24753 this.update(this.activeDate.add("d", -1));
24756 "right" : function(e){
24758 this.showNextMonth() :
24759 this.update(this.activeDate.add("d", 1));
24762 "up" : function(e){
24764 this.showNextYear() :
24765 this.update(this.activeDate.add("d", -7));
24768 "down" : function(e){
24770 this.showPrevYear() :
24771 this.update(this.activeDate.add("d", 7));
24774 "pageUp" : function(e){
24775 this.showNextMonth();
24778 "pageDown" : function(e){
24779 this.showPrevMonth();
24782 "enter" : function(e){
24783 e.stopPropagation();
24790 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24792 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24794 this.el.unselectable();
24796 this.cells = this.el.select("table.x-date-inner tbody td");
24797 this.textNodes = this.el.query("table.x-date-inner tbody span");
24799 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24801 tooltip: this.monthYearText
24804 this.mbtn.on('click', this.showMonthPicker, this);
24805 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24808 var today = (new Date()).dateFormat(this.format);
24810 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24811 if (this.showClear) {
24812 baseTb.add( new Roo.Toolbar.Fill());
24815 text: String.format(this.todayText, today),
24816 tooltip: String.format(this.todayTip, today),
24817 handler: this.selectToday,
24821 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24824 if (this.showClear) {
24826 baseTb.add( new Roo.Toolbar.Fill());
24829 cls: 'x-btn-icon x-btn-clear',
24830 handler: function() {
24832 this.fireEvent("select", this, '');
24842 this.update(this.value);
24845 createMonthPicker : function(){
24846 if(!this.monthPicker.dom.firstChild){
24847 var buf = ['<table border="0" cellspacing="0">'];
24848 for(var i = 0; i < 6; i++){
24850 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24851 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24853 '<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>' :
24854 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24858 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24860 '</button><button type="button" class="x-date-mp-cancel">',
24862 '</button></td></tr>',
24865 this.monthPicker.update(buf.join(''));
24866 this.monthPicker.on('click', this.onMonthClick, this);
24867 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24869 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24870 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24872 this.mpMonths.each(function(m, a, i){
24875 m.dom.xmonth = 5 + Math.round(i * .5);
24877 m.dom.xmonth = Math.round((i-1) * .5);
24883 showMonthPicker : function(){
24884 this.createMonthPicker();
24885 var size = this.el.getSize();
24886 this.monthPicker.setSize(size);
24887 this.monthPicker.child('table').setSize(size);
24889 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24890 this.updateMPMonth(this.mpSelMonth);
24891 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24892 this.updateMPYear(this.mpSelYear);
24894 this.monthPicker.slideIn('t', {duration:.2});
24897 updateMPYear : function(y){
24899 var ys = this.mpYears.elements;
24900 for(var i = 1; i <= 10; i++){
24901 var td = ys[i-1], y2;
24903 y2 = y + Math.round(i * .5);
24904 td.firstChild.innerHTML = y2;
24907 y2 = y - (5-Math.round(i * .5));
24908 td.firstChild.innerHTML = y2;
24911 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24915 updateMPMonth : function(sm){
24916 this.mpMonths.each(function(m, a, i){
24917 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24921 selectMPMonth: function(m){
24925 onMonthClick : function(e, t){
24927 var el = new Roo.Element(t), pn;
24928 if(el.is('button.x-date-mp-cancel')){
24929 this.hideMonthPicker();
24931 else if(el.is('button.x-date-mp-ok')){
24932 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24933 this.hideMonthPicker();
24935 else if(pn = el.up('td.x-date-mp-month', 2)){
24936 this.mpMonths.removeClass('x-date-mp-sel');
24937 pn.addClass('x-date-mp-sel');
24938 this.mpSelMonth = pn.dom.xmonth;
24940 else if(pn = el.up('td.x-date-mp-year', 2)){
24941 this.mpYears.removeClass('x-date-mp-sel');
24942 pn.addClass('x-date-mp-sel');
24943 this.mpSelYear = pn.dom.xyear;
24945 else if(el.is('a.x-date-mp-prev')){
24946 this.updateMPYear(this.mpyear-10);
24948 else if(el.is('a.x-date-mp-next')){
24949 this.updateMPYear(this.mpyear+10);
24953 onMonthDblClick : function(e, t){
24955 var el = new Roo.Element(t), pn;
24956 if(pn = el.up('td.x-date-mp-month', 2)){
24957 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24958 this.hideMonthPicker();
24960 else if(pn = el.up('td.x-date-mp-year', 2)){
24961 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24962 this.hideMonthPicker();
24966 hideMonthPicker : function(disableAnim){
24967 if(this.monthPicker){
24968 if(disableAnim === true){
24969 this.monthPicker.hide();
24971 this.monthPicker.slideOut('t', {duration:.2});
24977 showPrevMonth : function(e){
24978 this.update(this.activeDate.add("mo", -1));
24982 showNextMonth : function(e){
24983 this.update(this.activeDate.add("mo", 1));
24987 showPrevYear : function(){
24988 this.update(this.activeDate.add("y", -1));
24992 showNextYear : function(){
24993 this.update(this.activeDate.add("y", 1));
24997 handleMouseWheel : function(e){
24998 var delta = e.getWheelDelta();
25000 this.showPrevMonth();
25002 } else if(delta < 0){
25003 this.showNextMonth();
25009 handleDateClick : function(e, t){
25011 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25012 this.setValue(new Date(t.dateValue));
25013 this.fireEvent("select", this, this.value);
25018 selectToday : function(){
25019 this.setValue(new Date().clearTime());
25020 this.fireEvent("select", this, this.value);
25024 update : function(date){
25025 var vd = this.activeDate;
25026 this.activeDate = date;
25028 var t = date.getTime();
25029 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25030 this.cells.removeClass("x-date-selected");
25031 this.cells.each(function(c){
25032 if(c.dom.firstChild.dateValue == t){
25033 c.addClass("x-date-selected");
25034 setTimeout(function(){
25035 try{c.dom.firstChild.focus();}catch(e){}
25043 var days = date.getDaysInMonth();
25044 var firstOfMonth = date.getFirstDateOfMonth();
25045 var startingPos = firstOfMonth.getDay()-this.startDay;
25047 if(startingPos <= this.startDay){
25051 var pm = date.add("mo", -1);
25052 var prevStart = pm.getDaysInMonth()-startingPos;
25054 var cells = this.cells.elements;
25055 var textEls = this.textNodes;
25056 days += startingPos;
25058 // convert everything to numbers so it's fast
25059 var day = 86400000;
25060 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25061 var today = new Date().clearTime().getTime();
25062 var sel = date.clearTime().getTime();
25063 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25064 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25065 var ddMatch = this.disabledDatesRE;
25066 var ddText = this.disabledDatesText;
25067 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25068 var ddaysText = this.disabledDaysText;
25069 var format = this.format;
25071 var setCellClass = function(cal, cell){
25073 var t = d.getTime();
25074 cell.firstChild.dateValue = t;
25076 cell.className += " x-date-today";
25077 cell.title = cal.todayText;
25080 cell.className += " x-date-selected";
25081 setTimeout(function(){
25082 try{cell.firstChild.focus();}catch(e){}
25087 cell.className = " x-date-disabled";
25088 cell.title = cal.minText;
25092 cell.className = " x-date-disabled";
25093 cell.title = cal.maxText;
25097 if(ddays.indexOf(d.getDay()) != -1){
25098 cell.title = ddaysText;
25099 cell.className = " x-date-disabled";
25102 if(ddMatch && format){
25103 var fvalue = d.dateFormat(format);
25104 if(ddMatch.test(fvalue)){
25105 cell.title = ddText.replace("%0", fvalue);
25106 cell.className = " x-date-disabled";
25112 for(; i < startingPos; i++) {
25113 textEls[i].innerHTML = (++prevStart);
25114 d.setDate(d.getDate()+1);
25115 cells[i].className = "x-date-prevday";
25116 setCellClass(this, cells[i]);
25118 for(; i < days; i++){
25119 intDay = i - startingPos + 1;
25120 textEls[i].innerHTML = (intDay);
25121 d.setDate(d.getDate()+1);
25122 cells[i].className = "x-date-active";
25123 setCellClass(this, cells[i]);
25126 for(; i < 42; i++) {
25127 textEls[i].innerHTML = (++extraDays);
25128 d.setDate(d.getDate()+1);
25129 cells[i].className = "x-date-nextday";
25130 setCellClass(this, cells[i]);
25133 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25135 if(!this.internalRender){
25136 var main = this.el.dom.firstChild;
25137 var w = main.offsetWidth;
25138 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25139 Roo.fly(main).setWidth(w);
25140 this.internalRender = true;
25141 // opera does not respect the auto grow header center column
25142 // then, after it gets a width opera refuses to recalculate
25143 // without a second pass
25144 if(Roo.isOpera && !this.secondPass){
25145 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25146 this.secondPass = true;
25147 this.update.defer(10, this, [date]);
25153 * Ext JS Library 1.1.1
25154 * Copyright(c) 2006-2007, Ext JS, LLC.
25156 * Originally Released Under LGPL - original licence link has changed is not relivant.
25159 * <script type="text/javascript">
25162 * @class Roo.TabPanel
25163 * @extends Roo.util.Observable
25164 * A lightweight tab container.
25168 // basic tabs 1, built from existing content
25169 var tabs = new Roo.TabPanel("tabs1");
25170 tabs.addTab("script", "View Script");
25171 tabs.addTab("markup", "View Markup");
25172 tabs.activate("script");
25174 // more advanced tabs, built from javascript
25175 var jtabs = new Roo.TabPanel("jtabs");
25176 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25178 // set up the UpdateManager
25179 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25180 var updater = tab2.getUpdateManager();
25181 updater.setDefaultUrl("ajax1.htm");
25182 tab2.on('activate', updater.refresh, updater, true);
25184 // Use setUrl for Ajax loading
25185 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25186 tab3.setUrl("ajax2.htm", null, true);
25189 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25192 jtabs.activate("jtabs-1");
25195 * Create a new TabPanel.
25196 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25197 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25199 Roo.TabPanel = function(container, config){
25201 * The container element for this TabPanel.
25202 * @type Roo.Element
25204 this.el = Roo.get(container, true);
25206 if(typeof config == "boolean"){
25207 this.tabPosition = config ? "bottom" : "top";
25209 Roo.apply(this, config);
25212 if(this.tabPosition == "bottom"){
25213 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25214 this.el.addClass("x-tabs-bottom");
25216 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25217 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25218 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25220 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25222 if(this.tabPosition != "bottom"){
25223 /** The body element that contains {@link Roo.TabPanelItem} bodies.
25224 * @type Roo.Element
25226 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25227 this.el.addClass("x-tabs-top");
25231 this.bodyEl.setStyle("position", "relative");
25233 this.active = null;
25234 this.activateDelegate = this.activate.createDelegate(this);
25239 * Fires when the active tab changes
25240 * @param {Roo.TabPanel} this
25241 * @param {Roo.TabPanelItem} activePanel The new active tab
25245 * @event beforetabchange
25246 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25247 * @param {Roo.TabPanel} this
25248 * @param {Object} e Set cancel to true on this object to cancel the tab change
25249 * @param {Roo.TabPanelItem} tab The tab being changed to
25251 "beforetabchange" : true
25254 Roo.EventManager.onWindowResize(this.onResize, this);
25255 this.cpad = this.el.getPadding("lr");
25256 this.hiddenCount = 0;
25258 Roo.TabPanel.superclass.constructor.call(this);
25261 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25263 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25265 tabPosition : "top",
25267 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25269 currentTabWidth : 0,
25271 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25275 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25279 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25281 preferredTabWidth : 175,
25283 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25285 resizeTabs : false,
25287 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25289 monitorResize : true,
25292 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25293 * @param {String} id The id of the div to use <b>or create</b>
25294 * @param {String} text The text for the tab
25295 * @param {String} content (optional) Content to put in the TabPanelItem body
25296 * @param {Boolean} closable (optional) True to create a close icon on the tab
25297 * @return {Roo.TabPanelItem} The created TabPanelItem
25299 addTab : function(id, text, content, closable){
25300 var item = new Roo.TabPanelItem(this, id, text, closable);
25301 this.addTabItem(item);
25303 item.setContent(content);
25309 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25310 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25311 * @return {Roo.TabPanelItem}
25313 getTab : function(id){
25314 return this.items[id];
25318 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25319 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25321 hideTab : function(id){
25322 var t = this.items[id];
25325 this.hiddenCount++;
25326 this.autoSizeTabs();
25331 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25332 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25334 unhideTab : function(id){
25335 var t = this.items[id];
25337 t.setHidden(false);
25338 this.hiddenCount--;
25339 this.autoSizeTabs();
25344 * Adds an existing {@link Roo.TabPanelItem}.
25345 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25347 addTabItem : function(item){
25348 this.items[item.id] = item;
25349 this.items.push(item);
25350 if(this.resizeTabs){
25351 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25352 this.autoSizeTabs();
25359 * Removes a {@link Roo.TabPanelItem}.
25360 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25362 removeTab : function(id){
25363 var items = this.items;
25364 var tab = items[id];
25365 if(!tab) { return; }
25366 var index = items.indexOf(tab);
25367 if(this.active == tab && items.length > 1){
25368 var newTab = this.getNextAvailable(index);
25373 this.stripEl.dom.removeChild(tab.pnode.dom);
25374 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25375 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25377 items.splice(index, 1);
25378 delete this.items[tab.id];
25379 tab.fireEvent("close", tab);
25380 tab.purgeListeners();
25381 this.autoSizeTabs();
25384 getNextAvailable : function(start){
25385 var items = this.items;
25387 // look for a next tab that will slide over to
25388 // replace the one being removed
25389 while(index < items.length){
25390 var item = items[++index];
25391 if(item && !item.isHidden()){
25395 // if one isn't found select the previous tab (on the left)
25398 var item = items[--index];
25399 if(item && !item.isHidden()){
25407 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25408 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25410 disableTab : function(id){
25411 var tab = this.items[id];
25412 if(tab && this.active != tab){
25418 * Enables a {@link Roo.TabPanelItem} that is disabled.
25419 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25421 enableTab : function(id){
25422 var tab = this.items[id];
25427 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25428 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25429 * @return {Roo.TabPanelItem} The TabPanelItem.
25431 activate : function(id){
25432 var tab = this.items[id];
25436 if(tab == this.active || tab.disabled){
25440 this.fireEvent("beforetabchange", this, e, tab);
25441 if(e.cancel !== true && !tab.disabled){
25443 this.active.hide();
25445 this.active = this.items[id];
25446 this.active.show();
25447 this.fireEvent("tabchange", this, this.active);
25453 * Gets the active {@link Roo.TabPanelItem}.
25454 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25456 getActiveTab : function(){
25457 return this.active;
25461 * Updates the tab body element to fit the height of the container element
25462 * for overflow scrolling
25463 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25465 syncHeight : function(targetHeight){
25466 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25467 var bm = this.bodyEl.getMargins();
25468 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25469 this.bodyEl.setHeight(newHeight);
25473 onResize : function(){
25474 if(this.monitorResize){
25475 this.autoSizeTabs();
25480 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25482 beginUpdate : function(){
25483 this.updating = true;
25487 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25489 endUpdate : function(){
25490 this.updating = false;
25491 this.autoSizeTabs();
25495 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25497 autoSizeTabs : function(){
25498 var count = this.items.length;
25499 var vcount = count - this.hiddenCount;
25500 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25501 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25502 var availWidth = Math.floor(w / vcount);
25503 var b = this.stripBody;
25504 if(b.getWidth() > w){
25505 var tabs = this.items;
25506 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25507 if(availWidth < this.minTabWidth){
25508 /*if(!this.sleft){ // incomplete scrolling code
25509 this.createScrollButtons();
25512 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25515 if(this.currentTabWidth < this.preferredTabWidth){
25516 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25522 * Returns the number of tabs in this TabPanel.
25525 getCount : function(){
25526 return this.items.length;
25530 * Resizes all the tabs to the passed width
25531 * @param {Number} The new width
25533 setTabWidth : function(width){
25534 this.currentTabWidth = width;
25535 for(var i = 0, len = this.items.length; i < len; i++) {
25536 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25541 * Destroys this TabPanel
25542 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25544 destroy : function(removeEl){
25545 Roo.EventManager.removeResizeListener(this.onResize, this);
25546 for(var i = 0, len = this.items.length; i < len; i++){
25547 this.items[i].purgeListeners();
25549 if(removeEl === true){
25550 this.el.update("");
25557 * @class Roo.TabPanelItem
25558 * @extends Roo.util.Observable
25559 * Represents an individual item (tab plus body) in a TabPanel.
25560 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25561 * @param {String} id The id of this TabPanelItem
25562 * @param {String} text The text for the tab of this TabPanelItem
25563 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25565 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25567 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25568 * @type Roo.TabPanel
25570 this.tabPanel = tabPanel;
25572 * The id for this TabPanelItem
25577 this.disabled = false;
25581 this.loaded = false;
25582 this.closable = closable;
25585 * The body element for this TabPanelItem.
25586 * @type Roo.Element
25588 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25589 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25590 this.bodyEl.setStyle("display", "block");
25591 this.bodyEl.setStyle("zoom", "1");
25594 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25596 this.el = Roo.get(els.el, true);
25597 this.inner = Roo.get(els.inner, true);
25598 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25599 this.pnode = Roo.get(els.el.parentNode, true);
25600 this.el.on("mousedown", this.onTabMouseDown, this);
25601 this.el.on("click", this.onTabClick, this);
25604 var c = Roo.get(els.close, true);
25605 c.dom.title = this.closeText;
25606 c.addClassOnOver("close-over");
25607 c.on("click", this.closeClick, this);
25613 * Fires when this tab becomes the active tab.
25614 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25615 * @param {Roo.TabPanelItem} this
25619 * @event beforeclose
25620 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25621 * @param {Roo.TabPanelItem} this
25622 * @param {Object} e Set cancel to true on this object to cancel the close.
25624 "beforeclose": true,
25627 * Fires when this tab is closed.
25628 * @param {Roo.TabPanelItem} this
25632 * @event deactivate
25633 * Fires when this tab is no longer the active tab.
25634 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25635 * @param {Roo.TabPanelItem} this
25637 "deactivate" : true
25639 this.hidden = false;
25641 Roo.TabPanelItem.superclass.constructor.call(this);
25644 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25645 purgeListeners : function(){
25646 Roo.util.Observable.prototype.purgeListeners.call(this);
25647 this.el.removeAllListeners();
25650 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25653 this.pnode.addClass("on");
25656 this.tabPanel.stripWrap.repaint();
25658 this.fireEvent("activate", this.tabPanel, this);
25662 * Returns true if this tab is the active tab.
25663 * @return {Boolean}
25665 isActive : function(){
25666 return this.tabPanel.getActiveTab() == this;
25670 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25673 this.pnode.removeClass("on");
25675 this.fireEvent("deactivate", this.tabPanel, this);
25678 hideAction : function(){
25679 this.bodyEl.hide();
25680 this.bodyEl.setStyle("position", "absolute");
25681 this.bodyEl.setLeft("-20000px");
25682 this.bodyEl.setTop("-20000px");
25685 showAction : function(){
25686 this.bodyEl.setStyle("position", "relative");
25687 this.bodyEl.setTop("");
25688 this.bodyEl.setLeft("");
25689 this.bodyEl.show();
25693 * Set the tooltip for the tab.
25694 * @param {String} tooltip The tab's tooltip
25696 setTooltip : function(text){
25697 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25698 this.textEl.dom.qtip = text;
25699 this.textEl.dom.removeAttribute('title');
25701 this.textEl.dom.title = text;
25705 onTabClick : function(e){
25706 e.preventDefault();
25707 this.tabPanel.activate(this.id);
25710 onTabMouseDown : function(e){
25711 e.preventDefault();
25712 this.tabPanel.activate(this.id);
25715 getWidth : function(){
25716 return this.inner.getWidth();
25719 setWidth : function(width){
25720 var iwidth = width - this.pnode.getPadding("lr");
25721 this.inner.setWidth(iwidth);
25722 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25723 this.pnode.setWidth(width);
25727 * Show or hide the tab
25728 * @param {Boolean} hidden True to hide or false to show.
25730 setHidden : function(hidden){
25731 this.hidden = hidden;
25732 this.pnode.setStyle("display", hidden ? "none" : "");
25736 * Returns true if this tab is "hidden"
25737 * @return {Boolean}
25739 isHidden : function(){
25740 return this.hidden;
25744 * Returns the text for this tab
25747 getText : function(){
25751 autoSize : function(){
25752 //this.el.beginMeasure();
25753 this.textEl.setWidth(1);
25754 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25755 //this.el.endMeasure();
25759 * Sets the text for the tab (Note: this also sets the tooltip text)
25760 * @param {String} text The tab's text and tooltip
25762 setText : function(text){
25764 this.textEl.update(text);
25765 this.setTooltip(text);
25766 if(!this.tabPanel.resizeTabs){
25771 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25773 activate : function(){
25774 this.tabPanel.activate(this.id);
25778 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25780 disable : function(){
25781 if(this.tabPanel.active != this){
25782 this.disabled = true;
25783 this.pnode.addClass("disabled");
25788 * Enables this TabPanelItem if it was previously disabled.
25790 enable : function(){
25791 this.disabled = false;
25792 this.pnode.removeClass("disabled");
25796 * Sets the content for this TabPanelItem.
25797 * @param {String} content The content
25798 * @param {Boolean} loadScripts true to look for and load scripts
25800 setContent : function(content, loadScripts){
25801 this.bodyEl.update(content, loadScripts);
25805 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25806 * @return {Roo.UpdateManager} The UpdateManager
25808 getUpdateManager : function(){
25809 return this.bodyEl.getUpdateManager();
25813 * Set a URL to be used to load the content for this TabPanelItem.
25814 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25815 * @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)
25816 * @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)
25817 * @return {Roo.UpdateManager} The UpdateManager
25819 setUrl : function(url, params, loadOnce){
25820 if(this.refreshDelegate){
25821 this.un('activate', this.refreshDelegate);
25823 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25824 this.on("activate", this.refreshDelegate);
25825 return this.bodyEl.getUpdateManager();
25829 _handleRefresh : function(url, params, loadOnce){
25830 if(!loadOnce || !this.loaded){
25831 var updater = this.bodyEl.getUpdateManager();
25832 updater.update(url, params, this._setLoaded.createDelegate(this));
25837 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25838 * Will fail silently if the setUrl method has not been called.
25839 * This does not activate the panel, just updates its content.
25841 refresh : function(){
25842 if(this.refreshDelegate){
25843 this.loaded = false;
25844 this.refreshDelegate();
25849 _setLoaded : function(){
25850 this.loaded = true;
25854 closeClick : function(e){
25857 this.fireEvent("beforeclose", this, o);
25858 if(o.cancel !== true){
25859 this.tabPanel.removeTab(this.id);
25863 * The text displayed in the tooltip for the close icon.
25866 closeText : "Close this tab"
25870 Roo.TabPanel.prototype.createStrip = function(container){
25871 var strip = document.createElement("div");
25872 strip.className = "x-tabs-wrap";
25873 container.appendChild(strip);
25877 Roo.TabPanel.prototype.createStripList = function(strip){
25878 // div wrapper for retard IE
25879 strip.innerHTML = '<div class="x-tabs-strip-wrap"><table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
25880 return strip.firstChild.firstChild.firstChild.firstChild;
25883 Roo.TabPanel.prototype.createBody = function(container){
25884 var body = document.createElement("div");
25885 Roo.id(body, "tab-body");
25886 Roo.fly(body).addClass("x-tabs-body");
25887 container.appendChild(body);
25891 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25892 var body = Roo.getDom(id);
25894 body = document.createElement("div");
25897 Roo.fly(body).addClass("x-tabs-item-body");
25898 bodyEl.insertBefore(body, bodyEl.firstChild);
25902 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25903 var td = document.createElement("td");
25904 stripEl.appendChild(td);
25906 td.className = "x-tabs-closable";
25907 if(!this.closeTpl){
25908 this.closeTpl = new Roo.Template(
25909 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25910 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25911 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25914 var el = this.closeTpl.overwrite(td, {"text": text});
25915 var close = el.getElementsByTagName("div")[0];
25916 var inner = el.getElementsByTagName("em")[0];
25917 return {"el": el, "close": close, "inner": inner};
25920 this.tabTpl = new Roo.Template(
25921 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25922 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25925 var el = this.tabTpl.overwrite(td, {"text": text});
25926 var inner = el.getElementsByTagName("em")[0];
25927 return {"el": el, "inner": inner};
25931 * Ext JS Library 1.1.1
25932 * Copyright(c) 2006-2007, Ext JS, LLC.
25934 * Originally Released Under LGPL - original licence link has changed is not relivant.
25937 * <script type="text/javascript">
25941 * @class Roo.Button
25942 * @extends Roo.util.Observable
25943 * Simple Button class
25944 * @cfg {String} text The button text
25945 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25946 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25947 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25948 * @cfg {Object} scope The scope of the handler
25949 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25950 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25951 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25952 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25953 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25954 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25955 applies if enableToggle = true)
25956 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25957 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25958 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25960 * Create a new button
25961 * @param {Object} config The config object
25963 Roo.Button = function(renderTo, config)
25967 renderTo = config.renderTo || false;
25970 Roo.apply(this, config);
25974 * Fires when this button is clicked
25975 * @param {Button} this
25976 * @param {EventObject} e The click event
25981 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25982 * @param {Button} this
25983 * @param {Boolean} pressed
25988 * Fires when the mouse hovers over the button
25989 * @param {Button} this
25990 * @param {Event} e The event object
25992 'mouseover' : true,
25995 * Fires when the mouse exits the button
25996 * @param {Button} this
25997 * @param {Event} e The event object
26002 * Fires when the button is rendered
26003 * @param {Button} this
26008 this.menu = Roo.menu.MenuMgr.get(this.menu);
26010 // register listeners first!! - so render can be captured..
26011 Roo.util.Observable.call(this);
26013 this.render(renderTo);
26019 Roo.extend(Roo.Button, Roo.util.Observable, {
26025 * Read-only. True if this button is hidden
26030 * Read-only. True if this button is disabled
26035 * Read-only. True if this button is pressed (only if enableToggle = true)
26041 * @cfg {Number} tabIndex
26042 * The DOM tabIndex for this button (defaults to undefined)
26044 tabIndex : undefined,
26047 * @cfg {Boolean} enableToggle
26048 * True to enable pressed/not pressed toggling (defaults to false)
26050 enableToggle: false,
26052 * @cfg {Mixed} menu
26053 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26057 * @cfg {String} menuAlign
26058 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26060 menuAlign : "tl-bl?",
26063 * @cfg {String} iconCls
26064 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26066 iconCls : undefined,
26068 * @cfg {String} type
26069 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26074 menuClassTarget: 'tr',
26077 * @cfg {String} clickEvent
26078 * The type of event to map to the button's event handler (defaults to 'click')
26080 clickEvent : 'click',
26083 * @cfg {Boolean} handleMouseEvents
26084 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26086 handleMouseEvents : true,
26089 * @cfg {String} tooltipType
26090 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26092 tooltipType : 'qtip',
26095 * @cfg {String} cls
26096 * A CSS class to apply to the button's main element.
26100 * @cfg {Roo.Template} template (Optional)
26101 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26102 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26103 * require code modifications if required elements (e.g. a button) aren't present.
26107 render : function(renderTo){
26109 if(this.hideParent){
26110 this.parentEl = Roo.get(renderTo);
26112 if(!this.dhconfig){
26113 if(!this.template){
26114 if(!Roo.Button.buttonTemplate){
26115 // hideous table template
26116 Roo.Button.buttonTemplate = new Roo.Template(
26117 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26118 '<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>',
26119 "</tr></tbody></table>");
26121 this.template = Roo.Button.buttonTemplate;
26123 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26124 var btnEl = btn.child("button:first");
26125 btnEl.on('focus', this.onFocus, this);
26126 btnEl.on('blur', this.onBlur, this);
26128 btn.addClass(this.cls);
26131 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26134 btnEl.addClass(this.iconCls);
26136 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26139 if(this.tabIndex !== undefined){
26140 btnEl.dom.tabIndex = this.tabIndex;
26143 if(typeof this.tooltip == 'object'){
26144 Roo.QuickTips.tips(Roo.apply({
26148 btnEl.dom[this.tooltipType] = this.tooltip;
26152 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26156 this.el.dom.id = this.el.id = this.id;
26159 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26160 this.menu.on("show", this.onMenuShow, this);
26161 this.menu.on("hide", this.onMenuHide, this);
26163 btn.addClass("x-btn");
26164 if(Roo.isIE && !Roo.isIE7){
26165 this.autoWidth.defer(1, this);
26169 if(this.handleMouseEvents){
26170 btn.on("mouseover", this.onMouseOver, this);
26171 btn.on("mouseout", this.onMouseOut, this);
26172 btn.on("mousedown", this.onMouseDown, this);
26174 btn.on(this.clickEvent, this.onClick, this);
26175 //btn.on("mouseup", this.onMouseUp, this);
26182 Roo.ButtonToggleMgr.register(this);
26184 this.el.addClass("x-btn-pressed");
26187 var repeater = new Roo.util.ClickRepeater(btn,
26188 typeof this.repeat == "object" ? this.repeat : {}
26190 repeater.on("click", this.onClick, this);
26193 this.fireEvent('render', this);
26197 * Returns the button's underlying element
26198 * @return {Roo.Element} The element
26200 getEl : function(){
26205 * Destroys this Button and removes any listeners.
26207 destroy : function(){
26208 Roo.ButtonToggleMgr.unregister(this);
26209 this.el.removeAllListeners();
26210 this.purgeListeners();
26215 autoWidth : function(){
26217 this.el.setWidth("auto");
26218 if(Roo.isIE7 && Roo.isStrict){
26219 var ib = this.el.child('button');
26220 if(ib && ib.getWidth() > 20){
26222 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26227 this.el.beginMeasure();
26229 if(this.el.getWidth() < this.minWidth){
26230 this.el.setWidth(this.minWidth);
26233 this.el.endMeasure();
26240 * Assigns this button's click handler
26241 * @param {Function} handler The function to call when the button is clicked
26242 * @param {Object} scope (optional) Scope for the function passed in
26244 setHandler : function(handler, scope){
26245 this.handler = handler;
26246 this.scope = scope;
26250 * Sets this button's text
26251 * @param {String} text The button text
26253 setText : function(text){
26256 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26262 * Gets the text for this button
26263 * @return {String} The button text
26265 getText : function(){
26273 this.hidden = false;
26275 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26283 this.hidden = true;
26285 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26290 * Convenience function for boolean show/hide
26291 * @param {Boolean} visible True to show, false to hide
26293 setVisible: function(visible){
26302 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26303 * @param {Boolean} state (optional) Force a particular state
26305 toggle : function(state){
26306 state = state === undefined ? !this.pressed : state;
26307 if(state != this.pressed){
26309 this.el.addClass("x-btn-pressed");
26310 this.pressed = true;
26311 this.fireEvent("toggle", this, true);
26313 this.el.removeClass("x-btn-pressed");
26314 this.pressed = false;
26315 this.fireEvent("toggle", this, false);
26317 if(this.toggleHandler){
26318 this.toggleHandler.call(this.scope || this, this, state);
26326 focus : function(){
26327 this.el.child('button:first').focus();
26331 * Disable this button
26333 disable : function(){
26335 this.el.addClass("x-btn-disabled");
26337 this.disabled = true;
26341 * Enable this button
26343 enable : function(){
26345 this.el.removeClass("x-btn-disabled");
26347 this.disabled = false;
26351 * Convenience function for boolean enable/disable
26352 * @param {Boolean} enabled True to enable, false to disable
26354 setDisabled : function(v){
26355 this[v !== true ? "enable" : "disable"]();
26359 onClick : function(e){
26361 e.preventDefault();
26366 if(!this.disabled){
26367 if(this.enableToggle){
26370 if(this.menu && !this.menu.isVisible()){
26371 this.menu.show(this.el, this.menuAlign);
26373 this.fireEvent("click", this, e);
26375 this.el.removeClass("x-btn-over");
26376 this.handler.call(this.scope || this, this, e);
26381 onMouseOver : function(e){
26382 if(!this.disabled){
26383 this.el.addClass("x-btn-over");
26384 this.fireEvent('mouseover', this, e);
26388 onMouseOut : function(e){
26389 if(!e.within(this.el, true)){
26390 this.el.removeClass("x-btn-over");
26391 this.fireEvent('mouseout', this, e);
26395 onFocus : function(e){
26396 if(!this.disabled){
26397 this.el.addClass("x-btn-focus");
26401 onBlur : function(e){
26402 this.el.removeClass("x-btn-focus");
26405 onMouseDown : function(e){
26406 if(!this.disabled && e.button == 0){
26407 this.el.addClass("x-btn-click");
26408 Roo.get(document).on('mouseup', this.onMouseUp, this);
26412 onMouseUp : function(e){
26414 this.el.removeClass("x-btn-click");
26415 Roo.get(document).un('mouseup', this.onMouseUp, this);
26419 onMenuShow : function(e){
26420 this.el.addClass("x-btn-menu-active");
26423 onMenuHide : function(e){
26424 this.el.removeClass("x-btn-menu-active");
26428 // Private utility class used by Button
26429 Roo.ButtonToggleMgr = function(){
26432 function toggleGroup(btn, state){
26434 var g = groups[btn.toggleGroup];
26435 for(var i = 0, l = g.length; i < l; i++){
26437 g[i].toggle(false);
26444 register : function(btn){
26445 if(!btn.toggleGroup){
26448 var g = groups[btn.toggleGroup];
26450 g = groups[btn.toggleGroup] = [];
26453 btn.on("toggle", toggleGroup);
26456 unregister : function(btn){
26457 if(!btn.toggleGroup){
26460 var g = groups[btn.toggleGroup];
26463 btn.un("toggle", toggleGroup);
26469 * Ext JS Library 1.1.1
26470 * Copyright(c) 2006-2007, Ext JS, LLC.
26472 * Originally Released Under LGPL - original licence link has changed is not relivant.
26475 * <script type="text/javascript">
26479 * @class Roo.SplitButton
26480 * @extends Roo.Button
26481 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26482 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26483 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26484 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26485 * @cfg {String} arrowTooltip The title attribute of the arrow
26487 * Create a new menu button
26488 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26489 * @param {Object} config The config object
26491 Roo.SplitButton = function(renderTo, config){
26492 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26494 * @event arrowclick
26495 * Fires when this button's arrow is clicked
26496 * @param {SplitButton} this
26497 * @param {EventObject} e The click event
26499 this.addEvents({"arrowclick":true});
26502 Roo.extend(Roo.SplitButton, Roo.Button, {
26503 render : function(renderTo){
26504 // this is one sweet looking template!
26505 var tpl = new Roo.Template(
26506 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26507 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26508 '<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>',
26509 "</tbody></table></td><td>",
26510 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26511 '<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>',
26512 "</tbody></table></td></tr></table>"
26514 var btn = tpl.append(renderTo, [this.text, this.type], true);
26515 var btnEl = btn.child("button");
26517 btn.addClass(this.cls);
26520 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26523 btnEl.addClass(this.iconCls);
26525 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26529 if(this.handleMouseEvents){
26530 btn.on("mouseover", this.onMouseOver, this);
26531 btn.on("mouseout", this.onMouseOut, this);
26532 btn.on("mousedown", this.onMouseDown, this);
26533 btn.on("mouseup", this.onMouseUp, this);
26535 btn.on(this.clickEvent, this.onClick, this);
26537 if(typeof this.tooltip == 'object'){
26538 Roo.QuickTips.tips(Roo.apply({
26542 btnEl.dom[this.tooltipType] = this.tooltip;
26545 if(this.arrowTooltip){
26546 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26555 this.el.addClass("x-btn-pressed");
26557 if(Roo.isIE && !Roo.isIE7){
26558 this.autoWidth.defer(1, this);
26563 this.menu.on("show", this.onMenuShow, this);
26564 this.menu.on("hide", this.onMenuHide, this);
26566 this.fireEvent('render', this);
26570 autoWidth : function(){
26572 var tbl = this.el.child("table:first");
26573 var tbl2 = this.el.child("table:last");
26574 this.el.setWidth("auto");
26575 tbl.setWidth("auto");
26576 if(Roo.isIE7 && Roo.isStrict){
26577 var ib = this.el.child('button:first');
26578 if(ib && ib.getWidth() > 20){
26580 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26585 this.el.beginMeasure();
26587 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26588 tbl.setWidth(this.minWidth-tbl2.getWidth());
26591 this.el.endMeasure();
26594 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26598 * Sets this button's click handler
26599 * @param {Function} handler The function to call when the button is clicked
26600 * @param {Object} scope (optional) Scope for the function passed above
26602 setHandler : function(handler, scope){
26603 this.handler = handler;
26604 this.scope = scope;
26608 * Sets this button's arrow click handler
26609 * @param {Function} handler The function to call when the arrow is clicked
26610 * @param {Object} scope (optional) Scope for the function passed above
26612 setArrowHandler : function(handler, scope){
26613 this.arrowHandler = handler;
26614 this.scope = scope;
26620 focus : function(){
26622 this.el.child("button:first").focus();
26627 onClick : function(e){
26628 e.preventDefault();
26629 if(!this.disabled){
26630 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26631 if(this.menu && !this.menu.isVisible()){
26632 this.menu.show(this.el, this.menuAlign);
26634 this.fireEvent("arrowclick", this, e);
26635 if(this.arrowHandler){
26636 this.arrowHandler.call(this.scope || this, this, e);
26639 this.fireEvent("click", this, e);
26641 this.handler.call(this.scope || this, this, e);
26647 onMouseDown : function(e){
26648 if(!this.disabled){
26649 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26653 onMouseUp : function(e){
26654 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26659 // backwards compat
26660 Roo.MenuButton = Roo.SplitButton;/*
26662 * Ext JS Library 1.1.1
26663 * Copyright(c) 2006-2007, Ext JS, LLC.
26665 * Originally Released Under LGPL - original licence link has changed is not relivant.
26668 * <script type="text/javascript">
26672 * @class Roo.Toolbar
26673 * Basic Toolbar class.
26675 * Creates a new Toolbar
26676 * @param {Object} config The config object
26678 Roo.Toolbar = function(container, buttons, config)
26680 /// old consturctor format still supported..
26681 if(container instanceof Array){ // omit the container for later rendering
26682 buttons = container;
26686 if (typeof(container) == 'object' && container.xtype) {
26687 config = container;
26688 container = config.container;
26689 buttons = config.buttons; // not really - use items!!
26692 if (config && config.items) {
26693 xitems = config.items;
26694 delete config.items;
26696 Roo.apply(this, config);
26697 this.buttons = buttons;
26700 this.render(container);
26702 Roo.each(xitems, function(b) {
26708 Roo.Toolbar.prototype = {
26710 * @cfg {Roo.data.Store} items
26711 * array of button configs or elements to add
26715 * @cfg {String/HTMLElement/Element} container
26716 * The id or element that will contain the toolbar
26719 render : function(ct){
26720 this.el = Roo.get(ct);
26722 this.el.addClass(this.cls);
26724 // using a table allows for vertical alignment
26725 // 100% width is needed by Safari...
26726 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26727 this.tr = this.el.child("tr", true);
26729 this.items = new Roo.util.MixedCollection(false, function(o){
26730 return o.id || ("item" + (++autoId));
26733 this.add.apply(this, this.buttons);
26734 delete this.buttons;
26739 * Adds element(s) to the toolbar -- this function takes a variable number of
26740 * arguments of mixed type and adds them to the toolbar.
26741 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26743 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26744 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26745 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26746 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26747 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26748 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26749 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26750 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26751 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26753 * @param {Mixed} arg2
26754 * @param {Mixed} etc.
26757 var a = arguments, l = a.length;
26758 for(var i = 0; i < l; i++){
26763 _add : function(el) {
26766 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26769 if (el.applyTo){ // some kind of form field
26770 return this.addField(el);
26772 if (el.render){ // some kind of Toolbar.Item
26773 return this.addItem(el);
26775 if (typeof el == "string"){ // string
26776 if(el == "separator" || el == "-"){
26777 return this.addSeparator();
26780 return this.addSpacer();
26783 return this.addFill();
26785 return this.addText(el);
26788 if(el.tagName){ // element
26789 return this.addElement(el);
26791 if(typeof el == "object"){ // must be button config?
26792 return this.addButton(el);
26794 // and now what?!?!
26800 * Add an Xtype element
26801 * @param {Object} xtype Xtype Object
26802 * @return {Object} created Object
26804 addxtype : function(e){
26805 return this.add(e);
26809 * Returns the Element for this toolbar.
26810 * @return {Roo.Element}
26812 getEl : function(){
26818 * @return {Roo.Toolbar.Item} The separator item
26820 addSeparator : function(){
26821 return this.addItem(new Roo.Toolbar.Separator());
26825 * Adds a spacer element
26826 * @return {Roo.Toolbar.Spacer} The spacer item
26828 addSpacer : function(){
26829 return this.addItem(new Roo.Toolbar.Spacer());
26833 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26834 * @return {Roo.Toolbar.Fill} The fill item
26836 addFill : function(){
26837 return this.addItem(new Roo.Toolbar.Fill());
26841 * Adds any standard HTML element to the toolbar
26842 * @param {String/HTMLElement/Element} el The element or id of the element to add
26843 * @return {Roo.Toolbar.Item} The element's item
26845 addElement : function(el){
26846 return this.addItem(new Roo.Toolbar.Item(el));
26849 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26850 * @type Roo.util.MixedCollection
26855 * Adds any Toolbar.Item or subclass
26856 * @param {Roo.Toolbar.Item} item
26857 * @return {Roo.Toolbar.Item} The item
26859 addItem : function(item){
26860 var td = this.nextBlock();
26862 this.items.add(item);
26867 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26868 * @param {Object/Array} config A button config or array of configs
26869 * @return {Roo.Toolbar.Button/Array}
26871 addButton : function(config){
26872 if(config instanceof Array){
26874 for(var i = 0, len = config.length; i < len; i++) {
26875 buttons.push(this.addButton(config[i]));
26880 if(!(config instanceof Roo.Toolbar.Button)){
26882 new Roo.Toolbar.SplitButton(config) :
26883 new Roo.Toolbar.Button(config);
26885 var td = this.nextBlock();
26892 * Adds text to the toolbar
26893 * @param {String} text The text to add
26894 * @return {Roo.Toolbar.Item} The element's item
26896 addText : function(text){
26897 return this.addItem(new Roo.Toolbar.TextItem(text));
26901 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26902 * @param {Number} index The index where the item is to be inserted
26903 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26904 * @return {Roo.Toolbar.Button/Item}
26906 insertButton : function(index, item){
26907 if(item instanceof Array){
26909 for(var i = 0, len = item.length; i < len; i++) {
26910 buttons.push(this.insertButton(index + i, item[i]));
26914 if (!(item instanceof Roo.Toolbar.Button)){
26915 item = new Roo.Toolbar.Button(item);
26917 var td = document.createElement("td");
26918 this.tr.insertBefore(td, this.tr.childNodes[index]);
26920 this.items.insert(index, item);
26925 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26926 * @param {Object} config
26927 * @return {Roo.Toolbar.Item} The element's item
26929 addDom : function(config, returnEl){
26930 var td = this.nextBlock();
26931 Roo.DomHelper.overwrite(td, config);
26932 var ti = new Roo.Toolbar.Item(td.firstChild);
26934 this.items.add(ti);
26939 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26940 * @type Roo.util.MixedCollection
26945 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26946 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26947 * @param {Roo.form.Field} field
26948 * @return {Roo.ToolbarItem}
26952 addField : function(field) {
26953 if (!this.fields) {
26955 this.fields = new Roo.util.MixedCollection(false, function(o){
26956 return o.id || ("item" + (++autoId));
26961 var td = this.nextBlock();
26963 var ti = new Roo.Toolbar.Item(td.firstChild);
26965 this.items.add(ti);
26966 this.fields.add(field);
26977 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26978 this.el.child('div').hide();
26986 this.el.child('div').show();
26990 nextBlock : function(){
26991 var td = document.createElement("td");
26992 this.tr.appendChild(td);
26997 destroy : function(){
26998 if(this.items){ // rendered?
26999 Roo.destroy.apply(Roo, this.items.items);
27001 if(this.fields){ // rendered?
27002 Roo.destroy.apply(Roo, this.fields.items);
27004 Roo.Element.uncache(this.el, this.tr);
27009 * @class Roo.Toolbar.Item
27010 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27012 * Creates a new Item
27013 * @param {HTMLElement} el
27015 Roo.Toolbar.Item = function(el){
27016 this.el = Roo.getDom(el);
27017 this.id = Roo.id(this.el);
27018 this.hidden = false;
27021 Roo.Toolbar.Item.prototype = {
27024 * Get this item's HTML Element
27025 * @return {HTMLElement}
27027 getEl : function(){
27032 render : function(td){
27034 td.appendChild(this.el);
27038 * Removes and destroys this item.
27040 destroy : function(){
27041 this.td.parentNode.removeChild(this.td);
27048 this.hidden = false;
27049 this.td.style.display = "";
27056 this.hidden = true;
27057 this.td.style.display = "none";
27061 * Convenience function for boolean show/hide.
27062 * @param {Boolean} visible true to show/false to hide
27064 setVisible: function(visible){
27073 * Try to focus this item.
27075 focus : function(){
27076 Roo.fly(this.el).focus();
27080 * Disables this item.
27082 disable : function(){
27083 Roo.fly(this.td).addClass("x-item-disabled");
27084 this.disabled = true;
27085 this.el.disabled = true;
27089 * Enables this item.
27091 enable : function(){
27092 Roo.fly(this.td).removeClass("x-item-disabled");
27093 this.disabled = false;
27094 this.el.disabled = false;
27100 * @class Roo.Toolbar.Separator
27101 * @extends Roo.Toolbar.Item
27102 * A simple toolbar separator class
27104 * Creates a new Separator
27106 Roo.Toolbar.Separator = function(){
27107 var s = document.createElement("span");
27108 s.className = "ytb-sep";
27109 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27111 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27112 enable:Roo.emptyFn,
27113 disable:Roo.emptyFn,
27118 * @class Roo.Toolbar.Spacer
27119 * @extends Roo.Toolbar.Item
27120 * A simple element that adds extra horizontal space to a toolbar.
27122 * Creates a new Spacer
27124 Roo.Toolbar.Spacer = function(){
27125 var s = document.createElement("div");
27126 s.className = "ytb-spacer";
27127 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27129 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27130 enable:Roo.emptyFn,
27131 disable:Roo.emptyFn,
27136 * @class Roo.Toolbar.Fill
27137 * @extends Roo.Toolbar.Spacer
27138 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27140 * Creates a new Spacer
27142 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27144 render : function(td){
27145 td.style.width = '100%';
27146 Roo.Toolbar.Fill.superclass.render.call(this, td);
27151 * @class Roo.Toolbar.TextItem
27152 * @extends Roo.Toolbar.Item
27153 * A simple class that renders text directly into a toolbar.
27155 * Creates a new TextItem
27156 * @param {String} text
27158 Roo.Toolbar.TextItem = function(text){
27159 if (typeof(text) == 'object') {
27162 var s = document.createElement("span");
27163 s.className = "ytb-text";
27164 s.innerHTML = text;
27165 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27167 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27168 enable:Roo.emptyFn,
27169 disable:Roo.emptyFn,
27174 * @class Roo.Toolbar.Button
27175 * @extends Roo.Button
27176 * A button that renders into a toolbar.
27178 * Creates a new Button
27179 * @param {Object} config A standard {@link Roo.Button} config object
27181 Roo.Toolbar.Button = function(config){
27182 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27184 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27185 render : function(td){
27187 Roo.Toolbar.Button.superclass.render.call(this, td);
27191 * Removes and destroys this button
27193 destroy : function(){
27194 Roo.Toolbar.Button.superclass.destroy.call(this);
27195 this.td.parentNode.removeChild(this.td);
27199 * Shows this button
27202 this.hidden = false;
27203 this.td.style.display = "";
27207 * Hides this button
27210 this.hidden = true;
27211 this.td.style.display = "none";
27215 * Disables this item
27217 disable : function(){
27218 Roo.fly(this.td).addClass("x-item-disabled");
27219 this.disabled = true;
27223 * Enables this item
27225 enable : function(){
27226 Roo.fly(this.td).removeClass("x-item-disabled");
27227 this.disabled = false;
27230 // backwards compat
27231 Roo.ToolbarButton = Roo.Toolbar.Button;
27234 * @class Roo.Toolbar.SplitButton
27235 * @extends Roo.SplitButton
27236 * A menu button that renders into a toolbar.
27238 * Creates a new SplitButton
27239 * @param {Object} config A standard {@link Roo.SplitButton} config object
27241 Roo.Toolbar.SplitButton = function(config){
27242 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27244 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27245 render : function(td){
27247 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27251 * Removes and destroys this button
27253 destroy : function(){
27254 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27255 this.td.parentNode.removeChild(this.td);
27259 * Shows this button
27262 this.hidden = false;
27263 this.td.style.display = "";
27267 * Hides this button
27270 this.hidden = true;
27271 this.td.style.display = "none";
27275 // backwards compat
27276 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27278 * Ext JS Library 1.1.1
27279 * Copyright(c) 2006-2007, Ext JS, LLC.
27281 * Originally Released Under LGPL - original licence link has changed is not relivant.
27284 * <script type="text/javascript">
27288 * @class Roo.PagingToolbar
27289 * @extends Roo.Toolbar
27290 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27292 * Create a new PagingToolbar
27293 * @param {Object} config The config object
27295 Roo.PagingToolbar = function(el, ds, config)
27297 // old args format still supported... - xtype is prefered..
27298 if (typeof(el) == 'object' && el.xtype) {
27299 // created from xtype...
27301 ds = el.dataSource;
27302 el = config.container;
27305 if (config.items) {
27306 items = config.items;
27310 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27313 this.renderButtons(this.el);
27316 // supprot items array.
27318 Roo.each(items, function(e) {
27319 this.add(Roo.factory(e));
27324 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27326 * @cfg {Roo.data.Store} dataSource
27327 * The underlying data store providing the paged data
27330 * @cfg {String/HTMLElement/Element} container
27331 * container The id or element that will contain the toolbar
27334 * @cfg {Boolean} displayInfo
27335 * True to display the displayMsg (defaults to false)
27338 * @cfg {Number} pageSize
27339 * The number of records to display per page (defaults to 20)
27343 * @cfg {String} displayMsg
27344 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27346 displayMsg : 'Displaying {0} - {1} of {2}',
27348 * @cfg {String} emptyMsg
27349 * The message to display when no records are found (defaults to "No data to display")
27351 emptyMsg : 'No data to display',
27353 * Customizable piece of the default paging text (defaults to "Page")
27356 beforePageText : "Page",
27358 * Customizable piece of the default paging text (defaults to "of %0")
27361 afterPageText : "of {0}",
27363 * Customizable piece of the default paging text (defaults to "First Page")
27366 firstText : "First Page",
27368 * Customizable piece of the default paging text (defaults to "Previous Page")
27371 prevText : "Previous Page",
27373 * Customizable piece of the default paging text (defaults to "Next Page")
27376 nextText : "Next Page",
27378 * Customizable piece of the default paging text (defaults to "Last Page")
27381 lastText : "Last Page",
27383 * Customizable piece of the default paging text (defaults to "Refresh")
27386 refreshText : "Refresh",
27389 renderButtons : function(el){
27390 Roo.PagingToolbar.superclass.render.call(this, el);
27391 this.first = this.addButton({
27392 tooltip: this.firstText,
27393 cls: "x-btn-icon x-grid-page-first",
27395 handler: this.onClick.createDelegate(this, ["first"])
27397 this.prev = this.addButton({
27398 tooltip: this.prevText,
27399 cls: "x-btn-icon x-grid-page-prev",
27401 handler: this.onClick.createDelegate(this, ["prev"])
27403 //this.addSeparator();
27404 this.add(this.beforePageText);
27405 this.field = Roo.get(this.addDom({
27410 cls: "x-grid-page-number"
27412 this.field.on("keydown", this.onPagingKeydown, this);
27413 this.field.on("focus", function(){this.dom.select();});
27414 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27415 this.field.setHeight(18);
27416 //this.addSeparator();
27417 this.next = this.addButton({
27418 tooltip: this.nextText,
27419 cls: "x-btn-icon x-grid-page-next",
27421 handler: this.onClick.createDelegate(this, ["next"])
27423 this.last = this.addButton({
27424 tooltip: this.lastText,
27425 cls: "x-btn-icon x-grid-page-last",
27427 handler: this.onClick.createDelegate(this, ["last"])
27429 //this.addSeparator();
27430 this.loading = this.addButton({
27431 tooltip: this.refreshText,
27432 cls: "x-btn-icon x-grid-loading",
27433 handler: this.onClick.createDelegate(this, ["refresh"])
27436 if(this.displayInfo){
27437 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27442 updateInfo : function(){
27443 if(this.displayEl){
27444 var count = this.ds.getCount();
27445 var msg = count == 0 ?
27449 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27451 this.displayEl.update(msg);
27456 onLoad : function(ds, r, o){
27457 this.cursor = o.params ? o.params.start : 0;
27458 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27460 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27461 this.field.dom.value = ap;
27462 this.first.setDisabled(ap == 1);
27463 this.prev.setDisabled(ap == 1);
27464 this.next.setDisabled(ap == ps);
27465 this.last.setDisabled(ap == ps);
27466 this.loading.enable();
27471 getPageData : function(){
27472 var total = this.ds.getTotalCount();
27475 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27476 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27481 onLoadError : function(){
27482 this.loading.enable();
27486 onPagingKeydown : function(e){
27487 var k = e.getKey();
27488 var d = this.getPageData();
27490 var v = this.field.dom.value, pageNum;
27491 if(!v || isNaN(pageNum = parseInt(v, 10))){
27492 this.field.dom.value = d.activePage;
27495 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27496 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27499 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))
27501 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27502 this.field.dom.value = pageNum;
27503 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27506 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27508 var v = this.field.dom.value, pageNum;
27509 var increment = (e.shiftKey) ? 10 : 1;
27510 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27512 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27513 this.field.dom.value = d.activePage;
27516 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27518 this.field.dom.value = parseInt(v, 10) + increment;
27519 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27520 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27527 beforeLoad : function(){
27529 this.loading.disable();
27534 onClick : function(which){
27538 ds.load({params:{start: 0, limit: this.pageSize}});
27541 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27544 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27547 var total = ds.getTotalCount();
27548 var extra = total % this.pageSize;
27549 var lastStart = extra ? (total - extra) : total-this.pageSize;
27550 ds.load({params:{start: lastStart, limit: this.pageSize}});
27553 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27559 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27560 * @param {Roo.data.Store} store The data store to unbind
27562 unbind : function(ds){
27563 ds.un("beforeload", this.beforeLoad, this);
27564 ds.un("load", this.onLoad, this);
27565 ds.un("loadexception", this.onLoadError, this);
27566 ds.un("remove", this.updateInfo, this);
27567 ds.un("add", this.updateInfo, this);
27568 this.ds = undefined;
27572 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27573 * @param {Roo.data.Store} store The data store to bind
27575 bind : function(ds){
27576 ds.on("beforeload", this.beforeLoad, this);
27577 ds.on("load", this.onLoad, this);
27578 ds.on("loadexception", this.onLoadError, this);
27579 ds.on("remove", this.updateInfo, this);
27580 ds.on("add", this.updateInfo, this);
27585 * Ext JS Library 1.1.1
27586 * Copyright(c) 2006-2007, Ext JS, LLC.
27588 * Originally Released Under LGPL - original licence link has changed is not relivant.
27591 * <script type="text/javascript">
27595 * @class Roo.Resizable
27596 * @extends Roo.util.Observable
27597 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27598 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27599 * 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
27600 * the element will be wrapped for you automatically.</p>
27601 * <p>Here is the list of valid resize handles:</p>
27604 ------ -------------------
27613 'hd' horizontal drag
27616 * <p>Here's an example showing the creation of a typical Resizable:</p>
27618 var resizer = new Roo.Resizable("element-id", {
27626 resizer.on("resize", myHandler);
27628 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27629 * resizer.east.setDisplayed(false);</p>
27630 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27631 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27632 * resize operation's new size (defaults to [0, 0])
27633 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27634 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27635 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27636 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27637 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27638 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27639 * @cfg {Number} width The width of the element in pixels (defaults to null)
27640 * @cfg {Number} height The height of the element in pixels (defaults to null)
27641 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27642 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27643 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27644 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27645 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27646 * in favor of the handles config option (defaults to false)
27647 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27648 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27649 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27650 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27651 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27652 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27653 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27654 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27655 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27656 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27657 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27659 * Create a new resizable component
27660 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27661 * @param {Object} config configuration options
27663 Roo.Resizable = function(el, config)
27665 this.el = Roo.get(el);
27667 if(config && config.wrap){
27668 config.resizeChild = this.el;
27669 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27670 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27671 this.el.setStyle("overflow", "hidden");
27672 this.el.setPositioning(config.resizeChild.getPositioning());
27673 config.resizeChild.clearPositioning();
27674 if(!config.width || !config.height){
27675 var csize = config.resizeChild.getSize();
27676 this.el.setSize(csize.width, csize.height);
27678 if(config.pinned && !config.adjustments){
27679 config.adjustments = "auto";
27683 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27684 this.proxy.unselectable();
27685 this.proxy.enableDisplayMode('block');
27687 Roo.apply(this, config);
27690 this.disableTrackOver = true;
27691 this.el.addClass("x-resizable-pinned");
27693 // if the element isn't positioned, make it relative
27694 var position = this.el.getStyle("position");
27695 if(position != "absolute" && position != "fixed"){
27696 this.el.setStyle("position", "relative");
27698 if(!this.handles){ // no handles passed, must be legacy style
27699 this.handles = 's,e,se';
27700 if(this.multiDirectional){
27701 this.handles += ',n,w';
27704 if(this.handles == "all"){
27705 this.handles = "n s e w ne nw se sw";
27707 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27708 var ps = Roo.Resizable.positions;
27709 for(var i = 0, len = hs.length; i < len; i++){
27710 if(hs[i] && ps[hs[i]]){
27711 var pos = ps[hs[i]];
27712 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27716 this.corner = this.southeast;
27718 // updateBox = the box can move..
27719 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27720 this.updateBox = true;
27723 this.activeHandle = null;
27725 if(this.resizeChild){
27726 if(typeof this.resizeChild == "boolean"){
27727 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27729 this.resizeChild = Roo.get(this.resizeChild, true);
27733 if(this.adjustments == "auto"){
27734 var rc = this.resizeChild;
27735 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27736 if(rc && (hw || hn)){
27737 rc.position("relative");
27738 rc.setLeft(hw ? hw.el.getWidth() : 0);
27739 rc.setTop(hn ? hn.el.getHeight() : 0);
27741 this.adjustments = [
27742 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27743 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27747 if(this.draggable){
27748 this.dd = this.dynamic ?
27749 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27750 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27756 * @event beforeresize
27757 * Fired before resize is allowed. Set enabled to false to cancel resize.
27758 * @param {Roo.Resizable} this
27759 * @param {Roo.EventObject} e The mousedown event
27761 "beforeresize" : true,
27764 * Fired after a resize.
27765 * @param {Roo.Resizable} this
27766 * @param {Number} width The new width
27767 * @param {Number} height The new height
27768 * @param {Roo.EventObject} e The mouseup event
27773 if(this.width !== null && this.height !== null){
27774 this.resizeTo(this.width, this.height);
27776 this.updateChildSize();
27779 this.el.dom.style.zoom = 1;
27781 Roo.Resizable.superclass.constructor.call(this);
27784 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27785 resizeChild : false,
27786 adjustments : [0, 0],
27796 multiDirectional : false,
27797 disableTrackOver : false,
27798 easing : 'easeOutStrong',
27799 widthIncrement : 0,
27800 heightIncrement : 0,
27804 preserveRatio : false,
27805 transparent: false,
27811 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27813 constrainTo: undefined,
27815 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27817 resizeRegion: undefined,
27821 * Perform a manual resize
27822 * @param {Number} width
27823 * @param {Number} height
27825 resizeTo : function(width, height){
27826 this.el.setSize(width, height);
27827 this.updateChildSize();
27828 this.fireEvent("resize", this, width, height, null);
27832 startSizing : function(e, handle){
27833 this.fireEvent("beforeresize", this, e);
27834 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27837 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27838 this.overlay.unselectable();
27839 this.overlay.enableDisplayMode("block");
27840 this.overlay.on("mousemove", this.onMouseMove, this);
27841 this.overlay.on("mouseup", this.onMouseUp, this);
27843 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27845 this.resizing = true;
27846 this.startBox = this.el.getBox();
27847 this.startPoint = e.getXY();
27848 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27849 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27851 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27852 this.overlay.show();
27854 if(this.constrainTo) {
27855 var ct = Roo.get(this.constrainTo);
27856 this.resizeRegion = ct.getRegion().adjust(
27857 ct.getFrameWidth('t'),
27858 ct.getFrameWidth('l'),
27859 -ct.getFrameWidth('b'),
27860 -ct.getFrameWidth('r')
27864 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27866 this.proxy.setBox(this.startBox);
27868 this.proxy.setStyle('visibility', 'visible');
27874 onMouseDown : function(handle, e){
27877 this.activeHandle = handle;
27878 this.startSizing(e, handle);
27883 onMouseUp : function(e){
27884 var size = this.resizeElement();
27885 this.resizing = false;
27887 this.overlay.hide();
27889 this.fireEvent("resize", this, size.width, size.height, e);
27893 updateChildSize : function(){
27894 if(this.resizeChild){
27896 var child = this.resizeChild;
27897 var adj = this.adjustments;
27898 if(el.dom.offsetWidth){
27899 var b = el.getSize(true);
27900 child.setSize(b.width+adj[0], b.height+adj[1]);
27902 // Second call here for IE
27903 // The first call enables instant resizing and
27904 // the second call corrects scroll bars if they
27907 setTimeout(function(){
27908 if(el.dom.offsetWidth){
27909 var b = el.getSize(true);
27910 child.setSize(b.width+adj[0], b.height+adj[1]);
27918 snap : function(value, inc, min){
27919 if(!inc || !value) return value;
27920 var newValue = value;
27921 var m = value % inc;
27924 newValue = value + (inc-m);
27926 newValue = value - m;
27929 return Math.max(min, newValue);
27933 resizeElement : function(){
27934 var box = this.proxy.getBox();
27935 if(this.updateBox){
27936 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27938 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27940 this.updateChildSize();
27948 constrain : function(v, diff, m, mx){
27951 }else if(v - diff > mx){
27958 onMouseMove : function(e){
27960 try{// try catch so if something goes wrong the user doesn't get hung
27962 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27966 //var curXY = this.startPoint;
27967 var curSize = this.curSize || this.startBox;
27968 var x = this.startBox.x, y = this.startBox.y;
27969 var ox = x, oy = y;
27970 var w = curSize.width, h = curSize.height;
27971 var ow = w, oh = h;
27972 var mw = this.minWidth, mh = this.minHeight;
27973 var mxw = this.maxWidth, mxh = this.maxHeight;
27974 var wi = this.widthIncrement;
27975 var hi = this.heightIncrement;
27977 var eventXY = e.getXY();
27978 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27979 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27981 var pos = this.activeHandle.position;
27986 w = Math.min(Math.max(mw, w), mxw);
27991 h = Math.min(Math.max(mh, h), mxh);
27996 w = Math.min(Math.max(mw, w), mxw);
27997 h = Math.min(Math.max(mh, h), mxh);
28000 diffY = this.constrain(h, diffY, mh, mxh);
28007 var adiffX = Math.abs(diffX);
28008 var sub = (adiffX % wi); // how much
28009 if (sub > (wi/2)) { // far enough to snap
28010 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28012 // remove difference..
28013 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28017 x = Math.max(this.minX, x);
28020 diffX = this.constrain(w, diffX, mw, mxw);
28026 w = Math.min(Math.max(mw, w), mxw);
28027 diffY = this.constrain(h, diffY, mh, mxh);
28032 diffX = this.constrain(w, diffX, mw, mxw);
28033 diffY = this.constrain(h, diffY, mh, mxh);
28040 diffX = this.constrain(w, diffX, mw, mxw);
28042 h = Math.min(Math.max(mh, h), mxh);
28048 var sw = this.snap(w, wi, mw);
28049 var sh = this.snap(h, hi, mh);
28050 if(sw != w || sh != h){
28073 if(this.preserveRatio){
28078 h = Math.min(Math.max(mh, h), mxh);
28083 w = Math.min(Math.max(mw, w), mxw);
28088 w = Math.min(Math.max(mw, w), mxw);
28094 w = Math.min(Math.max(mw, w), mxw);
28100 h = Math.min(Math.max(mh, h), mxh);
28108 h = Math.min(Math.max(mh, h), mxh);
28118 h = Math.min(Math.max(mh, h), mxh);
28126 if (pos == 'hdrag') {
28129 this.proxy.setBounds(x, y, w, h);
28131 this.resizeElement();
28138 handleOver : function(){
28140 this.el.addClass("x-resizable-over");
28145 handleOut : function(){
28146 if(!this.resizing){
28147 this.el.removeClass("x-resizable-over");
28152 * Returns the element this component is bound to.
28153 * @return {Roo.Element}
28155 getEl : function(){
28160 * Returns the resizeChild element (or null).
28161 * @return {Roo.Element}
28163 getResizeChild : function(){
28164 return this.resizeChild;
28168 * Destroys this resizable. If the element was wrapped and
28169 * removeEl is not true then the element remains.
28170 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28172 destroy : function(removeEl){
28173 this.proxy.remove();
28175 this.overlay.removeAllListeners();
28176 this.overlay.remove();
28178 var ps = Roo.Resizable.positions;
28180 if(typeof ps[k] != "function" && this[ps[k]]){
28181 var h = this[ps[k]];
28182 h.el.removeAllListeners();
28187 this.el.update("");
28194 // hash to map config positions to true positions
28195 Roo.Resizable.positions = {
28196 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28201 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28203 // only initialize the template if resizable is used
28204 var tpl = Roo.DomHelper.createTemplate(
28205 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28208 Roo.Resizable.Handle.prototype.tpl = tpl;
28210 this.position = pos;
28212 // show north drag fro topdra
28213 var handlepos = pos == 'hdrag' ? 'north' : pos;
28215 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28216 if (pos == 'hdrag') {
28217 this.el.setStyle('cursor', 'pointer');
28219 this.el.unselectable();
28221 this.el.setOpacity(0);
28223 this.el.on("mousedown", this.onMouseDown, this);
28224 if(!disableTrackOver){
28225 this.el.on("mouseover", this.onMouseOver, this);
28226 this.el.on("mouseout", this.onMouseOut, this);
28231 Roo.Resizable.Handle.prototype = {
28232 afterResize : function(rz){
28236 onMouseDown : function(e){
28237 this.rz.onMouseDown(this, e);
28240 onMouseOver : function(e){
28241 this.rz.handleOver(this, e);
28244 onMouseOut : function(e){
28245 this.rz.handleOut(this, e);
28249 * Ext JS Library 1.1.1
28250 * Copyright(c) 2006-2007, Ext JS, LLC.
28252 * Originally Released Under LGPL - original licence link has changed is not relivant.
28255 * <script type="text/javascript">
28259 * @class Roo.Editor
28260 * @extends Roo.Component
28261 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28263 * Create a new Editor
28264 * @param {Roo.form.Field} field The Field object (or descendant)
28265 * @param {Object} config The config object
28267 Roo.Editor = function(field, config){
28268 Roo.Editor.superclass.constructor.call(this, config);
28269 this.field = field;
28272 * @event beforestartedit
28273 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28274 * false from the handler of this event.
28275 * @param {Editor} this
28276 * @param {Roo.Element} boundEl The underlying element bound to this editor
28277 * @param {Mixed} value The field value being set
28279 "beforestartedit" : true,
28282 * Fires when this editor is displayed
28283 * @param {Roo.Element} boundEl The underlying element bound to this editor
28284 * @param {Mixed} value The starting field value
28286 "startedit" : true,
28288 * @event beforecomplete
28289 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28290 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28291 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28292 * event will not fire since no edit actually occurred.
28293 * @param {Editor} this
28294 * @param {Mixed} value The current field value
28295 * @param {Mixed} startValue The original field value
28297 "beforecomplete" : true,
28300 * Fires after editing is complete and any changed value has been written to the underlying field.
28301 * @param {Editor} this
28302 * @param {Mixed} value The current field value
28303 * @param {Mixed} startValue The original field value
28307 * @event specialkey
28308 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28309 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28310 * @param {Roo.form.Field} this
28311 * @param {Roo.EventObject} e The event object
28313 "specialkey" : true
28317 Roo.extend(Roo.Editor, Roo.Component, {
28319 * @cfg {Boolean/String} autosize
28320 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28321 * or "height" to adopt the height only (defaults to false)
28324 * @cfg {Boolean} revertInvalid
28325 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28326 * validation fails (defaults to true)
28329 * @cfg {Boolean} ignoreNoChange
28330 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28331 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28332 * will never be ignored.
28335 * @cfg {Boolean} hideEl
28336 * False to keep the bound element visible while the editor is displayed (defaults to true)
28339 * @cfg {Mixed} value
28340 * The data value of the underlying field (defaults to "")
28344 * @cfg {String} alignment
28345 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28349 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28350 * for bottom-right shadow (defaults to "frame")
28354 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28358 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28360 completeOnEnter : false,
28362 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28364 cancelOnEsc : false,
28366 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28371 onRender : function(ct, position){
28372 this.el = new Roo.Layer({
28373 shadow: this.shadow,
28379 constrain: this.constrain
28381 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28382 if(this.field.msgTarget != 'title'){
28383 this.field.msgTarget = 'qtip';
28385 this.field.render(this.el);
28387 this.field.el.dom.setAttribute('autocomplete', 'off');
28389 this.field.on("specialkey", this.onSpecialKey, this);
28390 if(this.swallowKeys){
28391 this.field.el.swallowEvent(['keydown','keypress']);
28394 this.field.on("blur", this.onBlur, this);
28395 if(this.field.grow){
28396 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28400 onSpecialKey : function(field, e)
28402 //Roo.log('editor onSpecialKey');
28403 if(this.completeOnEnter && e.getKey() == e.ENTER){
28405 this.completeEdit();
28408 // do not fire special key otherwise it might hide close the editor...
28409 if(e.getKey() == e.ENTER){
28412 if(this.cancelOnEsc && e.getKey() == e.ESC){
28416 this.fireEvent('specialkey', field, e);
28421 * Starts the editing process and shows the editor.
28422 * @param {String/HTMLElement/Element} el The element to edit
28423 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28424 * to the innerHTML of el.
28426 startEdit : function(el, value){
28428 this.completeEdit();
28430 this.boundEl = Roo.get(el);
28431 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28432 if(!this.rendered){
28433 this.render(this.parentEl || document.body);
28435 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28438 this.startValue = v;
28439 this.field.setValue(v);
28441 var sz = this.boundEl.getSize();
28442 switch(this.autoSize){
28444 this.setSize(sz.width, "");
28447 this.setSize("", sz.height);
28450 this.setSize(sz.width, sz.height);
28453 this.el.alignTo(this.boundEl, this.alignment);
28454 this.editing = true;
28456 Roo.QuickTips.disable();
28462 * Sets the height and width of this editor.
28463 * @param {Number} width The new width
28464 * @param {Number} height The new height
28466 setSize : function(w, h){
28467 this.field.setSize(w, h);
28474 * Realigns the editor to the bound field based on the current alignment config value.
28476 realign : function(){
28477 this.el.alignTo(this.boundEl, this.alignment);
28481 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28482 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28484 completeEdit : function(remainVisible){
28488 var v = this.getValue();
28489 if(this.revertInvalid !== false && !this.field.isValid()){
28490 v = this.startValue;
28491 this.cancelEdit(true);
28493 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28494 this.editing = false;
28498 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28499 this.editing = false;
28500 if(this.updateEl && this.boundEl){
28501 this.boundEl.update(v);
28503 if(remainVisible !== true){
28506 this.fireEvent("complete", this, v, this.startValue);
28511 onShow : function(){
28513 if(this.hideEl !== false){
28514 this.boundEl.hide();
28517 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28518 this.fixIEFocus = true;
28519 this.deferredFocus.defer(50, this);
28521 this.field.focus();
28523 this.fireEvent("startedit", this.boundEl, this.startValue);
28526 deferredFocus : function(){
28528 this.field.focus();
28533 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28534 * reverted to the original starting value.
28535 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28536 * cancel (defaults to false)
28538 cancelEdit : function(remainVisible){
28540 this.setValue(this.startValue);
28541 if(remainVisible !== true){
28548 onBlur : function(){
28549 if(this.allowBlur !== true && this.editing){
28550 this.completeEdit();
28555 onHide : function(){
28557 this.completeEdit();
28561 if(this.field.collapse){
28562 this.field.collapse();
28565 if(this.hideEl !== false){
28566 this.boundEl.show();
28569 Roo.QuickTips.enable();
28574 * Sets the data value of the editor
28575 * @param {Mixed} value Any valid value supported by the underlying field
28577 setValue : function(v){
28578 this.field.setValue(v);
28582 * Gets the data value of the editor
28583 * @return {Mixed} The data value
28585 getValue : function(){
28586 return this.field.getValue();
28590 * Ext JS Library 1.1.1
28591 * Copyright(c) 2006-2007, Ext JS, LLC.
28593 * Originally Released Under LGPL - original licence link has changed is not relivant.
28596 * <script type="text/javascript">
28600 * @class Roo.BasicDialog
28601 * @extends Roo.util.Observable
28602 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28604 var dlg = new Roo.BasicDialog("my-dlg", {
28613 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28614 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28615 dlg.addButton('Cancel', dlg.hide, dlg);
28618 <b>A Dialog should always be a direct child of the body element.</b>
28619 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28620 * @cfg {String} title Default text to display in the title bar (defaults to null)
28621 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28622 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28623 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28624 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28625 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28626 * (defaults to null with no animation)
28627 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28628 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28629 * property for valid values (defaults to 'all')
28630 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28631 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28632 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28633 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28634 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28635 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28636 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28637 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28638 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28639 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28640 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28641 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28642 * draggable = true (defaults to false)
28643 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28644 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28645 * shadow (defaults to false)
28646 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28647 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28648 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28649 * @cfg {Array} buttons Array of buttons
28650 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28652 * Create a new BasicDialog.
28653 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28654 * @param {Object} config Configuration options
28656 Roo.BasicDialog = function(el, config){
28657 this.el = Roo.get(el);
28658 var dh = Roo.DomHelper;
28659 if(!this.el && config && config.autoCreate){
28660 if(typeof config.autoCreate == "object"){
28661 if(!config.autoCreate.id){
28662 config.autoCreate.id = el;
28664 this.el = dh.append(document.body,
28665 config.autoCreate, true);
28667 this.el = dh.append(document.body,
28668 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28672 el.setDisplayed(true);
28673 el.hide = this.hideAction;
28675 el.addClass("x-dlg");
28677 Roo.apply(this, config);
28679 this.proxy = el.createProxy("x-dlg-proxy");
28680 this.proxy.hide = this.hideAction;
28681 this.proxy.setOpacity(.5);
28685 el.setWidth(config.width);
28688 el.setHeight(config.height);
28690 this.size = el.getSize();
28691 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28692 this.xy = [config.x,config.y];
28694 this.xy = el.getCenterXY(true);
28696 /** The header element @type Roo.Element */
28697 this.header = el.child("> .x-dlg-hd");
28698 /** The body element @type Roo.Element */
28699 this.body = el.child("> .x-dlg-bd");
28700 /** The footer element @type Roo.Element */
28701 this.footer = el.child("> .x-dlg-ft");
28704 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28707 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28710 this.header.unselectable();
28712 this.header.update(this.title);
28714 // this element allows the dialog to be focused for keyboard event
28715 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28716 this.focusEl.swallowEvent("click", true);
28718 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28720 // wrap the body and footer for special rendering
28721 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28723 this.bwrap.dom.appendChild(this.footer.dom);
28726 this.bg = this.el.createChild({
28727 tag: "div", cls:"x-dlg-bg",
28728 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28730 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28733 if(this.autoScroll !== false && !this.autoTabs){
28734 this.body.setStyle("overflow", "auto");
28737 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28739 if(this.closable !== false){
28740 this.el.addClass("x-dlg-closable");
28741 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28742 this.close.on("click", this.closeClick, this);
28743 this.close.addClassOnOver("x-dlg-close-over");
28745 if(this.collapsible !== false){
28746 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28747 this.collapseBtn.on("click", this.collapseClick, this);
28748 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28749 this.header.on("dblclick", this.collapseClick, this);
28751 if(this.resizable !== false){
28752 this.el.addClass("x-dlg-resizable");
28753 this.resizer = new Roo.Resizable(el, {
28754 minWidth: this.minWidth || 80,
28755 minHeight:this.minHeight || 80,
28756 handles: this.resizeHandles || "all",
28759 this.resizer.on("beforeresize", this.beforeResize, this);
28760 this.resizer.on("resize", this.onResize, this);
28762 if(this.draggable !== false){
28763 el.addClass("x-dlg-draggable");
28764 if (!this.proxyDrag) {
28765 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28768 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28770 dd.setHandleElId(this.header.id);
28771 dd.endDrag = this.endMove.createDelegate(this);
28772 dd.startDrag = this.startMove.createDelegate(this);
28773 dd.onDrag = this.onDrag.createDelegate(this);
28778 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28779 this.mask.enableDisplayMode("block");
28781 this.el.addClass("x-dlg-modal");
28784 this.shadow = new Roo.Shadow({
28785 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28786 offset : this.shadowOffset
28789 this.shadowOffset = 0;
28791 if(Roo.useShims && this.shim !== false){
28792 this.shim = this.el.createShim();
28793 this.shim.hide = this.hideAction;
28801 if (this.buttons) {
28802 var bts= this.buttons;
28804 Roo.each(bts, function(b) {
28813 * Fires when a key is pressed
28814 * @param {Roo.BasicDialog} this
28815 * @param {Roo.EventObject} e
28820 * Fires when this dialog is moved by the user.
28821 * @param {Roo.BasicDialog} this
28822 * @param {Number} x The new page X
28823 * @param {Number} y The new page Y
28828 * Fires when this dialog is resized by the user.
28829 * @param {Roo.BasicDialog} this
28830 * @param {Number} width The new width
28831 * @param {Number} height The new height
28835 * @event beforehide
28836 * Fires before this dialog is hidden.
28837 * @param {Roo.BasicDialog} this
28839 "beforehide" : true,
28842 * Fires when this dialog is hidden.
28843 * @param {Roo.BasicDialog} this
28847 * @event beforeshow
28848 * Fires before this dialog is shown.
28849 * @param {Roo.BasicDialog} this
28851 "beforeshow" : true,
28854 * Fires when this dialog is shown.
28855 * @param {Roo.BasicDialog} this
28859 el.on("keydown", this.onKeyDown, this);
28860 el.on("mousedown", this.toFront, this);
28861 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28863 Roo.DialogManager.register(this);
28864 Roo.BasicDialog.superclass.constructor.call(this);
28867 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28868 shadowOffset: Roo.isIE ? 6 : 5,
28871 minButtonWidth: 75,
28872 defaultButton: null,
28873 buttonAlign: "right",
28878 * Sets the dialog title text
28879 * @param {String} text The title text to display
28880 * @return {Roo.BasicDialog} this
28882 setTitle : function(text){
28883 this.header.update(text);
28888 closeClick : function(){
28893 collapseClick : function(){
28894 this[this.collapsed ? "expand" : "collapse"]();
28898 * Collapses the dialog to its minimized state (only the title bar is visible).
28899 * Equivalent to the user clicking the collapse dialog button.
28901 collapse : function(){
28902 if(!this.collapsed){
28903 this.collapsed = true;
28904 this.el.addClass("x-dlg-collapsed");
28905 this.restoreHeight = this.el.getHeight();
28906 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28911 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28912 * clicking the expand dialog button.
28914 expand : function(){
28915 if(this.collapsed){
28916 this.collapsed = false;
28917 this.el.removeClass("x-dlg-collapsed");
28918 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28923 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28924 * @return {Roo.TabPanel} The tabs component
28926 initTabs : function(){
28927 var tabs = this.getTabs();
28928 while(tabs.getTab(0)){
28931 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28933 tabs.addTab(Roo.id(dom), dom.title);
28941 beforeResize : function(){
28942 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28946 onResize : function(){
28947 this.refreshSize();
28948 this.syncBodyHeight();
28949 this.adjustAssets();
28951 this.fireEvent("resize", this, this.size.width, this.size.height);
28955 onKeyDown : function(e){
28956 if(this.isVisible()){
28957 this.fireEvent("keydown", this, e);
28962 * Resizes the dialog.
28963 * @param {Number} width
28964 * @param {Number} height
28965 * @return {Roo.BasicDialog} this
28967 resizeTo : function(width, height){
28968 this.el.setSize(width, height);
28969 this.size = {width: width, height: height};
28970 this.syncBodyHeight();
28971 if(this.fixedcenter){
28974 if(this.isVisible()){
28975 this.constrainXY();
28976 this.adjustAssets();
28978 this.fireEvent("resize", this, width, height);
28984 * Resizes the dialog to fit the specified content size.
28985 * @param {Number} width
28986 * @param {Number} height
28987 * @return {Roo.BasicDialog} this
28989 setContentSize : function(w, h){
28990 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28991 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28992 //if(!this.el.isBorderBox()){
28993 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28994 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28997 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28998 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29000 this.resizeTo(w, h);
29005 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29006 * executed in response to a particular key being pressed while the dialog is active.
29007 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29008 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29009 * @param {Function} fn The function to call
29010 * @param {Object} scope (optional) The scope of the function
29011 * @return {Roo.BasicDialog} this
29013 addKeyListener : function(key, fn, scope){
29014 var keyCode, shift, ctrl, alt;
29015 if(typeof key == "object" && !(key instanceof Array)){
29016 keyCode = key["key"];
29017 shift = key["shift"];
29018 ctrl = key["ctrl"];
29023 var handler = function(dlg, e){
29024 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29025 var k = e.getKey();
29026 if(keyCode instanceof Array){
29027 for(var i = 0, len = keyCode.length; i < len; i++){
29028 if(keyCode[i] == k){
29029 fn.call(scope || window, dlg, k, e);
29035 fn.call(scope || window, dlg, k, e);
29040 this.on("keydown", handler);
29045 * Returns the TabPanel component (creates it if it doesn't exist).
29046 * Note: If you wish to simply check for the existence of tabs without creating them,
29047 * check for a null 'tabs' property.
29048 * @return {Roo.TabPanel} The tabs component
29050 getTabs : function(){
29052 this.el.addClass("x-dlg-auto-tabs");
29053 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29054 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29060 * Adds a button to the footer section of the dialog.
29061 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29062 * object or a valid Roo.DomHelper element config
29063 * @param {Function} handler The function called when the button is clicked
29064 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29065 * @return {Roo.Button} The new button
29067 addButton : function(config, handler, scope){
29068 var dh = Roo.DomHelper;
29070 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29072 if(!this.btnContainer){
29073 var tb = this.footer.createChild({
29075 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29076 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29078 this.btnContainer = tb.firstChild.firstChild.firstChild;
29083 minWidth: this.minButtonWidth,
29086 if(typeof config == "string"){
29087 bconfig.text = config;
29090 bconfig.dhconfig = config;
29092 Roo.apply(bconfig, config);
29096 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29097 bconfig.position = Math.max(0, bconfig.position);
29098 fc = this.btnContainer.childNodes[bconfig.position];
29101 var btn = new Roo.Button(
29103 this.btnContainer.insertBefore(document.createElement("td"),fc)
29104 : this.btnContainer.appendChild(document.createElement("td")),
29105 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29108 this.syncBodyHeight();
29111 * Array of all the buttons that have been added to this dialog via addButton
29116 this.buttons.push(btn);
29121 * Sets the default button to be focused when the dialog is displayed.
29122 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29123 * @return {Roo.BasicDialog} this
29125 setDefaultButton : function(btn){
29126 this.defaultButton = btn;
29131 getHeaderFooterHeight : function(safe){
29134 height += this.header.getHeight();
29137 var fm = this.footer.getMargins();
29138 height += (this.footer.getHeight()+fm.top+fm.bottom);
29140 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29141 height += this.centerBg.getPadding("tb");
29146 syncBodyHeight : function(){
29147 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29148 var height = this.size.height - this.getHeaderFooterHeight(false);
29149 bd.setHeight(height-bd.getMargins("tb"));
29150 var hh = this.header.getHeight();
29151 var h = this.size.height-hh;
29153 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29154 bw.setHeight(h-cb.getPadding("tb"));
29155 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29156 bd.setWidth(bw.getWidth(true));
29158 this.tabs.syncHeight();
29160 this.tabs.el.repaint();
29166 * Restores the previous state of the dialog if Roo.state is configured.
29167 * @return {Roo.BasicDialog} this
29169 restoreState : function(){
29170 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29171 if(box && box.width){
29172 this.xy = [box.x, box.y];
29173 this.resizeTo(box.width, box.height);
29179 beforeShow : function(){
29181 if(this.fixedcenter){
29182 this.xy = this.el.getCenterXY(true);
29185 Roo.get(document.body).addClass("x-body-masked");
29186 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29189 this.constrainXY();
29193 animShow : function(){
29194 var b = Roo.get(this.animateTarget).getBox();
29195 this.proxy.setSize(b.width, b.height);
29196 this.proxy.setLocation(b.x, b.y);
29198 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29199 true, .35, this.showEl.createDelegate(this));
29203 * Shows the dialog.
29204 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29205 * @return {Roo.BasicDialog} this
29207 show : function(animateTarget){
29208 if (this.fireEvent("beforeshow", this) === false){
29211 if(this.syncHeightBeforeShow){
29212 this.syncBodyHeight();
29213 }else if(this.firstShow){
29214 this.firstShow = false;
29215 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29217 this.animateTarget = animateTarget || this.animateTarget;
29218 if(!this.el.isVisible()){
29220 if(this.animateTarget && Roo.get(this.animateTarget)){
29230 showEl : function(){
29232 this.el.setXY(this.xy);
29234 this.adjustAssets(true);
29237 // IE peekaboo bug - fix found by Dave Fenwick
29241 this.fireEvent("show", this);
29245 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29246 * dialog itself will receive focus.
29248 focus : function(){
29249 if(this.defaultButton){
29250 this.defaultButton.focus();
29252 this.focusEl.focus();
29257 constrainXY : function(){
29258 if(this.constraintoviewport !== false){
29259 if(!this.viewSize){
29260 if(this.container){
29261 var s = this.container.getSize();
29262 this.viewSize = [s.width, s.height];
29264 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29267 var s = Roo.get(this.container||document).getScroll();
29269 var x = this.xy[0], y = this.xy[1];
29270 var w = this.size.width, h = this.size.height;
29271 var vw = this.viewSize[0], vh = this.viewSize[1];
29272 // only move it if it needs it
29274 // first validate right/bottom
29275 if(x + w > vw+s.left){
29279 if(y + h > vh+s.top){
29283 // then make sure top/left isn't negative
29295 if(this.isVisible()){
29296 this.el.setLocation(x, y);
29297 this.adjustAssets();
29304 onDrag : function(){
29305 if(!this.proxyDrag){
29306 this.xy = this.el.getXY();
29307 this.adjustAssets();
29312 adjustAssets : function(doShow){
29313 var x = this.xy[0], y = this.xy[1];
29314 var w = this.size.width, h = this.size.height;
29315 if(doShow === true){
29317 this.shadow.show(this.el);
29323 if(this.shadow && this.shadow.isVisible()){
29324 this.shadow.show(this.el);
29326 if(this.shim && this.shim.isVisible()){
29327 this.shim.setBounds(x, y, w, h);
29332 adjustViewport : function(w, h){
29334 w = Roo.lib.Dom.getViewWidth();
29335 h = Roo.lib.Dom.getViewHeight();
29338 this.viewSize = [w, h];
29339 if(this.modal && this.mask.isVisible()){
29340 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29341 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29343 if(this.isVisible()){
29344 this.constrainXY();
29349 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29350 * shadow, proxy, mask, etc.) Also removes all event listeners.
29351 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29353 destroy : function(removeEl){
29354 if(this.isVisible()){
29355 this.animateTarget = null;
29358 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29360 this.tabs.destroy(removeEl);
29373 for(var i = 0, len = this.buttons.length; i < len; i++){
29374 this.buttons[i].destroy();
29377 this.el.removeAllListeners();
29378 if(removeEl === true){
29379 this.el.update("");
29382 Roo.DialogManager.unregister(this);
29386 startMove : function(){
29387 if(this.proxyDrag){
29390 if(this.constraintoviewport !== false){
29391 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29396 endMove : function(){
29397 if(!this.proxyDrag){
29398 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29400 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29403 this.refreshSize();
29404 this.adjustAssets();
29406 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29410 * Brings this dialog to the front of any other visible dialogs
29411 * @return {Roo.BasicDialog} this
29413 toFront : function(){
29414 Roo.DialogManager.bringToFront(this);
29419 * Sends this dialog to the back (under) of any other visible dialogs
29420 * @return {Roo.BasicDialog} this
29422 toBack : function(){
29423 Roo.DialogManager.sendToBack(this);
29428 * Centers this dialog in the viewport
29429 * @return {Roo.BasicDialog} this
29431 center : function(){
29432 var xy = this.el.getCenterXY(true);
29433 this.moveTo(xy[0], xy[1]);
29438 * Moves the dialog's top-left corner to the specified point
29439 * @param {Number} x
29440 * @param {Number} y
29441 * @return {Roo.BasicDialog} this
29443 moveTo : function(x, y){
29445 if(this.isVisible()){
29446 this.el.setXY(this.xy);
29447 this.adjustAssets();
29453 * Aligns the dialog to the specified element
29454 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29455 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29456 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29457 * @return {Roo.BasicDialog} this
29459 alignTo : function(element, position, offsets){
29460 this.xy = this.el.getAlignToXY(element, position, offsets);
29461 if(this.isVisible()){
29462 this.el.setXY(this.xy);
29463 this.adjustAssets();
29469 * Anchors an element to another element and realigns it when the window is resized.
29470 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29471 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29472 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29473 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29474 * is a number, it is used as the buffer delay (defaults to 50ms).
29475 * @return {Roo.BasicDialog} this
29477 anchorTo : function(el, alignment, offsets, monitorScroll){
29478 var action = function(){
29479 this.alignTo(el, alignment, offsets);
29481 Roo.EventManager.onWindowResize(action, this);
29482 var tm = typeof monitorScroll;
29483 if(tm != 'undefined'){
29484 Roo.EventManager.on(window, 'scroll', action, this,
29485 {buffer: tm == 'number' ? monitorScroll : 50});
29492 * Returns true if the dialog is visible
29493 * @return {Boolean}
29495 isVisible : function(){
29496 return this.el.isVisible();
29500 animHide : function(callback){
29501 var b = Roo.get(this.animateTarget).getBox();
29503 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29505 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29506 this.hideEl.createDelegate(this, [callback]));
29510 * Hides the dialog.
29511 * @param {Function} callback (optional) Function to call when the dialog is hidden
29512 * @return {Roo.BasicDialog} this
29514 hide : function(callback){
29515 if (this.fireEvent("beforehide", this) === false){
29519 this.shadow.hide();
29524 // sometimes animateTarget seems to get set.. causing problems...
29525 // this just double checks..
29526 if(this.animateTarget && Roo.get(this.animateTarget)) {
29527 this.animHide(callback);
29530 this.hideEl(callback);
29536 hideEl : function(callback){
29540 Roo.get(document.body).removeClass("x-body-masked");
29542 this.fireEvent("hide", this);
29543 if(typeof callback == "function"){
29549 hideAction : function(){
29550 this.setLeft("-10000px");
29551 this.setTop("-10000px");
29552 this.setStyle("visibility", "hidden");
29556 refreshSize : function(){
29557 this.size = this.el.getSize();
29558 this.xy = this.el.getXY();
29559 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29563 // z-index is managed by the DialogManager and may be overwritten at any time
29564 setZIndex : function(index){
29566 this.mask.setStyle("z-index", index);
29569 this.shim.setStyle("z-index", ++index);
29572 this.shadow.setZIndex(++index);
29574 this.el.setStyle("z-index", ++index);
29576 this.proxy.setStyle("z-index", ++index);
29579 this.resizer.proxy.setStyle("z-index", ++index);
29582 this.lastZIndex = index;
29586 * Returns the element for this dialog
29587 * @return {Roo.Element} The underlying dialog Element
29589 getEl : function(){
29595 * @class Roo.DialogManager
29596 * Provides global access to BasicDialogs that have been created and
29597 * support for z-indexing (layering) multiple open dialogs.
29599 Roo.DialogManager = function(){
29601 var accessList = [];
29605 var sortDialogs = function(d1, d2){
29606 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29610 var orderDialogs = function(){
29611 accessList.sort(sortDialogs);
29612 var seed = Roo.DialogManager.zseed;
29613 for(var i = 0, len = accessList.length; i < len; i++){
29614 var dlg = accessList[i];
29616 dlg.setZIndex(seed + (i*10));
29623 * The starting z-index for BasicDialogs (defaults to 9000)
29624 * @type Number The z-index value
29629 register : function(dlg){
29630 list[dlg.id] = dlg;
29631 accessList.push(dlg);
29635 unregister : function(dlg){
29636 delete list[dlg.id];
29639 if(!accessList.indexOf){
29640 for( i = 0, len = accessList.length; i < len; i++){
29641 if(accessList[i] == dlg){
29642 accessList.splice(i, 1);
29647 i = accessList.indexOf(dlg);
29649 accessList.splice(i, 1);
29655 * Gets a registered dialog by id
29656 * @param {String/Object} id The id of the dialog or a dialog
29657 * @return {Roo.BasicDialog} this
29659 get : function(id){
29660 return typeof id == "object" ? id : list[id];
29664 * Brings the specified dialog to the front
29665 * @param {String/Object} dlg The id of the dialog or a dialog
29666 * @return {Roo.BasicDialog} this
29668 bringToFront : function(dlg){
29669 dlg = this.get(dlg);
29672 dlg._lastAccess = new Date().getTime();
29679 * Sends the specified dialog to the back
29680 * @param {String/Object} dlg The id of the dialog or a dialog
29681 * @return {Roo.BasicDialog} this
29683 sendToBack : function(dlg){
29684 dlg = this.get(dlg);
29685 dlg._lastAccess = -(new Date().getTime());
29691 * Hides all dialogs
29693 hideAll : function(){
29694 for(var id in list){
29695 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29704 * @class Roo.LayoutDialog
29705 * @extends Roo.BasicDialog
29706 * Dialog which provides adjustments for working with a layout in a Dialog.
29707 * Add your necessary layout config options to the dialog's config.<br>
29708 * Example usage (including a nested layout):
29711 dialog = new Roo.LayoutDialog("download-dlg", {
29720 // layout config merges with the dialog config
29722 tabPosition: "top",
29723 alwaysShowTabs: true
29726 dialog.addKeyListener(27, dialog.hide, dialog);
29727 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29728 dialog.addButton("Build It!", this.getDownload, this);
29730 // we can even add nested layouts
29731 var innerLayout = new Roo.BorderLayout("dl-inner", {
29741 innerLayout.beginUpdate();
29742 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29743 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29744 innerLayout.endUpdate(true);
29746 var layout = dialog.getLayout();
29747 layout.beginUpdate();
29748 layout.add("center", new Roo.ContentPanel("standard-panel",
29749 {title: "Download the Source", fitToFrame:true}));
29750 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29751 {title: "Build your own roo.js"}));
29752 layout.getRegion("center").showPanel(sp);
29753 layout.endUpdate();
29757 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29758 * @param {Object} config configuration options
29760 Roo.LayoutDialog = function(el, cfg){
29763 if (typeof(cfg) == 'undefined') {
29764 config = Roo.apply({}, el);
29765 // not sure why we use documentElement here.. - it should always be body.
29766 // IE7 borks horribly if we use documentElement.
29767 // webkit also does not like documentElement - it creates a body element...
29768 el = Roo.get( document.body || document.documentElement ).createChild();
29769 //config.autoCreate = true;
29773 config.autoTabs = false;
29774 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29775 this.body.setStyle({overflow:"hidden", position:"relative"});
29776 this.layout = new Roo.BorderLayout(this.body.dom, config);
29777 this.layout.monitorWindowResize = false;
29778 this.el.addClass("x-dlg-auto-layout");
29779 // fix case when center region overwrites center function
29780 this.center = Roo.BasicDialog.prototype.center;
29781 this.on("show", this.layout.layout, this.layout, true);
29782 if (config.items) {
29783 var xitems = config.items;
29784 delete config.items;
29785 Roo.each(xitems, this.addxtype, this);
29790 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29792 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29795 endUpdate : function(){
29796 this.layout.endUpdate();
29800 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29803 beginUpdate : function(){
29804 this.layout.beginUpdate();
29808 * Get the BorderLayout for this dialog
29809 * @return {Roo.BorderLayout}
29811 getLayout : function(){
29812 return this.layout;
29815 showEl : function(){
29816 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29818 this.layout.layout();
29823 // Use the syncHeightBeforeShow config option to control this automatically
29824 syncBodyHeight : function(){
29825 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29826 if(this.layout){this.layout.layout();}
29830 * Add an xtype element (actually adds to the layout.)
29831 * @return {Object} xdata xtype object data.
29834 addxtype : function(c) {
29835 return this.layout.addxtype(c);
29839 * Ext JS Library 1.1.1
29840 * Copyright(c) 2006-2007, Ext JS, LLC.
29842 * Originally Released Under LGPL - original licence link has changed is not relivant.
29845 * <script type="text/javascript">
29849 * @class Roo.MessageBox
29850 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29854 Roo.Msg.alert('Status', 'Changes saved successfully.');
29856 // Prompt for user data:
29857 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29859 // process text value...
29863 // Show a dialog using config options:
29865 title:'Save Changes?',
29866 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29867 buttons: Roo.Msg.YESNOCANCEL,
29874 Roo.MessageBox = function(){
29875 var dlg, opt, mask, waitTimer;
29876 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29877 var buttons, activeTextEl, bwidth;
29880 var handleButton = function(button){
29882 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29886 var handleHide = function(){
29887 if(opt && opt.cls){
29888 dlg.el.removeClass(opt.cls);
29891 Roo.TaskMgr.stop(waitTimer);
29897 var updateButtons = function(b){
29900 buttons["ok"].hide();
29901 buttons["cancel"].hide();
29902 buttons["yes"].hide();
29903 buttons["no"].hide();
29904 dlg.footer.dom.style.display = 'none';
29907 dlg.footer.dom.style.display = '';
29908 for(var k in buttons){
29909 if(typeof buttons[k] != "function"){
29912 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29913 width += buttons[k].el.getWidth()+15;
29923 var handleEsc = function(d, k, e){
29924 if(opt && opt.closable !== false){
29934 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29935 * @return {Roo.BasicDialog} The BasicDialog element
29937 getDialog : function(){
29939 dlg = new Roo.BasicDialog("x-msg-box", {
29944 constraintoviewport:false,
29946 collapsible : false,
29949 width:400, height:100,
29950 buttonAlign:"center",
29951 closeClick : function(){
29952 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29953 handleButton("no");
29955 handleButton("cancel");
29959 dlg.on("hide", handleHide);
29961 dlg.addKeyListener(27, handleEsc);
29963 var bt = this.buttonText;
29964 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29965 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29966 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29967 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29968 bodyEl = dlg.body.createChild({
29970 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>'
29972 msgEl = bodyEl.dom.firstChild;
29973 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29974 textboxEl.enableDisplayMode();
29975 textboxEl.addKeyListener([10,13], function(){
29976 if(dlg.isVisible() && opt && opt.buttons){
29977 if(opt.buttons.ok){
29978 handleButton("ok");
29979 }else if(opt.buttons.yes){
29980 handleButton("yes");
29984 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29985 textareaEl.enableDisplayMode();
29986 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29987 progressEl.enableDisplayMode();
29988 var pf = progressEl.dom.firstChild;
29990 pp = Roo.get(pf.firstChild);
29991 pp.setHeight(pf.offsetHeight);
29999 * Updates the message box body text
30000 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30001 * the XHTML-compliant non-breaking space character '&#160;')
30002 * @return {Roo.MessageBox} This message box
30004 updateText : function(text){
30005 if(!dlg.isVisible() && !opt.width){
30006 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30008 msgEl.innerHTML = text || ' ';
30009 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
30010 Math.max(opt.minWidth || this.minWidth, bwidth));
30012 activeTextEl.setWidth(w);
30014 if(dlg.isVisible()){
30015 dlg.fixedcenter = false;
30017 dlg.setContentSize(w, bodyEl.getHeight());
30018 if(dlg.isVisible()){
30019 dlg.fixedcenter = true;
30025 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30026 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30027 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30028 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30029 * @return {Roo.MessageBox} This message box
30031 updateProgress : function(value, text){
30033 this.updateText(text);
30035 if (pp) { // weird bug on my firefox - for some reason this is not defined
30036 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30042 * Returns true if the message box is currently displayed
30043 * @return {Boolean} True if the message box is visible, else false
30045 isVisible : function(){
30046 return dlg && dlg.isVisible();
30050 * Hides the message box if it is displayed
30053 if(this.isVisible()){
30059 * Displays a new message box, or reinitializes an existing message box, based on the config options
30060 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30061 * The following config object properties are supported:
30063 Property Type Description
30064 ---------- --------------- ------------------------------------------------------------------------------------
30065 animEl String/Element An id or Element from which the message box should animate as it opens and
30066 closes (defaults to undefined)
30067 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30068 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30069 closable Boolean False to hide the top-right close button (defaults to true). Note that
30070 progress and wait dialogs will ignore this property and always hide the
30071 close button as they can only be closed programmatically.
30072 cls String A custom CSS class to apply to the message box element
30073 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30074 displayed (defaults to 75)
30075 fn Function A callback function to execute after closing the dialog. The arguments to the
30076 function will be btn (the name of the button that was clicked, if applicable,
30077 e.g. "ok"), and text (the value of the active text field, if applicable).
30078 Progress and wait dialogs will ignore this option since they do not respond to
30079 user actions and can only be closed programmatically, so any required function
30080 should be called by the same code after it closes the dialog.
30081 icon String A CSS class that provides a background image to be used as an icon for
30082 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30083 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30084 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30085 modal Boolean False to allow user interaction with the page while the message box is
30086 displayed (defaults to true)
30087 msg String A string that will replace the existing message box body text (defaults
30088 to the XHTML-compliant non-breaking space character ' ')
30089 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30090 progress Boolean True to display a progress bar (defaults to false)
30091 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30092 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30093 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30094 title String The title text
30095 value String The string value to set into the active textbox element if displayed
30096 wait Boolean True to display a progress bar (defaults to false)
30097 width Number The width of the dialog in pixels
30104 msg: 'Please enter your address:',
30106 buttons: Roo.MessageBox.OKCANCEL,
30109 animEl: 'addAddressBtn'
30112 * @param {Object} config Configuration options
30113 * @return {Roo.MessageBox} This message box
30115 show : function(options){
30116 if(this.isVisible()){
30119 var d = this.getDialog();
30121 d.setTitle(opt.title || " ");
30122 d.close.setDisplayed(opt.closable !== false);
30123 activeTextEl = textboxEl;
30124 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30129 textareaEl.setHeight(typeof opt.multiline == "number" ?
30130 opt.multiline : this.defaultTextHeight);
30131 activeTextEl = textareaEl;
30140 progressEl.setDisplayed(opt.progress === true);
30141 this.updateProgress(0);
30142 activeTextEl.dom.value = opt.value || "";
30144 dlg.setDefaultButton(activeTextEl);
30146 var bs = opt.buttons;
30149 db = buttons["ok"];
30150 }else if(bs && bs.yes){
30151 db = buttons["yes"];
30153 dlg.setDefaultButton(db);
30155 bwidth = updateButtons(opt.buttons);
30156 this.updateText(opt.msg);
30158 d.el.addClass(opt.cls);
30160 d.proxyDrag = opt.proxyDrag === true;
30161 d.modal = opt.modal !== false;
30162 d.mask = opt.modal !== false ? mask : false;
30163 if(!d.isVisible()){
30164 // force it to the end of the z-index stack so it gets a cursor in FF
30165 document.body.appendChild(dlg.el.dom);
30166 d.animateTarget = null;
30167 d.show(options.animEl);
30173 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30174 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30175 * and closing the message box when the process is complete.
30176 * @param {String} title The title bar text
30177 * @param {String} msg The message box body text
30178 * @return {Roo.MessageBox} This message box
30180 progress : function(title, msg){
30187 minWidth: this.minProgressWidth,
30194 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30195 * If a callback function is passed it will be called after the user clicks the button, and the
30196 * id of the button that was clicked will be passed as the only parameter to the callback
30197 * (could also be the top-right close button).
30198 * @param {String} title The title bar text
30199 * @param {String} msg The message box body text
30200 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30201 * @param {Object} scope (optional) The scope of the callback function
30202 * @return {Roo.MessageBox} This message box
30204 alert : function(title, msg, fn, scope){
30217 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30218 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30219 * You are responsible for closing the message box when the process is complete.
30220 * @param {String} msg The message box body text
30221 * @param {String} title (optional) The title bar text
30222 * @return {Roo.MessageBox} This message box
30224 wait : function(msg, title){
30235 waitTimer = Roo.TaskMgr.start({
30237 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30245 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30246 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30247 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30248 * @param {String} title The title bar text
30249 * @param {String} msg The message box body text
30250 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30251 * @param {Object} scope (optional) The scope of the callback function
30252 * @return {Roo.MessageBox} This message box
30254 confirm : function(title, msg, fn, scope){
30258 buttons: this.YESNO,
30267 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30268 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30269 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30270 * (could also be the top-right close button) and the text that was entered will be passed as the two
30271 * parameters to the callback.
30272 * @param {String} title The title bar text
30273 * @param {String} msg The message box body text
30274 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30275 * @param {Object} scope (optional) The scope of the callback function
30276 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30277 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30278 * @return {Roo.MessageBox} This message box
30280 prompt : function(title, msg, fn, scope, multiline){
30284 buttons: this.OKCANCEL,
30289 multiline: multiline,
30296 * Button config that displays a single OK button
30301 * Button config that displays Yes and No buttons
30304 YESNO : {yes:true, no:true},
30306 * Button config that displays OK and Cancel buttons
30309 OKCANCEL : {ok:true, cancel:true},
30311 * Button config that displays Yes, No and Cancel buttons
30314 YESNOCANCEL : {yes:true, no:true, cancel:true},
30317 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30320 defaultTextHeight : 75,
30322 * The maximum width in pixels of the message box (defaults to 600)
30327 * The minimum width in pixels of the message box (defaults to 100)
30332 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30333 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30336 minProgressWidth : 250,
30338 * An object containing the default button text strings that can be overriden for localized language support.
30339 * Supported properties are: ok, cancel, yes and no.
30340 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30353 * Shorthand for {@link Roo.MessageBox}
30355 Roo.Msg = Roo.MessageBox;/*
30357 * Ext JS Library 1.1.1
30358 * Copyright(c) 2006-2007, Ext JS, LLC.
30360 * Originally Released Under LGPL - original licence link has changed is not relivant.
30363 * <script type="text/javascript">
30366 * @class Roo.QuickTips
30367 * Provides attractive and customizable tooltips for any element.
30370 Roo.QuickTips = function(){
30371 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30372 var ce, bd, xy, dd;
30373 var visible = false, disabled = true, inited = false;
30374 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30376 var onOver = function(e){
30380 var t = e.getTarget();
30381 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30384 if(ce && t == ce.el){
30385 clearTimeout(hideProc);
30388 if(t && tagEls[t.id]){
30389 tagEls[t.id].el = t;
30390 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30393 var ttp, et = Roo.fly(t);
30394 var ns = cfg.namespace;
30395 if(tm.interceptTitles && t.title){
30398 t.removeAttribute("title");
30399 e.preventDefault();
30401 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30404 showProc = show.defer(tm.showDelay, tm, [{
30407 width: et.getAttributeNS(ns, cfg.width),
30408 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30409 title: et.getAttributeNS(ns, cfg.title),
30410 cls: et.getAttributeNS(ns, cfg.cls)
30415 var onOut = function(e){
30416 clearTimeout(showProc);
30417 var t = e.getTarget();
30418 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30419 hideProc = setTimeout(hide, tm.hideDelay);
30423 var onMove = function(e){
30429 if(tm.trackMouse && ce){
30434 var onDown = function(e){
30435 clearTimeout(showProc);
30436 clearTimeout(hideProc);
30438 if(tm.hideOnClick){
30441 tm.enable.defer(100, tm);
30446 var getPad = function(){
30447 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30450 var show = function(o){
30454 clearTimeout(dismissProc);
30456 if(removeCls){ // in case manually hidden
30457 el.removeClass(removeCls);
30461 el.addClass(ce.cls);
30462 removeCls = ce.cls;
30465 tipTitle.update(ce.title);
30468 tipTitle.update('');
30471 el.dom.style.width = tm.maxWidth+'px';
30472 //tipBody.dom.style.width = '';
30473 tipBodyText.update(o.text);
30474 var p = getPad(), w = ce.width;
30476 var td = tipBodyText.dom;
30477 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30478 if(aw > tm.maxWidth){
30480 }else if(aw < tm.minWidth){
30486 //tipBody.setWidth(w);
30487 el.setWidth(parseInt(w, 10) + p);
30488 if(ce.autoHide === false){
30489 close.setDisplayed(true);
30494 close.setDisplayed(false);
30500 el.avoidY = xy[1]-18;
30505 el.setStyle("visibility", "visible");
30506 el.fadeIn({callback: afterShow});
30512 var afterShow = function(){
30516 if(tm.autoDismiss && ce.autoHide !== false){
30517 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30522 var hide = function(noanim){
30523 clearTimeout(dismissProc);
30524 clearTimeout(hideProc);
30526 if(el.isVisible()){
30528 if(noanim !== true && tm.animate){
30529 el.fadeOut({callback: afterHide});
30536 var afterHide = function(){
30539 el.removeClass(removeCls);
30546 * @cfg {Number} minWidth
30547 * The minimum width of the quick tip (defaults to 40)
30551 * @cfg {Number} maxWidth
30552 * The maximum width of the quick tip (defaults to 300)
30556 * @cfg {Boolean} interceptTitles
30557 * True to automatically use the element's DOM title value if available (defaults to false)
30559 interceptTitles : false,
30561 * @cfg {Boolean} trackMouse
30562 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30564 trackMouse : false,
30566 * @cfg {Boolean} hideOnClick
30567 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30569 hideOnClick : true,
30571 * @cfg {Number} showDelay
30572 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30576 * @cfg {Number} hideDelay
30577 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30581 * @cfg {Boolean} autoHide
30582 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30583 * Used in conjunction with hideDelay.
30588 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30589 * (defaults to true). Used in conjunction with autoDismissDelay.
30591 autoDismiss : true,
30594 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30596 autoDismissDelay : 5000,
30598 * @cfg {Boolean} animate
30599 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30604 * @cfg {String} title
30605 * Title text to display (defaults to ''). This can be any valid HTML markup.
30609 * @cfg {String} text
30610 * Body text to display (defaults to ''). This can be any valid HTML markup.
30614 * @cfg {String} cls
30615 * A CSS class to apply to the base quick tip element (defaults to '').
30619 * @cfg {Number} width
30620 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30621 * minWidth or maxWidth.
30626 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30627 * or display QuickTips in a page.
30630 tm = Roo.QuickTips;
30631 cfg = tm.tagConfig;
30633 if(!Roo.isReady){ // allow calling of init() before onReady
30634 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30637 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30638 el.fxDefaults = {stopFx: true};
30639 // maximum custom styling
30640 //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>');
30641 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>');
30642 tipTitle = el.child('h3');
30643 tipTitle.enableDisplayMode("block");
30644 tipBody = el.child('div.x-tip-bd');
30645 tipBodyText = el.child('div.x-tip-bd-inner');
30646 //bdLeft = el.child('div.x-tip-bd-left');
30647 //bdRight = el.child('div.x-tip-bd-right');
30648 close = el.child('div.x-tip-close');
30649 close.enableDisplayMode("block");
30650 close.on("click", hide);
30651 var d = Roo.get(document);
30652 d.on("mousedown", onDown);
30653 d.on("mouseover", onOver);
30654 d.on("mouseout", onOut);
30655 d.on("mousemove", onMove);
30656 esc = d.addKeyListener(27, hide);
30659 dd = el.initDD("default", null, {
30660 onDrag : function(){
30664 dd.setHandleElId(tipTitle.id);
30673 * Configures a new quick tip instance and assigns it to a target element. The following config options
30676 Property Type Description
30677 ---------- --------------------- ------------------------------------------------------------------------
30678 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30680 * @param {Object} config The config object
30682 register : function(config){
30683 var cs = config instanceof Array ? config : arguments;
30684 for(var i = 0, len = cs.length; i < len; i++) {
30686 var target = c.target;
30688 if(target instanceof Array){
30689 for(var j = 0, jlen = target.length; j < jlen; j++){
30690 tagEls[target[j]] = c;
30693 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30700 * Removes this quick tip from its element and destroys it.
30701 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30703 unregister : function(el){
30704 delete tagEls[Roo.id(el)];
30708 * Enable this quick tip.
30710 enable : function(){
30711 if(inited && disabled){
30713 if(locks.length < 1){
30720 * Disable this quick tip.
30722 disable : function(){
30724 clearTimeout(showProc);
30725 clearTimeout(hideProc);
30726 clearTimeout(dismissProc);
30734 * Returns true if the quick tip is enabled, else false.
30736 isEnabled : function(){
30743 attribute : "qtip",
30753 // backwards compat
30754 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30756 * Ext JS Library 1.1.1
30757 * Copyright(c) 2006-2007, Ext JS, LLC.
30759 * Originally Released Under LGPL - original licence link has changed is not relivant.
30762 * <script type="text/javascript">
30767 * @class Roo.tree.TreePanel
30768 * @extends Roo.data.Tree
30770 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30771 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30772 * @cfg {Boolean} enableDD true to enable drag and drop
30773 * @cfg {Boolean} enableDrag true to enable just drag
30774 * @cfg {Boolean} enableDrop true to enable just drop
30775 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30776 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30777 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30778 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30779 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30780 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30781 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30782 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30783 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30784 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30785 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30786 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30787 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30788 * @cfg {Function} renderer Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
30789 * @cfg {Function} rendererTip Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
30792 * @param {String/HTMLElement/Element} el The container element
30793 * @param {Object} config
30795 Roo.tree.TreePanel = function(el, config){
30797 var loader = false;
30799 root = config.root;
30800 delete config.root;
30802 if (config.loader) {
30803 loader = config.loader;
30804 delete config.loader;
30807 Roo.apply(this, config);
30808 Roo.tree.TreePanel.superclass.constructor.call(this);
30809 this.el = Roo.get(el);
30810 this.el.addClass('x-tree');
30811 //console.log(root);
30813 this.setRootNode( Roo.factory(root, Roo.tree));
30816 this.loader = Roo.factory(loader, Roo.tree);
30819 * Read-only. The id of the container element becomes this TreePanel's id.
30821 this.id = this.el.id;
30824 * @event beforeload
30825 * Fires before a node is loaded, return false to cancel
30826 * @param {Node} node The node being loaded
30828 "beforeload" : true,
30831 * Fires when a node is loaded
30832 * @param {Node} node The node that was loaded
30836 * @event textchange
30837 * Fires when the text for a node is changed
30838 * @param {Node} node The node
30839 * @param {String} text The new text
30840 * @param {String} oldText The old text
30842 "textchange" : true,
30844 * @event beforeexpand
30845 * Fires before a node is expanded, return false to cancel.
30846 * @param {Node} node The node
30847 * @param {Boolean} deep
30848 * @param {Boolean} anim
30850 "beforeexpand" : true,
30852 * @event beforecollapse
30853 * Fires before a node is collapsed, return false to cancel.
30854 * @param {Node} node The node
30855 * @param {Boolean} deep
30856 * @param {Boolean} anim
30858 "beforecollapse" : true,
30861 * Fires when a node is expanded
30862 * @param {Node} node The node
30866 * @event disabledchange
30867 * Fires when the disabled status of a node changes
30868 * @param {Node} node The node
30869 * @param {Boolean} disabled
30871 "disabledchange" : true,
30874 * Fires when a node is collapsed
30875 * @param {Node} node The node
30879 * @event beforeclick
30880 * Fires before click processing on a node. Return false to cancel the default action.
30881 * @param {Node} node The node
30882 * @param {Roo.EventObject} e The event object
30884 "beforeclick":true,
30886 * @event checkchange
30887 * Fires when a node with a checkbox's checked property changes
30888 * @param {Node} this This node
30889 * @param {Boolean} checked
30891 "checkchange":true,
30894 * Fires when a node is clicked
30895 * @param {Node} node The node
30896 * @param {Roo.EventObject} e The event object
30901 * Fires when a node is double clicked
30902 * @param {Node} node The node
30903 * @param {Roo.EventObject} e The event object
30907 * @event contextmenu
30908 * Fires when a node is right clicked
30909 * @param {Node} node The node
30910 * @param {Roo.EventObject} e The event object
30912 "contextmenu":true,
30914 * @event beforechildrenrendered
30915 * Fires right before the child nodes for a node are rendered
30916 * @param {Node} node The node
30918 "beforechildrenrendered":true,
30921 * Fires when a node starts being dragged
30922 * @param {Roo.tree.TreePanel} this
30923 * @param {Roo.tree.TreeNode} node
30924 * @param {event} e The raw browser event
30926 "startdrag" : true,
30929 * Fires when a drag operation is complete
30930 * @param {Roo.tree.TreePanel} this
30931 * @param {Roo.tree.TreeNode} node
30932 * @param {event} e The raw browser event
30937 * Fires when a dragged node is dropped on a valid DD target
30938 * @param {Roo.tree.TreePanel} this
30939 * @param {Roo.tree.TreeNode} node
30940 * @param {DD} dd The dd it was dropped on
30941 * @param {event} e The raw browser event
30945 * @event beforenodedrop
30946 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30947 * passed to handlers has the following properties:<br />
30948 * <ul style="padding:5px;padding-left:16px;">
30949 * <li>tree - The TreePanel</li>
30950 * <li>target - The node being targeted for the drop</li>
30951 * <li>data - The drag data from the drag source</li>
30952 * <li>point - The point of the drop - append, above or below</li>
30953 * <li>source - The drag source</li>
30954 * <li>rawEvent - Raw mouse event</li>
30955 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30956 * to be inserted by setting them on this object.</li>
30957 * <li>cancel - Set this to true to cancel the drop.</li>
30959 * @param {Object} dropEvent
30961 "beforenodedrop" : true,
30964 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30965 * passed to handlers has the following properties:<br />
30966 * <ul style="padding:5px;padding-left:16px;">
30967 * <li>tree - The TreePanel</li>
30968 * <li>target - The node being targeted for the drop</li>
30969 * <li>data - The drag data from the drag source</li>
30970 * <li>point - The point of the drop - append, above or below</li>
30971 * <li>source - The drag source</li>
30972 * <li>rawEvent - Raw mouse event</li>
30973 * <li>dropNode - Dropped node(s).</li>
30975 * @param {Object} dropEvent
30979 * @event nodedragover
30980 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30981 * passed to handlers has the following properties:<br />
30982 * <ul style="padding:5px;padding-left:16px;">
30983 * <li>tree - The TreePanel</li>
30984 * <li>target - The node being targeted for the drop</li>
30985 * <li>data - The drag data from the drag source</li>
30986 * <li>point - The point of the drop - append, above or below</li>
30987 * <li>source - The drag source</li>
30988 * <li>rawEvent - Raw mouse event</li>
30989 * <li>dropNode - Drop node(s) provided by the source.</li>
30990 * <li>cancel - Set this to true to signal drop not allowed.</li>
30992 * @param {Object} dragOverEvent
30994 "nodedragover" : true
30997 if(this.singleExpand){
30998 this.on("beforeexpand", this.restrictExpand, this);
31001 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31002 rootVisible : true,
31003 animate: Roo.enableFx,
31006 hlDrop : Roo.enableFx,
31010 rendererTip: false,
31012 restrictExpand : function(node){
31013 var p = node.parentNode;
31015 if(p.expandedChild && p.expandedChild.parentNode == p){
31016 p.expandedChild.collapse();
31018 p.expandedChild = node;
31022 // private override
31023 setRootNode : function(node){
31024 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31025 if(!this.rootVisible){
31026 node.ui = new Roo.tree.RootTreeNodeUI(node);
31032 * Returns the container element for this TreePanel
31034 getEl : function(){
31039 * Returns the default TreeLoader for this TreePanel
31041 getLoader : function(){
31042 return this.loader;
31048 expandAll : function(){
31049 this.root.expand(true);
31053 * Collapse all nodes
31055 collapseAll : function(){
31056 this.root.collapse(true);
31060 * Returns the selection model used by this TreePanel
31062 getSelectionModel : function(){
31063 if(!this.selModel){
31064 this.selModel = new Roo.tree.DefaultSelectionModel();
31066 return this.selModel;
31070 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31071 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31072 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31075 getChecked : function(a, startNode){
31076 startNode = startNode || this.root;
31078 var f = function(){
31079 if(this.attributes.checked){
31080 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31083 startNode.cascade(f);
31088 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31089 * @param {String} path
31090 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31091 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31092 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31094 expandPath : function(path, attr, callback){
31095 attr = attr || "id";
31096 var keys = path.split(this.pathSeparator);
31097 var curNode = this.root;
31098 if(curNode.attributes[attr] != keys[1]){ // invalid root
31100 callback(false, null);
31105 var f = function(){
31106 if(++index == keys.length){
31108 callback(true, curNode);
31112 var c = curNode.findChild(attr, keys[index]);
31115 callback(false, curNode);
31120 c.expand(false, false, f);
31122 curNode.expand(false, false, f);
31126 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31127 * @param {String} path
31128 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31129 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31130 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31132 selectPath : function(path, attr, callback){
31133 attr = attr || "id";
31134 var keys = path.split(this.pathSeparator);
31135 var v = keys.pop();
31136 if(keys.length > 0){
31137 var f = function(success, node){
31138 if(success && node){
31139 var n = node.findChild(attr, v);
31145 }else if(callback){
31146 callback(false, n);
31150 callback(false, n);
31154 this.expandPath(keys.join(this.pathSeparator), attr, f);
31156 this.root.select();
31158 callback(true, this.root);
31163 getTreeEl : function(){
31168 * Trigger rendering of this TreePanel
31170 render : function(){
31171 if (this.innerCt) {
31172 return this; // stop it rendering more than once!!
31175 this.innerCt = this.el.createChild({tag:"ul",
31176 cls:"x-tree-root-ct " +
31177 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31179 if(this.containerScroll){
31180 Roo.dd.ScrollManager.register(this.el);
31182 if((this.enableDD || this.enableDrop) && !this.dropZone){
31184 * The dropZone used by this tree if drop is enabled
31185 * @type Roo.tree.TreeDropZone
31187 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31188 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31191 if((this.enableDD || this.enableDrag) && !this.dragZone){
31193 * The dragZone used by this tree if drag is enabled
31194 * @type Roo.tree.TreeDragZone
31196 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31197 ddGroup: this.ddGroup || "TreeDD",
31198 scroll: this.ddScroll
31201 this.getSelectionModel().init(this);
31203 console.log("ROOT not set in tree");
31206 this.root.render();
31207 if(!this.rootVisible){
31208 this.root.renderChildren();
31214 * Ext JS Library 1.1.1
31215 * Copyright(c) 2006-2007, Ext JS, LLC.
31217 * Originally Released Under LGPL - original licence link has changed is not relivant.
31220 * <script type="text/javascript">
31225 * @class Roo.tree.DefaultSelectionModel
31226 * @extends Roo.util.Observable
31227 * The default single selection for a TreePanel.
31229 Roo.tree.DefaultSelectionModel = function(){
31230 this.selNode = null;
31234 * @event selectionchange
31235 * Fires when the selected node changes
31236 * @param {DefaultSelectionModel} this
31237 * @param {TreeNode} node the new selection
31239 "selectionchange" : true,
31242 * @event beforeselect
31243 * Fires before the selected node changes, return false to cancel the change
31244 * @param {DefaultSelectionModel} this
31245 * @param {TreeNode} node the new selection
31246 * @param {TreeNode} node the old selection
31248 "beforeselect" : true
31252 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31253 init : function(tree){
31255 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31256 tree.on("click", this.onNodeClick, this);
31259 onNodeClick : function(node, e){
31260 if (e.ctrlKey && this.selNode == node) {
31261 this.unselect(node);
31269 * @param {TreeNode} node The node to select
31270 * @return {TreeNode} The selected node
31272 select : function(node){
31273 var last = this.selNode;
31274 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31276 last.ui.onSelectedChange(false);
31278 this.selNode = node;
31279 node.ui.onSelectedChange(true);
31280 this.fireEvent("selectionchange", this, node, last);
31287 * @param {TreeNode} node The node to unselect
31289 unselect : function(node){
31290 if(this.selNode == node){
31291 this.clearSelections();
31296 * Clear all selections
31298 clearSelections : function(){
31299 var n = this.selNode;
31301 n.ui.onSelectedChange(false);
31302 this.selNode = null;
31303 this.fireEvent("selectionchange", this, null);
31309 * Get the selected node
31310 * @return {TreeNode} The selected node
31312 getSelectedNode : function(){
31313 return this.selNode;
31317 * Returns true if the node is selected
31318 * @param {TreeNode} node The node to check
31319 * @return {Boolean}
31321 isSelected : function(node){
31322 return this.selNode == node;
31326 * Selects the node above the selected node in the tree, intelligently walking the nodes
31327 * @return TreeNode The new selection
31329 selectPrevious : function(){
31330 var s = this.selNode || this.lastSelNode;
31334 var ps = s.previousSibling;
31336 if(!ps.isExpanded() || ps.childNodes.length < 1){
31337 return this.select(ps);
31339 var lc = ps.lastChild;
31340 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31343 return this.select(lc);
31345 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31346 return this.select(s.parentNode);
31352 * Selects the node above the selected node in the tree, intelligently walking the nodes
31353 * @return TreeNode The new selection
31355 selectNext : function(){
31356 var s = this.selNode || this.lastSelNode;
31360 if(s.firstChild && s.isExpanded()){
31361 return this.select(s.firstChild);
31362 }else if(s.nextSibling){
31363 return this.select(s.nextSibling);
31364 }else if(s.parentNode){
31366 s.parentNode.bubble(function(){
31367 if(this.nextSibling){
31368 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31377 onKeyDown : function(e){
31378 var s = this.selNode || this.lastSelNode;
31379 // undesirable, but required
31384 var k = e.getKey();
31392 this.selectPrevious();
31395 e.preventDefault();
31396 if(s.hasChildNodes()){
31397 if(!s.isExpanded()){
31399 }else if(s.firstChild){
31400 this.select(s.firstChild, e);
31405 e.preventDefault();
31406 if(s.hasChildNodes() && s.isExpanded()){
31408 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31409 this.select(s.parentNode, e);
31417 * @class Roo.tree.MultiSelectionModel
31418 * @extends Roo.util.Observable
31419 * Multi selection for a TreePanel.
31421 Roo.tree.MultiSelectionModel = function(){
31422 this.selNodes = [];
31426 * @event selectionchange
31427 * Fires when the selected nodes change
31428 * @param {MultiSelectionModel} this
31429 * @param {Array} nodes Array of the selected nodes
31431 "selectionchange" : true
31435 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31436 init : function(tree){
31438 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31439 tree.on("click", this.onNodeClick, this);
31442 onNodeClick : function(node, e){
31443 this.select(node, e, e.ctrlKey);
31448 * @param {TreeNode} node The node to select
31449 * @param {EventObject} e (optional) An event associated with the selection
31450 * @param {Boolean} keepExisting True to retain existing selections
31451 * @return {TreeNode} The selected node
31453 select : function(node, e, keepExisting){
31454 if(keepExisting !== true){
31455 this.clearSelections(true);
31457 if(this.isSelected(node)){
31458 this.lastSelNode = node;
31461 this.selNodes.push(node);
31462 this.selMap[node.id] = node;
31463 this.lastSelNode = node;
31464 node.ui.onSelectedChange(true);
31465 this.fireEvent("selectionchange", this, this.selNodes);
31471 * @param {TreeNode} node The node to unselect
31473 unselect : function(node){
31474 if(this.selMap[node.id]){
31475 node.ui.onSelectedChange(false);
31476 var sn = this.selNodes;
31479 index = sn.indexOf(node);
31481 for(var i = 0, len = sn.length; i < len; i++){
31489 this.selNodes.splice(index, 1);
31491 delete this.selMap[node.id];
31492 this.fireEvent("selectionchange", this, this.selNodes);
31497 * Clear all selections
31499 clearSelections : function(suppressEvent){
31500 var sn = this.selNodes;
31502 for(var i = 0, len = sn.length; i < len; i++){
31503 sn[i].ui.onSelectedChange(false);
31505 this.selNodes = [];
31507 if(suppressEvent !== true){
31508 this.fireEvent("selectionchange", this, this.selNodes);
31514 * Returns true if the node is selected
31515 * @param {TreeNode} node The node to check
31516 * @return {Boolean}
31518 isSelected : function(node){
31519 return this.selMap[node.id] ? true : false;
31523 * Returns an array of the selected nodes
31526 getSelectedNodes : function(){
31527 return this.selNodes;
31530 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31532 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31534 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31537 * Ext JS Library 1.1.1
31538 * Copyright(c) 2006-2007, Ext JS, LLC.
31540 * Originally Released Under LGPL - original licence link has changed is not relivant.
31543 * <script type="text/javascript">
31547 * @class Roo.tree.TreeNode
31548 * @extends Roo.data.Node
31549 * @cfg {String} text The text for this node
31550 * @cfg {Boolean} expanded true to start the node expanded
31551 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31552 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31553 * @cfg {Boolean} disabled true to start the node disabled
31554 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31555 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31556 * @cfg {String} cls A css class to be added to the node
31557 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31558 * @cfg {String} href URL of the link used for the node (defaults to #)
31559 * @cfg {String} hrefTarget target frame for the link
31560 * @cfg {String} qtip An Ext QuickTip for the node
31561 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31562 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31563 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31564 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31565 * (defaults to undefined with no checkbox rendered)
31567 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31569 Roo.tree.TreeNode = function(attributes){
31570 attributes = attributes || {};
31571 if(typeof attributes == "string"){
31572 attributes = {text: attributes};
31574 this.childrenRendered = false;
31575 this.rendered = false;
31576 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31577 this.expanded = attributes.expanded === true;
31578 this.isTarget = attributes.isTarget !== false;
31579 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31580 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31583 * Read-only. The text for this node. To change it use setText().
31586 this.text = attributes.text;
31588 * True if this node is disabled.
31591 this.disabled = attributes.disabled === true;
31595 * @event textchange
31596 * Fires when the text for this node is changed
31597 * @param {Node} this This node
31598 * @param {String} text The new text
31599 * @param {String} oldText The old text
31601 "textchange" : true,
31603 * @event beforeexpand
31604 * Fires before this node is expanded, return false to cancel.
31605 * @param {Node} this This node
31606 * @param {Boolean} deep
31607 * @param {Boolean} anim
31609 "beforeexpand" : true,
31611 * @event beforecollapse
31612 * Fires before this node is collapsed, return false to cancel.
31613 * @param {Node} this This node
31614 * @param {Boolean} deep
31615 * @param {Boolean} anim
31617 "beforecollapse" : true,
31620 * Fires when this node is expanded
31621 * @param {Node} this This node
31625 * @event disabledchange
31626 * Fires when the disabled status of this node changes
31627 * @param {Node} this This node
31628 * @param {Boolean} disabled
31630 "disabledchange" : true,
31633 * Fires when this node is collapsed
31634 * @param {Node} this This node
31638 * @event beforeclick
31639 * Fires before click processing. Return false to cancel the default action.
31640 * @param {Node} this This node
31641 * @param {Roo.EventObject} e The event object
31643 "beforeclick":true,
31645 * @event checkchange
31646 * Fires when a node with a checkbox's checked property changes
31647 * @param {Node} this This node
31648 * @param {Boolean} checked
31650 "checkchange":true,
31653 * Fires when this node is clicked
31654 * @param {Node} this This node
31655 * @param {Roo.EventObject} e The event object
31660 * Fires when this node is double clicked
31661 * @param {Node} this This node
31662 * @param {Roo.EventObject} e The event object
31666 * @event contextmenu
31667 * Fires when this node is right clicked
31668 * @param {Node} this This node
31669 * @param {Roo.EventObject} e The event object
31671 "contextmenu":true,
31673 * @event beforechildrenrendered
31674 * Fires right before the child nodes for this node are rendered
31675 * @param {Node} this This node
31677 "beforechildrenrendered":true
31680 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31683 * Read-only. The UI for this node
31686 this.ui = new uiClass(this);
31688 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31689 preventHScroll: true,
31691 * Returns true if this node is expanded
31692 * @return {Boolean}
31694 isExpanded : function(){
31695 return this.expanded;
31699 * Returns the UI object for this node
31700 * @return {TreeNodeUI}
31702 getUI : function(){
31706 // private override
31707 setFirstChild : function(node){
31708 var of = this.firstChild;
31709 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31710 if(this.childrenRendered && of && node != of){
31711 of.renderIndent(true, true);
31714 this.renderIndent(true, true);
31718 // private override
31719 setLastChild : function(node){
31720 var ol = this.lastChild;
31721 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31722 if(this.childrenRendered && ol && node != ol){
31723 ol.renderIndent(true, true);
31726 this.renderIndent(true, true);
31730 // these methods are overridden to provide lazy rendering support
31731 // private override
31732 appendChild : function(){
31733 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31734 if(node && this.childrenRendered){
31737 this.ui.updateExpandIcon();
31741 // private override
31742 removeChild : function(node){
31743 this.ownerTree.getSelectionModel().unselect(node);
31744 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31745 // if it's been rendered remove dom node
31746 if(this.childrenRendered){
31749 if(this.childNodes.length < 1){
31750 this.collapse(false, false);
31752 this.ui.updateExpandIcon();
31754 if(!this.firstChild) {
31755 this.childrenRendered = false;
31760 // private override
31761 insertBefore : function(node, refNode){
31762 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31763 if(newNode && refNode && this.childrenRendered){
31766 this.ui.updateExpandIcon();
31771 * Sets the text for this node
31772 * @param {String} text
31774 setText : function(text){
31775 var oldText = this.text;
31777 this.attributes.text = text;
31778 if(this.rendered){ // event without subscribing
31779 this.ui.onTextChange(this, text, oldText);
31781 this.fireEvent("textchange", this, text, oldText);
31785 * Triggers selection of this node
31787 select : function(){
31788 this.getOwnerTree().getSelectionModel().select(this);
31792 * Triggers deselection of this node
31794 unselect : function(){
31795 this.getOwnerTree().getSelectionModel().unselect(this);
31799 * Returns true if this node is selected
31800 * @return {Boolean}
31802 isSelected : function(){
31803 return this.getOwnerTree().getSelectionModel().isSelected(this);
31807 * Expand this node.
31808 * @param {Boolean} deep (optional) True to expand all children as well
31809 * @param {Boolean} anim (optional) false to cancel the default animation
31810 * @param {Function} callback (optional) A callback to be called when
31811 * expanding this node completes (does not wait for deep expand to complete).
31812 * Called with 1 parameter, this node.
31814 expand : function(deep, anim, callback){
31815 if(!this.expanded){
31816 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31819 if(!this.childrenRendered){
31820 this.renderChildren();
31822 this.expanded = true;
31823 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31824 this.ui.animExpand(function(){
31825 this.fireEvent("expand", this);
31826 if(typeof callback == "function"){
31830 this.expandChildNodes(true);
31832 }.createDelegate(this));
31836 this.fireEvent("expand", this);
31837 if(typeof callback == "function"){
31842 if(typeof callback == "function"){
31847 this.expandChildNodes(true);
31851 isHiddenRoot : function(){
31852 return this.isRoot && !this.getOwnerTree().rootVisible;
31856 * Collapse this node.
31857 * @param {Boolean} deep (optional) True to collapse all children as well
31858 * @param {Boolean} anim (optional) false to cancel the default animation
31860 collapse : function(deep, anim){
31861 if(this.expanded && !this.isHiddenRoot()){
31862 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31865 this.expanded = false;
31866 if((this.getOwnerTree().animate && anim !== false) || anim){
31867 this.ui.animCollapse(function(){
31868 this.fireEvent("collapse", this);
31870 this.collapseChildNodes(true);
31872 }.createDelegate(this));
31875 this.ui.collapse();
31876 this.fireEvent("collapse", this);
31880 var cs = this.childNodes;
31881 for(var i = 0, len = cs.length; i < len; i++) {
31882 cs[i].collapse(true, false);
31888 delayedExpand : function(delay){
31889 if(!this.expandProcId){
31890 this.expandProcId = this.expand.defer(delay, this);
31895 cancelExpand : function(){
31896 if(this.expandProcId){
31897 clearTimeout(this.expandProcId);
31899 this.expandProcId = false;
31903 * Toggles expanded/collapsed state of the node
31905 toggle : function(){
31914 * Ensures all parent nodes are expanded
31916 ensureVisible : function(callback){
31917 var tree = this.getOwnerTree();
31918 tree.expandPath(this.parentNode.getPath(), false, function(){
31919 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31920 Roo.callback(callback);
31921 }.createDelegate(this));
31925 * Expand all child nodes
31926 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31928 expandChildNodes : function(deep){
31929 var cs = this.childNodes;
31930 for(var i = 0, len = cs.length; i < len; i++) {
31931 cs[i].expand(deep);
31936 * Collapse all child nodes
31937 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31939 collapseChildNodes : function(deep){
31940 var cs = this.childNodes;
31941 for(var i = 0, len = cs.length; i < len; i++) {
31942 cs[i].collapse(deep);
31947 * Disables this node
31949 disable : function(){
31950 this.disabled = true;
31952 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31953 this.ui.onDisableChange(this, true);
31955 this.fireEvent("disabledchange", this, true);
31959 * Enables this node
31961 enable : function(){
31962 this.disabled = false;
31963 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31964 this.ui.onDisableChange(this, false);
31966 this.fireEvent("disabledchange", this, false);
31970 renderChildren : function(suppressEvent){
31971 if(suppressEvent !== false){
31972 this.fireEvent("beforechildrenrendered", this);
31974 var cs = this.childNodes;
31975 for(var i = 0, len = cs.length; i < len; i++){
31976 cs[i].render(true);
31978 this.childrenRendered = true;
31982 sort : function(fn, scope){
31983 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31984 if(this.childrenRendered){
31985 var cs = this.childNodes;
31986 for(var i = 0, len = cs.length; i < len; i++){
31987 cs[i].render(true);
31993 render : function(bulkRender){
31994 this.ui.render(bulkRender);
31995 if(!this.rendered){
31996 this.rendered = true;
31998 this.expanded = false;
31999 this.expand(false, false);
32005 renderIndent : function(deep, refresh){
32007 this.ui.childIndent = null;
32009 this.ui.renderIndent();
32010 if(deep === true && this.childrenRendered){
32011 var cs = this.childNodes;
32012 for(var i = 0, len = cs.length; i < len; i++){
32013 cs[i].renderIndent(true, refresh);
32019 * Ext JS Library 1.1.1
32020 * Copyright(c) 2006-2007, Ext JS, LLC.
32022 * Originally Released Under LGPL - original licence link has changed is not relivant.
32025 * <script type="text/javascript">
32029 * @class Roo.tree.AsyncTreeNode
32030 * @extends Roo.tree.TreeNode
32031 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32033 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32035 Roo.tree.AsyncTreeNode = function(config){
32036 this.loaded = false;
32037 this.loading = false;
32038 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32040 * @event beforeload
32041 * Fires before this node is loaded, return false to cancel
32042 * @param {Node} this This node
32044 this.addEvents({'beforeload':true, 'load': true});
32047 * Fires when this node is loaded
32048 * @param {Node} this This node
32051 * The loader used by this node (defaults to using the tree's defined loader)
32056 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32057 expand : function(deep, anim, callback){
32058 if(this.loading){ // if an async load is already running, waiting til it's done
32060 var f = function(){
32061 if(!this.loading){ // done loading
32062 clearInterval(timer);
32063 this.expand(deep, anim, callback);
32065 }.createDelegate(this);
32066 timer = setInterval(f, 200);
32070 if(this.fireEvent("beforeload", this) === false){
32073 this.loading = true;
32074 this.ui.beforeLoad(this);
32075 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32077 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32081 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32085 * Returns true if this node is currently loading
32086 * @return {Boolean}
32088 isLoading : function(){
32089 return this.loading;
32092 loadComplete : function(deep, anim, callback){
32093 this.loading = false;
32094 this.loaded = true;
32095 this.ui.afterLoad(this);
32096 this.fireEvent("load", this);
32097 this.expand(deep, anim, callback);
32101 * Returns true if this node has been loaded
32102 * @return {Boolean}
32104 isLoaded : function(){
32105 return this.loaded;
32108 hasChildNodes : function(){
32109 if(!this.isLeaf() && !this.loaded){
32112 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32117 * Trigger a reload for this node
32118 * @param {Function} callback
32120 reload : function(callback){
32121 this.collapse(false, false);
32122 while(this.firstChild){
32123 this.removeChild(this.firstChild);
32125 this.childrenRendered = false;
32126 this.loaded = false;
32127 if(this.isHiddenRoot()){
32128 this.expanded = false;
32130 this.expand(false, false, callback);
32134 * Ext JS Library 1.1.1
32135 * Copyright(c) 2006-2007, Ext JS, LLC.
32137 * Originally Released Under LGPL - original licence link has changed is not relivant.
32140 * <script type="text/javascript">
32144 * @class Roo.tree.TreeNodeUI
32146 * @param {Object} node The node to render
32147 * The TreeNode UI implementation is separate from the
32148 * tree implementation. Unless you are customizing the tree UI,
32149 * you should never have to use this directly.
32151 Roo.tree.TreeNodeUI = function(node){
32153 this.rendered = false;
32154 this.animating = false;
32155 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32158 Roo.tree.TreeNodeUI.prototype = {
32159 removeChild : function(node){
32161 this.ctNode.removeChild(node.ui.getEl());
32165 beforeLoad : function(){
32166 this.addClass("x-tree-node-loading");
32169 afterLoad : function(){
32170 this.removeClass("x-tree-node-loading");
32173 onTextChange : function(node, text, oldText){
32175 this.textNode.innerHTML = text;
32179 onDisableChange : function(node, state){
32180 this.disabled = state;
32182 this.addClass("x-tree-node-disabled");
32184 this.removeClass("x-tree-node-disabled");
32188 onSelectedChange : function(state){
32191 this.addClass("x-tree-selected");
32194 this.removeClass("x-tree-selected");
32198 onMove : function(tree, node, oldParent, newParent, index, refNode){
32199 this.childIndent = null;
32201 var targetNode = newParent.ui.getContainer();
32202 if(!targetNode){//target not rendered
32203 this.holder = document.createElement("div");
32204 this.holder.appendChild(this.wrap);
32207 var insertBefore = refNode ? refNode.ui.getEl() : null;
32209 targetNode.insertBefore(this.wrap, insertBefore);
32211 targetNode.appendChild(this.wrap);
32213 this.node.renderIndent(true);
32217 addClass : function(cls){
32219 Roo.fly(this.elNode).addClass(cls);
32223 removeClass : function(cls){
32225 Roo.fly(this.elNode).removeClass(cls);
32229 remove : function(){
32231 this.holder = document.createElement("div");
32232 this.holder.appendChild(this.wrap);
32236 fireEvent : function(){
32237 return this.node.fireEvent.apply(this.node, arguments);
32240 initEvents : function(){
32241 this.node.on("move", this.onMove, this);
32242 var E = Roo.EventManager;
32243 var a = this.anchor;
32245 var el = Roo.fly(a, '_treeui');
32247 if(Roo.isOpera){ // opera render bug ignores the CSS
32248 el.setStyle("text-decoration", "none");
32251 el.on("click", this.onClick, this);
32252 el.on("dblclick", this.onDblClick, this);
32255 Roo.EventManager.on(this.checkbox,
32256 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32259 el.on("contextmenu", this.onContextMenu, this);
32261 var icon = Roo.fly(this.iconNode);
32262 icon.on("click", this.onClick, this);
32263 icon.on("dblclick", this.onDblClick, this);
32264 icon.on("contextmenu", this.onContextMenu, this);
32265 E.on(this.ecNode, "click", this.ecClick, this, true);
32267 if(this.node.disabled){
32268 this.addClass("x-tree-node-disabled");
32270 if(this.node.hidden){
32271 this.addClass("x-tree-node-disabled");
32273 var ot = this.node.getOwnerTree();
32274 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32275 if(dd && (!this.node.isRoot || ot.rootVisible)){
32276 Roo.dd.Registry.register(this.elNode, {
32278 handles: this.getDDHandles(),
32284 getDDHandles : function(){
32285 return [this.iconNode, this.textNode];
32290 this.wrap.style.display = "none";
32296 this.wrap.style.display = "";
32300 onContextMenu : function(e){
32301 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32302 e.preventDefault();
32304 this.fireEvent("contextmenu", this.node, e);
32308 onClick : function(e){
32313 if(this.fireEvent("beforeclick", this.node, e) !== false){
32314 if(!this.disabled && this.node.attributes.href){
32315 this.fireEvent("click", this.node, e);
32318 e.preventDefault();
32323 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32324 this.node.toggle();
32327 this.fireEvent("click", this.node, e);
32333 onDblClick : function(e){
32334 e.preventDefault();
32339 this.toggleCheck();
32341 if(!this.animating && this.node.hasChildNodes()){
32342 this.node.toggle();
32344 this.fireEvent("dblclick", this.node, e);
32347 onCheckChange : function(){
32348 var checked = this.checkbox.checked;
32349 this.node.attributes.checked = checked;
32350 this.fireEvent('checkchange', this.node, checked);
32353 ecClick : function(e){
32354 if(!this.animating && this.node.hasChildNodes()){
32355 this.node.toggle();
32359 startDrop : function(){
32360 this.dropping = true;
32363 // delayed drop so the click event doesn't get fired on a drop
32364 endDrop : function(){
32365 setTimeout(function(){
32366 this.dropping = false;
32367 }.createDelegate(this), 50);
32370 expand : function(){
32371 this.updateExpandIcon();
32372 this.ctNode.style.display = "";
32375 focus : function(){
32376 if(!this.node.preventHScroll){
32377 try{this.anchor.focus();
32379 }else if(!Roo.isIE){
32381 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32382 var l = noscroll.scrollLeft;
32383 this.anchor.focus();
32384 noscroll.scrollLeft = l;
32389 toggleCheck : function(value){
32390 var cb = this.checkbox;
32392 cb.checked = (value === undefined ? !cb.checked : value);
32398 this.anchor.blur();
32402 animExpand : function(callback){
32403 var ct = Roo.get(this.ctNode);
32405 if(!this.node.hasChildNodes()){
32406 this.updateExpandIcon();
32407 this.ctNode.style.display = "";
32408 Roo.callback(callback);
32411 this.animating = true;
32412 this.updateExpandIcon();
32415 callback : function(){
32416 this.animating = false;
32417 Roo.callback(callback);
32420 duration: this.node.ownerTree.duration || .25
32424 highlight : function(){
32425 var tree = this.node.getOwnerTree();
32426 Roo.fly(this.wrap).highlight(
32427 tree.hlColor || "C3DAF9",
32428 {endColor: tree.hlBaseColor}
32432 collapse : function(){
32433 this.updateExpandIcon();
32434 this.ctNode.style.display = "none";
32437 animCollapse : function(callback){
32438 var ct = Roo.get(this.ctNode);
32439 ct.enableDisplayMode('block');
32442 this.animating = true;
32443 this.updateExpandIcon();
32446 callback : function(){
32447 this.animating = false;
32448 Roo.callback(callback);
32451 duration: this.node.ownerTree.duration || .25
32455 getContainer : function(){
32456 return this.ctNode;
32459 getEl : function(){
32463 appendDDGhost : function(ghostNode){
32464 ghostNode.appendChild(this.elNode.cloneNode(true));
32467 getDDRepairXY : function(){
32468 return Roo.lib.Dom.getXY(this.iconNode);
32471 onRender : function(){
32475 render : function(bulkRender){
32476 var n = this.node, a = n.attributes;
32477 var targetNode = n.parentNode ?
32478 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32480 if(!this.rendered){
32481 this.rendered = true;
32483 this.renderElements(n, a, targetNode, bulkRender);
32486 if(this.textNode.setAttributeNS){
32487 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32489 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32492 this.textNode.setAttribute("ext:qtip", a.qtip);
32494 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32497 }else if(a.qtipCfg){
32498 a.qtipCfg.target = Roo.id(this.textNode);
32499 Roo.QuickTips.register(a.qtipCfg);
32502 if(!this.node.expanded){
32503 this.updateExpandIcon();
32506 if(bulkRender === true) {
32507 targetNode.appendChild(this.wrap);
32512 renderElements : function(n, a, targetNode, bulkRender){
32513 // add some indent caching, this helps performance when rendering a large tree
32514 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32515 var t = n.getOwnerTree();
32516 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32517 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32518 var cb = typeof a.checked == 'boolean';
32519 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32520 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32521 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32522 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32523 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32524 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32525 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32526 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32527 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32528 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32531 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32532 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32533 n.nextSibling.ui.getEl(), buf.join(""));
32535 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32538 this.elNode = this.wrap.childNodes[0];
32539 this.ctNode = this.wrap.childNodes[1];
32540 var cs = this.elNode.childNodes;
32541 this.indentNode = cs[0];
32542 this.ecNode = cs[1];
32543 this.iconNode = cs[2];
32546 this.checkbox = cs[3];
32549 this.anchor = cs[index];
32550 this.textNode = cs[index].firstChild;
32553 getAnchor : function(){
32554 return this.anchor;
32557 getTextEl : function(){
32558 return this.textNode;
32561 getIconEl : function(){
32562 return this.iconNode;
32565 isChecked : function(){
32566 return this.checkbox ? this.checkbox.checked : false;
32569 updateExpandIcon : function(){
32571 var n = this.node, c1, c2;
32572 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32573 var hasChild = n.hasChildNodes();
32577 c1 = "x-tree-node-collapsed";
32578 c2 = "x-tree-node-expanded";
32581 c1 = "x-tree-node-expanded";
32582 c2 = "x-tree-node-collapsed";
32585 this.removeClass("x-tree-node-leaf");
32586 this.wasLeaf = false;
32588 if(this.c1 != c1 || this.c2 != c2){
32589 Roo.fly(this.elNode).replaceClass(c1, c2);
32590 this.c1 = c1; this.c2 = c2;
32594 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32597 this.wasLeaf = true;
32600 var ecc = "x-tree-ec-icon "+cls;
32601 if(this.ecc != ecc){
32602 this.ecNode.className = ecc;
32608 getChildIndent : function(){
32609 if(!this.childIndent){
32613 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32615 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32617 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32622 this.childIndent = buf.join("");
32624 return this.childIndent;
32627 renderIndent : function(){
32630 var p = this.node.parentNode;
32632 indent = p.ui.getChildIndent();
32634 if(this.indentMarkup != indent){ // don't rerender if not required
32635 this.indentNode.innerHTML = indent;
32636 this.indentMarkup = indent;
32638 this.updateExpandIcon();
32643 Roo.tree.RootTreeNodeUI = function(){
32644 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32646 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32647 render : function(){
32648 if(!this.rendered){
32649 var targetNode = this.node.ownerTree.innerCt.dom;
32650 this.node.expanded = true;
32651 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32652 this.wrap = this.ctNode = targetNode.firstChild;
32655 collapse : function(){
32657 expand : function(){
32661 * Ext JS Library 1.1.1
32662 * Copyright(c) 2006-2007, Ext JS, LLC.
32664 * Originally Released Under LGPL - original licence link has changed is not relivant.
32667 * <script type="text/javascript">
32670 * @class Roo.tree.TreeLoader
32671 * @extends Roo.util.Observable
32672 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32673 * nodes from a specified URL. The response must be a javascript Array definition
32674 * who's elements are node definition objects. eg:
32676 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32677 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32680 * A server request is sent, and child nodes are loaded only when a node is expanded.
32681 * The loading node's id is passed to the server under the parameter name "node" to
32682 * enable the server to produce the correct child nodes.
32684 * To pass extra parameters, an event handler may be attached to the "beforeload"
32685 * event, and the parameters specified in the TreeLoader's baseParams property:
32687 myTreeLoader.on("beforeload", function(treeLoader, node) {
32688 this.baseParams.category = node.attributes.category;
32691 * This would pass an HTTP parameter called "category" to the server containing
32692 * the value of the Node's "category" attribute.
32694 * Creates a new Treeloader.
32695 * @param {Object} config A config object containing config properties.
32697 Roo.tree.TreeLoader = function(config){
32698 this.baseParams = {};
32699 this.requestMethod = "POST";
32700 Roo.apply(this, config);
32705 * @event beforeload
32706 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32707 * @param {Object} This TreeLoader object.
32708 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32709 * @param {Object} callback The callback function specified in the {@link #load} call.
32714 * Fires when the node has been successfuly loaded.
32715 * @param {Object} This TreeLoader object.
32716 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32717 * @param {Object} response The response object containing the data from the server.
32721 * @event loadexception
32722 * Fires if the network request failed.
32723 * @param {Object} This TreeLoader object.
32724 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32725 * @param {Object} response The response object containing the data from the server.
32727 loadexception : true,
32730 * Fires before a node is created, enabling you to return custom Node types
32731 * @param {Object} This TreeLoader object.
32732 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32737 Roo.tree.TreeLoader.superclass.constructor.call(this);
32740 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32742 * @cfg {String} dataUrl The URL from which to request a Json string which
32743 * specifies an array of node definition object representing the child nodes
32747 * @cfg {Object} baseParams (optional) An object containing properties which
32748 * specify HTTP parameters to be passed to each request for child nodes.
32751 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32752 * created by this loader. If the attributes sent by the server have an attribute in this object,
32753 * they take priority.
32756 * @cfg {Object} uiProviders (optional) An object containing properties which
32758 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32759 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32760 * <i>uiProvider</i> attribute of a returned child node is a string rather
32761 * than a reference to a TreeNodeUI implementation, this that string value
32762 * is used as a property name in the uiProviders object. You can define the provider named
32763 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32768 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32769 * child nodes before loading.
32771 clearOnLoad : true,
32774 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32775 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32776 * Grid query { data : [ .....] }
32781 * @cfg {String} queryParam (optional)
32782 * Name of the query as it will be passed on the querystring (defaults to 'node')
32783 * eg. the request will be ?node=[id]
32790 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32791 * This is called automatically when a node is expanded, but may be used to reload
32792 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32793 * @param {Roo.tree.TreeNode} node
32794 * @param {Function} callback
32796 load : function(node, callback){
32797 if(this.clearOnLoad){
32798 while(node.firstChild){
32799 node.removeChild(node.firstChild);
32802 if(node.attributes.children){ // preloaded json children
32803 var cs = node.attributes.children;
32804 for(var i = 0, len = cs.length; i < len; i++){
32805 node.appendChild(this.createNode(cs[i]));
32807 if(typeof callback == "function"){
32810 }else if(this.dataUrl){
32811 this.requestData(node, callback);
32815 getParams: function(node){
32816 var buf = [], bp = this.baseParams;
32817 for(var key in bp){
32818 if(typeof bp[key] != "function"){
32819 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32822 var n = this.queryParam === false ? 'node' : this.queryParam;
32823 buf.push(n + "=", encodeURIComponent(node.id));
32824 return buf.join("");
32827 requestData : function(node, callback){
32828 if(this.fireEvent("beforeload", this, node, callback) !== false){
32829 this.transId = Roo.Ajax.request({
32830 method:this.requestMethod,
32831 url: this.dataUrl||this.url,
32832 success: this.handleResponse,
32833 failure: this.handleFailure,
32835 argument: {callback: callback, node: node},
32836 params: this.getParams(node)
32839 // if the load is cancelled, make sure we notify
32840 // the node that we are done
32841 if(typeof callback == "function"){
32847 isLoading : function(){
32848 return this.transId ? true : false;
32851 abort : function(){
32852 if(this.isLoading()){
32853 Roo.Ajax.abort(this.transId);
32858 createNode : function(attr){
32859 // apply baseAttrs, nice idea Corey!
32860 if(this.baseAttrs){
32861 Roo.applyIf(attr, this.baseAttrs);
32863 if(this.applyLoader !== false){
32864 attr.loader = this;
32866 // uiProvider = depreciated..
32868 if(typeof(attr.uiProvider) == 'string'){
32869 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32870 /** eval:var:attr */ eval(attr.uiProvider);
32872 if(typeof(this.uiProviders['default']) != 'undefined') {
32873 attr.uiProvider = this.uiProviders['default'];
32876 this.fireEvent('create', this, attr);
32878 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32880 new Roo.tree.TreeNode(attr) :
32881 new Roo.tree.AsyncTreeNode(attr));
32884 processResponse : function(response, node, callback){
32885 var json = response.responseText;
32888 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32889 if (this.root !== false) {
32893 for(var i = 0, len = o.length; i < len; i++){
32894 var n = this.createNode(o[i]);
32896 node.appendChild(n);
32899 if(typeof callback == "function"){
32900 callback(this, node);
32903 this.handleFailure(response);
32907 handleResponse : function(response){
32908 this.transId = false;
32909 var a = response.argument;
32910 this.processResponse(response, a.node, a.callback);
32911 this.fireEvent("load", this, a.node, response);
32914 handleFailure : function(response){
32915 this.transId = false;
32916 var a = response.argument;
32917 this.fireEvent("loadexception", this, a.node, response);
32918 if(typeof a.callback == "function"){
32919 a.callback(this, a.node);
32924 * Ext JS Library 1.1.1
32925 * Copyright(c) 2006-2007, Ext JS, LLC.
32927 * Originally Released Under LGPL - original licence link has changed is not relivant.
32930 * <script type="text/javascript">
32934 * @class Roo.tree.TreeFilter
32935 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32936 * @param {TreePanel} tree
32937 * @param {Object} config (optional)
32939 Roo.tree.TreeFilter = function(tree, config){
32941 this.filtered = {};
32942 Roo.apply(this, config);
32945 Roo.tree.TreeFilter.prototype = {
32952 * Filter the data by a specific attribute.
32953 * @param {String/RegExp} value Either string that the attribute value
32954 * should start with or a RegExp to test against the attribute
32955 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32956 * @param {TreeNode} startNode (optional) The node to start the filter at.
32958 filter : function(value, attr, startNode){
32959 attr = attr || "text";
32961 if(typeof value == "string"){
32962 var vlen = value.length;
32963 // auto clear empty filter
32964 if(vlen == 0 && this.clearBlank){
32968 value = value.toLowerCase();
32970 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32972 }else if(value.exec){ // regex?
32974 return value.test(n.attributes[attr]);
32977 throw 'Illegal filter type, must be string or regex';
32979 this.filterBy(f, null, startNode);
32983 * Filter by a function. The passed function will be called with each
32984 * node in the tree (or from the startNode). If the function returns true, the node is kept
32985 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32986 * @param {Function} fn The filter function
32987 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32989 filterBy : function(fn, scope, startNode){
32990 startNode = startNode || this.tree.root;
32991 if(this.autoClear){
32994 var af = this.filtered, rv = this.reverse;
32995 var f = function(n){
32996 if(n == startNode){
33002 var m = fn.call(scope || n, n);
33010 startNode.cascade(f);
33013 if(typeof id != "function"){
33015 if(n && n.parentNode){
33016 n.parentNode.removeChild(n);
33024 * Clears the current filter. Note: with the "remove" option
33025 * set a filter cannot be cleared.
33027 clear : function(){
33029 var af = this.filtered;
33031 if(typeof id != "function"){
33038 this.filtered = {};
33043 * Ext JS Library 1.1.1
33044 * Copyright(c) 2006-2007, Ext JS, LLC.
33046 * Originally Released Under LGPL - original licence link has changed is not relivant.
33049 * <script type="text/javascript">
33054 * @class Roo.tree.TreeSorter
33055 * Provides sorting of nodes in a TreePanel
33057 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33058 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33059 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33060 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33061 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33062 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33064 * @param {TreePanel} tree
33065 * @param {Object} config
33067 Roo.tree.TreeSorter = function(tree, config){
33068 Roo.apply(this, config);
33069 tree.on("beforechildrenrendered", this.doSort, this);
33070 tree.on("append", this.updateSort, this);
33071 tree.on("insert", this.updateSort, this);
33073 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33074 var p = this.property || "text";
33075 var sortType = this.sortType;
33076 var fs = this.folderSort;
33077 var cs = this.caseSensitive === true;
33078 var leafAttr = this.leafAttr || 'leaf';
33080 this.sortFn = function(n1, n2){
33082 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33085 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33089 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33090 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33092 return dsc ? +1 : -1;
33094 return dsc ? -1 : +1;
33101 Roo.tree.TreeSorter.prototype = {
33102 doSort : function(node){
33103 node.sort(this.sortFn);
33106 compareNodes : function(n1, n2){
33107 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33110 updateSort : function(tree, node){
33111 if(node.childrenRendered){
33112 this.doSort.defer(1, this, [node]);
33117 * Ext JS Library 1.1.1
33118 * Copyright(c) 2006-2007, Ext JS, LLC.
33120 * Originally Released Under LGPL - original licence link has changed is not relivant.
33123 * <script type="text/javascript">
33126 if(Roo.dd.DropZone){
33128 Roo.tree.TreeDropZone = function(tree, config){
33129 this.allowParentInsert = false;
33130 this.allowContainerDrop = false;
33131 this.appendOnly = false;
33132 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33134 this.lastInsertClass = "x-tree-no-status";
33135 this.dragOverData = {};
33138 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33139 ddGroup : "TreeDD",
33141 expandDelay : 1000,
33143 expandNode : function(node){
33144 if(node.hasChildNodes() && !node.isExpanded()){
33145 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33149 queueExpand : function(node){
33150 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33153 cancelExpand : function(){
33154 if(this.expandProcId){
33155 clearTimeout(this.expandProcId);
33156 this.expandProcId = false;
33160 isValidDropPoint : function(n, pt, dd, e, data){
33161 if(!n || !data){ return false; }
33162 var targetNode = n.node;
33163 var dropNode = data.node;
33164 // default drop rules
33165 if(!(targetNode && targetNode.isTarget && pt)){
33168 if(pt == "append" && targetNode.allowChildren === false){
33171 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33174 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33177 // reuse the object
33178 var overEvent = this.dragOverData;
33179 overEvent.tree = this.tree;
33180 overEvent.target = targetNode;
33181 overEvent.data = data;
33182 overEvent.point = pt;
33183 overEvent.source = dd;
33184 overEvent.rawEvent = e;
33185 overEvent.dropNode = dropNode;
33186 overEvent.cancel = false;
33187 var result = this.tree.fireEvent("nodedragover", overEvent);
33188 return overEvent.cancel === false && result !== false;
33191 getDropPoint : function(e, n, dd){
33194 return tn.allowChildren !== false ? "append" : false; // always append for root
33196 var dragEl = n.ddel;
33197 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33198 var y = Roo.lib.Event.getPageY(e);
33199 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33201 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33202 var noAppend = tn.allowChildren === false;
33203 if(this.appendOnly || tn.parentNode.allowChildren === false){
33204 return noAppend ? false : "append";
33206 var noBelow = false;
33207 if(!this.allowParentInsert){
33208 noBelow = tn.hasChildNodes() && tn.isExpanded();
33210 var q = (b - t) / (noAppend ? 2 : 3);
33211 if(y >= t && y < (t + q)){
33213 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33220 onNodeEnter : function(n, dd, e, data){
33221 this.cancelExpand();
33224 onNodeOver : function(n, dd, e, data){
33225 var pt = this.getDropPoint(e, n, dd);
33228 // auto node expand check
33229 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33230 this.queueExpand(node);
33231 }else if(pt != "append"){
33232 this.cancelExpand();
33235 // set the insert point style on the target node
33236 var returnCls = this.dropNotAllowed;
33237 if(this.isValidDropPoint(n, pt, dd, e, data)){
33242 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33243 cls = "x-tree-drag-insert-above";
33244 }else if(pt == "below"){
33245 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33246 cls = "x-tree-drag-insert-below";
33248 returnCls = "x-tree-drop-ok-append";
33249 cls = "x-tree-drag-append";
33251 if(this.lastInsertClass != cls){
33252 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33253 this.lastInsertClass = cls;
33260 onNodeOut : function(n, dd, e, data){
33261 this.cancelExpand();
33262 this.removeDropIndicators(n);
33265 onNodeDrop : function(n, dd, e, data){
33266 var point = this.getDropPoint(e, n, dd);
33267 var targetNode = n.node;
33268 targetNode.ui.startDrop();
33269 if(!this.isValidDropPoint(n, point, dd, e, data)){
33270 targetNode.ui.endDrop();
33273 // first try to find the drop node
33274 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33277 target: targetNode,
33282 dropNode: dropNode,
33285 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33286 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33287 targetNode.ui.endDrop();
33290 // allow target changing
33291 targetNode = dropEvent.target;
33292 if(point == "append" && !targetNode.isExpanded()){
33293 targetNode.expand(false, null, function(){
33294 this.completeDrop(dropEvent);
33295 }.createDelegate(this));
33297 this.completeDrop(dropEvent);
33302 completeDrop : function(de){
33303 var ns = de.dropNode, p = de.point, t = de.target;
33304 if(!(ns instanceof Array)){
33308 for(var i = 0, len = ns.length; i < len; i++){
33311 t.parentNode.insertBefore(n, t);
33312 }else if(p == "below"){
33313 t.parentNode.insertBefore(n, t.nextSibling);
33319 if(this.tree.hlDrop){
33323 this.tree.fireEvent("nodedrop", de);
33326 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33327 if(this.tree.hlDrop){
33328 dropNode.ui.focus();
33329 dropNode.ui.highlight();
33331 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33334 getTree : function(){
33338 removeDropIndicators : function(n){
33341 Roo.fly(el).removeClass([
33342 "x-tree-drag-insert-above",
33343 "x-tree-drag-insert-below",
33344 "x-tree-drag-append"]);
33345 this.lastInsertClass = "_noclass";
33349 beforeDragDrop : function(target, e, id){
33350 this.cancelExpand();
33354 afterRepair : function(data){
33355 if(data && Roo.enableFx){
33356 data.node.ui.highlight();
33365 * Ext JS Library 1.1.1
33366 * Copyright(c) 2006-2007, Ext JS, LLC.
33368 * Originally Released Under LGPL - original licence link has changed is not relivant.
33371 * <script type="text/javascript">
33375 if(Roo.dd.DragZone){
33376 Roo.tree.TreeDragZone = function(tree, config){
33377 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33381 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33382 ddGroup : "TreeDD",
33384 onBeforeDrag : function(data, e){
33386 return n && n.draggable && !n.disabled;
33389 onInitDrag : function(e){
33390 var data = this.dragData;
33391 this.tree.getSelectionModel().select(data.node);
33392 this.proxy.update("");
33393 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33394 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33397 getRepairXY : function(e, data){
33398 return data.node.ui.getDDRepairXY();
33401 onEndDrag : function(data, e){
33402 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33405 onValidDrop : function(dd, e, id){
33406 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33410 beforeInvalidDrop : function(e, id){
33411 // this scrolls the original position back into view
33412 var sm = this.tree.getSelectionModel();
33413 sm.clearSelections();
33414 sm.select(this.dragData.node);
33419 * Ext JS Library 1.1.1
33420 * Copyright(c) 2006-2007, Ext JS, LLC.
33422 * Originally Released Under LGPL - original licence link has changed is not relivant.
33425 * <script type="text/javascript">
33428 * @class Roo.tree.TreeEditor
33429 * @extends Roo.Editor
33430 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33431 * as the editor field.
33433 * @param {TreePanel} tree
33434 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33436 Roo.tree.TreeEditor = function(tree, config){
33437 config = config || {};
33438 var field = config.events ? config : new Roo.form.TextField(config);
33439 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33443 tree.on('beforeclick', this.beforeNodeClick, this);
33444 tree.getTreeEl().on('mousedown', this.hide, this);
33445 this.on('complete', this.updateNode, this);
33446 this.on('beforestartedit', this.fitToTree, this);
33447 this.on('startedit', this.bindScroll, this, {delay:10});
33448 this.on('specialkey', this.onSpecialKey, this);
33451 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33453 * @cfg {String} alignment
33454 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33460 * @cfg {Boolean} hideEl
33461 * True to hide the bound element while the editor is displayed (defaults to false)
33465 * @cfg {String} cls
33466 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33468 cls: "x-small-editor x-tree-editor",
33470 * @cfg {Boolean} shim
33471 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33477 * @cfg {Number} maxWidth
33478 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33479 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33480 * scroll and client offsets into account prior to each edit.
33487 fitToTree : function(ed, el){
33488 var td = this.tree.getTreeEl().dom, nd = el.dom;
33489 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33490 td.scrollLeft = nd.offsetLeft;
33494 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33495 this.setSize(w, '');
33499 triggerEdit : function(node){
33500 this.completeEdit();
33501 this.editNode = node;
33502 this.startEdit(node.ui.textNode, node.text);
33506 bindScroll : function(){
33507 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33511 beforeNodeClick : function(node, e){
33512 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33513 this.lastClick = new Date();
33514 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33516 this.triggerEdit(node);
33522 updateNode : function(ed, value){
33523 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33524 this.editNode.setText(value);
33528 onHide : function(){
33529 Roo.tree.TreeEditor.superclass.onHide.call(this);
33531 this.editNode.ui.focus();
33536 onSpecialKey : function(field, e){
33537 var k = e.getKey();
33541 }else if(k == e.ENTER && !e.hasModifier()){
33543 this.completeEdit();
33546 });//<Script type="text/javascript">
33549 * Ext JS Library 1.1.1
33550 * Copyright(c) 2006-2007, Ext JS, LLC.
33552 * Originally Released Under LGPL - original licence link has changed is not relivant.
33555 * <script type="text/javascript">
33559 * Not documented??? - probably should be...
33562 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33563 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33565 renderElements : function(n, a, targetNode, bulkRender){
33566 //consel.log("renderElements?");
33567 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33569 var t = n.getOwnerTree();
33570 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33572 var cols = t.columns;
33573 var bw = t.borderWidth;
33575 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33576 var cb = typeof a.checked == "boolean";
33577 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33578 var colcls = 'x-t-' + tid + '-c0';
33580 '<li class="x-tree-node">',
33583 '<div class="x-tree-node-el ', a.cls,'">',
33585 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33588 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33589 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33590 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33591 (a.icon ? ' x-tree-node-inline-icon' : ''),
33592 (a.iconCls ? ' '+a.iconCls : ''),
33593 '" unselectable="on" />',
33594 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33595 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33597 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33598 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33599 '<span unselectable="on" qtip="' + tx + '">',
33603 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33604 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33606 for(var i = 1, len = cols.length; i < len; i++){
33608 colcls = 'x-t-' + tid + '-c' +i;
33609 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33610 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33611 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33617 '<div class="x-clear"></div></div>',
33618 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33621 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33622 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33623 n.nextSibling.ui.getEl(), buf.join(""));
33625 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33627 var el = this.wrap.firstChild;
33629 this.elNode = el.firstChild;
33630 this.ranchor = el.childNodes[1];
33631 this.ctNode = this.wrap.childNodes[1];
33632 var cs = el.firstChild.childNodes;
33633 this.indentNode = cs[0];
33634 this.ecNode = cs[1];
33635 this.iconNode = cs[2];
33638 this.checkbox = cs[3];
33641 this.anchor = cs[index];
33643 this.textNode = cs[index].firstChild;
33645 //el.on("click", this.onClick, this);
33646 //el.on("dblclick", this.onDblClick, this);
33649 // console.log(this);
33651 initEvents : function(){
33652 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33655 var a = this.ranchor;
33657 var el = Roo.get(a);
33659 if(Roo.isOpera){ // opera render bug ignores the CSS
33660 el.setStyle("text-decoration", "none");
33663 el.on("click", this.onClick, this);
33664 el.on("dblclick", this.onDblClick, this);
33665 el.on("contextmenu", this.onContextMenu, this);
33669 /*onSelectedChange : function(state){
33672 this.addClass("x-tree-selected");
33675 this.removeClass("x-tree-selected");
33678 addClass : function(cls){
33680 Roo.fly(this.elRow).addClass(cls);
33686 removeClass : function(cls){
33688 Roo.fly(this.elRow).removeClass(cls);
33694 });//<Script type="text/javascript">
33698 * Ext JS Library 1.1.1
33699 * Copyright(c) 2006-2007, Ext JS, LLC.
33701 * Originally Released Under LGPL - original licence link has changed is not relivant.
33704 * <script type="text/javascript">
33709 * @class Roo.tree.ColumnTree
33710 * @extends Roo.data.TreePanel
33711 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33712 * @cfg {int} borderWidth compined right/left border allowance
33714 * @param {String/HTMLElement/Element} el The container element
33715 * @param {Object} config
33717 Roo.tree.ColumnTree = function(el, config)
33719 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33723 * Fire this event on a container when it resizes
33724 * @param {int} w Width
33725 * @param {int} h Height
33729 this.on('resize', this.onResize, this);
33732 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33736 borderWidth: Roo.isBorderBox ? 0 : 2,
33739 render : function(){
33740 // add the header.....
33742 Roo.tree.ColumnTree.superclass.render.apply(this);
33744 this.el.addClass('x-column-tree');
33746 this.headers = this.el.createChild(
33747 {cls:'x-tree-headers'},this.innerCt.dom);
33749 var cols = this.columns, c;
33750 var totalWidth = 0;
33752 var len = cols.length;
33753 for(var i = 0; i < len; i++){
33755 totalWidth += c.width;
33756 this.headEls.push(this.headers.createChild({
33757 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33759 cls:'x-tree-hd-text',
33762 style:'width:'+(c.width-this.borderWidth)+'px;'
33765 this.headers.createChild({cls:'x-clear'});
33766 // prevent floats from wrapping when clipped
33767 this.headers.setWidth(totalWidth);
33768 //this.innerCt.setWidth(totalWidth);
33769 this.innerCt.setStyle({ overflow: 'auto' });
33770 this.onResize(this.width, this.height);
33774 onResize : function(w,h)
33779 this.innerCt.setWidth(this.width);
33780 this.innerCt.setHeight(this.height-20);
33783 var cols = this.columns, c;
33784 var totalWidth = 0;
33786 var len = cols.length;
33787 for(var i = 0; i < len; i++){
33789 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33790 // it's the expander..
33791 expEl = this.headEls[i];
33794 totalWidth += c.width;
33798 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33800 this.headers.setWidth(w-20);
33809 * Ext JS Library 1.1.1
33810 * Copyright(c) 2006-2007, Ext JS, LLC.
33812 * Originally Released Under LGPL - original licence link has changed is not relivant.
33815 * <script type="text/javascript">
33819 * @class Roo.menu.Menu
33820 * @extends Roo.util.Observable
33821 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33822 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33824 * Creates a new Menu
33825 * @param {Object} config Configuration options
33827 Roo.menu.Menu = function(config){
33828 Roo.apply(this, config);
33829 this.id = this.id || Roo.id();
33832 * @event beforeshow
33833 * Fires before this menu is displayed
33834 * @param {Roo.menu.Menu} this
33838 * @event beforehide
33839 * Fires before this menu is hidden
33840 * @param {Roo.menu.Menu} this
33845 * Fires after this menu is displayed
33846 * @param {Roo.menu.Menu} this
33851 * Fires after this menu is hidden
33852 * @param {Roo.menu.Menu} this
33857 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33858 * @param {Roo.menu.Menu} this
33859 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33860 * @param {Roo.EventObject} e
33865 * Fires when the mouse is hovering over this menu
33866 * @param {Roo.menu.Menu} this
33867 * @param {Roo.EventObject} e
33868 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33873 * Fires when the mouse exits this menu
33874 * @param {Roo.menu.Menu} this
33875 * @param {Roo.EventObject} e
33876 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33881 * Fires when a menu item contained in this menu is clicked
33882 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33883 * @param {Roo.EventObject} e
33887 if (this.registerMenu) {
33888 Roo.menu.MenuMgr.register(this);
33891 var mis = this.items;
33892 this.items = new Roo.util.MixedCollection();
33894 this.add.apply(this, mis);
33898 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33900 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33904 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33905 * for bottom-right shadow (defaults to "sides")
33909 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33910 * this menu (defaults to "tl-tr?")
33912 subMenuAlign : "tl-tr?",
33914 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33915 * relative to its element of origin (defaults to "tl-bl?")
33917 defaultAlign : "tl-bl?",
33919 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33921 allowOtherMenus : false,
33923 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33925 registerMenu : true,
33930 render : function(){
33934 var el = this.el = new Roo.Layer({
33936 shadow:this.shadow,
33938 parentEl: this.parentEl || document.body,
33942 this.keyNav = new Roo.menu.MenuNav(this);
33945 el.addClass("x-menu-plain");
33948 el.addClass(this.cls);
33950 // generic focus element
33951 this.focusEl = el.createChild({
33952 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33954 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33955 ul.on("click", this.onClick, this);
33956 ul.on("mouseover", this.onMouseOver, this);
33957 ul.on("mouseout", this.onMouseOut, this);
33958 this.items.each(function(item){
33959 var li = document.createElement("li");
33960 li.className = "x-menu-list-item";
33961 ul.dom.appendChild(li);
33962 item.render(li, this);
33969 autoWidth : function(){
33970 var el = this.el, ul = this.ul;
33974 var w = this.width;
33977 }else if(Roo.isIE){
33978 el.setWidth(this.minWidth);
33979 var t = el.dom.offsetWidth; // force recalc
33980 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33985 delayAutoWidth : function(){
33988 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33990 this.awTask.delay(20);
33995 findTargetItem : function(e){
33996 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33997 if(t && t.menuItemId){
33998 return this.items.get(t.menuItemId);
34003 onClick : function(e){
34005 if(t = this.findTargetItem(e)){
34007 this.fireEvent("click", this, t, e);
34012 setActiveItem : function(item, autoExpand){
34013 if(item != this.activeItem){
34014 if(this.activeItem){
34015 this.activeItem.deactivate();
34017 this.activeItem = item;
34018 item.activate(autoExpand);
34019 }else if(autoExpand){
34025 tryActivate : function(start, step){
34026 var items = this.items;
34027 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34028 var item = items.get(i);
34029 if(!item.disabled && item.canActivate){
34030 this.setActiveItem(item, false);
34038 onMouseOver : function(e){
34040 if(t = this.findTargetItem(e)){
34041 if(t.canActivate && !t.disabled){
34042 this.setActiveItem(t, true);
34045 this.fireEvent("mouseover", this, e, t);
34049 onMouseOut : function(e){
34051 if(t = this.findTargetItem(e)){
34052 if(t == this.activeItem && t.shouldDeactivate(e)){
34053 this.activeItem.deactivate();
34054 delete this.activeItem;
34057 this.fireEvent("mouseout", this, e, t);
34061 * Read-only. Returns true if the menu is currently displayed, else false.
34064 isVisible : function(){
34065 return this.el && !this.hidden;
34069 * Displays this menu relative to another element
34070 * @param {String/HTMLElement/Roo.Element} element The element to align to
34071 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34072 * the element (defaults to this.defaultAlign)
34073 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34075 show : function(el, pos, parentMenu){
34076 this.parentMenu = parentMenu;
34080 this.fireEvent("beforeshow", this);
34081 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34085 * Displays this menu at a specific xy position
34086 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34087 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34089 showAt : function(xy, parentMenu, /* private: */_e){
34090 this.parentMenu = parentMenu;
34095 this.fireEvent("beforeshow", this);
34096 xy = this.el.adjustForConstraints(xy);
34100 this.hidden = false;
34102 this.fireEvent("show", this);
34105 focus : function(){
34107 this.doFocus.defer(50, this);
34111 doFocus : function(){
34113 this.focusEl.focus();
34118 * Hides this menu and optionally all parent menus
34119 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34121 hide : function(deep){
34122 if(this.el && this.isVisible()){
34123 this.fireEvent("beforehide", this);
34124 if(this.activeItem){
34125 this.activeItem.deactivate();
34126 this.activeItem = null;
34129 this.hidden = true;
34130 this.fireEvent("hide", this);
34132 if(deep === true && this.parentMenu){
34133 this.parentMenu.hide(true);
34138 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34139 * Any of the following are valid:
34141 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34142 * <li>An HTMLElement object which will be converted to a menu item</li>
34143 * <li>A menu item config object that will be created as a new menu item</li>
34144 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34145 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34150 var menu = new Roo.menu.Menu();
34152 // Create a menu item to add by reference
34153 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34155 // Add a bunch of items at once using different methods.
34156 // Only the last item added will be returned.
34157 var item = menu.add(
34158 menuItem, // add existing item by ref
34159 'Dynamic Item', // new TextItem
34160 '-', // new separator
34161 { text: 'Config Item' } // new item by config
34164 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34165 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34168 var a = arguments, l = a.length, item;
34169 for(var i = 0; i < l; i++){
34171 if ((typeof(el) == "object") && el.xtype && el.xns) {
34172 el = Roo.factory(el, Roo.menu);
34175 if(el.render){ // some kind of Item
34176 item = this.addItem(el);
34177 }else if(typeof el == "string"){ // string
34178 if(el == "separator" || el == "-"){
34179 item = this.addSeparator();
34181 item = this.addText(el);
34183 }else if(el.tagName || el.el){ // element
34184 item = this.addElement(el);
34185 }else if(typeof el == "object"){ // must be menu item config?
34186 item = this.addMenuItem(el);
34193 * Returns this menu's underlying {@link Roo.Element} object
34194 * @return {Roo.Element} The element
34196 getEl : function(){
34204 * Adds a separator bar to the menu
34205 * @return {Roo.menu.Item} The menu item that was added
34207 addSeparator : function(){
34208 return this.addItem(new Roo.menu.Separator());
34212 * Adds an {@link Roo.Element} object to the menu
34213 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34214 * @return {Roo.menu.Item} The menu item that was added
34216 addElement : function(el){
34217 return this.addItem(new Roo.menu.BaseItem(el));
34221 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34222 * @param {Roo.menu.Item} item The menu item to add
34223 * @return {Roo.menu.Item} The menu item that was added
34225 addItem : function(item){
34226 this.items.add(item);
34228 var li = document.createElement("li");
34229 li.className = "x-menu-list-item";
34230 this.ul.dom.appendChild(li);
34231 item.render(li, this);
34232 this.delayAutoWidth();
34238 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34239 * @param {Object} config A MenuItem config object
34240 * @return {Roo.menu.Item} The menu item that was added
34242 addMenuItem : function(config){
34243 if(!(config instanceof Roo.menu.Item)){
34244 if(typeof config.checked == "boolean"){ // must be check menu item config?
34245 config = new Roo.menu.CheckItem(config);
34247 config = new Roo.menu.Item(config);
34250 return this.addItem(config);
34254 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34255 * @param {String} text The text to display in the menu item
34256 * @return {Roo.menu.Item} The menu item that was added
34258 addText : function(text){
34259 return this.addItem(new Roo.menu.TextItem({ text : text }));
34263 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34264 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34265 * @param {Roo.menu.Item} item The menu item to add
34266 * @return {Roo.menu.Item} The menu item that was added
34268 insert : function(index, item){
34269 this.items.insert(index, item);
34271 var li = document.createElement("li");
34272 li.className = "x-menu-list-item";
34273 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34274 item.render(li, this);
34275 this.delayAutoWidth();
34281 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34282 * @param {Roo.menu.Item} item The menu item to remove
34284 remove : function(item){
34285 this.items.removeKey(item.id);
34290 * Removes and destroys all items in the menu
34292 removeAll : function(){
34294 while(f = this.items.first()){
34300 // MenuNav is a private utility class used internally by the Menu
34301 Roo.menu.MenuNav = function(menu){
34302 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34303 this.scope = this.menu = menu;
34306 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34307 doRelay : function(e, h){
34308 var k = e.getKey();
34309 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34310 this.menu.tryActivate(0, 1);
34313 return h.call(this.scope || this, e, this.menu);
34316 up : function(e, m){
34317 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34318 m.tryActivate(m.items.length-1, -1);
34322 down : function(e, m){
34323 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34324 m.tryActivate(0, 1);
34328 right : function(e, m){
34330 m.activeItem.expandMenu(true);
34334 left : function(e, m){
34336 if(m.parentMenu && m.parentMenu.activeItem){
34337 m.parentMenu.activeItem.activate();
34341 enter : function(e, m){
34343 e.stopPropagation();
34344 m.activeItem.onClick(e);
34345 m.fireEvent("click", this, m.activeItem);
34351 * Ext JS Library 1.1.1
34352 * Copyright(c) 2006-2007, Ext JS, LLC.
34354 * Originally Released Under LGPL - original licence link has changed is not relivant.
34357 * <script type="text/javascript">
34361 * @class Roo.menu.MenuMgr
34362 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34365 Roo.menu.MenuMgr = function(){
34366 var menus, active, groups = {}, attached = false, lastShow = new Date();
34368 // private - called when first menu is created
34371 active = new Roo.util.MixedCollection();
34372 Roo.get(document).addKeyListener(27, function(){
34373 if(active.length > 0){
34380 function hideAll(){
34381 if(active && active.length > 0){
34382 var c = active.clone();
34383 c.each(function(m){
34390 function onHide(m){
34392 if(active.length < 1){
34393 Roo.get(document).un("mousedown", onMouseDown);
34399 function onShow(m){
34400 var last = active.last();
34401 lastShow = new Date();
34404 Roo.get(document).on("mousedown", onMouseDown);
34408 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34409 m.parentMenu.activeChild = m;
34410 }else if(last && last.isVisible()){
34411 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34416 function onBeforeHide(m){
34418 m.activeChild.hide();
34420 if(m.autoHideTimer){
34421 clearTimeout(m.autoHideTimer);
34422 delete m.autoHideTimer;
34427 function onBeforeShow(m){
34428 var pm = m.parentMenu;
34429 if(!pm && !m.allowOtherMenus){
34431 }else if(pm && pm.activeChild && active != m){
34432 pm.activeChild.hide();
34437 function onMouseDown(e){
34438 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34444 function onBeforeCheck(mi, state){
34446 var g = groups[mi.group];
34447 for(var i = 0, l = g.length; i < l; i++){
34449 g[i].setChecked(false);
34458 * Hides all menus that are currently visible
34460 hideAll : function(){
34465 register : function(menu){
34469 menus[menu.id] = menu;
34470 menu.on("beforehide", onBeforeHide);
34471 menu.on("hide", onHide);
34472 menu.on("beforeshow", onBeforeShow);
34473 menu.on("show", onShow);
34474 var g = menu.group;
34475 if(g && menu.events["checkchange"]){
34479 groups[g].push(menu);
34480 menu.on("checkchange", onCheck);
34485 * Returns a {@link Roo.menu.Menu} object
34486 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34487 * be used to generate and return a new Menu instance.
34489 get : function(menu){
34490 if(typeof menu == "string"){ // menu id
34491 return menus[menu];
34492 }else if(menu.events){ // menu instance
34494 }else if(typeof menu.length == 'number'){ // array of menu items?
34495 return new Roo.menu.Menu({items:menu});
34496 }else{ // otherwise, must be a config
34497 return new Roo.menu.Menu(menu);
34502 unregister : function(menu){
34503 delete menus[menu.id];
34504 menu.un("beforehide", onBeforeHide);
34505 menu.un("hide", onHide);
34506 menu.un("beforeshow", onBeforeShow);
34507 menu.un("show", onShow);
34508 var g = menu.group;
34509 if(g && menu.events["checkchange"]){
34510 groups[g].remove(menu);
34511 menu.un("checkchange", onCheck);
34516 registerCheckable : function(menuItem){
34517 var g = menuItem.group;
34522 groups[g].push(menuItem);
34523 menuItem.on("beforecheckchange", onBeforeCheck);
34528 unregisterCheckable : function(menuItem){
34529 var g = menuItem.group;
34531 groups[g].remove(menuItem);
34532 menuItem.un("beforecheckchange", onBeforeCheck);
34538 * Ext JS Library 1.1.1
34539 * Copyright(c) 2006-2007, Ext JS, LLC.
34541 * Originally Released Under LGPL - original licence link has changed is not relivant.
34544 * <script type="text/javascript">
34549 * @class Roo.menu.BaseItem
34550 * @extends Roo.Component
34551 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34552 * management and base configuration options shared by all menu components.
34554 * Creates a new BaseItem
34555 * @param {Object} config Configuration options
34557 Roo.menu.BaseItem = function(config){
34558 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34563 * Fires when this item is clicked
34564 * @param {Roo.menu.BaseItem} this
34565 * @param {Roo.EventObject} e
34570 * Fires when this item is activated
34571 * @param {Roo.menu.BaseItem} this
34575 * @event deactivate
34576 * Fires when this item is deactivated
34577 * @param {Roo.menu.BaseItem} this
34583 this.on("click", this.handler, this.scope, true);
34587 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34589 * @cfg {Function} handler
34590 * A function that will handle the click event of this menu item (defaults to undefined)
34593 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34595 canActivate : false,
34597 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34599 activeClass : "x-menu-item-active",
34601 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34603 hideOnClick : true,
34605 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34610 ctype: "Roo.menu.BaseItem",
34613 actionMode : "container",
34616 render : function(container, parentMenu){
34617 this.parentMenu = parentMenu;
34618 Roo.menu.BaseItem.superclass.render.call(this, container);
34619 this.container.menuItemId = this.id;
34623 onRender : function(container, position){
34624 this.el = Roo.get(this.el);
34625 container.dom.appendChild(this.el.dom);
34629 onClick : function(e){
34630 if(!this.disabled && this.fireEvent("click", this, e) !== false
34631 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34632 this.handleClick(e);
34639 activate : function(){
34643 var li = this.container;
34644 li.addClass(this.activeClass);
34645 this.region = li.getRegion().adjust(2, 2, -2, -2);
34646 this.fireEvent("activate", this);
34651 deactivate : function(){
34652 this.container.removeClass(this.activeClass);
34653 this.fireEvent("deactivate", this);
34657 shouldDeactivate : function(e){
34658 return !this.region || !this.region.contains(e.getPoint());
34662 handleClick : function(e){
34663 if(this.hideOnClick){
34664 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34669 expandMenu : function(autoActivate){
34674 hideMenu : function(){
34679 * Ext JS Library 1.1.1
34680 * Copyright(c) 2006-2007, Ext JS, LLC.
34682 * Originally Released Under LGPL - original licence link has changed is not relivant.
34685 * <script type="text/javascript">
34689 * @class Roo.menu.Adapter
34690 * @extends Roo.menu.BaseItem
34691 * 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.
34692 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34694 * Creates a new Adapter
34695 * @param {Object} config Configuration options
34697 Roo.menu.Adapter = function(component, config){
34698 Roo.menu.Adapter.superclass.constructor.call(this, config);
34699 this.component = component;
34701 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34703 canActivate : true,
34706 onRender : function(container, position){
34707 this.component.render(container);
34708 this.el = this.component.getEl();
34712 activate : function(){
34716 this.component.focus();
34717 this.fireEvent("activate", this);
34722 deactivate : function(){
34723 this.fireEvent("deactivate", this);
34727 disable : function(){
34728 this.component.disable();
34729 Roo.menu.Adapter.superclass.disable.call(this);
34733 enable : function(){
34734 this.component.enable();
34735 Roo.menu.Adapter.superclass.enable.call(this);
34739 * Ext JS Library 1.1.1
34740 * Copyright(c) 2006-2007, Ext JS, LLC.
34742 * Originally Released Under LGPL - original licence link has changed is not relivant.
34745 * <script type="text/javascript">
34749 * @class Roo.menu.TextItem
34750 * @extends Roo.menu.BaseItem
34751 * Adds a static text string to a menu, usually used as either a heading or group separator.
34752 * Note: old style constructor with text is still supported.
34755 * Creates a new TextItem
34756 * @param {Object} cfg Configuration
34758 Roo.menu.TextItem = function(cfg){
34759 if (typeof(cfg) == 'string') {
34762 Roo.apply(this,cfg);
34765 Roo.menu.TextItem.superclass.constructor.call(this);
34768 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34770 * @cfg {Boolean} text Text to show on item.
34775 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34777 hideOnClick : false,
34779 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34781 itemCls : "x-menu-text",
34784 onRender : function(){
34785 var s = document.createElement("span");
34786 s.className = this.itemCls;
34787 s.innerHTML = this.text;
34789 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34793 * Ext JS Library 1.1.1
34794 * Copyright(c) 2006-2007, Ext JS, LLC.
34796 * Originally Released Under LGPL - original licence link has changed is not relivant.
34799 * <script type="text/javascript">
34803 * @class Roo.menu.Separator
34804 * @extends Roo.menu.BaseItem
34805 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34806 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34808 * @param {Object} config Configuration options
34810 Roo.menu.Separator = function(config){
34811 Roo.menu.Separator.superclass.constructor.call(this, config);
34814 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34816 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34818 itemCls : "x-menu-sep",
34820 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34822 hideOnClick : false,
34825 onRender : function(li){
34826 var s = document.createElement("span");
34827 s.className = this.itemCls;
34828 s.innerHTML = " ";
34830 li.addClass("x-menu-sep-li");
34831 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34835 * Ext JS Library 1.1.1
34836 * Copyright(c) 2006-2007, Ext JS, LLC.
34838 * Originally Released Under LGPL - original licence link has changed is not relivant.
34841 * <script type="text/javascript">
34844 * @class Roo.menu.Item
34845 * @extends Roo.menu.BaseItem
34846 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34847 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34848 * activation and click handling.
34850 * Creates a new Item
34851 * @param {Object} config Configuration options
34853 Roo.menu.Item = function(config){
34854 Roo.menu.Item.superclass.constructor.call(this, config);
34856 this.menu = Roo.menu.MenuMgr.get(this.menu);
34859 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34862 * @cfg {String} text
34863 * The text to show on the menu item.
34867 * @cfg {String} HTML to render in menu
34868 * The text to show on the menu item (HTML version).
34872 * @cfg {String} icon
34873 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34877 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34879 itemCls : "x-menu-item",
34881 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34883 canActivate : true,
34885 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34888 // doc'd in BaseItem
34892 ctype: "Roo.menu.Item",
34895 onRender : function(container, position){
34896 var el = document.createElement("a");
34897 el.hideFocus = true;
34898 el.unselectable = "on";
34899 el.href = this.href || "#";
34900 if(this.hrefTarget){
34901 el.target = this.hrefTarget;
34903 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34905 var html = this.html.length ? this.html : String.format('{0}',this.text);
34907 el.innerHTML = String.format(
34908 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
34909 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
34911 Roo.menu.Item.superclass.onRender.call(this, container, position);
34915 * Sets the text to display in this menu item
34916 * @param {String} text The text to display
34917 * @param {Boolean} isHTML true to indicate text is pure html.
34919 setText : function(text, isHTML){
34927 var html = this.html.length ? this.html : String.format('{0}',this.text);
34929 this.el.update(String.format(
34930 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
34931 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34932 this.parentMenu.autoWidth();
34937 handleClick : function(e){
34938 if(!this.href){ // if no link defined, stop the event automatically
34941 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34945 activate : function(autoExpand){
34946 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34956 shouldDeactivate : function(e){
34957 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34958 if(this.menu && this.menu.isVisible()){
34959 return !this.menu.getEl().getRegion().contains(e.getPoint());
34967 deactivate : function(){
34968 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34973 expandMenu : function(autoActivate){
34974 if(!this.disabled && this.menu){
34975 clearTimeout(this.hideTimer);
34976 delete this.hideTimer;
34977 if(!this.menu.isVisible() && !this.showTimer){
34978 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34979 }else if (this.menu.isVisible() && autoActivate){
34980 this.menu.tryActivate(0, 1);
34986 deferExpand : function(autoActivate){
34987 delete this.showTimer;
34988 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34990 this.menu.tryActivate(0, 1);
34995 hideMenu : function(){
34996 clearTimeout(this.showTimer);
34997 delete this.showTimer;
34998 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34999 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35004 deferHide : function(){
35005 delete this.hideTimer;
35010 * Ext JS Library 1.1.1
35011 * Copyright(c) 2006-2007, Ext JS, LLC.
35013 * Originally Released Under LGPL - original licence link has changed is not relivant.
35016 * <script type="text/javascript">
35020 * @class Roo.menu.CheckItem
35021 * @extends Roo.menu.Item
35022 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35024 * Creates a new CheckItem
35025 * @param {Object} config Configuration options
35027 Roo.menu.CheckItem = function(config){
35028 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35031 * @event beforecheckchange
35032 * Fires before the checked value is set, providing an opportunity to cancel if needed
35033 * @param {Roo.menu.CheckItem} this
35034 * @param {Boolean} checked The new checked value that will be set
35036 "beforecheckchange" : true,
35038 * @event checkchange
35039 * Fires after the checked value has been set
35040 * @param {Roo.menu.CheckItem} this
35041 * @param {Boolean} checked The checked value that was set
35043 "checkchange" : true
35045 if(this.checkHandler){
35046 this.on('checkchange', this.checkHandler, this.scope);
35049 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35051 * @cfg {String} group
35052 * All check items with the same group name will automatically be grouped into a single-select
35053 * radio button group (defaults to '')
35056 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35058 itemCls : "x-menu-item x-menu-check-item",
35060 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35062 groupClass : "x-menu-group-item",
35065 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35066 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35067 * initialized with checked = true will be rendered as checked.
35072 ctype: "Roo.menu.CheckItem",
35075 onRender : function(c){
35076 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35078 this.el.addClass(this.groupClass);
35080 Roo.menu.MenuMgr.registerCheckable(this);
35082 this.checked = false;
35083 this.setChecked(true, true);
35088 destroy : function(){
35090 Roo.menu.MenuMgr.unregisterCheckable(this);
35092 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35096 * Set the checked state of this item
35097 * @param {Boolean} checked The new checked value
35098 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35100 setChecked : function(state, suppressEvent){
35101 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35102 if(this.container){
35103 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35105 this.checked = state;
35106 if(suppressEvent !== true){
35107 this.fireEvent("checkchange", this, state);
35113 handleClick : function(e){
35114 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35115 this.setChecked(!this.checked);
35117 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35121 * Ext JS Library 1.1.1
35122 * Copyright(c) 2006-2007, Ext JS, LLC.
35124 * Originally Released Under LGPL - original licence link has changed is not relivant.
35127 * <script type="text/javascript">
35131 * @class Roo.menu.DateItem
35132 * @extends Roo.menu.Adapter
35133 * A menu item that wraps the {@link Roo.DatPicker} component.
35135 * Creates a new DateItem
35136 * @param {Object} config Configuration options
35138 Roo.menu.DateItem = function(config){
35139 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35140 /** The Roo.DatePicker object @type Roo.DatePicker */
35141 this.picker = this.component;
35142 this.addEvents({select: true});
35144 this.picker.on("render", function(picker){
35145 picker.getEl().swallowEvent("click");
35146 picker.container.addClass("x-menu-date-item");
35149 this.picker.on("select", this.onSelect, this);
35152 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35154 onSelect : function(picker, date){
35155 this.fireEvent("select", this, date, picker);
35156 Roo.menu.DateItem.superclass.handleClick.call(this);
35160 * Ext JS Library 1.1.1
35161 * Copyright(c) 2006-2007, Ext JS, LLC.
35163 * Originally Released Under LGPL - original licence link has changed is not relivant.
35166 * <script type="text/javascript">
35170 * @class Roo.menu.ColorItem
35171 * @extends Roo.menu.Adapter
35172 * A menu item that wraps the {@link Roo.ColorPalette} component.
35174 * Creates a new ColorItem
35175 * @param {Object} config Configuration options
35177 Roo.menu.ColorItem = function(config){
35178 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35179 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35180 this.palette = this.component;
35181 this.relayEvents(this.palette, ["select"]);
35182 if(this.selectHandler){
35183 this.on('select', this.selectHandler, this.scope);
35186 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35188 * Ext JS Library 1.1.1
35189 * Copyright(c) 2006-2007, Ext JS, LLC.
35191 * Originally Released Under LGPL - original licence link has changed is not relivant.
35194 * <script type="text/javascript">
35199 * @class Roo.menu.DateMenu
35200 * @extends Roo.menu.Menu
35201 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35203 * Creates a new DateMenu
35204 * @param {Object} config Configuration options
35206 Roo.menu.DateMenu = function(config){
35207 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35209 var di = new Roo.menu.DateItem(config);
35212 * The {@link Roo.DatePicker} instance for this DateMenu
35215 this.picker = di.picker;
35218 * @param {DatePicker} picker
35219 * @param {Date} date
35221 this.relayEvents(di, ["select"]);
35223 this.on('beforeshow', function(){
35225 this.picker.hideMonthPicker(true);
35229 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35233 * Ext JS Library 1.1.1
35234 * Copyright(c) 2006-2007, Ext JS, LLC.
35236 * Originally Released Under LGPL - original licence link has changed is not relivant.
35239 * <script type="text/javascript">
35244 * @class Roo.menu.ColorMenu
35245 * @extends Roo.menu.Menu
35246 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35248 * Creates a new ColorMenu
35249 * @param {Object} config Configuration options
35251 Roo.menu.ColorMenu = function(config){
35252 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35254 var ci = new Roo.menu.ColorItem(config);
35257 * The {@link Roo.ColorPalette} instance for this ColorMenu
35258 * @type ColorPalette
35260 this.palette = ci.palette;
35263 * @param {ColorPalette} palette
35264 * @param {String} color
35266 this.relayEvents(ci, ["select"]);
35268 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35270 * Ext JS Library 1.1.1
35271 * Copyright(c) 2006-2007, Ext JS, LLC.
35273 * Originally Released Under LGPL - original licence link has changed is not relivant.
35276 * <script type="text/javascript">
35280 * @class Roo.form.Field
35281 * @extends Roo.BoxComponent
35282 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35284 * Creates a new Field
35285 * @param {Object} config Configuration options
35287 Roo.form.Field = function(config){
35288 Roo.form.Field.superclass.constructor.call(this, config);
35291 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35293 * @cfg {String} fieldLabel Label to use when rendering a form.
35296 * @cfg {String} qtip Mouse over tip
35300 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35302 invalidClass : "x-form-invalid",
35304 * @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")
35306 invalidText : "The value in this field is invalid",
35308 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35310 focusClass : "x-form-focus",
35312 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35313 automatic validation (defaults to "keyup").
35315 validationEvent : "keyup",
35317 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35319 validateOnBlur : true,
35321 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35323 validationDelay : 250,
35325 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35326 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35328 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35330 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35332 fieldClass : "x-form-field",
35334 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35337 ----------- ----------------------------------------------------------------------
35338 qtip Display a quick tip when the user hovers over the field
35339 title Display a default browser title attribute popup
35340 under Add a block div beneath the field containing the error text
35341 side Add an error icon to the right of the field with a popup on hover
35342 [element id] Add the error text directly to the innerHTML of the specified element
35345 msgTarget : 'qtip',
35347 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35352 * @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.
35357 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35362 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35364 inputType : undefined,
35367 * @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).
35369 tabIndex : undefined,
35372 isFormField : true,
35377 * @property {Roo.Element} fieldEl
35378 * Element Containing the rendered Field (with label etc.)
35381 * @cfg {Mixed} value A value to initialize this field with.
35386 * @cfg {String} name The field's HTML name attribute.
35389 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35393 initComponent : function(){
35394 Roo.form.Field.superclass.initComponent.call(this);
35398 * Fires when this field receives input focus.
35399 * @param {Roo.form.Field} this
35404 * Fires when this field loses input focus.
35405 * @param {Roo.form.Field} this
35409 * @event specialkey
35410 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35411 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35412 * @param {Roo.form.Field} this
35413 * @param {Roo.EventObject} e The event object
35418 * Fires just before the field blurs if the field value has changed.
35419 * @param {Roo.form.Field} this
35420 * @param {Mixed} newValue The new value
35421 * @param {Mixed} oldValue The original value
35426 * Fires after the field has been marked as invalid.
35427 * @param {Roo.form.Field} this
35428 * @param {String} msg The validation message
35433 * Fires after the field has been validated with no errors.
35434 * @param {Roo.form.Field} this
35439 * Fires after the key up
35440 * @param {Roo.form.Field} this
35441 * @param {Roo.EventObject} e The event Object
35448 * Returns the name attribute of the field if available
35449 * @return {String} name The field name
35451 getName: function(){
35452 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35456 onRender : function(ct, position){
35457 Roo.form.Field.superclass.onRender.call(this, ct, position);
35459 var cfg = this.getAutoCreate();
35461 cfg.name = this.name || this.id;
35463 if(this.inputType){
35464 cfg.type = this.inputType;
35466 this.el = ct.createChild(cfg, position);
35468 var type = this.el.dom.type;
35470 if(type == 'password'){
35473 this.el.addClass('x-form-'+type);
35476 this.el.dom.readOnly = true;
35478 if(this.tabIndex !== undefined){
35479 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35482 this.el.addClass([this.fieldClass, this.cls]);
35487 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35488 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35489 * @return {Roo.form.Field} this
35491 applyTo : function(target){
35492 this.allowDomMove = false;
35493 this.el = Roo.get(target);
35494 this.render(this.el.dom.parentNode);
35499 initValue : function(){
35500 if(this.value !== undefined){
35501 this.setValue(this.value);
35502 }else if(this.el.dom.value.length > 0){
35503 this.setValue(this.el.dom.value);
35508 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35510 isDirty : function() {
35511 if(this.disabled) {
35514 return String(this.getValue()) !== String(this.originalValue);
35518 afterRender : function(){
35519 Roo.form.Field.superclass.afterRender.call(this);
35524 fireKey : function(e){
35525 //Roo.log('field ' + e.getKey());
35526 if(e.isNavKeyPress()){
35527 this.fireEvent("specialkey", this, e);
35532 * Resets the current field value to the originally loaded value and clears any validation messages
35534 reset : function(){
35535 this.setValue(this.originalValue);
35536 this.clearInvalid();
35540 initEvents : function(){
35541 // safari killled keypress - so keydown is now used..
35542 this.el.on("keydown" , this.fireKey, this);
35543 this.el.on("focus", this.onFocus, this);
35544 this.el.on("blur", this.onBlur, this);
35545 this.el.relayEvent('keyup', this);
35547 // reference to original value for reset
35548 this.originalValue = this.getValue();
35552 onFocus : function(){
35553 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35554 this.el.addClass(this.focusClass);
35556 if(!this.hasFocus){
35557 this.hasFocus = true;
35558 this.startValue = this.getValue();
35559 this.fireEvent("focus", this);
35563 beforeBlur : Roo.emptyFn,
35566 onBlur : function(){
35568 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35569 this.el.removeClass(this.focusClass);
35571 this.hasFocus = false;
35572 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35575 var v = this.getValue();
35576 if(String(v) !== String(this.startValue)){
35577 this.fireEvent('change', this, v, this.startValue);
35579 this.fireEvent("blur", this);
35583 * Returns whether or not the field value is currently valid
35584 * @param {Boolean} preventMark True to disable marking the field invalid
35585 * @return {Boolean} True if the value is valid, else false
35587 isValid : function(preventMark){
35591 var restore = this.preventMark;
35592 this.preventMark = preventMark === true;
35593 var v = this.validateValue(this.processValue(this.getRawValue()));
35594 this.preventMark = restore;
35599 * Validates the field value
35600 * @return {Boolean} True if the value is valid, else false
35602 validate : function(){
35603 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35604 this.clearInvalid();
35610 processValue : function(value){
35615 // Subclasses should provide the validation implementation by overriding this
35616 validateValue : function(value){
35621 * Mark this field as invalid
35622 * @param {String} msg The validation message
35624 markInvalid : function(msg){
35625 if(!this.rendered || this.preventMark){ // not rendered
35628 this.el.addClass(this.invalidClass);
35629 msg = msg || this.invalidText;
35630 switch(this.msgTarget){
35632 this.el.dom.qtip = msg;
35633 this.el.dom.qclass = 'x-form-invalid-tip';
35634 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35635 Roo.QuickTips.enable();
35639 this.el.dom.title = msg;
35643 var elp = this.el.findParent('.x-form-element', 5, true);
35644 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35645 this.errorEl.setWidth(elp.getWidth(true)-20);
35647 this.errorEl.update(msg);
35648 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35651 if(!this.errorIcon){
35652 var elp = this.el.findParent('.x-form-element', 5, true);
35653 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35655 this.alignErrorIcon();
35656 this.errorIcon.dom.qtip = msg;
35657 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35658 this.errorIcon.show();
35659 this.on('resize', this.alignErrorIcon, this);
35662 var t = Roo.getDom(this.msgTarget);
35664 t.style.display = this.msgDisplay;
35667 this.fireEvent('invalid', this, msg);
35671 alignErrorIcon : function(){
35672 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35676 * Clear any invalid styles/messages for this field
35678 clearInvalid : function(){
35679 if(!this.rendered || this.preventMark){ // not rendered
35682 this.el.removeClass(this.invalidClass);
35683 switch(this.msgTarget){
35685 this.el.dom.qtip = '';
35688 this.el.dom.title = '';
35692 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35696 if(this.errorIcon){
35697 this.errorIcon.dom.qtip = '';
35698 this.errorIcon.hide();
35699 this.un('resize', this.alignErrorIcon, this);
35703 var t = Roo.getDom(this.msgTarget);
35705 t.style.display = 'none';
35708 this.fireEvent('valid', this);
35712 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35713 * @return {Mixed} value The field value
35715 getRawValue : function(){
35716 var v = this.el.getValue();
35717 if(v === this.emptyText){
35724 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35725 * @return {Mixed} value The field value
35727 getValue : function(){
35728 var v = this.el.getValue();
35729 if(v === this.emptyText || v === undefined){
35736 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35737 * @param {Mixed} value The value to set
35739 setRawValue : function(v){
35740 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35744 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35745 * @param {Mixed} value The value to set
35747 setValue : function(v){
35750 this.el.dom.value = (v === null || v === undefined ? '' : v);
35755 adjustSize : function(w, h){
35756 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35757 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35761 adjustWidth : function(tag, w){
35762 tag = tag.toLowerCase();
35763 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35764 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35765 if(tag == 'input'){
35768 if(tag = 'textarea'){
35771 }else if(Roo.isOpera){
35772 if(tag == 'input'){
35775 if(tag = 'textarea'){
35785 // anything other than normal should be considered experimental
35786 Roo.form.Field.msgFx = {
35788 show: function(msgEl, f){
35789 msgEl.setDisplayed('block');
35792 hide : function(msgEl, f){
35793 msgEl.setDisplayed(false).update('');
35798 show: function(msgEl, f){
35799 msgEl.slideIn('t', {stopFx:true});
35802 hide : function(msgEl, f){
35803 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35808 show: function(msgEl, f){
35809 msgEl.fixDisplay();
35810 msgEl.alignTo(f.el, 'tl-tr');
35811 msgEl.slideIn('l', {stopFx:true});
35814 hide : function(msgEl, f){
35815 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35820 * Ext JS Library 1.1.1
35821 * Copyright(c) 2006-2007, Ext JS, LLC.
35823 * Originally Released Under LGPL - original licence link has changed is not relivant.
35826 * <script type="text/javascript">
35831 * @class Roo.form.TextField
35832 * @extends Roo.form.Field
35833 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35834 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35836 * Creates a new TextField
35837 * @param {Object} config Configuration options
35839 Roo.form.TextField = function(config){
35840 Roo.form.TextField.superclass.constructor.call(this, config);
35844 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35845 * according to the default logic, but this event provides a hook for the developer to apply additional
35846 * logic at runtime to resize the field if needed.
35847 * @param {Roo.form.Field} this This text field
35848 * @param {Number} width The new field width
35854 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35856 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35860 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35864 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35868 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35872 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35876 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35878 disableKeyFilter : false,
35880 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35884 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35888 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35890 maxLength : Number.MAX_VALUE,
35892 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35894 minLengthText : "The minimum length for this field is {0}",
35896 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35898 maxLengthText : "The maximum length for this field is {0}",
35900 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35902 selectOnFocus : false,
35904 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35906 blankText : "This field is required",
35908 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35909 * If available, this function will be called only after the basic validators all return true, and will be passed the
35910 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35914 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35915 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35916 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35920 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35924 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35928 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35929 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35931 emptyClass : 'x-form-empty-field',
35934 initEvents : function(){
35935 Roo.form.TextField.superclass.initEvents.call(this);
35936 if(this.validationEvent == 'keyup'){
35937 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35938 this.el.on('keyup', this.filterValidation, this);
35940 else if(this.validationEvent !== false){
35941 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35943 if(this.selectOnFocus || this.emptyText){
35944 this.on("focus", this.preFocus, this);
35945 if(this.emptyText){
35946 this.on('blur', this.postBlur, this);
35947 this.applyEmptyText();
35950 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35951 this.el.on("keypress", this.filterKeys, this);
35954 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35955 this.el.on("click", this.autoSize, this);
35959 processValue : function(value){
35960 if(this.stripCharsRe){
35961 var newValue = value.replace(this.stripCharsRe, '');
35962 if(newValue !== value){
35963 this.setRawValue(newValue);
35970 filterValidation : function(e){
35971 if(!e.isNavKeyPress()){
35972 this.validationTask.delay(this.validationDelay);
35977 onKeyUp : function(e){
35978 if(!e.isNavKeyPress()){
35984 * Resets the current field value to the originally-loaded value and clears any validation messages.
35985 * Also adds emptyText and emptyClass if the original value was blank.
35987 reset : function(){
35988 Roo.form.TextField.superclass.reset.call(this);
35989 this.applyEmptyText();
35992 applyEmptyText : function(){
35993 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35994 this.setRawValue(this.emptyText);
35995 this.el.addClass(this.emptyClass);
36000 preFocus : function(){
36001 if(this.emptyText){
36002 if(this.el.dom.value == this.emptyText){
36003 this.setRawValue('');
36005 this.el.removeClass(this.emptyClass);
36007 if(this.selectOnFocus){
36008 this.el.dom.select();
36013 postBlur : function(){
36014 this.applyEmptyText();
36018 filterKeys : function(e){
36019 var k = e.getKey();
36020 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36023 var c = e.getCharCode(), cc = String.fromCharCode(c);
36024 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36027 if(!this.maskRe.test(cc)){
36032 setValue : function(v){
36033 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
36034 this.el.removeClass(this.emptyClass);
36036 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36037 this.applyEmptyText();
36042 * Validates a value according to the field's validation rules and marks the field as invalid
36043 * if the validation fails
36044 * @param {Mixed} value The value to validate
36045 * @return {Boolean} True if the value is valid, else false
36047 validateValue : function(value){
36048 if(value.length < 1 || value === this.emptyText){ // if it's blank
36049 if(this.allowBlank){
36050 this.clearInvalid();
36053 this.markInvalid(this.blankText);
36057 if(value.length < this.minLength){
36058 this.markInvalid(String.format(this.minLengthText, this.minLength));
36061 if(value.length > this.maxLength){
36062 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36066 var vt = Roo.form.VTypes;
36067 if(!vt[this.vtype](value, this)){
36068 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36072 if(typeof this.validator == "function"){
36073 var msg = this.validator(value);
36075 this.markInvalid(msg);
36079 if(this.regex && !this.regex.test(value)){
36080 this.markInvalid(this.regexText);
36087 * Selects text in this field
36088 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36089 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36091 selectText : function(start, end){
36092 var v = this.getRawValue();
36094 start = start === undefined ? 0 : start;
36095 end = end === undefined ? v.length : end;
36096 var d = this.el.dom;
36097 if(d.setSelectionRange){
36098 d.setSelectionRange(start, end);
36099 }else if(d.createTextRange){
36100 var range = d.createTextRange();
36101 range.moveStart("character", start);
36102 range.moveEnd("character", v.length-end);
36109 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36110 * This only takes effect if grow = true, and fires the autosize event.
36112 autoSize : function(){
36113 if(!this.grow || !this.rendered){
36117 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36120 var v = el.dom.value;
36121 var d = document.createElement('div');
36122 d.appendChild(document.createTextNode(v));
36126 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36127 this.el.setWidth(w);
36128 this.fireEvent("autosize", this, w);
36132 * Ext JS Library 1.1.1
36133 * Copyright(c) 2006-2007, Ext JS, LLC.
36135 * Originally Released Under LGPL - original licence link has changed is not relivant.
36138 * <script type="text/javascript">
36142 * @class Roo.form.Hidden
36143 * @extends Roo.form.TextField
36144 * Simple Hidden element used on forms
36146 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36149 * Creates a new Hidden form element.
36150 * @param {Object} config Configuration options
36155 // easy hidden field...
36156 Roo.form.Hidden = function(config){
36157 Roo.form.Hidden.superclass.constructor.call(this, config);
36160 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36162 inputType: 'hidden',
36165 labelSeparator: '',
36167 itemCls : 'x-form-item-display-none'
36175 * Ext JS Library 1.1.1
36176 * Copyright(c) 2006-2007, Ext JS, LLC.
36178 * Originally Released Under LGPL - original licence link has changed is not relivant.
36181 * <script type="text/javascript">
36185 * @class Roo.form.TriggerField
36186 * @extends Roo.form.TextField
36187 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36188 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36189 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36190 * for which you can provide a custom implementation. For example:
36192 var trigger = new Roo.form.TriggerField();
36193 trigger.onTriggerClick = myTriggerFn;
36194 trigger.applyTo('my-field');
36197 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36198 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36199 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36200 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36202 * Create a new TriggerField.
36203 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36204 * to the base TextField)
36206 Roo.form.TriggerField = function(config){
36207 this.mimicing = false;
36208 Roo.form.TriggerField.superclass.constructor.call(this, config);
36211 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36213 * @cfg {String} triggerClass A CSS class to apply to the trigger
36216 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36217 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36219 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36221 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36225 /** @cfg {Boolean} grow @hide */
36226 /** @cfg {Number} growMin @hide */
36227 /** @cfg {Number} growMax @hide */
36233 autoSize: Roo.emptyFn,
36237 deferHeight : true,
36240 actionMode : 'wrap',
36242 onResize : function(w, h){
36243 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36244 if(typeof w == 'number'){
36245 var x = w - this.trigger.getWidth();
36246 this.el.setWidth(this.adjustWidth('input', x));
36247 this.trigger.setStyle('left', x+'px');
36252 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36255 getResizeEl : function(){
36260 getPositionEl : function(){
36265 alignErrorIcon : function(){
36266 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36270 onRender : function(ct, position){
36271 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36272 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36273 this.trigger = this.wrap.createChild(this.triggerConfig ||
36274 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36275 if(this.hideTrigger){
36276 this.trigger.setDisplayed(false);
36278 this.initTrigger();
36280 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36285 initTrigger : function(){
36286 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36287 this.trigger.addClassOnOver('x-form-trigger-over');
36288 this.trigger.addClassOnClick('x-form-trigger-click');
36292 onDestroy : function(){
36294 this.trigger.removeAllListeners();
36295 this.trigger.remove();
36298 this.wrap.remove();
36300 Roo.form.TriggerField.superclass.onDestroy.call(this);
36304 onFocus : function(){
36305 Roo.form.TriggerField.superclass.onFocus.call(this);
36306 if(!this.mimicing){
36307 this.wrap.addClass('x-trigger-wrap-focus');
36308 this.mimicing = true;
36309 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36310 if(this.monitorTab){
36311 this.el.on("keydown", this.checkTab, this);
36317 checkTab : function(e){
36318 if(e.getKey() == e.TAB){
36319 this.triggerBlur();
36324 onBlur : function(){
36329 mimicBlur : function(e, t){
36330 if(!this.wrap.contains(t) && this.validateBlur()){
36331 this.triggerBlur();
36336 triggerBlur : function(){
36337 this.mimicing = false;
36338 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36339 if(this.monitorTab){
36340 this.el.un("keydown", this.checkTab, this);
36342 this.wrap.removeClass('x-trigger-wrap-focus');
36343 Roo.form.TriggerField.superclass.onBlur.call(this);
36347 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36348 validateBlur : function(e, t){
36353 onDisable : function(){
36354 Roo.form.TriggerField.superclass.onDisable.call(this);
36356 this.wrap.addClass('x-item-disabled');
36361 onEnable : function(){
36362 Roo.form.TriggerField.superclass.onEnable.call(this);
36364 this.wrap.removeClass('x-item-disabled');
36369 onShow : function(){
36370 var ae = this.getActionEl();
36373 ae.dom.style.display = '';
36374 ae.dom.style.visibility = 'visible';
36380 onHide : function(){
36381 var ae = this.getActionEl();
36382 ae.dom.style.display = 'none';
36386 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36387 * by an implementing function.
36389 * @param {EventObject} e
36391 onTriggerClick : Roo.emptyFn
36394 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36395 // to be extended by an implementing class. For an example of implementing this class, see the custom
36396 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36397 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36398 initComponent : function(){
36399 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36401 this.triggerConfig = {
36402 tag:'span', cls:'x-form-twin-triggers', cn:[
36403 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36404 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36408 getTrigger : function(index){
36409 return this.triggers[index];
36412 initTrigger : function(){
36413 var ts = this.trigger.select('.x-form-trigger', true);
36414 this.wrap.setStyle('overflow', 'hidden');
36415 var triggerField = this;
36416 ts.each(function(t, all, index){
36417 t.hide = function(){
36418 var w = triggerField.wrap.getWidth();
36419 this.dom.style.display = 'none';
36420 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36422 t.show = function(){
36423 var w = triggerField.wrap.getWidth();
36424 this.dom.style.display = '';
36425 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36427 var triggerIndex = 'Trigger'+(index+1);
36429 if(this['hide'+triggerIndex]){
36430 t.dom.style.display = 'none';
36432 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36433 t.addClassOnOver('x-form-trigger-over');
36434 t.addClassOnClick('x-form-trigger-click');
36436 this.triggers = ts.elements;
36439 onTrigger1Click : Roo.emptyFn,
36440 onTrigger2Click : Roo.emptyFn
36443 * Ext JS Library 1.1.1
36444 * Copyright(c) 2006-2007, Ext JS, LLC.
36446 * Originally Released Under LGPL - original licence link has changed is not relivant.
36449 * <script type="text/javascript">
36453 * @class Roo.form.TextArea
36454 * @extends Roo.form.TextField
36455 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36456 * support for auto-sizing.
36458 * Creates a new TextArea
36459 * @param {Object} config Configuration options
36461 Roo.form.TextArea = function(config){
36462 Roo.form.TextArea.superclass.constructor.call(this, config);
36463 // these are provided exchanges for backwards compat
36464 // minHeight/maxHeight were replaced by growMin/growMax to be
36465 // compatible with TextField growing config values
36466 if(this.minHeight !== undefined){
36467 this.growMin = this.minHeight;
36469 if(this.maxHeight !== undefined){
36470 this.growMax = this.maxHeight;
36474 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36476 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36480 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36484 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36485 * in the field (equivalent to setting overflow: hidden, defaults to false)
36487 preventScrollbars: false,
36489 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36490 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36494 onRender : function(ct, position){
36496 this.defaultAutoCreate = {
36498 style:"width:300px;height:60px;",
36499 autocomplete: "off"
36502 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36504 this.textSizeEl = Roo.DomHelper.append(document.body, {
36505 tag: "pre", cls: "x-form-grow-sizer"
36507 if(this.preventScrollbars){
36508 this.el.setStyle("overflow", "hidden");
36510 this.el.setHeight(this.growMin);
36514 onDestroy : function(){
36515 if(this.textSizeEl){
36516 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36518 Roo.form.TextArea.superclass.onDestroy.call(this);
36522 onKeyUp : function(e){
36523 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36529 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36530 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36532 autoSize : function(){
36533 if(!this.grow || !this.textSizeEl){
36537 var v = el.dom.value;
36538 var ts = this.textSizeEl;
36541 ts.appendChild(document.createTextNode(v));
36544 Roo.fly(ts).setWidth(this.el.getWidth());
36546 v = "  ";
36549 v = v.replace(/\n/g, '<p> </p>');
36551 v += " \n ";
36554 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36555 if(h != this.lastHeight){
36556 this.lastHeight = h;
36557 this.el.setHeight(h);
36558 this.fireEvent("autosize", this, h);
36563 * Ext JS Library 1.1.1
36564 * Copyright(c) 2006-2007, Ext JS, LLC.
36566 * Originally Released Under LGPL - original licence link has changed is not relivant.
36569 * <script type="text/javascript">
36574 * @class Roo.form.NumberField
36575 * @extends Roo.form.TextField
36576 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36578 * Creates a new NumberField
36579 * @param {Object} config Configuration options
36581 Roo.form.NumberField = function(config){
36582 Roo.form.NumberField.superclass.constructor.call(this, config);
36585 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36587 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36589 fieldClass: "x-form-field x-form-num-field",
36591 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36593 allowDecimals : true,
36595 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36597 decimalSeparator : ".",
36599 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36601 decimalPrecision : 2,
36603 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36605 allowNegative : true,
36607 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36609 minValue : Number.NEGATIVE_INFINITY,
36611 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36613 maxValue : Number.MAX_VALUE,
36615 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36617 minText : "The minimum value for this field is {0}",
36619 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36621 maxText : "The maximum value for this field is {0}",
36623 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36624 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36626 nanText : "{0} is not a valid number",
36629 initEvents : function(){
36630 Roo.form.NumberField.superclass.initEvents.call(this);
36631 var allowed = "0123456789";
36632 if(this.allowDecimals){
36633 allowed += this.decimalSeparator;
36635 if(this.allowNegative){
36638 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36639 var keyPress = function(e){
36640 var k = e.getKey();
36641 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36644 var c = e.getCharCode();
36645 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36649 this.el.on("keypress", keyPress, this);
36653 validateValue : function(value){
36654 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36657 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36660 var num = this.parseValue(value);
36662 this.markInvalid(String.format(this.nanText, value));
36665 if(num < this.minValue){
36666 this.markInvalid(String.format(this.minText, this.minValue));
36669 if(num > this.maxValue){
36670 this.markInvalid(String.format(this.maxText, this.maxValue));
36676 getValue : function(){
36677 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36681 parseValue : function(value){
36682 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36683 return isNaN(value) ? '' : value;
36687 fixPrecision : function(value){
36688 var nan = isNaN(value);
36689 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36690 return nan ? '' : value;
36692 return parseFloat(value).toFixed(this.decimalPrecision);
36695 setValue : function(v){
36696 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36700 decimalPrecisionFcn : function(v){
36701 return Math.floor(v);
36704 beforeBlur : function(){
36705 var v = this.parseValue(this.getRawValue());
36707 this.setValue(this.fixPrecision(v));
36712 * Ext JS Library 1.1.1
36713 * Copyright(c) 2006-2007, Ext JS, LLC.
36715 * Originally Released Under LGPL - original licence link has changed is not relivant.
36718 * <script type="text/javascript">
36722 * @class Roo.form.DateField
36723 * @extends Roo.form.TriggerField
36724 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36726 * Create a new DateField
36727 * @param {Object} config
36729 Roo.form.DateField = function(config){
36730 Roo.form.DateField.superclass.constructor.call(this, config);
36736 * Fires when a date is selected
36737 * @param {Roo.form.DateField} combo This combo box
36738 * @param {Date} date The date selected
36745 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36746 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36747 this.ddMatch = null;
36748 if(this.disabledDates){
36749 var dd = this.disabledDates;
36751 for(var i = 0; i < dd.length; i++){
36753 if(i != dd.length-1) re += "|";
36755 this.ddMatch = new RegExp(re + ")");
36759 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36761 * @cfg {String} format
36762 * The default date format string which can be overriden for localization support. The format must be
36763 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36767 * @cfg {String} altFormats
36768 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36769 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36771 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36773 * @cfg {Array} disabledDays
36774 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36776 disabledDays : null,
36778 * @cfg {String} disabledDaysText
36779 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36781 disabledDaysText : "Disabled",
36783 * @cfg {Array} disabledDates
36784 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36785 * expression so they are very powerful. Some examples:
36787 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36788 * <li>["03/08", "09/16"] would disable those days for every year</li>
36789 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36790 * <li>["03/../2006"] would disable every day in March 2006</li>
36791 * <li>["^03"] would disable every day in every March</li>
36793 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36794 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36796 disabledDates : null,
36798 * @cfg {String} disabledDatesText
36799 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36801 disabledDatesText : "Disabled",
36803 * @cfg {Date/String} minValue
36804 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36805 * valid format (defaults to null).
36809 * @cfg {Date/String} maxValue
36810 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36811 * valid format (defaults to null).
36815 * @cfg {String} minText
36816 * The error text to display when the date in the cell is before minValue (defaults to
36817 * 'The date in this field must be after {minValue}').
36819 minText : "The date in this field must be equal to or after {0}",
36821 * @cfg {String} maxText
36822 * The error text to display when the date in the cell is after maxValue (defaults to
36823 * 'The date in this field must be before {maxValue}').
36825 maxText : "The date in this field must be equal to or before {0}",
36827 * @cfg {String} invalidText
36828 * The error text to display when the date in the field is invalid (defaults to
36829 * '{value} is not a valid date - it must be in the format {format}').
36831 invalidText : "{0} is not a valid date - it must be in the format {1}",
36833 * @cfg {String} triggerClass
36834 * An additional CSS class used to style the trigger button. The trigger will always get the
36835 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36836 * which displays a calendar icon).
36838 triggerClass : 'x-form-date-trigger',
36842 * @cfg {bool} useIso
36843 * if enabled, then the date field will use a hidden field to store the
36844 * real value as iso formated date. default (false)
36848 * @cfg {String/Object} autoCreate
36849 * A DomHelper element spec, or true for a default element spec (defaults to
36850 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36853 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36856 hiddenField: false,
36858 onRender : function(ct, position)
36860 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36862 this.el.dom.removeAttribute('name');
36863 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36865 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36866 // prevent input submission
36867 this.hiddenName = this.name;
36874 validateValue : function(value)
36876 value = this.formatDate(value);
36877 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36880 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36883 var svalue = value;
36884 value = this.parseDate(value);
36886 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36889 var time = value.getTime();
36890 if(this.minValue && time < this.minValue.getTime()){
36891 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36894 if(this.maxValue && time > this.maxValue.getTime()){
36895 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36898 if(this.disabledDays){
36899 var day = value.getDay();
36900 for(var i = 0; i < this.disabledDays.length; i++) {
36901 if(day === this.disabledDays[i]){
36902 this.markInvalid(this.disabledDaysText);
36907 var fvalue = this.formatDate(value);
36908 if(this.ddMatch && this.ddMatch.test(fvalue)){
36909 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36916 // Provides logic to override the default TriggerField.validateBlur which just returns true
36917 validateBlur : function(){
36918 return !this.menu || !this.menu.isVisible();
36922 * Returns the current date value of the date field.
36923 * @return {Date} The date value
36925 getValue : function(){
36927 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36931 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36932 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36933 * (the default format used is "m/d/y").
36936 //All of these calls set the same date value (May 4, 2006)
36938 //Pass a date object:
36939 var dt = new Date('5/4/06');
36940 dateField.setValue(dt);
36942 //Pass a date string (default format):
36943 dateField.setValue('5/4/06');
36945 //Pass a date string (custom format):
36946 dateField.format = 'Y-m-d';
36947 dateField.setValue('2006-5-4');
36949 * @param {String/Date} date The date or valid date string
36951 setValue : function(date){
36952 if (this.hiddenField) {
36953 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36955 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36959 parseDate : function(value){
36960 if(!value || value instanceof Date){
36963 var v = Date.parseDate(value, this.format);
36964 if(!v && this.altFormats){
36965 if(!this.altFormatsArray){
36966 this.altFormatsArray = this.altFormats.split("|");
36968 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36969 v = Date.parseDate(value, this.altFormatsArray[i]);
36976 formatDate : function(date, fmt){
36977 return (!date || !(date instanceof Date)) ?
36978 date : date.dateFormat(fmt || this.format);
36983 select: function(m, d){
36985 this.fireEvent('select', this, d);
36987 show : function(){ // retain focus styling
36991 this.focus.defer(10, this);
36992 var ml = this.menuListeners;
36993 this.menu.un("select", ml.select, this);
36994 this.menu.un("show", ml.show, this);
36995 this.menu.un("hide", ml.hide, this);
37000 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37001 onTriggerClick : function(){
37005 if(this.menu == null){
37006 this.menu = new Roo.menu.DateMenu();
37008 Roo.apply(this.menu.picker, {
37009 showClear: this.allowBlank,
37010 minDate : this.minValue,
37011 maxDate : this.maxValue,
37012 disabledDatesRE : this.ddMatch,
37013 disabledDatesText : this.disabledDatesText,
37014 disabledDays : this.disabledDays,
37015 disabledDaysText : this.disabledDaysText,
37016 format : this.format,
37017 minText : String.format(this.minText, this.formatDate(this.minValue)),
37018 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37020 this.menu.on(Roo.apply({}, this.menuListeners, {
37023 this.menu.picker.setValue(this.getValue() || new Date());
37024 this.menu.show(this.el, "tl-bl?");
37027 beforeBlur : function(){
37028 var v = this.parseDate(this.getRawValue());
37034 /** @cfg {Boolean} grow @hide */
37035 /** @cfg {Number} growMin @hide */
37036 /** @cfg {Number} growMax @hide */
37043 * Ext JS Library 1.1.1
37044 * Copyright(c) 2006-2007, Ext JS, LLC.
37046 * Originally Released Under LGPL - original licence link has changed is not relivant.
37049 * <script type="text/javascript">
37054 * @class Roo.form.ComboBox
37055 * @extends Roo.form.TriggerField
37056 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
37058 * Create a new ComboBox.
37059 * @param {Object} config Configuration options
37061 Roo.form.ComboBox = function(config){
37062 Roo.form.ComboBox.superclass.constructor.call(this, config);
37066 * Fires when the dropdown list is expanded
37067 * @param {Roo.form.ComboBox} combo This combo box
37072 * Fires when the dropdown list is collapsed
37073 * @param {Roo.form.ComboBox} combo This combo box
37077 * @event beforeselect
37078 * Fires before a list item is selected. Return false to cancel the selection.
37079 * @param {Roo.form.ComboBox} combo This combo box
37080 * @param {Roo.data.Record} record The data record returned from the underlying store
37081 * @param {Number} index The index of the selected item in the dropdown list
37083 'beforeselect' : true,
37086 * Fires when a list item is selected
37087 * @param {Roo.form.ComboBox} combo This combo box
37088 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37089 * @param {Number} index The index of the selected item in the dropdown list
37093 * @event beforequery
37094 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37095 * The event object passed has these properties:
37096 * @param {Roo.form.ComboBox} combo This combo box
37097 * @param {String} query The query
37098 * @param {Boolean} forceAll true to force "all" query
37099 * @param {Boolean} cancel true to cancel the query
37100 * @param {Object} e The query event object
37102 'beforequery': true,
37105 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37106 * @param {Roo.form.ComboBox} combo This combo box
37111 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37112 * @param {Roo.form.ComboBox} combo This combo box
37113 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37119 if(this.transform){
37120 this.allowDomMove = false;
37121 var s = Roo.getDom(this.transform);
37122 if(!this.hiddenName){
37123 this.hiddenName = s.name;
37126 this.mode = 'local';
37127 var d = [], opts = s.options;
37128 for(var i = 0, len = opts.length;i < len; i++){
37130 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37132 this.value = value;
37134 d.push([value, o.text]);
37136 this.store = new Roo.data.SimpleStore({
37138 fields: ['value', 'text'],
37141 this.valueField = 'value';
37142 this.displayField = 'text';
37144 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37145 if(!this.lazyRender){
37146 this.target = true;
37147 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37148 s.parentNode.removeChild(s); // remove it
37149 this.render(this.el.parentNode);
37151 s.parentNode.removeChild(s); // remove it
37156 this.store = Roo.factory(this.store, Roo.data);
37159 this.selectedIndex = -1;
37160 if(this.mode == 'local'){
37161 if(config.queryDelay === undefined){
37162 this.queryDelay = 10;
37164 if(config.minChars === undefined){
37170 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37172 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37175 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37176 * rendering into an Roo.Editor, defaults to false)
37179 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37180 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37183 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37186 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37187 * the dropdown list (defaults to undefined, with no header element)
37191 * @cfg {String/Roo.Template} tpl The template to use to render the output
37195 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37197 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37199 listWidth: undefined,
37201 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37202 * mode = 'remote' or 'text' if mode = 'local')
37204 displayField: undefined,
37206 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37207 * mode = 'remote' or 'value' if mode = 'local').
37208 * Note: use of a valueField requires the user make a selection
37209 * in order for a value to be mapped.
37211 valueField: undefined,
37213 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37214 * field's data value (defaults to the underlying DOM element's name)
37216 hiddenName: undefined,
37218 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37222 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37224 selectedClass: 'x-combo-selected',
37226 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37227 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37228 * which displays a downward arrow icon).
37230 triggerClass : 'x-form-arrow-trigger',
37232 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37236 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37237 * anchor positions (defaults to 'tl-bl')
37239 listAlign: 'tl-bl?',
37241 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37245 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37246 * query specified by the allQuery config option (defaults to 'query')
37248 triggerAction: 'query',
37250 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37251 * (defaults to 4, does not apply if editable = false)
37255 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37256 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37260 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37261 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37265 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37266 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37270 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37271 * when editable = true (defaults to false)
37273 selectOnFocus:false,
37275 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37277 queryParam: 'query',
37279 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37280 * when mode = 'remote' (defaults to 'Loading...')
37282 loadingText: 'Loading...',
37284 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37288 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37292 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37293 * traditional select (defaults to true)
37297 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37301 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37305 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37306 * listWidth has a higher value)
37310 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37311 * allow the user to set arbitrary text into the field (defaults to false)
37313 forceSelection:false,
37315 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37316 * if typeAhead = true (defaults to 250)
37318 typeAheadDelay : 250,
37320 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37321 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37323 valueNotFoundText : undefined,
37325 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37327 blockFocus : false,
37330 * @cfg {Boolean} disableClear Disable showing of clear button.
37332 disableClear : false,
37334 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37336 alwaysQuery : false,
37344 onRender : function(ct, position){
37345 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37346 if(this.hiddenName){
37347 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37349 this.hiddenField.value =
37350 this.hiddenValue !== undefined ? this.hiddenValue :
37351 this.value !== undefined ? this.value : '';
37353 // prevent input submission
37354 this.el.dom.removeAttribute('name');
37357 this.el.dom.setAttribute('autocomplete', 'off');
37360 var cls = 'x-combo-list';
37362 this.list = new Roo.Layer({
37363 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37366 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37367 this.list.setWidth(lw);
37368 this.list.swallowEvent('mousewheel');
37369 this.assetHeight = 0;
37372 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37373 this.assetHeight += this.header.getHeight();
37376 this.innerList = this.list.createChild({cls:cls+'-inner'});
37377 this.innerList.on('mouseover', this.onViewOver, this);
37378 this.innerList.on('mousemove', this.onViewMove, this);
37379 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37381 if(this.allowBlank && !this.pageSize && !this.disableClear){
37382 this.footer = this.list.createChild({cls:cls+'-ft'});
37383 this.pageTb = new Roo.Toolbar(this.footer);
37387 this.footer = this.list.createChild({cls:cls+'-ft'});
37388 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37389 {pageSize: this.pageSize});
37393 if (this.pageTb && this.allowBlank && !this.disableClear) {
37395 this.pageTb.add(new Roo.Toolbar.Fill(), {
37396 cls: 'x-btn-icon x-btn-clear',
37398 handler: function()
37401 _this.clearValue();
37402 _this.onSelect(false, -1);
37407 this.assetHeight += this.footer.getHeight();
37412 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37415 this.view = new Roo.View(this.innerList, this.tpl, {
37416 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37419 this.view.on('click', this.onViewClick, this);
37421 this.store.on('beforeload', this.onBeforeLoad, this);
37422 this.store.on('load', this.onLoad, this);
37423 this.store.on('loadexception', this.collapse, this);
37425 if(this.resizable){
37426 this.resizer = new Roo.Resizable(this.list, {
37427 pinned:true, handles:'se'
37429 this.resizer.on('resize', function(r, w, h){
37430 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37431 this.listWidth = w;
37432 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37433 this.restrictHeight();
37435 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37437 if(!this.editable){
37438 this.editable = true;
37439 this.setEditable(false);
37443 if (typeof(this.events.add.listeners) != 'undefined') {
37445 this.addicon = this.wrap.createChild(
37446 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37448 this.addicon.on('click', function(e) {
37449 this.fireEvent('add', this);
37452 if (typeof(this.events.edit.listeners) != 'undefined') {
37454 this.editicon = this.wrap.createChild(
37455 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37456 if (this.addicon) {
37457 this.editicon.setStyle('margin-left', '40px');
37459 this.editicon.on('click', function(e) {
37461 // we fire even if inothing is selected..
37462 this.fireEvent('edit', this, this.lastData );
37472 initEvents : function(){
37473 Roo.form.ComboBox.superclass.initEvents.call(this);
37475 this.keyNav = new Roo.KeyNav(this.el, {
37476 "up" : function(e){
37477 this.inKeyMode = true;
37481 "down" : function(e){
37482 if(!this.isExpanded()){
37483 this.onTriggerClick();
37485 this.inKeyMode = true;
37490 "enter" : function(e){
37491 this.onViewClick();
37495 "esc" : function(e){
37499 "tab" : function(e){
37500 this.onViewClick(false);
37506 doRelay : function(foo, bar, hname){
37507 if(hname == 'down' || this.scope.isExpanded()){
37508 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37515 this.queryDelay = Math.max(this.queryDelay || 10,
37516 this.mode == 'local' ? 10 : 250);
37517 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37518 if(this.typeAhead){
37519 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37521 if(this.editable !== false){
37522 this.el.on("keyup", this.onKeyUp, this);
37524 if(this.forceSelection){
37525 this.on('blur', this.doForce, this);
37529 onDestroy : function(){
37531 this.view.setStore(null);
37532 this.view.el.removeAllListeners();
37533 this.view.el.remove();
37534 this.view.purgeListeners();
37537 this.list.destroy();
37540 this.store.un('beforeload', this.onBeforeLoad, this);
37541 this.store.un('load', this.onLoad, this);
37542 this.store.un('loadexception', this.collapse, this);
37544 Roo.form.ComboBox.superclass.onDestroy.call(this);
37548 fireKey : function(e){
37549 if(e.isNavKeyPress() && !this.list.isVisible()){
37550 this.fireEvent("specialkey", this, e);
37555 onResize: function(w, h){
37556 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37558 if(typeof w != 'number'){
37559 // we do not handle it!?!?
37562 var tw = this.trigger.getWidth();
37563 tw += this.addicon ? this.addicon.getWidth() : 0;
37564 tw += this.editicon ? this.editicon.getWidth() : 0;
37566 this.el.setWidth( this.adjustWidth('input', x));
37568 this.trigger.setStyle('left', x+'px');
37570 if(this.list && this.listWidth === undefined){
37571 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37572 this.list.setWidth(lw);
37573 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37581 * Allow or prevent the user from directly editing the field text. If false is passed,
37582 * the user will only be able to select from the items defined in the dropdown list. This method
37583 * is the runtime equivalent of setting the 'editable' config option at config time.
37584 * @param {Boolean} value True to allow the user to directly edit the field text
37586 setEditable : function(value){
37587 if(value == this.editable){
37590 this.editable = value;
37592 this.el.dom.setAttribute('readOnly', true);
37593 this.el.on('mousedown', this.onTriggerClick, this);
37594 this.el.addClass('x-combo-noedit');
37596 this.el.dom.setAttribute('readOnly', false);
37597 this.el.un('mousedown', this.onTriggerClick, this);
37598 this.el.removeClass('x-combo-noedit');
37603 onBeforeLoad : function(){
37604 if(!this.hasFocus){
37607 this.innerList.update(this.loadingText ?
37608 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37609 this.restrictHeight();
37610 this.selectedIndex = -1;
37614 onLoad : function(){
37615 if(!this.hasFocus){
37618 if(this.store.getCount() > 0){
37620 this.restrictHeight();
37621 if(this.lastQuery == this.allQuery){
37623 this.el.dom.select();
37625 if(!this.selectByValue(this.value, true)){
37626 this.select(0, true);
37630 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37631 this.taTask.delay(this.typeAheadDelay);
37635 this.onEmptyResults();
37641 onTypeAhead : function(){
37642 if(this.store.getCount() > 0){
37643 var r = this.store.getAt(0);
37644 var newValue = r.data[this.displayField];
37645 var len = newValue.length;
37646 var selStart = this.getRawValue().length;
37647 if(selStart != len){
37648 this.setRawValue(newValue);
37649 this.selectText(selStart, newValue.length);
37655 onSelect : function(record, index){
37656 if(this.fireEvent('beforeselect', this, record, index) !== false){
37657 this.setFromData(index > -1 ? record.data : false);
37659 this.fireEvent('select', this, record, index);
37664 * Returns the currently selected field value or empty string if no value is set.
37665 * @return {String} value The selected value
37667 getValue : function(){
37668 if(this.valueField){
37669 return typeof this.value != 'undefined' ? this.value : '';
37671 return Roo.form.ComboBox.superclass.getValue.call(this);
37676 * Clears any text/value currently set in the field
37678 clearValue : function(){
37679 if(this.hiddenField){
37680 this.hiddenField.value = '';
37683 this.setRawValue('');
37684 this.lastSelectionText = '';
37685 this.applyEmptyText();
37689 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37690 * will be displayed in the field. If the value does not match the data value of an existing item,
37691 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37692 * Otherwise the field will be blank (although the value will still be set).
37693 * @param {String} value The value to match
37695 setValue : function(v){
37697 if(this.valueField){
37698 var r = this.findRecord(this.valueField, v);
37700 text = r.data[this.displayField];
37701 }else if(this.valueNotFoundText !== undefined){
37702 text = this.valueNotFoundText;
37705 this.lastSelectionText = text;
37706 if(this.hiddenField){
37707 this.hiddenField.value = v;
37709 Roo.form.ComboBox.superclass.setValue.call(this, text);
37713 * @property {Object} the last set data for the element
37718 * Sets the value of the field based on a object which is related to the record format for the store.
37719 * @param {Object} value the value to set as. or false on reset?
37721 setFromData : function(o){
37722 var dv = ''; // display value
37723 var vv = ''; // value value..
37725 if (this.displayField) {
37726 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37728 // this is an error condition!!!
37729 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
37732 if(this.valueField){
37733 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37735 if(this.hiddenField){
37736 this.hiddenField.value = vv;
37738 this.lastSelectionText = dv;
37739 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37743 // no hidden field.. - we store the value in 'value', but still display
37744 // display field!!!!
37745 this.lastSelectionText = dv;
37746 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37752 reset : function(){
37753 // overridden so that last data is reset..
37754 this.setValue(this.originalValue);
37755 this.clearInvalid();
37756 this.lastData = false;
37759 findRecord : function(prop, value){
37761 if(this.store.getCount() > 0){
37762 this.store.each(function(r){
37763 if(r.data[prop] == value){
37773 onViewMove : function(e, t){
37774 this.inKeyMode = false;
37778 onViewOver : function(e, t){
37779 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37782 var item = this.view.findItemFromChild(t);
37784 var index = this.view.indexOf(item);
37785 this.select(index, false);
37790 onViewClick : function(doFocus){
37791 var index = this.view.getSelectedIndexes()[0];
37792 var r = this.store.getAt(index);
37794 this.onSelect(r, index);
37796 if(doFocus !== false && !this.blockFocus){
37802 restrictHeight : function(){
37803 this.innerList.dom.style.height = '';
37804 var inner = this.innerList.dom;
37805 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37806 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37807 this.list.beginUpdate();
37808 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37809 this.list.alignTo(this.el, this.listAlign);
37810 this.list.endUpdate();
37814 onEmptyResults : function(){
37819 * Returns true if the dropdown list is expanded, else false.
37821 isExpanded : function(){
37822 return this.list.isVisible();
37826 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37827 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37828 * @param {String} value The data value of the item to select
37829 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37830 * selected item if it is not currently in view (defaults to true)
37831 * @return {Boolean} True if the value matched an item in the list, else false
37833 selectByValue : function(v, scrollIntoView){
37834 if(v !== undefined && v !== null){
37835 var r = this.findRecord(this.valueField || this.displayField, v);
37837 this.select(this.store.indexOf(r), scrollIntoView);
37845 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37846 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37847 * @param {Number} index The zero-based index of the list item to select
37848 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37849 * selected item if it is not currently in view (defaults to true)
37851 select : function(index, scrollIntoView){
37852 this.selectedIndex = index;
37853 this.view.select(index);
37854 if(scrollIntoView !== false){
37855 var el = this.view.getNode(index);
37857 this.innerList.scrollChildIntoView(el, false);
37863 selectNext : function(){
37864 var ct = this.store.getCount();
37866 if(this.selectedIndex == -1){
37868 }else if(this.selectedIndex < ct-1){
37869 this.select(this.selectedIndex+1);
37875 selectPrev : function(){
37876 var ct = this.store.getCount();
37878 if(this.selectedIndex == -1){
37880 }else if(this.selectedIndex != 0){
37881 this.select(this.selectedIndex-1);
37887 onKeyUp : function(e){
37888 if(this.editable !== false && !e.isSpecialKey()){
37889 this.lastKey = e.getKey();
37890 this.dqTask.delay(this.queryDelay);
37895 validateBlur : function(){
37896 return !this.list || !this.list.isVisible();
37900 initQuery : function(){
37901 this.doQuery(this.getRawValue());
37905 doForce : function(){
37906 if(this.el.dom.value.length > 0){
37907 this.el.dom.value =
37908 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37909 this.applyEmptyText();
37914 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37915 * query allowing the query action to be canceled if needed.
37916 * @param {String} query The SQL query to execute
37917 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37918 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37919 * saved in the current store (defaults to false)
37921 doQuery : function(q, forceAll){
37922 if(q === undefined || q === null){
37927 forceAll: forceAll,
37931 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37935 forceAll = qe.forceAll;
37936 if(forceAll === true || (q.length >= this.minChars)){
37937 if(this.lastQuery != q || this.alwaysQuery){
37938 this.lastQuery = q;
37939 if(this.mode == 'local'){
37940 this.selectedIndex = -1;
37942 this.store.clearFilter();
37944 this.store.filter(this.displayField, q);
37948 this.store.baseParams[this.queryParam] = q;
37950 params: this.getParams(q)
37955 this.selectedIndex = -1;
37962 getParams : function(q){
37964 //p[this.queryParam] = q;
37967 p.limit = this.pageSize;
37973 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37975 collapse : function(){
37976 if(!this.isExpanded()){
37980 Roo.get(document).un('mousedown', this.collapseIf, this);
37981 Roo.get(document).un('mousewheel', this.collapseIf, this);
37982 if (!this.editable) {
37983 Roo.get(document).un('keydown', this.listKeyPress, this);
37985 this.fireEvent('collapse', this);
37989 collapseIf : function(e){
37990 if(!e.within(this.wrap) && !e.within(this.list)){
37996 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37998 expand : function(){
37999 if(this.isExpanded() || !this.hasFocus){
38002 this.list.alignTo(this.el, this.listAlign);
38004 Roo.get(document).on('mousedown', this.collapseIf, this);
38005 Roo.get(document).on('mousewheel', this.collapseIf, this);
38006 if (!this.editable) {
38007 Roo.get(document).on('keydown', this.listKeyPress, this);
38010 this.fireEvent('expand', this);
38014 // Implements the default empty TriggerField.onTriggerClick function
38015 onTriggerClick : function(){
38019 if(this.isExpanded()){
38021 if (!this.blockFocus) {
38026 this.hasFocus = true;
38027 if(this.triggerAction == 'all') {
38028 this.doQuery(this.allQuery, true);
38030 this.doQuery(this.getRawValue());
38032 if (!this.blockFocus) {
38037 listKeyPress : function(e)
38039 //Roo.log('listkeypress');
38040 // scroll to first matching element based on key pres..
38041 if (e.isSpecialKey()) {
38044 var k = String.fromCharCode(e.getKey()).toUpperCase();
38047 var csel = this.view.getSelectedNodes();
38048 var cselitem = false;
38050 var ix = this.view.indexOf(csel[0]);
38051 cselitem = this.store.getAt(ix);
38052 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
38058 this.store.each(function(v) {
38060 // start at existing selection.
38061 if (cselitem.id == v.id) {
38067 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
38068 match = this.store.indexOf(v);
38073 if (match === false) {
38074 return true; // no more action?
38077 this.view.select(match);
38078 var sn = Roo.get(this.view.getSelectedNodes()[0])
38079 sn.scrollIntoView(sn.dom.parentNode, false);
38083 * @cfg {Boolean} grow
38087 * @cfg {Number} growMin
38091 * @cfg {Number} growMax
38100 * Ext JS Library 1.1.1
38101 * Copyright(c) 2006-2007, Ext JS, LLC.
38103 * Originally Released Under LGPL - original licence link has changed is not relivant.
38106 * <script type="text/javascript">
38109 * @class Roo.form.Checkbox
38110 * @extends Roo.form.Field
38111 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
38113 * Creates a new Checkbox
38114 * @param {Object} config Configuration options
38116 Roo.form.Checkbox = function(config){
38117 Roo.form.Checkbox.superclass.constructor.call(this, config);
38121 * Fires when the checkbox is checked or unchecked.
38122 * @param {Roo.form.Checkbox} this This checkbox
38123 * @param {Boolean} checked The new checked value
38129 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38131 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38133 focusClass : undefined,
38135 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38137 fieldClass: "x-form-field",
38139 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38143 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38144 * {tag: "input", type: "checkbox", autocomplete: "off"})
38146 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38148 * @cfg {String} boxLabel The text that appears beside the checkbox
38152 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38156 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38158 valueOff: '0', // value when not checked..
38160 actionMode : 'viewEl',
38163 itemCls : 'x-menu-check-item x-form-item',
38164 groupClass : 'x-menu-group-item',
38165 inputType : 'hidden',
38168 inSetChecked: false, // check that we are not calling self...
38170 inputElement: false, // real input element?
38171 basedOn: false, // ????
38173 isFormField: true, // not sure where this is needed!!!!
38175 onResize : function(){
38176 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38177 if(!this.boxLabel){
38178 this.el.alignTo(this.wrap, 'c-c');
38182 initEvents : function(){
38183 Roo.form.Checkbox.superclass.initEvents.call(this);
38184 this.el.on("click", this.onClick, this);
38185 this.el.on("change", this.onClick, this);
38189 getResizeEl : function(){
38193 getPositionEl : function(){
38198 onRender : function(ct, position){
38199 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38201 if(this.inputValue !== undefined){
38202 this.el.dom.value = this.inputValue;
38205 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38206 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38207 var viewEl = this.wrap.createChild({
38208 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38209 this.viewEl = viewEl;
38210 this.wrap.on('click', this.onClick, this);
38212 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38213 this.el.on('propertychange', this.setFromHidden, this); //ie
38218 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38219 // viewEl.on('click', this.onClick, this);
38221 //if(this.checked){
38222 this.setChecked(this.checked);
38224 //this.checked = this.el.dom;
38230 initValue : Roo.emptyFn,
38233 * Returns the checked state of the checkbox.
38234 * @return {Boolean} True if checked, else false
38236 getValue : function(){
38238 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38240 return this.valueOff;
38245 onClick : function(){
38246 this.setChecked(!this.checked);
38248 //if(this.el.dom.checked != this.checked){
38249 // this.setValue(this.el.dom.checked);
38254 * Sets the checked state of the checkbox.
38255 * On is always based on a string comparison between inputValue and the param.
38256 * @param {Boolean/String} value - the value to set
38257 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38259 setValue : function(v,suppressEvent){
38262 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38263 //if(this.el && this.el.dom){
38264 // this.el.dom.checked = this.checked;
38265 // this.el.dom.defaultChecked = this.checked;
38267 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38268 //this.fireEvent("check", this, this.checked);
38271 setChecked : function(state,suppressEvent)
38273 if (this.inSetChecked) {
38274 this.checked = state;
38280 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38282 this.checked = state;
38283 if(suppressEvent !== true){
38284 this.fireEvent('check', this, state);
38286 this.inSetChecked = true;
38287 this.el.dom.value = state ? this.inputValue : this.valueOff;
38288 this.inSetChecked = false;
38291 // handle setting of hidden value by some other method!!?!?
38292 setFromHidden: function()
38297 //console.log("SET FROM HIDDEN");
38298 //alert('setFrom hidden');
38299 this.setValue(this.el.dom.value);
38302 onDestroy : function()
38305 Roo.get(this.viewEl).remove();
38308 Roo.form.Checkbox.superclass.onDestroy.call(this);
38313 * Ext JS Library 1.1.1
38314 * Copyright(c) 2006-2007, Ext JS, LLC.
38316 * Originally Released Under LGPL - original licence link has changed is not relivant.
38319 * <script type="text/javascript">
38323 * @class Roo.form.Radio
38324 * @extends Roo.form.Checkbox
38325 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38326 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38328 * Creates a new Radio
38329 * @param {Object} config Configuration options
38331 Roo.form.Radio = function(){
38332 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38334 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38335 inputType: 'radio',
38338 * If this radio is part of a group, it will return the selected value
38341 getGroupValue : function(){
38342 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38344 });//<script type="text/javascript">
38347 * Ext JS Library 1.1.1
38348 * Copyright(c) 2006-2007, Ext JS, LLC.
38349 * licensing@extjs.com
38351 * http://www.extjs.com/license
38357 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38358 * - IE ? - no idea how much works there.
38366 * @class Ext.form.HtmlEditor
38367 * @extends Ext.form.Field
38368 * Provides a lightweight HTML Editor component.
38369 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38371 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38372 * supported by this editor.</b><br/><br/>
38373 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38374 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38376 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38378 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38382 * @cfg {String} createLinkText The default text for the create link prompt
38384 createLinkText : 'Please enter the URL for the link:',
38386 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38388 defaultLinkValue : 'http:/'+'/',
38394 // private properties
38395 validationEvent : false,
38397 initialized : false,
38399 sourceEditMode : false,
38400 onFocus : Roo.emptyFn,
38402 hideMode:'offsets',
38403 defaultAutoCreate : {
38405 style:"width:500px;height:300px;",
38406 autocomplete: "off"
38410 initComponent : function(){
38413 * @event initialize
38414 * Fires when the editor is fully initialized (including the iframe)
38415 * @param {HtmlEditor} this
38420 * Fires when the editor is first receives the focus. Any insertion must wait
38421 * until after this event.
38422 * @param {HtmlEditor} this
38426 * @event beforesync
38427 * Fires before the textarea is updated with content from the editor iframe. Return false
38428 * to cancel the sync.
38429 * @param {HtmlEditor} this
38430 * @param {String} html
38434 * @event beforepush
38435 * Fires before the iframe editor is updated with content from the textarea. Return false
38436 * to cancel the push.
38437 * @param {HtmlEditor} this
38438 * @param {String} html
38443 * Fires when the textarea is updated with content from the editor iframe.
38444 * @param {HtmlEditor} this
38445 * @param {String} html
38450 * Fires when the iframe editor is updated with content from the textarea.
38451 * @param {HtmlEditor} this
38452 * @param {String} html
38456 * @event editmodechange
38457 * Fires when the editor switches edit modes
38458 * @param {HtmlEditor} this
38459 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38461 editmodechange: true,
38463 * @event editorevent
38464 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38465 * @param {HtmlEditor} this
38472 * Protected method that will not generally be called directly. It
38473 * is called when the editor creates its toolbar. Override this method if you need to
38474 * add custom toolbar buttons.
38475 * @param {HtmlEditor} editor
38477 createToolbar : function(editor){
38478 if (!editor.toolbars || !editor.toolbars.length) {
38479 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38482 for (var i =0 ; i < editor.toolbars.length;i++) {
38483 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38484 editor.toolbars[i].init(editor);
38491 * Protected method that will not generally be called directly. It
38492 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38493 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38495 getDocMarkup : function(){
38496 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
38500 onRender : function(ct, position){
38501 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38502 this.el.dom.style.border = '0 none';
38503 this.el.dom.setAttribute('tabIndex', -1);
38504 this.el.addClass('x-hidden');
38505 if(Roo.isIE){ // fix IE 1px bogus margin
38506 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38508 this.wrap = this.el.wrap({
38509 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38512 this.frameId = Roo.id();
38513 this.createToolbar(this);
38520 var iframe = this.wrap.createChild({
38523 name: this.frameId,
38524 frameBorder : 'no',
38525 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38528 // console.log(iframe);
38529 //this.wrap.dom.appendChild(iframe);
38531 this.iframe = iframe.dom;
38533 this.assignDocWin();
38535 this.doc.designMode = 'on';
38538 this.doc.write(this.getDocMarkup());
38542 var task = { // must defer to wait for browser to be ready
38544 //console.log("run task?" + this.doc.readyState);
38545 this.assignDocWin();
38546 if(this.doc.body || this.doc.readyState == 'complete'){
38548 this.doc.designMode="on";
38552 Roo.TaskMgr.stop(task);
38553 this.initEditor.defer(10, this);
38560 Roo.TaskMgr.start(task);
38563 this.setSize(this.el.getSize());
38568 onResize : function(w, h){
38569 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38570 if(this.el && this.iframe){
38571 if(typeof w == 'number'){
38572 var aw = w - this.wrap.getFrameWidth('lr');
38573 this.el.setWidth(this.adjustWidth('textarea', aw));
38574 this.iframe.style.width = aw + 'px';
38576 if(typeof h == 'number'){
38578 for (var i =0; i < this.toolbars.length;i++) {
38579 // fixme - ask toolbars for heights?
38580 tbh += this.toolbars[i].tb.el.getHeight();
38586 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38587 this.el.setHeight(this.adjustWidth('textarea', ah));
38588 this.iframe.style.height = ah + 'px';
38590 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38597 * Toggles the editor between standard and source edit mode.
38598 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38600 toggleSourceEdit : function(sourceEditMode){
38602 this.sourceEditMode = sourceEditMode === true;
38604 if(this.sourceEditMode){
38607 this.iframe.className = 'x-hidden';
38608 this.el.removeClass('x-hidden');
38609 this.el.dom.removeAttribute('tabIndex');
38614 this.iframe.className = '';
38615 this.el.addClass('x-hidden');
38616 this.el.dom.setAttribute('tabIndex', -1);
38619 this.setSize(this.wrap.getSize());
38620 this.fireEvent('editmodechange', this, this.sourceEditMode);
38623 // private used internally
38624 createLink : function(){
38625 var url = prompt(this.createLinkText, this.defaultLinkValue);
38626 if(url && url != 'http:/'+'/'){
38627 this.relayCmd('createlink', url);
38631 // private (for BoxComponent)
38632 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38634 // private (for BoxComponent)
38635 getResizeEl : function(){
38639 // private (for BoxComponent)
38640 getPositionEl : function(){
38645 initEvents : function(){
38646 this.originalValue = this.getValue();
38650 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38653 markInvalid : Roo.emptyFn,
38655 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38658 clearInvalid : Roo.emptyFn,
38660 setValue : function(v){
38661 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38666 * Protected method that will not generally be called directly. If you need/want
38667 * custom HTML cleanup, this is the method you should override.
38668 * @param {String} html The HTML to be cleaned
38669 * return {String} The cleaned HTML
38671 cleanHtml : function(html){
38672 html = String(html);
38673 if(html.length > 5){
38674 if(Roo.isSafari){ // strip safari nonsense
38675 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38678 if(html == ' '){
38685 * Protected method that will not generally be called directly. Syncs the contents
38686 * of the editor iframe with the textarea.
38688 syncValue : function(){
38689 if(this.initialized){
38690 var bd = (this.doc.body || this.doc.documentElement);
38691 this.cleanUpPaste();
38692 var html = bd.innerHTML;
38694 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38695 var m = bs.match(/text-align:(.*?);/i);
38697 html = '<div style="'+m[0]+'">' + html + '</div>';
38700 html = this.cleanHtml(html);
38701 if(this.fireEvent('beforesync', this, html) !== false){
38702 this.el.dom.value = html;
38703 this.fireEvent('sync', this, html);
38709 * Protected method that will not generally be called directly. Pushes the value of the textarea
38710 * into the iframe editor.
38712 pushValue : function(){
38713 if(this.initialized){
38714 var v = this.el.dom.value;
38719 if(this.fireEvent('beforepush', this, v) !== false){
38720 var d = (this.doc.body || this.doc.documentElement);
38722 this.cleanUpPaste();
38723 this.el.dom.value = d.innerHTML;
38724 this.fireEvent('push', this, v);
38730 deferFocus : function(){
38731 this.focus.defer(10, this);
38735 focus : function(){
38736 if(this.win && !this.sourceEditMode){
38743 assignDocWin: function()
38745 var iframe = this.iframe;
38748 this.doc = iframe.contentWindow.document;
38749 this.win = iframe.contentWindow;
38751 if (!Roo.get(this.frameId)) {
38754 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38755 this.win = Roo.get(this.frameId).dom.contentWindow;
38760 initEditor : function(){
38761 //console.log("INIT EDITOR");
38762 this.assignDocWin();
38766 this.doc.designMode="on";
38768 this.doc.write(this.getDocMarkup());
38771 var dbody = (this.doc.body || this.doc.documentElement);
38772 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38773 // this copies styles from the containing element into thsi one..
38774 // not sure why we need all of this..
38775 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38776 ss['background-attachment'] = 'fixed'; // w3c
38777 dbody.bgProperties = 'fixed'; // ie
38778 Roo.DomHelper.applyStyles(dbody, ss);
38779 Roo.EventManager.on(this.doc, {
38780 'mousedown': this.onEditorEvent,
38781 'dblclick': this.onEditorEvent,
38782 'click': this.onEditorEvent,
38783 'keyup': this.onEditorEvent,
38788 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
38790 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38791 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38793 this.initialized = true;
38795 this.fireEvent('initialize', this);
38800 onDestroy : function(){
38806 for (var i =0; i < this.toolbars.length;i++) {
38807 // fixme - ask toolbars for heights?
38808 this.toolbars[i].onDestroy();
38811 this.wrap.dom.innerHTML = '';
38812 this.wrap.remove();
38817 onFirstFocus : function(){
38819 this.assignDocWin();
38822 this.activated = true;
38823 for (var i =0; i < this.toolbars.length;i++) {
38824 this.toolbars[i].onFirstFocus();
38827 if(Roo.isGecko){ // prevent silly gecko errors
38829 var s = this.win.getSelection();
38830 if(!s.focusNode || s.focusNode.nodeType != 3){
38831 var r = s.getRangeAt(0);
38832 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38837 this.execCmd('useCSS', true);
38838 this.execCmd('styleWithCSS', false);
38841 this.fireEvent('activate', this);
38845 adjustFont: function(btn){
38846 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38847 //if(Roo.isSafari){ // safari
38850 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38851 if(Roo.isSafari){ // safari
38852 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38853 v = (v < 10) ? 10 : v;
38854 v = (v > 48) ? 48 : v;
38855 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38860 v = Math.max(1, v+adjust);
38862 this.execCmd('FontSize', v );
38865 onEditorEvent : function(e){
38866 this.fireEvent('editorevent', this, e);
38867 // this.updateToolbar();
38871 insertTag : function(tg)
38873 // could be a bit smarter... -> wrap the current selected tRoo..
38875 this.execCmd("formatblock", tg);
38879 insertText : function(txt)
38883 range = this.createRange();
38884 range.deleteContents();
38885 //alert(Sender.getAttribute('label'));
38887 range.insertNode(this.doc.createTextNode(txt));
38891 relayBtnCmd : function(btn){
38892 this.relayCmd(btn.cmd);
38896 * Executes a Midas editor command on the editor document and performs necessary focus and
38897 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38898 * @param {String} cmd The Midas command
38899 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38901 relayCmd : function(cmd, value){
38903 this.execCmd(cmd, value);
38904 this.fireEvent('editorevent', this);
38905 //this.updateToolbar();
38910 * Executes a Midas editor command directly on the editor document.
38911 * For visual commands, you should use {@link #relayCmd} instead.
38912 * <b>This should only be called after the editor is initialized.</b>
38913 * @param {String} cmd The Midas command
38914 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38916 execCmd : function(cmd, value){
38917 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38923 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38925 * @param {String} text
38927 insertAtCursor : function(text){
38928 if(!this.activated){
38933 var r = this.doc.selection.createRange();
38940 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
38942 this.execCmd('InsertHTML', text);
38947 mozKeyPress : function(e){
38949 var c = e.getCharCode(), cmd;
38952 c = String.fromCharCode(c).toLowerCase();
38963 this.cleanUpPaste.defer(100, this);
38971 e.preventDefault();
38979 fixKeys : function(){ // load time branching for fastest keydown performance
38981 return function(e){
38982 var k = e.getKey(), r;
38985 r = this.doc.selection.createRange();
38988 r.pasteHTML('    ');
38995 r = this.doc.selection.createRange();
38997 var target = r.parentElement();
38998 if(!target || target.tagName.toLowerCase() != 'li'){
39000 r.pasteHTML('<br />');
39006 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39007 this.cleanUpPaste.defer(100, this);
39013 }else if(Roo.isOpera){
39014 return function(e){
39015 var k = e.getKey();
39019 this.execCmd('InsertHTML','    ');
39022 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39023 this.cleanUpPaste.defer(100, this);
39028 }else if(Roo.isSafari){
39029 return function(e){
39030 var k = e.getKey();
39034 this.execCmd('InsertText','\t');
39038 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39039 this.cleanUpPaste.defer(100, this);
39047 getAllAncestors: function()
39049 var p = this.getSelectedNode();
39052 a.push(p); // push blank onto stack..
39053 p = this.getParentElement();
39057 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
39061 a.push(this.doc.body);
39065 lastSelNode : false,
39068 getSelection : function()
39070 this.assignDocWin();
39071 return Roo.isIE ? this.doc.selection : this.win.getSelection();
39074 getSelectedNode: function()
39076 // this may only work on Gecko!!!
39078 // should we cache this!!!!
39083 var range = this.createRange(this.getSelection());
39086 var parent = range.parentElement();
39088 var testRange = range.duplicate();
39089 testRange.moveToElementText(parent);
39090 if (testRange.inRange(range)) {
39093 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
39096 parent = parent.parentElement;
39102 var ar = range.endContainer.childNodes;
39104 ar = range.commonAncestorContainer.childNodes;
39105 //alert(ar.length);
39108 var other_nodes = [];
39109 var has_other_nodes = false;
39110 for (var i=0;i<ar.length;i++) {
39111 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
39114 // fullly contained node.
39116 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
39121 // probably selected..
39122 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
39123 other_nodes.push(ar[i]);
39126 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39131 has_other_nodes = true;
39133 if (!nodes.length && other_nodes.length) {
39134 nodes= other_nodes;
39136 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39142 createRange: function(sel)
39144 // this has strange effects when using with
39145 // top toolbar - not sure if it's a great idea.
39146 //this.editor.contentWindow.focus();
39147 if (typeof sel != "undefined") {
39149 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39151 return this.doc.createRange();
39154 return this.doc.createRange();
39157 getParentElement: function()
39160 this.assignDocWin();
39161 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39163 var range = this.createRange(sel);
39166 var p = range.commonAncestorContainer;
39167 while (p.nodeType == 3) { // text node
39179 // BC Hacks - cause I cant work out what i was trying to do..
39180 rangeIntersectsNode : function(range, node)
39182 var nodeRange = node.ownerDocument.createRange();
39184 nodeRange.selectNode(node);
39187 nodeRange.selectNodeContents(node);
39190 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
39191 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
39193 rangeCompareNode : function(range, node) {
39194 var nodeRange = node.ownerDocument.createRange();
39196 nodeRange.selectNode(node);
39198 nodeRange.selectNodeContents(node);
39200 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
39201 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
39203 if (nodeIsBefore && !nodeIsAfter)
39205 if (!nodeIsBefore && nodeIsAfter)
39207 if (nodeIsBefore && nodeIsAfter)
39213 // private? - in a new class?
39214 cleanUpPaste : function()
39216 // cleans up the whole document..
39217 // console.log('cleanuppaste');
39218 this.cleanUpChildren(this.doc.body);
39222 cleanUpChildren : function (n)
39224 if (!n.childNodes.length) {
39227 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39228 this.cleanUpChild(n.childNodes[i]);
39235 cleanUpChild : function (node)
39237 //console.log(node);
39238 if (node.nodeName == "#text") {
39239 // clean up silly Windows -- stuff?
39242 if (node.nodeName == "#comment") {
39243 node.parentNode.removeChild(node);
39244 // clean up silly Windows -- stuff?
39248 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39250 node.parentNode.removeChild(node);
39254 if (!node.attributes || !node.attributes.length) {
39255 this.cleanUpChildren(node);
39259 function cleanAttr(n,v)
39262 if (v.match(/^\./) || v.match(/^\//)) {
39265 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39268 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39269 node.removeAttribute(n);
39273 function cleanStyle(n,v)
39275 if (v.match(/expression/)) { //XSS?? should we even bother..
39276 node.removeAttribute(n);
39281 var parts = v.split(/;/);
39282 Roo.each(parts, function(p) {
39283 p = p.replace(/\s+/g,'');
39287 var l = p.split(':').shift().replace(/\s+/g,'');
39289 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39290 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39291 node.removeAttribute(n);
39300 for (var i = node.attributes.length-1; i > -1 ; i--) {
39301 var a = node.attributes[i];
39303 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39304 node.removeAttribute(a.name);
39307 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39308 cleanAttr(a.name,a.value); // fixme..
39311 if (a.name == 'style') {
39312 cleanStyle(a.name,a.value);
39314 /// clean up MS crap..
39315 if (a.name == 'class') {
39316 if (a.value.match(/^Mso/)) {
39317 node.className = '';
39327 this.cleanUpChildren(node);
39333 // hide stuff that is not compatible
39347 * @event specialkey
39351 * @cfg {String} fieldClass @hide
39354 * @cfg {String} focusClass @hide
39357 * @cfg {String} autoCreate @hide
39360 * @cfg {String} inputType @hide
39363 * @cfg {String} invalidClass @hide
39366 * @cfg {String} invalidText @hide
39369 * @cfg {String} msgFx @hide
39372 * @cfg {String} validateOnBlur @hide
39376 Roo.form.HtmlEditor.white = [
39377 'area', 'br', 'img', 'input', 'hr', 'wbr',
39379 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39380 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39381 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39382 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39383 'table', 'ul', 'xmp',
39385 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39388 'dir', 'menu', 'ol', 'ul', 'dl',
39394 Roo.form.HtmlEditor.black = [
39395 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39397 'base', 'basefont', 'bgsound', 'blink', 'body',
39398 'frame', 'frameset', 'head', 'html', 'ilayer',
39399 'iframe', 'layer', 'link', 'meta', 'object',
39400 'script', 'style' ,'title', 'xml' // clean later..
39402 Roo.form.HtmlEditor.clean = [
39403 'script', 'style', 'title', 'xml'
39408 Roo.form.HtmlEditor.ablack = [
39412 Roo.form.HtmlEditor.aclean = [
39413 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39417 Roo.form.HtmlEditor.pwhite= [
39418 'http', 'https', 'mailto'
39421 Roo.form.HtmlEditor.cwhite= [
39426 // <script type="text/javascript">
39429 * Ext JS Library 1.1.1
39430 * Copyright(c) 2006-2007, Ext JS, LLC.
39436 * @class Roo.form.HtmlEditorToolbar1
39441 new Roo.form.HtmlEditor({
39444 new Roo.form.HtmlEditorToolbar1({
39445 disable : { fonts: 1 , format: 1, ..., ... , ...],
39451 * @cfg {Object} disable List of elements to disable..
39452 * @cfg {Array} btns List of additional buttons.
39456 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39459 Roo.form.HtmlEditor.ToolbarStandard = function(config)
39462 Roo.apply(this, config);
39463 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39464 // dont call parent... till later.
39467 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
39475 * @cfg {Object} disable List of toolbar elements to disable
39480 * @cfg {Array} fontFamilies An array of available font families
39498 // "á" , ?? a acute?
39503 "°" // , // degrees
39505 // "é" , // e ecute
39506 // "ú" , // u ecute?
39509 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
39510 "input:submit", "input:button", "select", "textarea", "label" ],
39513 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
39515 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39518 * @cfg {String} defaultFont default font to use.
39520 defaultFont: 'tahoma',
39522 fontSelect : false,
39525 formatCombo : false,
39527 init : function(editor)
39529 this.editor = editor;
39532 var fid = editor.frameId;
39534 function btn(id, toggle, handler){
39535 var xid = fid + '-'+ id ;
39539 cls : 'x-btn-icon x-edit-'+id,
39540 enableToggle:toggle !== false,
39541 scope: editor, // was editor...
39542 handler:handler||editor.relayBtnCmd,
39543 clickEvent:'mousedown',
39544 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39551 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
39553 // stop form submits
39554 tb.el.on('click', function(e){
39555 e.preventDefault(); // what does this do?
39558 if(!this.disable.font && !Roo.isSafari){
39559 /* why no safari for fonts
39560 editor.fontSelect = tb.el.createChild({
39563 cls:'x-font-select',
39564 html: editor.createFontOptions()
39566 editor.fontSelect.on('change', function(){
39567 var font = editor.fontSelect.dom.value;
39568 editor.relayCmd('fontname', font);
39569 editor.deferFocus();
39572 editor.fontSelect.dom,
39577 if(!this.disable.formats){
39578 this.formatCombo = new Roo.form.ComboBox({
39579 store: new Roo.data.SimpleStore({
39582 data : this.formats // from states.js
39585 //autoCreate : {tag: "div", size: "20"},
39586 displayField:'tag',
39590 triggerAction: 'all',
39591 emptyText:'Add tag',
39592 selectOnFocus:true,
39595 'select': function(c, r, i) {
39596 editor.insertTag(r.get('tag'));
39602 tb.addField(this.formatCombo);
39606 if(!this.disable.format){
39613 if(!this.disable.fontSize){
39618 btn('increasefontsize', false, editor.adjustFont),
39619 btn('decreasefontsize', false, editor.adjustFont)
39624 if(this.disable.colors){
39627 id:editor.frameId +'-forecolor',
39628 cls:'x-btn-icon x-edit-forecolor',
39629 clickEvent:'mousedown',
39630 tooltip: this.buttonTips['forecolor'] || undefined,
39632 menu : new Roo.menu.ColorMenu({
39633 allowReselect: true,
39634 focus: Roo.emptyFn,
39637 selectHandler: function(cp, color){
39638 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
39639 editor.deferFocus();
39642 clickEvent:'mousedown'
39645 id:editor.frameId +'backcolor',
39646 cls:'x-btn-icon x-edit-backcolor',
39647 clickEvent:'mousedown',
39648 tooltip: this.buttonTips['backcolor'] || undefined,
39650 menu : new Roo.menu.ColorMenu({
39651 focus: Roo.emptyFn,
39654 allowReselect: true,
39655 selectHandler: function(cp, color){
39657 editor.execCmd('useCSS', false);
39658 editor.execCmd('hilitecolor', color);
39659 editor.execCmd('useCSS', true);
39660 editor.deferFocus();
39662 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
39663 Roo.isSafari || Roo.isIE ? '#'+color : color);
39664 editor.deferFocus();
39668 clickEvent:'mousedown'
39673 // now add all the items...
39676 if(!this.disable.alignments){
39679 btn('justifyleft'),
39680 btn('justifycenter'),
39681 btn('justifyright')
39685 //if(!Roo.isSafari){
39686 if(!this.disable.links){
39689 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
39693 if(!this.disable.lists){
39696 btn('insertorderedlist'),
39697 btn('insertunorderedlist')
39700 if(!this.disable.sourceEdit){
39703 btn('sourceedit', true, function(btn){
39704 this.toggleSourceEdit(btn.pressed);
39711 // special menu.. - needs to be tidied up..
39712 if (!this.disable.special) {
39715 cls: 'x-edit-none',
39720 for (var i =0; i < this.specialChars.length; i++) {
39721 smenu.menu.items.push({
39723 html: this.specialChars[i],
39724 handler: function(a,b) {
39725 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
39738 for(var i =0; i< this.btns.length;i++) {
39739 var b = this.btns[i];
39740 b.cls = 'x-edit-none';
39749 // disable everything...
39751 this.tb.items.each(function(item){
39752 if(item.id != editor.frameId+ '-sourceedit'){
39756 this.rendered = true;
39758 // the all the btns;
39759 editor.on('editorevent', this.updateToolbar, this);
39760 // other toolbars need to implement this..
39761 //editor.on('editmodechange', this.updateToolbar, this);
39767 * Protected method that will not generally be called directly. It triggers
39768 * a toolbar update by reading the markup state of the current selection in the editor.
39770 updateToolbar: function(){
39772 if(!this.editor.activated){
39773 this.editor.onFirstFocus();
39777 var btns = this.tb.items.map,
39778 doc = this.editor.doc,
39779 frameId = this.editor.frameId;
39781 if(!this.disable.font && !Roo.isSafari){
39783 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39784 if(name != this.fontSelect.dom.value){
39785 this.fontSelect.dom.value = name;
39789 if(!this.disable.format){
39790 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39791 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39792 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39794 if(!this.disable.alignments){
39795 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39796 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39797 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39799 if(!Roo.isSafari && !this.disable.lists){
39800 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39801 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39804 var ans = this.editor.getAllAncestors();
39805 if (this.formatCombo) {
39808 var store = this.formatCombo.store;
39809 this.formatCombo.setValue("");
39810 for (var i =0; i < ans.length;i++) {
39811 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
39813 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39821 // hides menus... - so this cant be on a menu...
39822 Roo.menu.MenuMgr.hideAll();
39824 //this.editorsyncValue();
39828 createFontOptions : function(){
39829 var buf = [], fs = this.fontFamilies, ff, lc;
39830 for(var i = 0, len = fs.length; i< len; i++){
39832 lc = ff.toLowerCase();
39834 '<option value="',lc,'" style="font-family:',ff,';"',
39835 (this.defaultFont == lc ? ' selected="true">' : '>'),
39840 return buf.join('');
39843 toggleSourceEdit : function(sourceEditMode){
39844 if(sourceEditMode === undefined){
39845 sourceEditMode = !this.sourceEditMode;
39847 this.sourceEditMode = sourceEditMode === true;
39848 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39849 // just toggle the button?
39850 if(btn.pressed !== this.editor.sourceEditMode){
39851 btn.toggle(this.editor.sourceEditMode);
39855 if(this.sourceEditMode){
39856 this.tb.items.each(function(item){
39857 if(item.cmd != 'sourceedit'){
39863 if(this.initialized){
39864 this.tb.items.each(function(item){
39870 // tell the editor that it's been pressed..
39871 this.editor.toggleSourceEdit(sourceEditMode);
39875 * Object collection of toolbar tooltips for the buttons in the editor. The key
39876 * is the command id associated with that button and the value is a valid QuickTips object.
39881 title: 'Bold (Ctrl+B)',
39882 text: 'Make the selected text bold.',
39883 cls: 'x-html-editor-tip'
39886 title: 'Italic (Ctrl+I)',
39887 text: 'Make the selected text italic.',
39888 cls: 'x-html-editor-tip'
39896 title: 'Bold (Ctrl+B)',
39897 text: 'Make the selected text bold.',
39898 cls: 'x-html-editor-tip'
39901 title: 'Italic (Ctrl+I)',
39902 text: 'Make the selected text italic.',
39903 cls: 'x-html-editor-tip'
39906 title: 'Underline (Ctrl+U)',
39907 text: 'Underline the selected text.',
39908 cls: 'x-html-editor-tip'
39910 increasefontsize : {
39911 title: 'Grow Text',
39912 text: 'Increase the font size.',
39913 cls: 'x-html-editor-tip'
39915 decreasefontsize : {
39916 title: 'Shrink Text',
39917 text: 'Decrease the font size.',
39918 cls: 'x-html-editor-tip'
39921 title: 'Text Highlight Color',
39922 text: 'Change the background color of the selected text.',
39923 cls: 'x-html-editor-tip'
39926 title: 'Font Color',
39927 text: 'Change the color of the selected text.',
39928 cls: 'x-html-editor-tip'
39931 title: 'Align Text Left',
39932 text: 'Align text to the left.',
39933 cls: 'x-html-editor-tip'
39936 title: 'Center Text',
39937 text: 'Center text in the editor.',
39938 cls: 'x-html-editor-tip'
39941 title: 'Align Text Right',
39942 text: 'Align text to the right.',
39943 cls: 'x-html-editor-tip'
39945 insertunorderedlist : {
39946 title: 'Bullet List',
39947 text: 'Start a bulleted list.',
39948 cls: 'x-html-editor-tip'
39950 insertorderedlist : {
39951 title: 'Numbered List',
39952 text: 'Start a numbered list.',
39953 cls: 'x-html-editor-tip'
39956 title: 'Hyperlink',
39957 text: 'Make the selected text a hyperlink.',
39958 cls: 'x-html-editor-tip'
39961 title: 'Source Edit',
39962 text: 'Switch to source editing mode.',
39963 cls: 'x-html-editor-tip'
39967 onDestroy : function(){
39970 this.tb.items.each(function(item){
39972 item.menu.removeAll();
39974 item.menu.el.destroy();
39982 onFirstFocus: function() {
39983 this.tb.items.each(function(item){
39992 // <script type="text/javascript">
39995 * Ext JS Library 1.1.1
39996 * Copyright(c) 2006-2007, Ext JS, LLC.
40003 * @class Roo.form.HtmlEditor.ToolbarContext
40008 new Roo.form.HtmlEditor({
40011 new Roo.form.HtmlEditor.ToolbarStandard(),
40012 new Roo.form.HtmlEditor.ToolbarContext()
40017 * @config : {Object} disable List of elements to disable.. (not done yet.)
40022 Roo.form.HtmlEditor.ToolbarContext = function(config)
40025 Roo.apply(this, config);
40026 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
40027 // dont call parent... till later.
40029 Roo.form.HtmlEditor.ToolbarContext.types = {
40041 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
40103 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
40108 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40172 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40180 * @cfg {Object} disable List of toolbar elements to disable
40189 init : function(editor)
40191 this.editor = editor;
40194 var fid = editor.frameId;
40196 function btn(id, toggle, handler){
40197 var xid = fid + '-'+ id ;
40201 cls : 'x-btn-icon x-edit-'+id,
40202 enableToggle:toggle !== false,
40203 scope: editor, // was editor...
40204 handler:handler||editor.relayBtnCmd,
40205 clickEvent:'mousedown',
40206 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40210 // create a new element.
40211 var wdiv = editor.wrap.createChild({
40213 }, editor.wrap.dom.firstChild.nextSibling, true);
40215 // can we do this more than once??
40217 // stop form submits
40220 // disable everything...
40221 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40222 this.toolbars = {};
40224 for (var i in ty) {
40226 this.toolbars[i] = this.buildToolbar(ty[i],i);
40228 this.tb = this.toolbars.BODY;
40232 this.rendered = true;
40234 // the all the btns;
40235 editor.on('editorevent', this.updateToolbar, this);
40236 // other toolbars need to implement this..
40237 //editor.on('editmodechange', this.updateToolbar, this);
40243 * Protected method that will not generally be called directly. It triggers
40244 * a toolbar update by reading the markup state of the current selection in the editor.
40246 updateToolbar: function(){
40248 if(!this.editor.activated){
40249 this.editor.onFirstFocus();
40254 var ans = this.editor.getAllAncestors();
40257 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40258 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40259 sel = sel ? sel : this.editor.doc.body;
40260 sel = sel.tagName.length ? sel : this.editor.doc.body;
40261 var tn = sel.tagName.toUpperCase();
40262 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40263 tn = sel.tagName.toUpperCase();
40264 if (this.tb.name == tn) {
40265 return; // no change
40268 ///console.log("show: " + tn);
40269 this.tb = this.toolbars[tn];
40271 this.tb.fields.each(function(e) {
40272 e.setValue(sel.getAttribute(e.name));
40274 this.tb.selectedNode = sel;
40277 Roo.menu.MenuMgr.hideAll();
40279 //this.editorsyncValue();
40284 onDestroy : function(){
40287 this.tb.items.each(function(item){
40289 item.menu.removeAll();
40291 item.menu.el.destroy();
40299 onFirstFocus: function() {
40300 // need to do this for all the toolbars..
40301 this.tb.items.each(function(item){
40305 buildToolbar: function(tlist, nm)
40307 var editor = this.editor;
40308 // create a new element.
40309 var wdiv = editor.wrap.createChild({
40311 }, editor.wrap.dom.firstChild.nextSibling, true);
40314 var tb = new Roo.Toolbar(wdiv);
40315 tb.add(nm+ ": ");
40316 for (var i in tlist) {
40317 var item = tlist[i];
40318 tb.add(item.title + ": ");
40323 tb.addField( new Roo.form.ComboBox({
40324 store: new Roo.data.SimpleStore({
40327 data : item.opts // from states.js
40330 displayField:'val',
40334 triggerAction: 'all',
40335 emptyText:'Select',
40336 selectOnFocus:true,
40337 width: item.width ? item.width : 130,
40339 'select': function(c, r, i) {
40340 tb.selectedNode.setAttribute(c.name, r.get('val'));
40351 tb.addField( new Roo.form.TextField({
40354 //allowBlank:false,
40359 tb.addField( new Roo.form.TextField({
40365 'change' : function(f, nv, ov) {
40366 tb.selectedNode.setAttribute(f.name, nv);
40372 tb.el.on('click', function(e){
40373 e.preventDefault(); // what does this do?
40375 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40378 // dont need to disable them... as they will get hidden
40395 * Ext JS Library 1.1.1
40396 * Copyright(c) 2006-2007, Ext JS, LLC.
40398 * Originally Released Under LGPL - original licence link has changed is not relivant.
40401 * <script type="text/javascript">
40405 * @class Roo.form.BasicForm
40406 * @extends Roo.util.Observable
40407 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
40409 * @param {String/HTMLElement/Roo.Element} el The form element or its id
40410 * @param {Object} config Configuration options
40412 Roo.form.BasicForm = function(el, config){
40413 this.allItems = [];
40414 this.childForms = [];
40415 Roo.apply(this, config);
40417 * The Roo.form.Field items in this form.
40418 * @type MixedCollection
40422 this.items = new Roo.util.MixedCollection(false, function(o){
40423 return o.id || (o.id = Roo.id());
40427 * @event beforeaction
40428 * Fires before any action is performed. Return false to cancel the action.
40429 * @param {Form} this
40430 * @param {Action} action The action to be performed
40432 beforeaction: true,
40434 * @event actionfailed
40435 * Fires when an action fails.
40436 * @param {Form} this
40437 * @param {Action} action The action that failed
40439 actionfailed : true,
40441 * @event actioncomplete
40442 * Fires when an action is completed.
40443 * @param {Form} this
40444 * @param {Action} action The action that completed
40446 actioncomplete : true
40451 Roo.form.BasicForm.superclass.constructor.call(this);
40454 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
40456 * @cfg {String} method
40457 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
40460 * @cfg {DataReader} reader
40461 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
40462 * This is optional as there is built-in support for processing JSON.
40465 * @cfg {DataReader} errorReader
40466 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
40467 * This is completely optional as there is built-in support for processing JSON.
40470 * @cfg {String} url
40471 * The URL to use for form actions if one isn't supplied in the action options.
40474 * @cfg {Boolean} fileUpload
40475 * Set to true if this form is a file upload.
40479 * @cfg {Object} baseParams
40480 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
40485 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
40490 activeAction : null,
40493 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
40494 * or setValues() data instead of when the form was first created.
40496 trackResetOnLoad : false,
40500 * childForms - used for multi-tab forms
40503 childForms : false,
40506 * allItems - full list of fields.
40512 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
40513 * element by passing it or its id or mask the form itself by passing in true.
40516 waitMsgTarget : false,
40519 initEl : function(el){
40520 this.el = Roo.get(el);
40521 this.id = this.el.id || Roo.id();
40522 this.el.on('submit', this.onSubmit, this);
40523 this.el.addClass('x-form');
40527 onSubmit : function(e){
40532 * Returns true if client-side validation on the form is successful.
40535 isValid : function(){
40537 this.items.each(function(f){
40546 * Returns true if any fields in this form have changed since their original load.
40549 isDirty : function(){
40551 this.items.each(function(f){
40561 * Performs a predefined action (submit or load) or custom actions you define on this form.
40562 * @param {String} actionName The name of the action type
40563 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
40564 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
40565 * accept other config options):
40567 Property Type Description
40568 ---------------- --------------- ----------------------------------------------------------------------------------
40569 url String The url for the action (defaults to the form's url)
40570 method String The form method to use (defaults to the form's method, or POST if not defined)
40571 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
40572 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
40573 validate the form on the client (defaults to false)
40575 * @return {BasicForm} this
40577 doAction : function(action, options){
40578 if(typeof action == 'string'){
40579 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
40581 if(this.fireEvent('beforeaction', this, action) !== false){
40582 this.beforeAction(action);
40583 action.run.defer(100, action);
40589 * Shortcut to do a submit action.
40590 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40591 * @return {BasicForm} this
40593 submit : function(options){
40594 this.doAction('submit', options);
40599 * Shortcut to do a load action.
40600 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40601 * @return {BasicForm} this
40603 load : function(options){
40604 this.doAction('load', options);
40609 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
40610 * @param {Record} record The record to edit
40611 * @return {BasicForm} this
40613 updateRecord : function(record){
40614 record.beginEdit();
40615 var fs = record.fields;
40616 fs.each(function(f){
40617 var field = this.findField(f.name);
40619 record.set(f.name, field.getValue());
40627 * Loads an Roo.data.Record into this form.
40628 * @param {Record} record The record to load
40629 * @return {BasicForm} this
40631 loadRecord : function(record){
40632 this.setValues(record.data);
40637 beforeAction : function(action){
40638 var o = action.options;
40641 if(this.waitMsgTarget === true){
40642 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
40643 }else if(this.waitMsgTarget){
40644 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
40645 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
40647 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
40653 afterAction : function(action, success){
40654 this.activeAction = null;
40655 var o = action.options;
40657 if(this.waitMsgTarget === true){
40659 }else if(this.waitMsgTarget){
40660 this.waitMsgTarget.unmask();
40662 Roo.MessageBox.updateProgress(1);
40663 Roo.MessageBox.hide();
40670 Roo.callback(o.success, o.scope, [this, action]);
40671 this.fireEvent('actioncomplete', this, action);
40674 Roo.callback(o.failure, o.scope, [this, action]);
40675 // show an error message if no failed handler is set..
40676 if (!this.hasListener('actionfailed')) {
40677 Roo.MessageBox.alert("Error", "Saving Failed, please check your entries");
40680 this.fireEvent('actionfailed', this, action);
40686 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
40687 * @param {String} id The value to search for
40690 findField : function(id){
40691 var field = this.items.get(id);
40693 this.items.each(function(f){
40694 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
40700 return field || null;
40704 * Add a secondary form to this one,
40705 * Used to provide tabbed forms. One form is primary, with hidden values
40706 * which mirror the elements from the other forms.
40708 * @param {Roo.form.Form} form to add.
40711 addForm : function(form)
40714 if (this.childForms.indexOf(form) > -1) {
40718 this.childForms.push(form);
40720 Roo.each(form.allItems, function (fe) {
40722 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
40723 if (this.findField(n)) { // already added..
40726 var add = new Roo.form.Hidden({
40729 add.render(this.el);
40736 * Mark fields in this form invalid in bulk.
40737 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
40738 * @return {BasicForm} this
40740 markInvalid : function(errors){
40741 if(errors instanceof Array){
40742 for(var i = 0, len = errors.length; i < len; i++){
40743 var fieldError = errors[i];
40744 var f = this.findField(fieldError.id);
40746 f.markInvalid(fieldError.msg);
40752 if(typeof errors[id] != 'function' && (field = this.findField(id))){
40753 field.markInvalid(errors[id]);
40757 Roo.each(this.childForms || [], function (f) {
40758 f.markInvalid(errors);
40765 * Set values for fields in this form in bulk.
40766 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
40767 * @return {BasicForm} this
40769 setValues : function(values){
40770 if(values instanceof Array){ // array of objects
40771 for(var i = 0, len = values.length; i < len; i++){
40773 var f = this.findField(v.id);
40775 f.setValue(v.value);
40776 if(this.trackResetOnLoad){
40777 f.originalValue = f.getValue();
40781 }else{ // object hash
40784 if(typeof values[id] != 'function' && (field = this.findField(id))){
40786 if (field.setFromData &&
40787 field.valueField &&
40788 field.displayField &&
40789 // combos' with local stores can
40790 // be queried via setValue()
40791 // to set their value..
40792 (field.store && !field.store.isLocal)
40796 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40797 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40798 field.setFromData(sd);
40801 field.setValue(values[id]);
40805 if(this.trackResetOnLoad){
40806 field.originalValue = field.getValue();
40812 Roo.each(this.childForms || [], function (f) {
40813 f.setValues(values);
40820 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40821 * they are returned as an array.
40822 * @param {Boolean} asString
40825 getValues : function(asString){
40826 if (this.childForms) {
40827 // copy values from the child forms
40828 Roo.each(this.childForms, function (f) {
40829 this.setValues(f.getValues());
40835 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40836 if(asString === true){
40839 return Roo.urlDecode(fs);
40843 * Returns the fields in this form as an object with key/value pairs.
40844 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
40847 getFieldValues : function()
40849 if (this.childForms) {
40850 // copy values from the child forms
40851 Roo.each(this.childForms, function (f) {
40852 this.setValues(f.getValues());
40857 this.items.each(function(f){
40858 if (!f.getName()) {
40861 var v = f.getValue();
40862 if ((typeof(v) == 'object') && f.getRawValue) {
40863 v = f.getRawValue() ; // dates..
40865 ret[f.getName()] = v;
40872 * Clears all invalid messages in this form.
40873 * @return {BasicForm} this
40875 clearInvalid : function(){
40876 this.items.each(function(f){
40880 Roo.each(this.childForms || [], function (f) {
40889 * Resets this form.
40890 * @return {BasicForm} this
40892 reset : function(){
40893 this.items.each(function(f){
40897 Roo.each(this.childForms || [], function (f) {
40906 * Add Roo.form components to this form.
40907 * @param {Field} field1
40908 * @param {Field} field2 (optional)
40909 * @param {Field} etc (optional)
40910 * @return {BasicForm} this
40913 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40919 * Removes a field from the items collection (does NOT remove its markup).
40920 * @param {Field} field
40921 * @return {BasicForm} this
40923 remove : function(field){
40924 this.items.remove(field);
40929 * Looks at the fields in this form, checks them for an id attribute,
40930 * and calls applyTo on the existing dom element with that id.
40931 * @return {BasicForm} this
40933 render : function(){
40934 this.items.each(function(f){
40935 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40943 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40944 * @param {Object} values
40945 * @return {BasicForm} this
40947 applyToFields : function(o){
40948 this.items.each(function(f){
40955 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40956 * @param {Object} values
40957 * @return {BasicForm} this
40959 applyIfToFields : function(o){
40960 this.items.each(function(f){
40968 Roo.BasicForm = Roo.form.BasicForm;/*
40970 * Ext JS Library 1.1.1
40971 * Copyright(c) 2006-2007, Ext JS, LLC.
40973 * Originally Released Under LGPL - original licence link has changed is not relivant.
40976 * <script type="text/javascript">
40980 * @class Roo.form.Form
40981 * @extends Roo.form.BasicForm
40982 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40984 * @param {Object} config Configuration options
40986 Roo.form.Form = function(config){
40988 if (config.items) {
40989 xitems = config.items;
40990 delete config.items;
40994 Roo.form.Form.superclass.constructor.call(this, null, config);
40995 this.url = this.url || this.action;
40997 this.root = new Roo.form.Layout(Roo.applyIf({
41001 this.active = this.root;
41003 * Array of all the buttons that have been added to this form via {@link addButton}
41007 this.allItems = [];
41010 * @event clientvalidation
41011 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
41012 * @param {Form} this
41013 * @param {Boolean} valid true if the form has passed client-side validation
41015 clientvalidation: true,
41018 * Fires when the form is rendered
41019 * @param {Roo.form.Form} form
41024 if (this.progressUrl) {
41025 // push a hidden field onto the list of fields..
41029 name : 'UPLOAD_IDENTIFIER'
41034 Roo.each(xitems, this.addxtype, this);
41040 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
41042 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
41045 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
41048 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
41050 buttonAlign:'center',
41053 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
41058 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
41059 * This property cascades to child containers if not set.
41064 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
41065 * fires a looping event with that state. This is required to bind buttons to the valid
41066 * state using the config value formBind:true on the button.
41068 monitorValid : false,
41071 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
41076 * @cfg {String} progressUrl - Url to return progress data
41079 progressUrl : false,
41082 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
41083 * fields are added and the column is closed. If no fields are passed the column remains open
41084 * until end() is called.
41085 * @param {Object} config The config to pass to the column
41086 * @param {Field} field1 (optional)
41087 * @param {Field} field2 (optional)
41088 * @param {Field} etc (optional)
41089 * @return Column The column container object
41091 column : function(c){
41092 var col = new Roo.form.Column(c);
41094 if(arguments.length > 1){ // duplicate code required because of Opera
41095 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41102 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
41103 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
41104 * until end() is called.
41105 * @param {Object} config The config to pass to the fieldset
41106 * @param {Field} field1 (optional)
41107 * @param {Field} field2 (optional)
41108 * @param {Field} etc (optional)
41109 * @return FieldSet The fieldset container object
41111 fieldset : function(c){
41112 var fs = new Roo.form.FieldSet(c);
41114 if(arguments.length > 1){ // duplicate code required because of Opera
41115 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41122 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
41123 * fields are added and the container is closed. If no fields are passed the container remains open
41124 * until end() is called.
41125 * @param {Object} config The config to pass to the Layout
41126 * @param {Field} field1 (optional)
41127 * @param {Field} field2 (optional)
41128 * @param {Field} etc (optional)
41129 * @return Layout The container object
41131 container : function(c){
41132 var l = new Roo.form.Layout(c);
41134 if(arguments.length > 1){ // duplicate code required because of Opera
41135 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41142 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41143 * @param {Object} container A Roo.form.Layout or subclass of Layout
41144 * @return {Form} this
41146 start : function(c){
41147 // cascade label info
41148 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
41149 this.active.stack.push(c);
41150 c.ownerCt = this.active;
41156 * Closes the current open container
41157 * @return {Form} this
41160 if(this.active == this.root){
41163 this.active = this.active.ownerCt;
41168 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
41169 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
41170 * as the label of the field.
41171 * @param {Field} field1
41172 * @param {Field} field2 (optional)
41173 * @param {Field} etc. (optional)
41174 * @return {Form} this
41177 this.active.stack.push.apply(this.active.stack, arguments);
41178 this.allItems.push.apply(this.allItems,arguments);
41180 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
41181 if(a[i].isFormField){
41186 Roo.form.Form.superclass.add.apply(this, r);
41196 * Find any element that has been added to a form, using it's ID or name
41197 * This can include framesets, columns etc. along with regular fields..
41198 * @param {String} id - id or name to find.
41200 * @return {Element} e - or false if nothing found.
41202 findbyId : function(id)
41208 Roo.each(this.allItems, function(f){
41209 if (f.id == id || f.name == id ){
41220 * Render this form into the passed container. This should only be called once!
41221 * @param {String/HTMLElement/Element} container The element this component should be rendered into
41222 * @return {Form} this
41224 render : function(ct)
41230 var o = this.autoCreate || {
41232 method : this.method || 'POST',
41233 id : this.id || Roo.id()
41235 this.initEl(ct.createChild(o));
41237 this.root.render(this.el);
41241 this.items.each(function(f){
41242 f.render('x-form-el-'+f.id);
41245 if(this.buttons.length > 0){
41246 // tables are required to maintain order and for correct IE layout
41247 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
41248 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
41249 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
41251 var tr = tb.getElementsByTagName('tr')[0];
41252 for(var i = 0, len = this.buttons.length; i < len; i++) {
41253 var b = this.buttons[i];
41254 var td = document.createElement('td');
41255 td.className = 'x-form-btn-td';
41256 b.render(tr.appendChild(td));
41259 if(this.monitorValid){ // initialize after render
41260 this.startMonitoring();
41262 this.fireEvent('rendered', this);
41267 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
41268 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
41269 * object or a valid Roo.DomHelper element config
41270 * @param {Function} handler The function called when the button is clicked
41271 * @param {Object} scope (optional) The scope of the handler function
41272 * @return {Roo.Button}
41274 addButton : function(config, handler, scope){
41278 minWidth: this.minButtonWidth,
41281 if(typeof config == "string"){
41284 Roo.apply(bc, config);
41286 var btn = new Roo.Button(null, bc);
41287 this.buttons.push(btn);
41292 * Adds a series of form elements (using the xtype property as the factory method.
41293 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41294 * @param {Object} config
41297 addxtype : function()
41299 var ar = Array.prototype.slice.call(arguments, 0);
41301 for(var i = 0; i < ar.length; i++) {
41303 continue; // skip -- if this happends something invalid got sent, we
41304 // should ignore it, as basically that interface element will not show up
41305 // and that should be pretty obvious!!
41308 if (Roo.form[ar[i].xtype]) {
41310 var fe = Roo.factory(ar[i], Roo.form);
41316 fe.store.form = this;
41321 this.allItems.push(fe);
41322 if (fe.items && fe.addxtype) {
41323 fe.addxtype.apply(fe, fe.items);
41333 // console.log('adding ' + ar[i].xtype);
41335 if (ar[i].xtype == 'Button') {
41336 //console.log('adding button');
41337 //console.log(ar[i]);
41338 this.addButton(ar[i]);
41339 this.allItems.push(fe);
41343 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
41344 alert('end is not supported on xtype any more, use items');
41346 // //console.log('adding end');
41354 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
41355 * option "monitorValid"
41357 startMonitoring : function(){
41360 Roo.TaskMgr.start({
41361 run : this.bindHandler,
41362 interval : this.monitorPoll || 200,
41369 * Stops monitoring of the valid state of this form
41371 stopMonitoring : function(){
41372 this.bound = false;
41376 bindHandler : function(){
41378 return false; // stops binding
41381 this.items.each(function(f){
41382 if(!f.isValid(true)){
41387 for(var i = 0, len = this.buttons.length; i < len; i++){
41388 var btn = this.buttons[i];
41389 if(btn.formBind === true && btn.disabled === valid){
41390 btn.setDisabled(!valid);
41393 this.fireEvent('clientvalidation', this, valid);
41407 Roo.Form = Roo.form.Form;
41410 * Ext JS Library 1.1.1
41411 * Copyright(c) 2006-2007, Ext JS, LLC.
41413 * Originally Released Under LGPL - original licence link has changed is not relivant.
41416 * <script type="text/javascript">
41420 * @class Roo.form.Action
41421 * Internal Class used to handle form actions
41423 * @param {Roo.form.BasicForm} el The form element or its id
41424 * @param {Object} config Configuration options
41428 // define the action interface
41429 Roo.form.Action = function(form, options){
41431 this.options = options || {};
41434 * Client Validation Failed
41437 Roo.form.Action.CLIENT_INVALID = 'client';
41439 * Server Validation Failed
41442 Roo.form.Action.SERVER_INVALID = 'server';
41444 * Connect to Server Failed
41447 Roo.form.Action.CONNECT_FAILURE = 'connect';
41449 * Reading Data from Server Failed
41452 Roo.form.Action.LOAD_FAILURE = 'load';
41454 Roo.form.Action.prototype = {
41456 failureType : undefined,
41457 response : undefined,
41458 result : undefined,
41460 // interface method
41461 run : function(options){
41465 // interface method
41466 success : function(response){
41470 // interface method
41471 handleResponse : function(response){
41475 // default connection failure
41476 failure : function(response){
41478 this.response = response;
41479 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41480 this.form.afterAction(this, false);
41483 processResponse : function(response){
41484 this.response = response;
41485 if(!response.responseText){
41488 this.result = this.handleResponse(response);
41489 return this.result;
41492 // utility functions used internally
41493 getUrl : function(appendParams){
41494 var url = this.options.url || this.form.url || this.form.el.dom.action;
41496 var p = this.getParams();
41498 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
41504 getMethod : function(){
41505 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
41508 getParams : function(){
41509 var bp = this.form.baseParams;
41510 var p = this.options.params;
41512 if(typeof p == "object"){
41513 p = Roo.urlEncode(Roo.applyIf(p, bp));
41514 }else if(typeof p == 'string' && bp){
41515 p += '&' + Roo.urlEncode(bp);
41518 p = Roo.urlEncode(bp);
41523 createCallback : function(){
41525 success: this.success,
41526 failure: this.failure,
41528 timeout: (this.form.timeout*1000),
41529 upload: this.form.fileUpload ? this.success : undefined
41534 Roo.form.Action.Submit = function(form, options){
41535 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
41538 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
41541 haveProgress : false,
41542 uploadComplete : false,
41544 // uploadProgress indicator.
41545 uploadProgress : function()
41547 if (!this.form.progressUrl) {
41551 if (!this.haveProgress) {
41552 Roo.MessageBox.progress("Uploading", "Uploading");
41554 if (this.uploadComplete) {
41555 Roo.MessageBox.hide();
41559 this.haveProgress = true;
41561 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
41563 var c = new Roo.data.Connection();
41565 url : this.form.progressUrl,
41570 success : function(req){
41571 //console.log(data);
41575 rdata = Roo.decode(req.responseText)
41577 Roo.log("Invalid data from server..");
41581 if (!rdata || !rdata.success) {
41585 var data = rdata.data;
41587 if (this.uploadComplete) {
41588 Roo.MessageBox.hide();
41593 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
41594 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
41597 this.uploadProgress.defer(2000,this);
41600 failure: function(data) {
41601 Roo.log('progress url failed ');
41612 // run get Values on the form, so it syncs any secondary forms.
41613 this.form.getValues();
41615 var o = this.options;
41616 var method = this.getMethod();
41617 var isPost = method == 'POST';
41618 if(o.clientValidation === false || this.form.isValid()){
41620 if (this.form.progressUrl) {
41621 this.form.findField('UPLOAD_IDENTIFIER').setValue(
41622 (new Date() * 1) + '' + Math.random());
41627 Roo.Ajax.request(Roo.apply(this.createCallback(), {
41628 form:this.form.el.dom,
41629 url:this.getUrl(!isPost),
41631 params:isPost ? this.getParams() : null,
41632 isUpload: this.form.fileUpload
41635 this.uploadProgress();
41637 }else if (o.clientValidation !== false){ // client validation failed
41638 this.failureType = Roo.form.Action.CLIENT_INVALID;
41639 this.form.afterAction(this, false);
41643 success : function(response)
41645 this.uploadComplete= true;
41646 if (this.haveProgress) {
41647 Roo.MessageBox.hide();
41651 var result = this.processResponse(response);
41652 if(result === true || result.success){
41653 this.form.afterAction(this, true);
41657 this.form.markInvalid(result.errors);
41658 this.failureType = Roo.form.Action.SERVER_INVALID;
41660 this.form.afterAction(this, false);
41662 failure : function(response)
41664 this.uploadComplete= true;
41665 if (this.haveProgress) {
41666 Roo.MessageBox.hide();
41670 this.response = response;
41671 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41672 this.form.afterAction(this, false);
41675 handleResponse : function(response){
41676 if(this.form.errorReader){
41677 var rs = this.form.errorReader.read(response);
41680 for(var i = 0, len = rs.records.length; i < len; i++) {
41681 var r = rs.records[i];
41682 errors[i] = r.data;
41685 if(errors.length < 1){
41689 success : rs.success,
41695 ret = Roo.decode(response.responseText);
41699 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
41709 Roo.form.Action.Load = function(form, options){
41710 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
41711 this.reader = this.form.reader;
41714 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
41719 Roo.Ajax.request(Roo.apply(
41720 this.createCallback(), {
41721 method:this.getMethod(),
41722 url:this.getUrl(false),
41723 params:this.getParams()
41727 success : function(response){
41729 var result = this.processResponse(response);
41730 if(result === true || !result.success || !result.data){
41731 this.failureType = Roo.form.Action.LOAD_FAILURE;
41732 this.form.afterAction(this, false);
41735 this.form.clearInvalid();
41736 this.form.setValues(result.data);
41737 this.form.afterAction(this, true);
41740 handleResponse : function(response){
41741 if(this.form.reader){
41742 var rs = this.form.reader.read(response);
41743 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
41745 success : rs.success,
41749 return Roo.decode(response.responseText);
41753 Roo.form.Action.ACTION_TYPES = {
41754 'load' : Roo.form.Action.Load,
41755 'submit' : Roo.form.Action.Submit
41758 * Ext JS Library 1.1.1
41759 * Copyright(c) 2006-2007, Ext JS, LLC.
41761 * Originally Released Under LGPL - original licence link has changed is not relivant.
41764 * <script type="text/javascript">
41768 * @class Roo.form.Layout
41769 * @extends Roo.Component
41770 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
41772 * @param {Object} config Configuration options
41774 Roo.form.Layout = function(config){
41776 if (config.items) {
41777 xitems = config.items;
41778 delete config.items;
41780 Roo.form.Layout.superclass.constructor.call(this, config);
41782 Roo.each(xitems, this.addxtype, this);
41786 Roo.extend(Roo.form.Layout, Roo.Component, {
41788 * @cfg {String/Object} autoCreate
41789 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
41792 * @cfg {String/Object/Function} style
41793 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
41794 * a function which returns such a specification.
41797 * @cfg {String} labelAlign
41798 * Valid values are "left," "top" and "right" (defaults to "left")
41801 * @cfg {Number} labelWidth
41802 * Fixed width in pixels of all field labels (defaults to undefined)
41805 * @cfg {Boolean} clear
41806 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
41810 * @cfg {String} labelSeparator
41811 * The separator to use after field labels (defaults to ':')
41813 labelSeparator : ':',
41815 * @cfg {Boolean} hideLabels
41816 * True to suppress the display of field labels in this layout (defaults to false)
41818 hideLabels : false,
41821 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
41826 onRender : function(ct, position){
41827 if(this.el){ // from markup
41828 this.el = Roo.get(this.el);
41829 }else { // generate
41830 var cfg = this.getAutoCreate();
41831 this.el = ct.createChild(cfg, position);
41834 this.el.applyStyles(this.style);
41836 if(this.labelAlign){
41837 this.el.addClass('x-form-label-'+this.labelAlign);
41839 if(this.hideLabels){
41840 this.labelStyle = "display:none";
41841 this.elementStyle = "padding-left:0;";
41843 if(typeof this.labelWidth == 'number'){
41844 this.labelStyle = "width:"+this.labelWidth+"px;";
41845 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
41847 if(this.labelAlign == 'top'){
41848 this.labelStyle = "width:auto;";
41849 this.elementStyle = "padding-left:0;";
41852 var stack = this.stack;
41853 var slen = stack.length;
41855 if(!this.fieldTpl){
41856 var t = new Roo.Template(
41857 '<div class="x-form-item {5}">',
41858 '<label for="{0}" style="{2}">{1}{4}</label>',
41859 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41861 '</div><div class="x-form-clear-left"></div>'
41863 t.disableFormats = true;
41865 Roo.form.Layout.prototype.fieldTpl = t;
41867 for(var i = 0; i < slen; i++) {
41868 if(stack[i].isFormField){
41869 this.renderField(stack[i]);
41871 this.renderComponent(stack[i]);
41876 this.el.createChild({cls:'x-form-clear'});
41881 renderField : function(f){
41882 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
41885 f.labelStyle||this.labelStyle||'', //2
41886 this.elementStyle||'', //3
41887 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
41888 f.itemCls||this.itemCls||'' //5
41889 ], true).getPrevSibling());
41893 renderComponent : function(c){
41894 c.render(c.isLayout ? this.el : this.el.createChild());
41897 * Adds a object form elements (using the xtype property as the factory method.)
41898 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
41899 * @param {Object} config
41901 addxtype : function(o)
41903 // create the lement.
41904 o.form = this.form;
41905 var fe = Roo.factory(o, Roo.form);
41906 this.form.allItems.push(fe);
41907 this.stack.push(fe);
41909 if (fe.isFormField) {
41910 this.form.items.add(fe);
41918 * @class Roo.form.Column
41919 * @extends Roo.form.Layout
41920 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
41922 * @param {Object} config Configuration options
41924 Roo.form.Column = function(config){
41925 Roo.form.Column.superclass.constructor.call(this, config);
41928 Roo.extend(Roo.form.Column, Roo.form.Layout, {
41930 * @cfg {Number/String} width
41931 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41934 * @cfg {String/Object} autoCreate
41935 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41939 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41942 onRender : function(ct, position){
41943 Roo.form.Column.superclass.onRender.call(this, ct, position);
41945 this.el.setWidth(this.width);
41952 * @class Roo.form.Row
41953 * @extends Roo.form.Layout
41954 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41956 * @param {Object} config Configuration options
41960 Roo.form.Row = function(config){
41961 Roo.form.Row.superclass.constructor.call(this, config);
41964 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41966 * @cfg {Number/String} width
41967 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41970 * @cfg {Number/String} height
41971 * The fixed height of the column in pixels or CSS value (defaults to "auto")
41973 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
41977 onRender : function(ct, position){
41978 //console.log('row render');
41980 var t = new Roo.Template(
41981 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
41982 '<label for="{0}" style="{2}">{1}{4}</label>',
41983 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41987 t.disableFormats = true;
41989 Roo.form.Layout.prototype.rowTpl = t;
41991 this.fieldTpl = this.rowTpl;
41993 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
41994 var labelWidth = 100;
41996 if ((this.labelAlign != 'top')) {
41997 if (typeof this.labelWidth == 'number') {
41998 labelWidth = this.labelWidth
42000 this.padWidth = 20 + labelWidth;
42004 Roo.form.Column.superclass.onRender.call(this, ct, position);
42006 this.el.setWidth(this.width);
42009 this.el.setHeight(this.height);
42014 renderField : function(f){
42015 f.fieldEl = this.fieldTpl.append(this.el, [
42016 f.id, f.fieldLabel,
42017 f.labelStyle||this.labelStyle||'',
42018 this.elementStyle||'',
42019 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
42020 f.itemCls||this.itemCls||'',
42021 f.width ? f.width + this.padWidth : 160 + this.padWidth
42028 * @class Roo.form.FieldSet
42029 * @extends Roo.form.Layout
42030 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
42032 * @param {Object} config Configuration options
42034 Roo.form.FieldSet = function(config){
42035 Roo.form.FieldSet.superclass.constructor.call(this, config);
42038 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
42040 * @cfg {String} legend
42041 * The text to display as the legend for the FieldSet (defaults to '')
42044 * @cfg {String/Object} autoCreate
42045 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
42049 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
42052 onRender : function(ct, position){
42053 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
42055 this.setLegend(this.legend);
42060 setLegend : function(text){
42062 this.el.child('legend').update(text);
42067 * Ext JS Library 1.1.1
42068 * Copyright(c) 2006-2007, Ext JS, LLC.
42070 * Originally Released Under LGPL - original licence link has changed is not relivant.
42073 * <script type="text/javascript">
42076 * @class Roo.form.VTypes
42077 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
42080 Roo.form.VTypes = function(){
42081 // closure these in so they are only created once.
42082 var alpha = /^[a-zA-Z_]+$/;
42083 var alphanum = /^[a-zA-Z0-9_]+$/;
42084 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
42085 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
42087 // All these messages and functions are configurable
42090 * The function used to validate email addresses
42091 * @param {String} value The email address
42093 'email' : function(v){
42094 return email.test(v);
42097 * The error text to display when the email validation function returns false
42100 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
42102 * The keystroke filter mask to be applied on email input
42105 'emailMask' : /[a-z0-9_\.\-@]/i,
42108 * The function used to validate URLs
42109 * @param {String} value The URL
42111 'url' : function(v){
42112 return url.test(v);
42115 * The error text to display when the url validation function returns false
42118 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
42121 * The function used to validate alpha values
42122 * @param {String} value The value
42124 'alpha' : function(v){
42125 return alpha.test(v);
42128 * The error text to display when the alpha validation function returns false
42131 'alphaText' : 'This field should only contain letters and _',
42133 * The keystroke filter mask to be applied on alpha input
42136 'alphaMask' : /[a-z_]/i,
42139 * The function used to validate alphanumeric values
42140 * @param {String} value The value
42142 'alphanum' : function(v){
42143 return alphanum.test(v);
42146 * The error text to display when the alphanumeric validation function returns false
42149 'alphanumText' : 'This field should only contain letters, numbers and _',
42151 * The keystroke filter mask to be applied on alphanumeric input
42154 'alphanumMask' : /[a-z0-9_]/i
42156 }();//<script type="text/javascript">
42159 * @class Roo.form.FCKeditor
42160 * @extends Roo.form.TextArea
42161 * Wrapper around the FCKEditor http://www.fckeditor.net
42163 * Creates a new FCKeditor
42164 * @param {Object} config Configuration options
42166 Roo.form.FCKeditor = function(config){
42167 Roo.form.FCKeditor.superclass.constructor.call(this, config);
42170 * @event editorinit
42171 * Fired when the editor is initialized - you can add extra handlers here..
42172 * @param {FCKeditor} this
42173 * @param {Object} the FCK object.
42180 Roo.form.FCKeditor.editors = { };
42181 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
42183 //defaultAutoCreate : {
42184 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
42188 * @cfg {Object} fck options - see fck manual for details.
42193 * @cfg {Object} fck toolbar set (Basic or Default)
42195 toolbarSet : 'Basic',
42197 * @cfg {Object} fck BasePath
42199 basePath : '/fckeditor/',
42207 onRender : function(ct, position)
42210 this.defaultAutoCreate = {
42212 style:"width:300px;height:60px;",
42213 autocomplete: "off"
42216 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
42219 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
42220 if(this.preventScrollbars){
42221 this.el.setStyle("overflow", "hidden");
42223 this.el.setHeight(this.growMin);
42226 //console.log('onrender' + this.getId() );
42227 Roo.form.FCKeditor.editors[this.getId()] = this;
42230 this.replaceTextarea() ;
42234 getEditor : function() {
42235 return this.fckEditor;
42238 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
42239 * @param {Mixed} value The value to set
42243 setValue : function(value)
42245 //console.log('setValue: ' + value);
42247 if(typeof(value) == 'undefined') { // not sure why this is happending...
42250 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42252 //if(!this.el || !this.getEditor()) {
42253 // this.value = value;
42254 //this.setValue.defer(100,this,[value]);
42258 if(!this.getEditor()) {
42262 this.getEditor().SetData(value);
42269 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
42270 * @return {Mixed} value The field value
42272 getValue : function()
42275 if (this.frame && this.frame.dom.style.display == 'none') {
42276 return Roo.form.FCKeditor.superclass.getValue.call(this);
42279 if(!this.el || !this.getEditor()) {
42281 // this.getValue.defer(100,this);
42286 var value=this.getEditor().GetData();
42287 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42288 return Roo.form.FCKeditor.superclass.getValue.call(this);
42294 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
42295 * @return {Mixed} value The field value
42297 getRawValue : function()
42299 if (this.frame && this.frame.dom.style.display == 'none') {
42300 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42303 if(!this.el || !this.getEditor()) {
42304 //this.getRawValue.defer(100,this);
42311 var value=this.getEditor().GetData();
42312 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
42313 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42317 setSize : function(w,h) {
42321 //if (this.frame && this.frame.dom.style.display == 'none') {
42322 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42325 //if(!this.el || !this.getEditor()) {
42326 // this.setSize.defer(100,this, [w,h]);
42332 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42334 this.frame.dom.setAttribute('width', w);
42335 this.frame.dom.setAttribute('height', h);
42336 this.frame.setSize(w,h);
42340 toggleSourceEdit : function(value) {
42344 this.el.dom.style.display = value ? '' : 'none';
42345 this.frame.dom.style.display = value ? 'none' : '';
42350 focus: function(tag)
42352 if (this.frame.dom.style.display == 'none') {
42353 return Roo.form.FCKeditor.superclass.focus.call(this);
42355 if(!this.el || !this.getEditor()) {
42356 this.focus.defer(100,this, [tag]);
42363 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
42364 this.getEditor().Focus();
42366 if (!this.getEditor().Selection.GetSelection()) {
42367 this.focus.defer(100,this, [tag]);
42372 var r = this.getEditor().EditorDocument.createRange();
42373 r.setStart(tgs[0],0);
42374 r.setEnd(tgs[0],0);
42375 this.getEditor().Selection.GetSelection().removeAllRanges();
42376 this.getEditor().Selection.GetSelection().addRange(r);
42377 this.getEditor().Focus();
42384 replaceTextarea : function()
42386 if ( document.getElementById( this.getId() + '___Frame' ) )
42388 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
42390 // We must check the elements firstly using the Id and then the name.
42391 var oTextarea = document.getElementById( this.getId() );
42393 var colElementsByName = document.getElementsByName( this.getId() ) ;
42395 oTextarea.style.display = 'none' ;
42397 if ( oTextarea.tabIndex ) {
42398 this.TabIndex = oTextarea.tabIndex ;
42401 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
42402 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
42403 this.frame = Roo.get(this.getId() + '___Frame')
42406 _getConfigHtml : function()
42410 for ( var o in this.fckconfig ) {
42411 sConfig += sConfig.length > 0 ? '&' : '';
42412 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
42415 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
42419 _getIFrameHtml : function()
42421 var sFile = 'fckeditor.html' ;
42422 /* no idea what this is about..
42425 if ( (/fcksource=true/i).test( window.top.location.search ) )
42426 sFile = 'fckeditor.original.html' ;
42431 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
42432 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
42435 var html = '<iframe id="' + this.getId() +
42436 '___Frame" src="' + sLink +
42437 '" width="' + this.width +
42438 '" height="' + this.height + '"' +
42439 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
42440 ' frameborder="0" scrolling="no"></iframe>' ;
42445 _insertHtmlBefore : function( html, element )
42447 if ( element.insertAdjacentHTML ) {
42449 element.insertAdjacentHTML( 'beforeBegin', html ) ;
42451 var oRange = document.createRange() ;
42452 oRange.setStartBefore( element ) ;
42453 var oFragment = oRange.createContextualFragment( html );
42454 element.parentNode.insertBefore( oFragment, element ) ;
42467 //Roo.reg('fckeditor', Roo.form.FCKeditor);
42469 function FCKeditor_OnComplete(editorInstance){
42470 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
42471 f.fckEditor = editorInstance;
42472 //console.log("loaded");
42473 f.fireEvent('editorinit', f, editorInstance);
42493 //<script type="text/javascript">
42495 * @class Roo.form.GridField
42496 * @extends Roo.form.Field
42497 * Embed a grid (or editable grid into a form)
42500 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
42502 * xgrid.store = Roo.data.Store
42503 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
42504 * xgrid.store.reader = Roo.data.JsonReader
42508 * Creates a new GridField
42509 * @param {Object} config Configuration options
42511 Roo.form.GridField = function(config){
42512 Roo.form.GridField.superclass.constructor.call(this, config);
42516 Roo.extend(Roo.form.GridField, Roo.form.Field, {
42518 * @cfg {Number} width - used to restrict width of grid..
42522 * @cfg {Number} height - used to restrict height of grid..
42526 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
42532 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42533 * {tag: "input", type: "checkbox", autocomplete: "off"})
42535 // defaultAutoCreate : { tag: 'div' },
42536 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42538 * @cfg {String} addTitle Text to include for adding a title.
42542 onResize : function(){
42543 Roo.form.Field.superclass.onResize.apply(this, arguments);
42546 initEvents : function(){
42547 // Roo.form.Checkbox.superclass.initEvents.call(this);
42548 // has no events...
42553 getResizeEl : function(){
42557 getPositionEl : function(){
42562 onRender : function(ct, position){
42564 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
42565 var style = this.style;
42568 Roo.form.GridField.superclass.onRender.call(this, ct, position);
42569 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
42570 this.viewEl = this.wrap.createChild({ tag: 'div' });
42572 this.viewEl.applyStyles(style);
42575 this.viewEl.setWidth(this.width);
42578 this.viewEl.setHeight(this.height);
42580 //if(this.inputValue !== undefined){
42581 //this.setValue(this.value);
42584 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
42587 this.grid.render();
42588 this.grid.getDataSource().on('remove', this.refreshValue, this);
42589 this.grid.getDataSource().on('update', this.refreshValue, this);
42590 this.grid.on('afteredit', this.refreshValue, this);
42596 * Sets the value of the item.
42597 * @param {String} either an object or a string..
42599 setValue : function(v){
42601 v = v || []; // empty set..
42602 // this does not seem smart - it really only affects memoryproxy grids..
42603 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
42604 var ds = this.grid.getDataSource();
42605 // assumes a json reader..
42607 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
42608 ds.loadData( data);
42610 Roo.form.GridField.superclass.setValue.call(this, v);
42611 this.refreshValue();
42612 // should load data in the grid really....
42616 refreshValue: function() {
42618 this.grid.getDataSource().each(function(r) {
42621 this.el.dom.value = Roo.encode(val);
42629 * Ext JS Library 1.1.1
42630 * Copyright(c) 2006-2007, Ext JS, LLC.
42632 * Originally Released Under LGPL - original licence link has changed is not relivant.
42635 * <script type="text/javascript">
42638 * @class Roo.form.DisplayField
42639 * @extends Roo.form.Field
42640 * A generic Field to display non-editable data.
42642 * Creates a new Display Field item.
42643 * @param {Object} config Configuration options
42645 Roo.form.DisplayField = function(config){
42646 Roo.form.DisplayField.superclass.constructor.call(this, config);
42650 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
42651 inputType: 'hidden',
42657 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42659 focusClass : undefined,
42661 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42663 fieldClass: 'x-form-field',
42666 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
42668 valueRenderer: undefined,
42672 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42673 * {tag: "input", type: "checkbox", autocomplete: "off"})
42676 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42678 onResize : function(){
42679 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
42683 initEvents : function(){
42684 // Roo.form.Checkbox.superclass.initEvents.call(this);
42685 // has no events...
42690 getResizeEl : function(){
42694 getPositionEl : function(){
42699 onRender : function(ct, position){
42701 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
42702 //if(this.inputValue !== undefined){
42703 this.wrap = this.el.wrap();
42705 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
42707 if (this.bodyStyle) {
42708 this.viewEl.applyStyles(this.bodyStyle);
42710 //this.viewEl.setStyle('padding', '2px');
42712 this.setValue(this.value);
42717 initValue : Roo.emptyFn,
42722 onClick : function(){
42727 * Sets the checked state of the checkbox.
42728 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
42730 setValue : function(v){
42732 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
42733 // this might be called before we have a dom element..
42734 if (!this.viewEl) {
42737 this.viewEl.dom.innerHTML = html;
42738 Roo.form.DisplayField.superclass.setValue.call(this, v);
42748 * @class Roo.form.DayPicker
42749 * @extends Roo.form.Field
42750 * A Day picker show [M] [T] [W] ....
42752 * Creates a new Day Picker
42753 * @param {Object} config Configuration options
42755 Roo.form.DayPicker= function(config){
42756 Roo.form.DayPicker.superclass.constructor.call(this, config);
42760 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
42762 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42764 focusClass : undefined,
42766 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42768 fieldClass: "x-form-field",
42771 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42772 * {tag: "input", type: "checkbox", autocomplete: "off"})
42774 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42777 actionMode : 'viewEl',
42781 inputType : 'hidden',
42784 inputElement: false, // real input element?
42785 basedOn: false, // ????
42787 isFormField: true, // not sure where this is needed!!!!
42789 onResize : function(){
42790 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42791 if(!this.boxLabel){
42792 this.el.alignTo(this.wrap, 'c-c');
42796 initEvents : function(){
42797 Roo.form.Checkbox.superclass.initEvents.call(this);
42798 this.el.on("click", this.onClick, this);
42799 this.el.on("change", this.onClick, this);
42803 getResizeEl : function(){
42807 getPositionEl : function(){
42813 onRender : function(ct, position){
42814 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42816 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
42818 var r1 = '<table><tr>';
42819 var r2 = '<tr class="x-form-daypick-icons">';
42820 for (var i=0; i < 7; i++) {
42821 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
42822 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
42825 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
42826 viewEl.select('img').on('click', this.onClick, this);
42827 this.viewEl = viewEl;
42830 // this will not work on Chrome!!!
42831 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42832 this.el.on('propertychange', this.setFromHidden, this); //ie
42840 initValue : Roo.emptyFn,
42843 * Returns the checked state of the checkbox.
42844 * @return {Boolean} True if checked, else false
42846 getValue : function(){
42847 return this.el.dom.value;
42852 onClick : function(e){
42853 //this.setChecked(!this.checked);
42854 Roo.get(e.target).toggleClass('x-menu-item-checked');
42855 this.refreshValue();
42856 //if(this.el.dom.checked != this.checked){
42857 // this.setValue(this.el.dom.checked);
42862 refreshValue : function()
42865 this.viewEl.select('img',true).each(function(e,i,n) {
42866 val += e.is(".x-menu-item-checked") ? String(n) : '';
42868 this.setValue(val, true);
42872 * Sets the checked state of the checkbox.
42873 * On is always based on a string comparison between inputValue and the param.
42874 * @param {Boolean/String} value - the value to set
42875 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42877 setValue : function(v,suppressEvent){
42878 if (!this.el.dom) {
42881 var old = this.el.dom.value ;
42882 this.el.dom.value = v;
42883 if (suppressEvent) {
42887 // update display..
42888 this.viewEl.select('img',true).each(function(e,i,n) {
42890 var on = e.is(".x-menu-item-checked");
42891 var newv = v.indexOf(String(n)) > -1;
42893 e.toggleClass('x-menu-item-checked');
42899 this.fireEvent('change', this, v, old);
42904 // handle setting of hidden value by some other method!!?!?
42905 setFromHidden: function()
42910 //console.log("SET FROM HIDDEN");
42911 //alert('setFrom hidden');
42912 this.setValue(this.el.dom.value);
42915 onDestroy : function()
42918 Roo.get(this.viewEl).remove();
42921 Roo.form.DayPicker.superclass.onDestroy.call(this);
42924 });//<script type="text/javasscript">
42928 * @class Roo.DDView
42929 * A DnD enabled version of Roo.View.
42930 * @param {Element/String} container The Element in which to create the View.
42931 * @param {String} tpl The template string used to create the markup for each element of the View
42932 * @param {Object} config The configuration properties. These include all the config options of
42933 * {@link Roo.View} plus some specific to this class.<br>
42935 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
42936 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
42938 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
42939 .x-view-drag-insert-above {
42940 border-top:1px dotted #3366cc;
42942 .x-view-drag-insert-below {
42943 border-bottom:1px dotted #3366cc;
42949 Roo.DDView = function(container, tpl, config) {
42950 Roo.DDView.superclass.constructor.apply(this, arguments);
42951 this.getEl().setStyle("outline", "0px none");
42952 this.getEl().unselectable();
42953 if (this.dragGroup) {
42954 this.setDraggable(this.dragGroup.split(","));
42956 if (this.dropGroup) {
42957 this.setDroppable(this.dropGroup.split(","));
42959 if (this.deletable) {
42960 this.setDeletable();
42962 this.isDirtyFlag = false;
42968 Roo.extend(Roo.DDView, Roo.View, {
42969 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
42970 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
42971 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
42972 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
42976 reset: Roo.emptyFn,
42978 clearInvalid: Roo.form.Field.prototype.clearInvalid,
42980 validate: function() {
42984 destroy: function() {
42985 this.purgeListeners();
42986 this.getEl.removeAllListeners();
42987 this.getEl().remove();
42988 if (this.dragZone) {
42989 if (this.dragZone.destroy) {
42990 this.dragZone.destroy();
42993 if (this.dropZone) {
42994 if (this.dropZone.destroy) {
42995 this.dropZone.destroy();
43000 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
43001 getName: function() {
43005 /** Loads the View from a JSON string representing the Records to put into the Store. */
43006 setValue: function(v) {
43008 throw "DDView.setValue(). DDView must be constructed with a valid Store";
43011 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
43012 this.store.proxy = new Roo.data.MemoryProxy(data);
43016 /** @return {String} a parenthesised list of the ids of the Records in the View. */
43017 getValue: function() {
43019 this.store.each(function(rec) {
43020 result += rec.id + ',';
43022 return result.substr(0, result.length - 1) + ')';
43025 getIds: function() {
43026 var i = 0, result = new Array(this.store.getCount());
43027 this.store.each(function(rec) {
43028 result[i++] = rec.id;
43033 isDirty: function() {
43034 return this.isDirtyFlag;
43038 * Part of the Roo.dd.DropZone interface. If no target node is found, the
43039 * whole Element becomes the target, and this causes the drop gesture to append.
43041 getTargetFromEvent : function(e) {
43042 var target = e.getTarget();
43043 while ((target !== null) && (target.parentNode != this.el.dom)) {
43044 target = target.parentNode;
43047 target = this.el.dom.lastChild || this.el.dom;
43053 * Create the drag data which consists of an object which has the property "ddel" as
43054 * the drag proxy element.
43056 getDragData : function(e) {
43057 var target = this.findItemFromChild(e.getTarget());
43059 this.handleSelection(e);
43060 var selNodes = this.getSelectedNodes();
43063 copy: this.copy || (this.allowCopy && e.ctrlKey),
43067 var selectedIndices = this.getSelectedIndexes();
43068 for (var i = 0; i < selectedIndices.length; i++) {
43069 dragData.records.push(this.store.getAt(selectedIndices[i]));
43071 if (selNodes.length == 1) {
43072 dragData.ddel = target.cloneNode(true); // the div element
43074 var div = document.createElement('div'); // create the multi element drag "ghost"
43075 div.className = 'multi-proxy';
43076 for (var i = 0, len = selNodes.length; i < len; i++) {
43077 div.appendChild(selNodes[i].cloneNode(true));
43079 dragData.ddel = div;
43081 //console.log(dragData)
43082 //console.log(dragData.ddel.innerHTML)
43085 //console.log('nodragData')
43089 /** Specify to which ddGroup items in this DDView may be dragged. */
43090 setDraggable: function(ddGroup) {
43091 if (ddGroup instanceof Array) {
43092 Roo.each(ddGroup, this.setDraggable, this);
43095 if (this.dragZone) {
43096 this.dragZone.addToGroup(ddGroup);
43098 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
43099 containerScroll: true,
43103 // Draggability implies selection. DragZone's mousedown selects the element.
43104 if (!this.multiSelect) { this.singleSelect = true; }
43106 // Wire the DragZone's handlers up to methods in *this*
43107 this.dragZone.getDragData = this.getDragData.createDelegate(this);
43111 /** Specify from which ddGroup this DDView accepts drops. */
43112 setDroppable: function(ddGroup) {
43113 if (ddGroup instanceof Array) {
43114 Roo.each(ddGroup, this.setDroppable, this);
43117 if (this.dropZone) {
43118 this.dropZone.addToGroup(ddGroup);
43120 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
43121 containerScroll: true,
43125 // Wire the DropZone's handlers up to methods in *this*
43126 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
43127 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
43128 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
43129 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
43130 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
43134 /** Decide whether to drop above or below a View node. */
43135 getDropPoint : function(e, n, dd){
43136 if (n == this.el.dom) { return "above"; }
43137 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
43138 var c = t + (b - t) / 2;
43139 var y = Roo.lib.Event.getPageY(e);
43147 onNodeEnter : function(n, dd, e, data){
43151 onNodeOver : function(n, dd, e, data){
43152 var pt = this.getDropPoint(e, n, dd);
43153 // set the insert point style on the target node
43154 var dragElClass = this.dropNotAllowed;
43157 if (pt == "above"){
43158 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
43159 targetElClass = "x-view-drag-insert-above";
43161 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
43162 targetElClass = "x-view-drag-insert-below";
43164 if (this.lastInsertClass != targetElClass){
43165 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
43166 this.lastInsertClass = targetElClass;
43169 return dragElClass;
43172 onNodeOut : function(n, dd, e, data){
43173 this.removeDropIndicators(n);
43176 onNodeDrop : function(n, dd, e, data){
43177 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
43180 var pt = this.getDropPoint(e, n, dd);
43181 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
43182 if (pt == "below") { insertAt++; }
43183 for (var i = 0; i < data.records.length; i++) {
43184 var r = data.records[i];
43185 var dup = this.store.getById(r.id);
43186 if (dup && (dd != this.dragZone)) {
43187 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
43190 this.store.insert(insertAt++, r.copy());
43192 data.source.isDirtyFlag = true;
43194 this.store.insert(insertAt++, r);
43196 this.isDirtyFlag = true;
43199 this.dragZone.cachedTarget = null;
43203 removeDropIndicators : function(n){
43205 Roo.fly(n).removeClass([
43206 "x-view-drag-insert-above",
43207 "x-view-drag-insert-below"]);
43208 this.lastInsertClass = "_noclass";
43213 * Utility method. Add a delete option to the DDView's context menu.
43214 * @param {String} imageUrl The URL of the "delete" icon image.
43216 setDeletable: function(imageUrl) {
43217 if (!this.singleSelect && !this.multiSelect) {
43218 this.singleSelect = true;
43220 var c = this.getContextMenu();
43221 this.contextMenu.on("itemclick", function(item) {
43224 this.remove(this.getSelectedIndexes());
43228 this.contextMenu.add({
43235 /** Return the context menu for this DDView. */
43236 getContextMenu: function() {
43237 if (!this.contextMenu) {
43238 // Create the View's context menu
43239 this.contextMenu = new Roo.menu.Menu({
43240 id: this.id + "-contextmenu"
43242 this.el.on("contextmenu", this.showContextMenu, this);
43244 return this.contextMenu;
43247 disableContextMenu: function() {
43248 if (this.contextMenu) {
43249 this.el.un("contextmenu", this.showContextMenu, this);
43253 showContextMenu: function(e, item) {
43254 item = this.findItemFromChild(e.getTarget());
43257 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
43258 this.contextMenu.showAt(e.getXY());
43263 * Remove {@link Roo.data.Record}s at the specified indices.
43264 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
43266 remove: function(selectedIndices) {
43267 selectedIndices = [].concat(selectedIndices);
43268 for (var i = 0; i < selectedIndices.length; i++) {
43269 var rec = this.store.getAt(selectedIndices[i]);
43270 this.store.remove(rec);
43275 * Double click fires the event, but also, if this is draggable, and there is only one other
43276 * related DropZone, it transfers the selected node.
43278 onDblClick : function(e){
43279 var item = this.findItemFromChild(e.getTarget());
43281 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
43284 if (this.dragGroup) {
43285 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
43286 while (targets.indexOf(this.dropZone) > -1) {
43287 targets.remove(this.dropZone);
43289 if (targets.length == 1) {
43290 this.dragZone.cachedTarget = null;
43291 var el = Roo.get(targets[0].getEl());
43292 var box = el.getBox(true);
43293 targets[0].onNodeDrop(el.dom, {
43295 xy: [box.x, box.y + box.height - 1]
43296 }, null, this.getDragData(e));
43302 handleSelection: function(e) {
43303 this.dragZone.cachedTarget = null;
43304 var item = this.findItemFromChild(e.getTarget());
43306 this.clearSelections(true);
43309 if (item && (this.multiSelect || this.singleSelect)){
43310 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
43311 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
43312 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
43313 this.unselect(item);
43315 this.select(item, this.multiSelect && e.ctrlKey);
43316 this.lastSelection = item;
43321 onItemClick : function(item, index, e){
43322 if(this.fireEvent("beforeclick", this, index, item, e) === false){
43328 unselect : function(nodeInfo, suppressEvent){
43329 var node = this.getNode(nodeInfo);
43330 if(node && this.isSelected(node)){
43331 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
43332 Roo.fly(node).removeClass(this.selectedClass);
43333 this.selections.remove(node);
43334 if(!suppressEvent){
43335 this.fireEvent("selectionchange", this, this.selections);
43343 * Ext JS Library 1.1.1
43344 * Copyright(c) 2006-2007, Ext JS, LLC.
43346 * Originally Released Under LGPL - original licence link has changed is not relivant.
43349 * <script type="text/javascript">
43353 * @class Roo.LayoutManager
43354 * @extends Roo.util.Observable
43355 * Base class for layout managers.
43357 Roo.LayoutManager = function(container, config){
43358 Roo.LayoutManager.superclass.constructor.call(this);
43359 this.el = Roo.get(container);
43360 // ie scrollbar fix
43361 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
43362 document.body.scroll = "no";
43363 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
43364 this.el.position('relative');
43366 this.id = this.el.id;
43367 this.el.addClass("x-layout-container");
43368 /** false to disable window resize monitoring @type Boolean */
43369 this.monitorWindowResize = true;
43374 * Fires when a layout is performed.
43375 * @param {Roo.LayoutManager} this
43379 * @event regionresized
43380 * Fires when the user resizes a region.
43381 * @param {Roo.LayoutRegion} region The resized region
43382 * @param {Number} newSize The new size (width for east/west, height for north/south)
43384 "regionresized" : true,
43386 * @event regioncollapsed
43387 * Fires when a region is collapsed.
43388 * @param {Roo.LayoutRegion} region The collapsed region
43390 "regioncollapsed" : true,
43392 * @event regionexpanded
43393 * Fires when a region is expanded.
43394 * @param {Roo.LayoutRegion} region The expanded region
43396 "regionexpanded" : true
43398 this.updating = false;
43399 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
43402 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
43404 * Returns true if this layout is currently being updated
43405 * @return {Boolean}
43407 isUpdating : function(){
43408 return this.updating;
43412 * Suspend the LayoutManager from doing auto-layouts while
43413 * making multiple add or remove calls
43415 beginUpdate : function(){
43416 this.updating = true;
43420 * Restore auto-layouts and optionally disable the manager from performing a layout
43421 * @param {Boolean} noLayout true to disable a layout update
43423 endUpdate : function(noLayout){
43424 this.updating = false;
43430 layout: function(){
43434 onRegionResized : function(region, newSize){
43435 this.fireEvent("regionresized", region, newSize);
43439 onRegionCollapsed : function(region){
43440 this.fireEvent("regioncollapsed", region);
43443 onRegionExpanded : function(region){
43444 this.fireEvent("regionexpanded", region);
43448 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
43449 * performs box-model adjustments.
43450 * @return {Object} The size as an object {width: (the width), height: (the height)}
43452 getViewSize : function(){
43454 if(this.el.dom != document.body){
43455 size = this.el.getSize();
43457 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
43459 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
43460 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
43465 * Returns the Element this layout is bound to.
43466 * @return {Roo.Element}
43468 getEl : function(){
43473 * Returns the specified region.
43474 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
43475 * @return {Roo.LayoutRegion}
43477 getRegion : function(target){
43478 return this.regions[target.toLowerCase()];
43481 onWindowResize : function(){
43482 if(this.monitorWindowResize){
43488 * Ext JS Library 1.1.1
43489 * Copyright(c) 2006-2007, Ext JS, LLC.
43491 * Originally Released Under LGPL - original licence link has changed is not relivant.
43494 * <script type="text/javascript">
43497 * @class Roo.BorderLayout
43498 * @extends Roo.LayoutManager
43499 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
43500 * please see: <br><br>
43501 * <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>
43502 * <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>
43505 var layout = new Roo.BorderLayout(document.body, {
43539 preferredTabWidth: 150
43544 var CP = Roo.ContentPanel;
43546 layout.beginUpdate();
43547 layout.add("north", new CP("north", "North"));
43548 layout.add("south", new CP("south", {title: "South", closable: true}));
43549 layout.add("west", new CP("west", {title: "West"}));
43550 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
43551 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
43552 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
43553 layout.getRegion("center").showPanel("center1");
43554 layout.endUpdate();
43557 <b>The container the layout is rendered into can be either the body element or any other element.
43558 If it is not the body element, the container needs to either be an absolute positioned element,
43559 or you will need to add "position:relative" to the css of the container. You will also need to specify
43560 the container size if it is not the body element.</b>
43563 * Create a new BorderLayout
43564 * @param {String/HTMLElement/Element} container The container this layout is bound to
43565 * @param {Object} config Configuration options
43567 Roo.BorderLayout = function(container, config){
43568 config = config || {};
43569 Roo.BorderLayout.superclass.constructor.call(this, container, config);
43570 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
43571 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
43572 var target = this.factory.validRegions[i];
43573 if(config[target]){
43574 this.addRegion(target, config[target]);
43579 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
43581 * Creates and adds a new region if it doesn't already exist.
43582 * @param {String} target The target region key (north, south, east, west or center).
43583 * @param {Object} config The regions config object
43584 * @return {BorderLayoutRegion} The new region
43586 addRegion : function(target, config){
43587 if(!this.regions[target]){
43588 var r = this.factory.create(target, this, config);
43589 this.bindRegion(target, r);
43591 return this.regions[target];
43595 bindRegion : function(name, r){
43596 this.regions[name] = r;
43597 r.on("visibilitychange", this.layout, this);
43598 r.on("paneladded", this.layout, this);
43599 r.on("panelremoved", this.layout, this);
43600 r.on("invalidated", this.layout, this);
43601 r.on("resized", this.onRegionResized, this);
43602 r.on("collapsed", this.onRegionCollapsed, this);
43603 r.on("expanded", this.onRegionExpanded, this);
43607 * Performs a layout update.
43609 layout : function(){
43610 if(this.updating) return;
43611 var size = this.getViewSize();
43612 var w = size.width;
43613 var h = size.height;
43618 //var x = 0, y = 0;
43620 var rs = this.regions;
43621 var north = rs["north"];
43622 var south = rs["south"];
43623 var west = rs["west"];
43624 var east = rs["east"];
43625 var center = rs["center"];
43626 //if(this.hideOnLayout){ // not supported anymore
43627 //c.el.setStyle("display", "none");
43629 if(north && north.isVisible()){
43630 var b = north.getBox();
43631 var m = north.getMargins();
43632 b.width = w - (m.left+m.right);
43635 centerY = b.height + b.y + m.bottom;
43636 centerH -= centerY;
43637 north.updateBox(this.safeBox(b));
43639 if(south && south.isVisible()){
43640 var b = south.getBox();
43641 var m = south.getMargins();
43642 b.width = w - (m.left+m.right);
43644 var totalHeight = (b.height + m.top + m.bottom);
43645 b.y = h - totalHeight + m.top;
43646 centerH -= totalHeight;
43647 south.updateBox(this.safeBox(b));
43649 if(west && west.isVisible()){
43650 var b = west.getBox();
43651 var m = west.getMargins();
43652 b.height = centerH - (m.top+m.bottom);
43654 b.y = centerY + m.top;
43655 var totalWidth = (b.width + m.left + m.right);
43656 centerX += totalWidth;
43657 centerW -= totalWidth;
43658 west.updateBox(this.safeBox(b));
43660 if(east && east.isVisible()){
43661 var b = east.getBox();
43662 var m = east.getMargins();
43663 b.height = centerH - (m.top+m.bottom);
43664 var totalWidth = (b.width + m.left + m.right);
43665 b.x = w - totalWidth + m.left;
43666 b.y = centerY + m.top;
43667 centerW -= totalWidth;
43668 east.updateBox(this.safeBox(b));
43671 var m = center.getMargins();
43673 x: centerX + m.left,
43674 y: centerY + m.top,
43675 width: centerW - (m.left+m.right),
43676 height: centerH - (m.top+m.bottom)
43678 //if(this.hideOnLayout){
43679 //center.el.setStyle("display", "block");
43681 center.updateBox(this.safeBox(centerBox));
43684 this.fireEvent("layout", this);
43688 safeBox : function(box){
43689 box.width = Math.max(0, box.width);
43690 box.height = Math.max(0, box.height);
43695 * Adds a ContentPanel (or subclass) to this layout.
43696 * @param {String} target The target region key (north, south, east, west or center).
43697 * @param {Roo.ContentPanel} panel The panel to add
43698 * @return {Roo.ContentPanel} The added panel
43700 add : function(target, panel){
43702 target = target.toLowerCase();
43703 return this.regions[target].add(panel);
43707 * Remove a ContentPanel (or subclass) to this layout.
43708 * @param {String} target The target region key (north, south, east, west or center).
43709 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
43710 * @return {Roo.ContentPanel} The removed panel
43712 remove : function(target, panel){
43713 target = target.toLowerCase();
43714 return this.regions[target].remove(panel);
43718 * Searches all regions for a panel with the specified id
43719 * @param {String} panelId
43720 * @return {Roo.ContentPanel} The panel or null if it wasn't found
43722 findPanel : function(panelId){
43723 var rs = this.regions;
43724 for(var target in rs){
43725 if(typeof rs[target] != "function"){
43726 var p = rs[target].getPanel(panelId);
43736 * Searches all regions for a panel with the specified id and activates (shows) it.
43737 * @param {String/ContentPanel} panelId The panels id or the panel itself
43738 * @return {Roo.ContentPanel} The shown panel or null
43740 showPanel : function(panelId) {
43741 var rs = this.regions;
43742 for(var target in rs){
43743 var r = rs[target];
43744 if(typeof r != "function"){
43745 if(r.hasPanel(panelId)){
43746 return r.showPanel(panelId);
43754 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
43755 * @param {Roo.state.Provider} provider (optional) An alternate state provider
43757 restoreState : function(provider){
43759 provider = Roo.state.Manager;
43761 var sm = new Roo.LayoutStateManager();
43762 sm.init(this, provider);
43766 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
43767 * object should contain properties for each region to add ContentPanels to, and each property's value should be
43768 * a valid ContentPanel config object. Example:
43770 // Create the main layout
43771 var layout = new Roo.BorderLayout('main-ct', {
43782 // Create and add multiple ContentPanels at once via configs
43785 id: 'source-files',
43787 title:'Ext Source Files',
43800 * @param {Object} regions An object containing ContentPanel configs by region name
43802 batchAdd : function(regions){
43803 this.beginUpdate();
43804 for(var rname in regions){
43805 var lr = this.regions[rname];
43807 this.addTypedPanels(lr, regions[rname]);
43814 addTypedPanels : function(lr, ps){
43815 if(typeof ps == 'string'){
43816 lr.add(new Roo.ContentPanel(ps));
43818 else if(ps instanceof Array){
43819 for(var i =0, len = ps.length; i < len; i++){
43820 this.addTypedPanels(lr, ps[i]);
43823 else if(!ps.events){ // raw config?
43825 delete ps.el; // prevent conflict
43826 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
43828 else { // panel object assumed!
43833 * Adds a xtype elements to the layout.
43837 xtype : 'ContentPanel',
43844 xtype : 'NestedLayoutPanel',
43850 items : [ ... list of content panels or nested layout panels.. ]
43854 * @param {Object} cfg Xtype definition of item to add.
43856 addxtype : function(cfg)
43858 // basically accepts a pannel...
43859 // can accept a layout region..!?!?
43860 // console.log('BorderLayout add ' + cfg.xtype)
43862 if (!cfg.xtype.match(/Panel$/)) {
43866 var region = cfg.region;
43872 xitems = cfg.items;
43879 case 'ContentPanel': // ContentPanel (el, cfg)
43880 case 'ScrollPanel': // ContentPanel (el, cfg)
43881 if(cfg.autoCreate) {
43882 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43884 var el = this.el.createChild();
43885 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
43888 this.add(region, ret);
43892 case 'TreePanel': // our new panel!
43893 cfg.el = this.el.createChild();
43894 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43895 this.add(region, ret);
43898 case 'NestedLayoutPanel':
43899 // create a new Layout (which is a Border Layout...
43900 var el = this.el.createChild();
43901 var clayout = cfg.layout;
43903 clayout.items = clayout.items || [];
43904 // replace this exitems with the clayout ones..
43905 xitems = clayout.items;
43908 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
43909 cfg.background = false;
43911 var layout = new Roo.BorderLayout(el, clayout);
43913 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
43914 //console.log('adding nested layout panel ' + cfg.toSource());
43915 this.add(region, ret);
43921 // needs grid and region
43923 //var el = this.getRegion(region).el.createChild();
43924 var el = this.el.createChild();
43925 // create the grid first...
43927 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
43929 if (region == 'center' && this.active ) {
43930 cfg.background = false;
43932 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
43934 this.add(region, ret);
43935 if (cfg.background) {
43936 ret.on('activate', function(gp) {
43937 if (!gp.grid.rendered) {
43950 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
43952 // GridPanel (grid, cfg)
43955 this.beginUpdate();
43957 Roo.each(xitems, function(i) {
43967 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
43968 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
43969 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
43970 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
43973 var CP = Roo.ContentPanel;
43975 var layout = Roo.BorderLayout.create({
43979 panels: [new CP("north", "North")]
43988 panels: [new CP("west", {title: "West"})]
43997 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
44006 panels: [new CP("south", {title: "South", closable: true})]
44013 preferredTabWidth: 150,
44015 new CP("center1", {title: "Close Me", closable: true}),
44016 new CP("center2", {title: "Center Panel", closable: false})
44021 layout.getRegion("center").showPanel("center1");
44026 Roo.BorderLayout.create = function(config, targetEl){
44027 var layout = new Roo.BorderLayout(targetEl || document.body, config);
44028 layout.beginUpdate();
44029 var regions = Roo.BorderLayout.RegionFactory.validRegions;
44030 for(var j = 0, jlen = regions.length; j < jlen; j++){
44031 var lr = regions[j];
44032 if(layout.regions[lr] && config[lr].panels){
44033 var r = layout.regions[lr];
44034 var ps = config[lr].panels;
44035 layout.addTypedPanels(r, ps);
44038 layout.endUpdate();
44043 Roo.BorderLayout.RegionFactory = {
44045 validRegions : ["north","south","east","west","center"],
44048 create : function(target, mgr, config){
44049 target = target.toLowerCase();
44050 if(config.lightweight || config.basic){
44051 return new Roo.BasicLayoutRegion(mgr, config, target);
44055 return new Roo.NorthLayoutRegion(mgr, config);
44057 return new Roo.SouthLayoutRegion(mgr, config);
44059 return new Roo.EastLayoutRegion(mgr, config);
44061 return new Roo.WestLayoutRegion(mgr, config);
44063 return new Roo.CenterLayoutRegion(mgr, config);
44065 throw 'Layout region "'+target+'" not supported.';
44069 * Ext JS Library 1.1.1
44070 * Copyright(c) 2006-2007, Ext JS, LLC.
44072 * Originally Released Under LGPL - original licence link has changed is not relivant.
44075 * <script type="text/javascript">
44079 * @class Roo.BasicLayoutRegion
44080 * @extends Roo.util.Observable
44081 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
44082 * and does not have a titlebar, tabs or any other features. All it does is size and position
44083 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
44085 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
44087 this.position = pos;
44090 * @scope Roo.BasicLayoutRegion
44094 * @event beforeremove
44095 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
44096 * @param {Roo.LayoutRegion} this
44097 * @param {Roo.ContentPanel} panel The panel
44098 * @param {Object} e The cancel event object
44100 "beforeremove" : true,
44102 * @event invalidated
44103 * Fires when the layout for this region is changed.
44104 * @param {Roo.LayoutRegion} this
44106 "invalidated" : true,
44108 * @event visibilitychange
44109 * Fires when this region is shown or hidden
44110 * @param {Roo.LayoutRegion} this
44111 * @param {Boolean} visibility true or false
44113 "visibilitychange" : true,
44115 * @event paneladded
44116 * Fires when a panel is added.
44117 * @param {Roo.LayoutRegion} this
44118 * @param {Roo.ContentPanel} panel The panel
44120 "paneladded" : true,
44122 * @event panelremoved
44123 * Fires when a panel is removed.
44124 * @param {Roo.LayoutRegion} this
44125 * @param {Roo.ContentPanel} panel The panel
44127 "panelremoved" : true,
44130 * Fires when this region is collapsed.
44131 * @param {Roo.LayoutRegion} this
44133 "collapsed" : true,
44136 * Fires when this region is expanded.
44137 * @param {Roo.LayoutRegion} this
44142 * Fires when this region is slid into view.
44143 * @param {Roo.LayoutRegion} this
44145 "slideshow" : true,
44148 * Fires when this region slides out of view.
44149 * @param {Roo.LayoutRegion} this
44151 "slidehide" : true,
44153 * @event panelactivated
44154 * Fires when a panel is activated.
44155 * @param {Roo.LayoutRegion} this
44156 * @param {Roo.ContentPanel} panel The activated panel
44158 "panelactivated" : true,
44161 * Fires when the user resizes this region.
44162 * @param {Roo.LayoutRegion} this
44163 * @param {Number} newSize The new size (width for east/west, height for north/south)
44167 /** A collection of panels in this region. @type Roo.util.MixedCollection */
44168 this.panels = new Roo.util.MixedCollection();
44169 this.panels.getKey = this.getPanelId.createDelegate(this);
44171 this.activePanel = null;
44172 // ensure listeners are added...
44174 if (config.listeners || config.events) {
44175 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
44176 listeners : config.listeners || {},
44177 events : config.events || {}
44181 if(skipConfig !== true){
44182 this.applyConfig(config);
44186 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
44187 getPanelId : function(p){
44191 applyConfig : function(config){
44192 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44193 this.config = config;
44198 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
44199 * the width, for horizontal (north, south) the height.
44200 * @param {Number} newSize The new width or height
44202 resizeTo : function(newSize){
44203 var el = this.el ? this.el :
44204 (this.activePanel ? this.activePanel.getEl() : null);
44206 switch(this.position){
44209 el.setWidth(newSize);
44210 this.fireEvent("resized", this, newSize);
44214 el.setHeight(newSize);
44215 this.fireEvent("resized", this, newSize);
44221 getBox : function(){
44222 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
44225 getMargins : function(){
44226 return this.margins;
44229 updateBox : function(box){
44231 var el = this.activePanel.getEl();
44232 el.dom.style.left = box.x + "px";
44233 el.dom.style.top = box.y + "px";
44234 this.activePanel.setSize(box.width, box.height);
44238 * Returns the container element for this region.
44239 * @return {Roo.Element}
44241 getEl : function(){
44242 return this.activePanel;
44246 * Returns true if this region is currently visible.
44247 * @return {Boolean}
44249 isVisible : function(){
44250 return this.activePanel ? true : false;
44253 setActivePanel : function(panel){
44254 panel = this.getPanel(panel);
44255 if(this.activePanel && this.activePanel != panel){
44256 this.activePanel.setActiveState(false);
44257 this.activePanel.getEl().setLeftTop(-10000,-10000);
44259 this.activePanel = panel;
44260 panel.setActiveState(true);
44262 panel.setSize(this.box.width, this.box.height);
44264 this.fireEvent("panelactivated", this, panel);
44265 this.fireEvent("invalidated");
44269 * Show the specified panel.
44270 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
44271 * @return {Roo.ContentPanel} The shown panel or null
44273 showPanel : function(panel){
44274 if(panel = this.getPanel(panel)){
44275 this.setActivePanel(panel);
44281 * Get the active panel for this region.
44282 * @return {Roo.ContentPanel} The active panel or null
44284 getActivePanel : function(){
44285 return this.activePanel;
44289 * Add the passed ContentPanel(s)
44290 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44291 * @return {Roo.ContentPanel} The panel added (if only one was added)
44293 add : function(panel){
44294 if(arguments.length > 1){
44295 for(var i = 0, len = arguments.length; i < len; i++) {
44296 this.add(arguments[i]);
44300 if(this.hasPanel(panel)){
44301 this.showPanel(panel);
44304 var el = panel.getEl();
44305 if(el.dom.parentNode != this.mgr.el.dom){
44306 this.mgr.el.dom.appendChild(el.dom);
44308 if(panel.setRegion){
44309 panel.setRegion(this);
44311 this.panels.add(panel);
44312 el.setStyle("position", "absolute");
44313 if(!panel.background){
44314 this.setActivePanel(panel);
44315 if(this.config.initialSize && this.panels.getCount()==1){
44316 this.resizeTo(this.config.initialSize);
44319 this.fireEvent("paneladded", this, panel);
44324 * Returns true if the panel is in this region.
44325 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44326 * @return {Boolean}
44328 hasPanel : function(panel){
44329 if(typeof panel == "object"){ // must be panel obj
44330 panel = panel.getId();
44332 return this.getPanel(panel) ? true : false;
44336 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44337 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44338 * @param {Boolean} preservePanel Overrides the config preservePanel option
44339 * @return {Roo.ContentPanel} The panel that was removed
44341 remove : function(panel, preservePanel){
44342 panel = this.getPanel(panel);
44347 this.fireEvent("beforeremove", this, panel, e);
44348 if(e.cancel === true){
44351 var panelId = panel.getId();
44352 this.panels.removeKey(panelId);
44357 * Returns the panel specified or null if it's not in this region.
44358 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44359 * @return {Roo.ContentPanel}
44361 getPanel : function(id){
44362 if(typeof id == "object"){ // must be panel obj
44365 return this.panels.get(id);
44369 * Returns this regions position (north/south/east/west/center).
44372 getPosition: function(){
44373 return this.position;
44377 * Ext JS Library 1.1.1
44378 * Copyright(c) 2006-2007, Ext JS, LLC.
44380 * Originally Released Under LGPL - original licence link has changed is not relivant.
44383 * <script type="text/javascript">
44387 * @class Roo.LayoutRegion
44388 * @extends Roo.BasicLayoutRegion
44389 * This class represents a region in a layout manager.
44390 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
44391 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
44392 * @cfg {Boolean} floatable False to disable floating (defaults to true)
44393 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
44394 * @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})
44395 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
44396 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
44397 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
44398 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
44399 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
44400 * @cfg {String} title The title for the region (overrides panel titles)
44401 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
44402 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
44403 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
44404 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
44405 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
44406 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
44407 * the space available, similar to FireFox 1.5 tabs (defaults to false)
44408 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
44409 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
44410 * @cfg {Boolean} showPin True to show a pin button
44411 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
44412 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
44413 * @cfg {Boolean} disableTabTips True to disable tab tooltips
44414 * @cfg {Number} width For East/West panels
44415 * @cfg {Number} height For North/South panels
44416 * @cfg {Boolean} split To show the splitter
44418 Roo.LayoutRegion = function(mgr, config, pos){
44419 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
44420 var dh = Roo.DomHelper;
44421 /** This region's container element
44422 * @type Roo.Element */
44423 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
44424 /** This region's title element
44425 * @type Roo.Element */
44427 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
44428 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
44429 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
44431 this.titleEl.enableDisplayMode();
44432 /** This region's title text element
44433 * @type HTMLElement */
44434 this.titleTextEl = this.titleEl.dom.firstChild;
44435 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
44436 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
44437 this.closeBtn.enableDisplayMode();
44438 this.closeBtn.on("click", this.closeClicked, this);
44439 this.closeBtn.hide();
44441 this.createBody(config);
44442 this.visible = true;
44443 this.collapsed = false;
44445 if(config.hideWhenEmpty){
44447 this.on("paneladded", this.validateVisibility, this);
44448 this.on("panelremoved", this.validateVisibility, this);
44450 this.applyConfig(config);
44453 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
44455 createBody : function(){
44456 /** This region's body element
44457 * @type Roo.Element */
44458 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
44461 applyConfig : function(c){
44462 if(c.collapsible && this.position != "center" && !this.collapsedEl){
44463 var dh = Roo.DomHelper;
44464 if(c.titlebar !== false){
44465 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
44466 this.collapseBtn.on("click", this.collapse, this);
44467 this.collapseBtn.enableDisplayMode();
44469 if(c.showPin === true || this.showPin){
44470 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
44471 this.stickBtn.enableDisplayMode();
44472 this.stickBtn.on("click", this.expand, this);
44473 this.stickBtn.hide();
44476 /** This region's collapsed element
44477 * @type Roo.Element */
44478 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
44479 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
44481 if(c.floatable !== false){
44482 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
44483 this.collapsedEl.on("click", this.collapseClick, this);
44486 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
44487 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
44488 id: "message", unselectable: "on", style:{"float":"left"}});
44489 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
44491 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
44492 this.expandBtn.on("click", this.expand, this);
44494 if(this.collapseBtn){
44495 this.collapseBtn.setVisible(c.collapsible == true);
44497 this.cmargins = c.cmargins || this.cmargins ||
44498 (this.position == "west" || this.position == "east" ?
44499 {top: 0, left: 2, right:2, bottom: 0} :
44500 {top: 2, left: 0, right:0, bottom: 2});
44501 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44502 this.bottomTabs = c.tabPosition != "top";
44503 this.autoScroll = c.autoScroll || false;
44504 if(this.autoScroll){
44505 this.bodyEl.setStyle("overflow", "auto");
44507 this.bodyEl.setStyle("overflow", "hidden");
44509 //if(c.titlebar !== false){
44510 if((!c.titlebar && !c.title) || c.titlebar === false){
44511 this.titleEl.hide();
44513 this.titleEl.show();
44515 this.titleTextEl.innerHTML = c.title;
44519 this.duration = c.duration || .30;
44520 this.slideDuration = c.slideDuration || .45;
44523 this.collapse(true);
44530 * Returns true if this region is currently visible.
44531 * @return {Boolean}
44533 isVisible : function(){
44534 return this.visible;
44538 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
44539 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
44541 setCollapsedTitle : function(title){
44542 title = title || " ";
44543 if(this.collapsedTitleTextEl){
44544 this.collapsedTitleTextEl.innerHTML = title;
44548 getBox : function(){
44550 if(!this.collapsed){
44551 b = this.el.getBox(false, true);
44553 b = this.collapsedEl.getBox(false, true);
44558 getMargins : function(){
44559 return this.collapsed ? this.cmargins : this.margins;
44562 highlight : function(){
44563 this.el.addClass("x-layout-panel-dragover");
44566 unhighlight : function(){
44567 this.el.removeClass("x-layout-panel-dragover");
44570 updateBox : function(box){
44572 if(!this.collapsed){
44573 this.el.dom.style.left = box.x + "px";
44574 this.el.dom.style.top = box.y + "px";
44575 this.updateBody(box.width, box.height);
44577 this.collapsedEl.dom.style.left = box.x + "px";
44578 this.collapsedEl.dom.style.top = box.y + "px";
44579 this.collapsedEl.setSize(box.width, box.height);
44582 this.tabs.autoSizeTabs();
44586 updateBody : function(w, h){
44588 this.el.setWidth(w);
44589 w -= this.el.getBorderWidth("rl");
44590 if(this.config.adjustments){
44591 w += this.config.adjustments[0];
44595 this.el.setHeight(h);
44596 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
44597 h -= this.el.getBorderWidth("tb");
44598 if(this.config.adjustments){
44599 h += this.config.adjustments[1];
44601 this.bodyEl.setHeight(h);
44603 h = this.tabs.syncHeight(h);
44606 if(this.panelSize){
44607 w = w !== null ? w : this.panelSize.width;
44608 h = h !== null ? h : this.panelSize.height;
44610 if(this.activePanel){
44611 var el = this.activePanel.getEl();
44612 w = w !== null ? w : el.getWidth();
44613 h = h !== null ? h : el.getHeight();
44614 this.panelSize = {width: w, height: h};
44615 this.activePanel.setSize(w, h);
44617 if(Roo.isIE && this.tabs){
44618 this.tabs.el.repaint();
44623 * Returns the container element for this region.
44624 * @return {Roo.Element}
44626 getEl : function(){
44631 * Hides this region.
44634 if(!this.collapsed){
44635 this.el.dom.style.left = "-2000px";
44638 this.collapsedEl.dom.style.left = "-2000px";
44639 this.collapsedEl.hide();
44641 this.visible = false;
44642 this.fireEvent("visibilitychange", this, false);
44646 * Shows this region if it was previously hidden.
44649 if(!this.collapsed){
44652 this.collapsedEl.show();
44654 this.visible = true;
44655 this.fireEvent("visibilitychange", this, true);
44658 closeClicked : function(){
44659 if(this.activePanel){
44660 this.remove(this.activePanel);
44664 collapseClick : function(e){
44666 e.stopPropagation();
44669 e.stopPropagation();
44675 * Collapses this region.
44676 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
44678 collapse : function(skipAnim){
44679 if(this.collapsed) return;
44680 this.collapsed = true;
44682 this.split.el.hide();
44684 if(this.config.animate && skipAnim !== true){
44685 this.fireEvent("invalidated", this);
44686 this.animateCollapse();
44688 this.el.setLocation(-20000,-20000);
44690 this.collapsedEl.show();
44691 this.fireEvent("collapsed", this);
44692 this.fireEvent("invalidated", this);
44696 animateCollapse : function(){
44701 * Expands this region if it was previously collapsed.
44702 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
44703 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
44705 expand : function(e, skipAnim){
44706 if(e) e.stopPropagation();
44707 if(!this.collapsed || this.el.hasActiveFx()) return;
44709 this.afterSlideIn();
44712 this.collapsed = false;
44713 if(this.config.animate && skipAnim !== true){
44714 this.animateExpand();
44718 this.split.el.show();
44720 this.collapsedEl.setLocation(-2000,-2000);
44721 this.collapsedEl.hide();
44722 this.fireEvent("invalidated", this);
44723 this.fireEvent("expanded", this);
44727 animateExpand : function(){
44731 initTabs : function(){
44732 this.bodyEl.setStyle("overflow", "hidden");
44733 var ts = new Roo.TabPanel(this.bodyEl.dom, {
44734 tabPosition: this.bottomTabs ? 'bottom' : 'top',
44735 disableTooltips: this.config.disableTabTips
44737 if(this.config.hideTabs){
44738 ts.stripWrap.setDisplayed(false);
44741 ts.resizeTabs = this.config.resizeTabs === true;
44742 ts.minTabWidth = this.config.minTabWidth || 40;
44743 ts.maxTabWidth = this.config.maxTabWidth || 250;
44744 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
44745 ts.monitorResize = false;
44746 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44747 ts.bodyEl.addClass('x-layout-tabs-body');
44748 this.panels.each(this.initPanelAsTab, this);
44751 initPanelAsTab : function(panel){
44752 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
44753 this.config.closeOnTab && panel.isClosable());
44754 if(panel.tabTip !== undefined){
44755 ti.setTooltip(panel.tabTip);
44757 ti.on("activate", function(){
44758 this.setActivePanel(panel);
44760 if(this.config.closeOnTab){
44761 ti.on("beforeclose", function(t, e){
44763 this.remove(panel);
44769 updatePanelTitle : function(panel, title){
44770 if(this.activePanel == panel){
44771 this.updateTitle(title);
44774 var ti = this.tabs.getTab(panel.getEl().id);
44776 if(panel.tabTip !== undefined){
44777 ti.setTooltip(panel.tabTip);
44782 updateTitle : function(title){
44783 if(this.titleTextEl && !this.config.title){
44784 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
44788 setActivePanel : function(panel){
44789 panel = this.getPanel(panel);
44790 if(this.activePanel && this.activePanel != panel){
44791 this.activePanel.setActiveState(false);
44793 this.activePanel = panel;
44794 panel.setActiveState(true);
44795 if(this.panelSize){
44796 panel.setSize(this.panelSize.width, this.panelSize.height);
44799 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
44801 this.updateTitle(panel.getTitle());
44803 this.fireEvent("invalidated", this);
44805 this.fireEvent("panelactivated", this, panel);
44809 * Shows the specified panel.
44810 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
44811 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
44813 showPanel : function(panel){
44814 if(panel = this.getPanel(panel)){
44816 var tab = this.tabs.getTab(panel.getEl().id);
44817 if(tab.isHidden()){
44818 this.tabs.unhideTab(tab.id);
44822 this.setActivePanel(panel);
44829 * Get the active panel for this region.
44830 * @return {Roo.ContentPanel} The active panel or null
44832 getActivePanel : function(){
44833 return this.activePanel;
44836 validateVisibility : function(){
44837 if(this.panels.getCount() < 1){
44838 this.updateTitle(" ");
44839 this.closeBtn.hide();
44842 if(!this.isVisible()){
44849 * Adds the passed ContentPanel(s) to this region.
44850 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44851 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
44853 add : function(panel){
44854 if(arguments.length > 1){
44855 for(var i = 0, len = arguments.length; i < len; i++) {
44856 this.add(arguments[i]);
44860 if(this.hasPanel(panel)){
44861 this.showPanel(panel);
44864 panel.setRegion(this);
44865 this.panels.add(panel);
44866 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
44867 this.bodyEl.dom.appendChild(panel.getEl().dom);
44868 if(panel.background !== true){
44869 this.setActivePanel(panel);
44871 this.fireEvent("paneladded", this, panel);
44877 this.initPanelAsTab(panel);
44879 if(panel.background !== true){
44880 this.tabs.activate(panel.getEl().id);
44882 this.fireEvent("paneladded", this, panel);
44887 * Hides the tab for the specified panel.
44888 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44890 hidePanel : function(panel){
44891 if(this.tabs && (panel = this.getPanel(panel))){
44892 this.tabs.hideTab(panel.getEl().id);
44897 * Unhides the tab for a previously hidden panel.
44898 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44900 unhidePanel : function(panel){
44901 if(this.tabs && (panel = this.getPanel(panel))){
44902 this.tabs.unhideTab(panel.getEl().id);
44906 clearPanels : function(){
44907 while(this.panels.getCount() > 0){
44908 this.remove(this.panels.first());
44913 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44914 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44915 * @param {Boolean} preservePanel Overrides the config preservePanel option
44916 * @return {Roo.ContentPanel} The panel that was removed
44918 remove : function(panel, preservePanel){
44919 panel = this.getPanel(panel);
44924 this.fireEvent("beforeremove", this, panel, e);
44925 if(e.cancel === true){
44928 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
44929 var panelId = panel.getId();
44930 this.panels.removeKey(panelId);
44932 document.body.appendChild(panel.getEl().dom);
44935 this.tabs.removeTab(panel.getEl().id);
44936 }else if (!preservePanel){
44937 this.bodyEl.dom.removeChild(panel.getEl().dom);
44939 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
44940 var p = this.panels.first();
44941 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
44942 tempEl.appendChild(p.getEl().dom);
44943 this.bodyEl.update("");
44944 this.bodyEl.dom.appendChild(p.getEl().dom);
44946 this.updateTitle(p.getTitle());
44948 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44949 this.setActivePanel(p);
44951 panel.setRegion(null);
44952 if(this.activePanel == panel){
44953 this.activePanel = null;
44955 if(this.config.autoDestroy !== false && preservePanel !== true){
44956 try{panel.destroy();}catch(e){}
44958 this.fireEvent("panelremoved", this, panel);
44963 * Returns the TabPanel component used by this region
44964 * @return {Roo.TabPanel}
44966 getTabs : function(){
44970 createTool : function(parentEl, className){
44971 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
44972 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
44973 btn.addClassOnOver("x-layout-tools-button-over");
44978 * Ext JS Library 1.1.1
44979 * Copyright(c) 2006-2007, Ext JS, LLC.
44981 * Originally Released Under LGPL - original licence link has changed is not relivant.
44984 * <script type="text/javascript">
44990 * @class Roo.SplitLayoutRegion
44991 * @extends Roo.LayoutRegion
44992 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
44994 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
44995 this.cursor = cursor;
44996 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
44999 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
45000 splitTip : "Drag to resize.",
45001 collapsibleSplitTip : "Drag to resize. Double click to hide.",
45002 useSplitTips : false,
45004 applyConfig : function(config){
45005 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
45008 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
45009 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
45010 /** The SplitBar for this region
45011 * @type Roo.SplitBar */
45012 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
45013 this.split.on("moved", this.onSplitMove, this);
45014 this.split.useShim = config.useShim === true;
45015 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
45016 if(this.useSplitTips){
45017 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
45019 if(config.collapsible){
45020 this.split.el.on("dblclick", this.collapse, this);
45023 if(typeof config.minSize != "undefined"){
45024 this.split.minSize = config.minSize;
45026 if(typeof config.maxSize != "undefined"){
45027 this.split.maxSize = config.maxSize;
45029 if(config.hideWhenEmpty || config.hidden || config.collapsed){
45030 this.hideSplitter();
45035 getHMaxSize : function(){
45036 var cmax = this.config.maxSize || 10000;
45037 var center = this.mgr.getRegion("center");
45038 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
45041 getVMaxSize : function(){
45042 var cmax = this.config.maxSize || 10000;
45043 var center = this.mgr.getRegion("center");
45044 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
45047 onSplitMove : function(split, newSize){
45048 this.fireEvent("resized", this, newSize);
45052 * Returns the {@link Roo.SplitBar} for this region.
45053 * @return {Roo.SplitBar}
45055 getSplitBar : function(){
45060 this.hideSplitter();
45061 Roo.SplitLayoutRegion.superclass.hide.call(this);
45064 hideSplitter : function(){
45066 this.split.el.setLocation(-2000,-2000);
45067 this.split.el.hide();
45073 this.split.el.show();
45075 Roo.SplitLayoutRegion.superclass.show.call(this);
45078 beforeSlide: function(){
45079 if(Roo.isGecko){// firefox overflow auto bug workaround
45080 this.bodyEl.clip();
45081 if(this.tabs) this.tabs.bodyEl.clip();
45082 if(this.activePanel){
45083 this.activePanel.getEl().clip();
45085 if(this.activePanel.beforeSlide){
45086 this.activePanel.beforeSlide();
45092 afterSlide : function(){
45093 if(Roo.isGecko){// firefox overflow auto bug workaround
45094 this.bodyEl.unclip();
45095 if(this.tabs) this.tabs.bodyEl.unclip();
45096 if(this.activePanel){
45097 this.activePanel.getEl().unclip();
45098 if(this.activePanel.afterSlide){
45099 this.activePanel.afterSlide();
45105 initAutoHide : function(){
45106 if(this.autoHide !== false){
45107 if(!this.autoHideHd){
45108 var st = new Roo.util.DelayedTask(this.slideIn, this);
45109 this.autoHideHd = {
45110 "mouseout": function(e){
45111 if(!e.within(this.el, true)){
45115 "mouseover" : function(e){
45121 this.el.on(this.autoHideHd);
45125 clearAutoHide : function(){
45126 if(this.autoHide !== false){
45127 this.el.un("mouseout", this.autoHideHd.mouseout);
45128 this.el.un("mouseover", this.autoHideHd.mouseover);
45132 clearMonitor : function(){
45133 Roo.get(document).un("click", this.slideInIf, this);
45136 // these names are backwards but not changed for compat
45137 slideOut : function(){
45138 if(this.isSlid || this.el.hasActiveFx()){
45141 this.isSlid = true;
45142 if(this.collapseBtn){
45143 this.collapseBtn.hide();
45145 this.closeBtnState = this.closeBtn.getStyle('display');
45146 this.closeBtn.hide();
45148 this.stickBtn.show();
45151 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
45152 this.beforeSlide();
45153 this.el.setStyle("z-index", 10001);
45154 this.el.slideIn(this.getSlideAnchor(), {
45155 callback: function(){
45157 this.initAutoHide();
45158 Roo.get(document).on("click", this.slideInIf, this);
45159 this.fireEvent("slideshow", this);
45166 afterSlideIn : function(){
45167 this.clearAutoHide();
45168 this.isSlid = false;
45169 this.clearMonitor();
45170 this.el.setStyle("z-index", "");
45171 if(this.collapseBtn){
45172 this.collapseBtn.show();
45174 this.closeBtn.setStyle('display', this.closeBtnState);
45176 this.stickBtn.hide();
45178 this.fireEvent("slidehide", this);
45181 slideIn : function(cb){
45182 if(!this.isSlid || this.el.hasActiveFx()){
45186 this.isSlid = false;
45187 this.beforeSlide();
45188 this.el.slideOut(this.getSlideAnchor(), {
45189 callback: function(){
45190 this.el.setLeftTop(-10000, -10000);
45192 this.afterSlideIn();
45200 slideInIf : function(e){
45201 if(!e.within(this.el)){
45206 animateCollapse : function(){
45207 this.beforeSlide();
45208 this.el.setStyle("z-index", 20000);
45209 var anchor = this.getSlideAnchor();
45210 this.el.slideOut(anchor, {
45211 callback : function(){
45212 this.el.setStyle("z-index", "");
45213 this.collapsedEl.slideIn(anchor, {duration:.3});
45215 this.el.setLocation(-10000,-10000);
45217 this.fireEvent("collapsed", this);
45224 animateExpand : function(){
45225 this.beforeSlide();
45226 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
45227 this.el.setStyle("z-index", 20000);
45228 this.collapsedEl.hide({
45231 this.el.slideIn(this.getSlideAnchor(), {
45232 callback : function(){
45233 this.el.setStyle("z-index", "");
45236 this.split.el.show();
45238 this.fireEvent("invalidated", this);
45239 this.fireEvent("expanded", this);
45267 getAnchor : function(){
45268 return this.anchors[this.position];
45271 getCollapseAnchor : function(){
45272 return this.canchors[this.position];
45275 getSlideAnchor : function(){
45276 return this.sanchors[this.position];
45279 getAlignAdj : function(){
45280 var cm = this.cmargins;
45281 switch(this.position){
45297 getExpandAdj : function(){
45298 var c = this.collapsedEl, cm = this.cmargins;
45299 switch(this.position){
45301 return [-(cm.right+c.getWidth()+cm.left), 0];
45304 return [cm.right+c.getWidth()+cm.left, 0];
45307 return [0, -(cm.top+cm.bottom+c.getHeight())];
45310 return [0, cm.top+cm.bottom+c.getHeight()];
45316 * Ext JS Library 1.1.1
45317 * Copyright(c) 2006-2007, Ext JS, LLC.
45319 * Originally Released Under LGPL - original licence link has changed is not relivant.
45322 * <script type="text/javascript">
45325 * These classes are private internal classes
45327 Roo.CenterLayoutRegion = function(mgr, config){
45328 Roo.LayoutRegion.call(this, mgr, config, "center");
45329 this.visible = true;
45330 this.minWidth = config.minWidth || 20;
45331 this.minHeight = config.minHeight || 20;
45334 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
45336 // center panel can't be hidden
45340 // center panel can't be hidden
45343 getMinWidth: function(){
45344 return this.minWidth;
45347 getMinHeight: function(){
45348 return this.minHeight;
45353 Roo.NorthLayoutRegion = function(mgr, config){
45354 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
45356 this.split.placement = Roo.SplitBar.TOP;
45357 this.split.orientation = Roo.SplitBar.VERTICAL;
45358 this.split.el.addClass("x-layout-split-v");
45360 var size = config.initialSize || config.height;
45361 if(typeof size != "undefined"){
45362 this.el.setHeight(size);
45365 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
45366 orientation: Roo.SplitBar.VERTICAL,
45367 getBox : function(){
45368 if(this.collapsed){
45369 return this.collapsedEl.getBox();
45371 var box = this.el.getBox();
45373 box.height += this.split.el.getHeight();
45378 updateBox : function(box){
45379 if(this.split && !this.collapsed){
45380 box.height -= this.split.el.getHeight();
45381 this.split.el.setLeft(box.x);
45382 this.split.el.setTop(box.y+box.height);
45383 this.split.el.setWidth(box.width);
45385 if(this.collapsed){
45386 this.updateBody(box.width, null);
45388 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45392 Roo.SouthLayoutRegion = function(mgr, config){
45393 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
45395 this.split.placement = Roo.SplitBar.BOTTOM;
45396 this.split.orientation = Roo.SplitBar.VERTICAL;
45397 this.split.el.addClass("x-layout-split-v");
45399 var size = config.initialSize || config.height;
45400 if(typeof size != "undefined"){
45401 this.el.setHeight(size);
45404 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
45405 orientation: Roo.SplitBar.VERTICAL,
45406 getBox : function(){
45407 if(this.collapsed){
45408 return this.collapsedEl.getBox();
45410 var box = this.el.getBox();
45412 var sh = this.split.el.getHeight();
45419 updateBox : function(box){
45420 if(this.split && !this.collapsed){
45421 var sh = this.split.el.getHeight();
45424 this.split.el.setLeft(box.x);
45425 this.split.el.setTop(box.y-sh);
45426 this.split.el.setWidth(box.width);
45428 if(this.collapsed){
45429 this.updateBody(box.width, null);
45431 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45435 Roo.EastLayoutRegion = function(mgr, config){
45436 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
45438 this.split.placement = Roo.SplitBar.RIGHT;
45439 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45440 this.split.el.addClass("x-layout-split-h");
45442 var size = config.initialSize || config.width;
45443 if(typeof size != "undefined"){
45444 this.el.setWidth(size);
45447 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
45448 orientation: Roo.SplitBar.HORIZONTAL,
45449 getBox : function(){
45450 if(this.collapsed){
45451 return this.collapsedEl.getBox();
45453 var box = this.el.getBox();
45455 var sw = this.split.el.getWidth();
45462 updateBox : function(box){
45463 if(this.split && !this.collapsed){
45464 var sw = this.split.el.getWidth();
45466 this.split.el.setLeft(box.x);
45467 this.split.el.setTop(box.y);
45468 this.split.el.setHeight(box.height);
45471 if(this.collapsed){
45472 this.updateBody(null, box.height);
45474 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45478 Roo.WestLayoutRegion = function(mgr, config){
45479 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
45481 this.split.placement = Roo.SplitBar.LEFT;
45482 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45483 this.split.el.addClass("x-layout-split-h");
45485 var size = config.initialSize || config.width;
45486 if(typeof size != "undefined"){
45487 this.el.setWidth(size);
45490 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
45491 orientation: Roo.SplitBar.HORIZONTAL,
45492 getBox : function(){
45493 if(this.collapsed){
45494 return this.collapsedEl.getBox();
45496 var box = this.el.getBox();
45498 box.width += this.split.el.getWidth();
45503 updateBox : function(box){
45504 if(this.split && !this.collapsed){
45505 var sw = this.split.el.getWidth();
45507 this.split.el.setLeft(box.x+box.width);
45508 this.split.el.setTop(box.y);
45509 this.split.el.setHeight(box.height);
45511 if(this.collapsed){
45512 this.updateBody(null, box.height);
45514 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45519 * Ext JS Library 1.1.1
45520 * Copyright(c) 2006-2007, Ext JS, LLC.
45522 * Originally Released Under LGPL - original licence link has changed is not relivant.
45525 * <script type="text/javascript">
45530 * Private internal class for reading and applying state
45532 Roo.LayoutStateManager = function(layout){
45533 // default empty state
45542 Roo.LayoutStateManager.prototype = {
45543 init : function(layout, provider){
45544 this.provider = provider;
45545 var state = provider.get(layout.id+"-layout-state");
45547 var wasUpdating = layout.isUpdating();
45549 layout.beginUpdate();
45551 for(var key in state){
45552 if(typeof state[key] != "function"){
45553 var rstate = state[key];
45554 var r = layout.getRegion(key);
45557 r.resizeTo(rstate.size);
45559 if(rstate.collapsed == true){
45562 r.expand(null, true);
45568 layout.endUpdate();
45570 this.state = state;
45572 this.layout = layout;
45573 layout.on("regionresized", this.onRegionResized, this);
45574 layout.on("regioncollapsed", this.onRegionCollapsed, this);
45575 layout.on("regionexpanded", this.onRegionExpanded, this);
45578 storeState : function(){
45579 this.provider.set(this.layout.id+"-layout-state", this.state);
45582 onRegionResized : function(region, newSize){
45583 this.state[region.getPosition()].size = newSize;
45587 onRegionCollapsed : function(region){
45588 this.state[region.getPosition()].collapsed = true;
45592 onRegionExpanded : function(region){
45593 this.state[region.getPosition()].collapsed = false;
45598 * Ext JS Library 1.1.1
45599 * Copyright(c) 2006-2007, Ext JS, LLC.
45601 * Originally Released Under LGPL - original licence link has changed is not relivant.
45604 * <script type="text/javascript">
45607 * @class Roo.ContentPanel
45608 * @extends Roo.util.Observable
45609 * A basic ContentPanel element.
45610 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
45611 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
45612 * @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
45613 * @cfg {Boolean} closable True if the panel can be closed/removed
45614 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
45615 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
45616 * @cfg {Toolbar} toolbar A toolbar for this panel
45617 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
45618 * @cfg {String} title The title for this panel
45619 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
45620 * @cfg {String} url Calls {@link #setUrl} with this value
45621 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
45622 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
45623 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
45625 * Create a new ContentPanel.
45626 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
45627 * @param {String/Object} config A string to set only the title or a config object
45628 * @param {String} content (optional) Set the HTML content for this panel
45629 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
45631 Roo.ContentPanel = function(el, config, content){
45635 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
45639 if (config && config.parentLayout) {
45640 el = config.parentLayout.el.createChild();
45643 if(el.autoCreate){ // xtype is available if this is called from factory
45647 this.el = Roo.get(el);
45648 if(!this.el && config && config.autoCreate){
45649 if(typeof config.autoCreate == "object"){
45650 if(!config.autoCreate.id){
45651 config.autoCreate.id = config.id||el;
45653 this.el = Roo.DomHelper.append(document.body,
45654 config.autoCreate, true);
45656 this.el = Roo.DomHelper.append(document.body,
45657 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
45660 this.closable = false;
45661 this.loaded = false;
45662 this.active = false;
45663 if(typeof config == "string"){
45664 this.title = config;
45666 Roo.apply(this, config);
45669 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
45670 this.wrapEl = this.el.wrap();
45671 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
45678 this.resizeEl = Roo.get(this.resizeEl, true);
45680 this.resizeEl = this.el;
45685 * Fires when this panel is activated.
45686 * @param {Roo.ContentPanel} this
45690 * @event deactivate
45691 * Fires when this panel is activated.
45692 * @param {Roo.ContentPanel} this
45694 "deactivate" : true,
45698 * Fires when this panel is resized if fitToFrame is true.
45699 * @param {Roo.ContentPanel} this
45700 * @param {Number} width The width after any component adjustments
45701 * @param {Number} height The height after any component adjustments
45705 if(this.autoScroll){
45706 this.resizeEl.setStyle("overflow", "auto");
45708 // fix randome scrolling
45709 this.el.on('scroll', function() {
45710 Roo.log('fix random scolling');
45711 this.scrollTo('top',0);
45714 content = content || this.content;
45716 this.setContent(content);
45718 if(config && config.url){
45719 this.setUrl(this.url, this.params, this.loadOnce);
45724 Roo.ContentPanel.superclass.constructor.call(this);
45727 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
45729 setRegion : function(region){
45730 this.region = region;
45732 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
45734 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
45739 * Returns the toolbar for this Panel if one was configured.
45740 * @return {Roo.Toolbar}
45742 getToolbar : function(){
45743 return this.toolbar;
45746 setActiveState : function(active){
45747 this.active = active;
45749 this.fireEvent("deactivate", this);
45751 this.fireEvent("activate", this);
45755 * Updates this panel's element
45756 * @param {String} content The new content
45757 * @param {Boolean} loadScripts (optional) true to look for and process scripts
45759 setContent : function(content, loadScripts){
45760 this.el.update(content, loadScripts);
45763 ignoreResize : function(w, h){
45764 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
45767 this.lastSize = {width: w, height: h};
45772 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
45773 * @return {Roo.UpdateManager} The UpdateManager
45775 getUpdateManager : function(){
45776 return this.el.getUpdateManager();
45779 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
45780 * @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:
45783 url: "your-url.php",
45784 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
45785 callback: yourFunction,
45786 scope: yourObject, //(optional scope)
45789 text: "Loading...",
45794 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
45795 * 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.
45796 * @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}
45797 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
45798 * @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.
45799 * @return {Roo.ContentPanel} this
45802 var um = this.el.getUpdateManager();
45803 um.update.apply(um, arguments);
45809 * 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.
45810 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
45811 * @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)
45812 * @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)
45813 * @return {Roo.UpdateManager} The UpdateManager
45815 setUrl : function(url, params, loadOnce){
45816 if(this.refreshDelegate){
45817 this.removeListener("activate", this.refreshDelegate);
45819 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
45820 this.on("activate", this.refreshDelegate);
45821 return this.el.getUpdateManager();
45824 _handleRefresh : function(url, params, loadOnce){
45825 if(!loadOnce || !this.loaded){
45826 var updater = this.el.getUpdateManager();
45827 updater.update(url, params, this._setLoaded.createDelegate(this));
45831 _setLoaded : function(){
45832 this.loaded = true;
45836 * Returns this panel's id
45839 getId : function(){
45844 * Returns this panel's element - used by regiosn to add.
45845 * @return {Roo.Element}
45847 getEl : function(){
45848 return this.wrapEl || this.el;
45851 adjustForComponents : function(width, height){
45852 if(this.resizeEl != this.el){
45853 width -= this.el.getFrameWidth('lr');
45854 height -= this.el.getFrameWidth('tb');
45857 var te = this.toolbar.getEl();
45858 height -= te.getHeight();
45859 te.setWidth(width);
45861 if(this.adjustments){
45862 width += this.adjustments[0];
45863 height += this.adjustments[1];
45865 return {"width": width, "height": height};
45868 setSize : function(width, height){
45869 if(this.fitToFrame && !this.ignoreResize(width, height)){
45870 if(this.fitContainer && this.resizeEl != this.el){
45871 this.el.setSize(width, height);
45873 var size = this.adjustForComponents(width, height);
45874 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
45875 this.fireEvent('resize', this, size.width, size.height);
45880 * Returns this panel's title
45883 getTitle : function(){
45888 * Set this panel's title
45889 * @param {String} title
45891 setTitle : function(title){
45892 this.title = title;
45894 this.region.updatePanelTitle(this, title);
45899 * Returns true is this panel was configured to be closable
45900 * @return {Boolean}
45902 isClosable : function(){
45903 return this.closable;
45906 beforeSlide : function(){
45908 this.resizeEl.clip();
45911 afterSlide : function(){
45913 this.resizeEl.unclip();
45917 * Force a content refresh from the URL specified in the {@link #setUrl} method.
45918 * Will fail silently if the {@link #setUrl} method has not been called.
45919 * This does not activate the panel, just updates its content.
45921 refresh : function(){
45922 if(this.refreshDelegate){
45923 this.loaded = false;
45924 this.refreshDelegate();
45929 * Destroys this panel
45931 destroy : function(){
45932 this.el.removeAllListeners();
45933 var tempEl = document.createElement("span");
45934 tempEl.appendChild(this.el.dom);
45935 tempEl.innerHTML = "";
45941 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
45951 * @param {Object} cfg Xtype definition of item to add.
45954 addxtype : function(cfg) {
45956 if (cfg.xtype.match(/^Form$/)) {
45957 var el = this.el.createChild();
45959 this.form = new Roo.form.Form(cfg);
45962 if ( this.form.allItems.length) this.form.render(el.dom);
45965 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
45967 cfg.el = this.el.appendChild(document.createElement("div"));
45969 var ret = new Roo[cfg.xtype](cfg);
45970 ret.render(false, ''); // render blank..
45980 * @class Roo.GridPanel
45981 * @extends Roo.ContentPanel
45983 * Create a new GridPanel.
45984 * @param {Roo.grid.Grid} grid The grid for this panel
45985 * @param {String/Object} config A string to set only the panel's title, or a config object
45987 Roo.GridPanel = function(grid, config){
45990 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
45991 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
45993 this.wrapper.dom.appendChild(grid.getGridEl().dom);
45995 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
45998 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
46000 // xtype created footer. - not sure if will work as we normally have to render first..
46001 if (this.footer && !this.footer.el && this.footer.xtype) {
46003 this.footer.container = this.grid.getView().getFooterPanel(true);
46004 this.footer.dataSource = this.grid.dataSource;
46005 this.footer = Roo.factory(this.footer, Roo);
46009 grid.monitorWindowResize = false; // turn off autosizing
46010 grid.autoHeight = false;
46011 grid.autoWidth = false;
46013 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
46016 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
46017 getId : function(){
46018 return this.grid.id;
46022 * Returns the grid for this panel
46023 * @return {Roo.grid.Grid}
46025 getGrid : function(){
46029 setSize : function(width, height){
46030 if(!this.ignoreResize(width, height)){
46031 var grid = this.grid;
46032 var size = this.adjustForComponents(width, height);
46033 grid.getGridEl().setSize(size.width, size.height);
46038 beforeSlide : function(){
46039 this.grid.getView().scroller.clip();
46042 afterSlide : function(){
46043 this.grid.getView().scroller.unclip();
46046 destroy : function(){
46047 this.grid.destroy();
46049 Roo.GridPanel.superclass.destroy.call(this);
46055 * @class Roo.NestedLayoutPanel
46056 * @extends Roo.ContentPanel
46058 * Create a new NestedLayoutPanel.
46061 * @param {Roo.BorderLayout} layout The layout for this panel
46062 * @param {String/Object} config A string to set only the title or a config object
46064 Roo.NestedLayoutPanel = function(layout, config)
46066 // construct with only one argument..
46067 /* FIXME - implement nicer consturctors
46068 if (layout.layout) {
46070 layout = config.layout;
46071 delete config.layout;
46073 if (layout.xtype && !layout.getEl) {
46074 // then layout needs constructing..
46075 layout = Roo.factory(layout, Roo);
46080 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
46082 layout.monitorWindowResize = false; // turn off autosizing
46083 this.layout = layout;
46084 this.layout.getEl().addClass("x-layout-nested-layout");
46091 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
46093 setSize : function(width, height){
46094 if(!this.ignoreResize(width, height)){
46095 var size = this.adjustForComponents(width, height);
46096 var el = this.layout.getEl();
46097 el.setSize(size.width, size.height);
46098 var touch = el.dom.offsetWidth;
46099 this.layout.layout();
46100 // ie requires a double layout on the first pass
46101 if(Roo.isIE && !this.initialized){
46102 this.initialized = true;
46103 this.layout.layout();
46108 // activate all subpanels if not currently active..
46110 setActiveState : function(active){
46111 this.active = active;
46113 this.fireEvent("deactivate", this);
46117 this.fireEvent("activate", this);
46118 // not sure if this should happen before or after..
46119 if (!this.layout) {
46120 return; // should not happen..
46123 for (var r in this.layout.regions) {
46124 reg = this.layout.getRegion(r);
46125 if (reg.getActivePanel()) {
46126 //reg.showPanel(reg.getActivePanel()); // force it to activate..
46127 reg.setActivePanel(reg.getActivePanel());
46130 if (!reg.panels.length) {
46133 reg.showPanel(reg.getPanel(0));
46142 * Returns the nested BorderLayout for this panel
46143 * @return {Roo.BorderLayout}
46145 getLayout : function(){
46146 return this.layout;
46150 * Adds a xtype elements to the layout of the nested panel
46154 xtype : 'ContentPanel',
46161 xtype : 'NestedLayoutPanel',
46167 items : [ ... list of content panels or nested layout panels.. ]
46171 * @param {Object} cfg Xtype definition of item to add.
46173 addxtype : function(cfg) {
46174 return this.layout.addxtype(cfg);
46179 Roo.ScrollPanel = function(el, config, content){
46180 config = config || {};
46181 config.fitToFrame = true;
46182 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
46184 this.el.dom.style.overflow = "hidden";
46185 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
46186 this.el.removeClass("x-layout-inactive-content");
46187 this.el.on("mousewheel", this.onWheel, this);
46189 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
46190 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
46191 up.unselectable(); down.unselectable();
46192 up.on("click", this.scrollUp, this);
46193 down.on("click", this.scrollDown, this);
46194 up.addClassOnOver("x-scroller-btn-over");
46195 down.addClassOnOver("x-scroller-btn-over");
46196 up.addClassOnClick("x-scroller-btn-click");
46197 down.addClassOnClick("x-scroller-btn-click");
46198 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
46200 this.resizeEl = this.el;
46201 this.el = wrap; this.up = up; this.down = down;
46204 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
46206 wheelIncrement : 5,
46207 scrollUp : function(){
46208 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
46211 scrollDown : function(){
46212 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
46215 afterScroll : function(){
46216 var el = this.resizeEl;
46217 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
46218 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
46219 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
46222 setSize : function(){
46223 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
46224 this.afterScroll();
46227 onWheel : function(e){
46228 var d = e.getWheelDelta();
46229 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
46230 this.afterScroll();
46234 setContent : function(content, loadScripts){
46235 this.resizeEl.update(content, loadScripts);
46249 * @class Roo.TreePanel
46250 * @extends Roo.ContentPanel
46252 * Create a new TreePanel. - defaults to fit/scoll contents.
46253 * @param {String/Object} config A string to set only the panel's title, or a config object
46254 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
46256 Roo.TreePanel = function(config){
46257 var el = config.el;
46258 var tree = config.tree;
46259 delete config.tree;
46260 delete config.el; // hopefull!
46262 // wrapper for IE7 strict & safari scroll issue
46264 var treeEl = el.createChild();
46265 config.resizeEl = treeEl;
46269 Roo.TreePanel.superclass.constructor.call(this, el, config);
46272 this.tree = new Roo.tree.TreePanel(treeEl , tree);
46273 //console.log(tree);
46274 this.on('activate', function()
46276 if (this.tree.rendered) {
46279 //console.log('render tree');
46280 this.tree.render();
46283 this.on('resize', function (cp, w, h) {
46284 this.tree.innerCt.setWidth(w);
46285 this.tree.innerCt.setHeight(h);
46286 this.tree.innerCt.setStyle('overflow-y', 'auto');
46293 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
46310 * Ext JS Library 1.1.1
46311 * Copyright(c) 2006-2007, Ext JS, LLC.
46313 * Originally Released Under LGPL - original licence link has changed is not relivant.
46316 * <script type="text/javascript">
46321 * @class Roo.ReaderLayout
46322 * @extends Roo.BorderLayout
46323 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
46324 * center region containing two nested regions (a top one for a list view and one for item preview below),
46325 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
46326 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
46327 * expedites the setup of the overall layout and regions for this common application style.
46330 var reader = new Roo.ReaderLayout();
46331 var CP = Roo.ContentPanel; // shortcut for adding
46333 reader.beginUpdate();
46334 reader.add("north", new CP("north", "North"));
46335 reader.add("west", new CP("west", {title: "West"}));
46336 reader.add("east", new CP("east", {title: "East"}));
46338 reader.regions.listView.add(new CP("listView", "List"));
46339 reader.regions.preview.add(new CP("preview", "Preview"));
46340 reader.endUpdate();
46343 * Create a new ReaderLayout
46344 * @param {Object} config Configuration options
46345 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
46346 * document.body if omitted)
46348 Roo.ReaderLayout = function(config, renderTo){
46349 var c = config || {size:{}};
46350 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
46351 north: c.north !== false ? Roo.apply({
46355 }, c.north) : false,
46356 west: c.west !== false ? Roo.apply({
46364 margins:{left:5,right:0,bottom:5,top:5},
46365 cmargins:{left:5,right:5,bottom:5,top:5}
46366 }, c.west) : false,
46367 east: c.east !== false ? Roo.apply({
46375 margins:{left:0,right:5,bottom:5,top:5},
46376 cmargins:{left:5,right:5,bottom:5,top:5}
46377 }, c.east) : false,
46378 center: Roo.apply({
46379 tabPosition: 'top',
46383 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
46387 this.el.addClass('x-reader');
46389 this.beginUpdate();
46391 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
46392 south: c.preview !== false ? Roo.apply({
46399 cmargins:{top:5,left:0, right:0, bottom:0}
46400 }, c.preview) : false,
46401 center: Roo.apply({
46407 this.add('center', new Roo.NestedLayoutPanel(inner,
46408 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
46412 this.regions.preview = inner.getRegion('south');
46413 this.regions.listView = inner.getRegion('center');
46416 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
46418 * Ext JS Library 1.1.1
46419 * Copyright(c) 2006-2007, Ext JS, LLC.
46421 * Originally Released Under LGPL - original licence link has changed is not relivant.
46424 * <script type="text/javascript">
46428 * @class Roo.grid.Grid
46429 * @extends Roo.util.Observable
46430 * This class represents the primary interface of a component based grid control.
46431 * <br><br>Usage:<pre><code>
46432 var grid = new Roo.grid.Grid("my-container-id", {
46435 selModel: mySelectionModel,
46436 autoSizeColumns: true,
46437 monitorWindowResize: false,
46438 trackMouseOver: true
46443 * <b>Common Problems:</b><br/>
46444 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
46445 * element will correct this<br/>
46446 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
46447 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
46448 * are unpredictable.<br/>
46449 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
46450 * grid to calculate dimensions/offsets.<br/>
46452 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
46453 * The container MUST have some type of size defined for the grid to fill. The container will be
46454 * automatically set to position relative if it isn't already.
46455 * @param {Object} config A config object that sets properties on this grid.
46457 Roo.grid.Grid = function(container, config){
46458 // initialize the container
46459 this.container = Roo.get(container);
46460 this.container.update("");
46461 this.container.setStyle("overflow", "hidden");
46462 this.container.addClass('x-grid-container');
46464 this.id = this.container.id;
46466 Roo.apply(this, config);
46467 // check and correct shorthanded configs
46469 this.dataSource = this.ds;
46473 this.colModel = this.cm;
46477 this.selModel = this.sm;
46481 if (this.selModel) {
46482 this.selModel = Roo.factory(this.selModel, Roo.grid);
46483 this.sm = this.selModel;
46484 this.sm.xmodule = this.xmodule || false;
46486 if (typeof(this.colModel.config) == 'undefined') {
46487 this.colModel = new Roo.grid.ColumnModel(this.colModel);
46488 this.cm = this.colModel;
46489 this.cm.xmodule = this.xmodule || false;
46491 if (this.dataSource) {
46492 this.dataSource= Roo.factory(this.dataSource, Roo.data);
46493 this.ds = this.dataSource;
46494 this.ds.xmodule = this.xmodule || false;
46501 this.container.setWidth(this.width);
46505 this.container.setHeight(this.height);
46512 * The raw click event for the entire grid.
46513 * @param {Roo.EventObject} e
46518 * The raw dblclick event for the entire grid.
46519 * @param {Roo.EventObject} e
46523 * @event contextmenu
46524 * The raw contextmenu event for the entire grid.
46525 * @param {Roo.EventObject} e
46527 "contextmenu" : true,
46530 * The raw mousedown event for the entire grid.
46531 * @param {Roo.EventObject} e
46533 "mousedown" : true,
46536 * The raw mouseup event for the entire grid.
46537 * @param {Roo.EventObject} e
46542 * The raw mouseover event for the entire grid.
46543 * @param {Roo.EventObject} e
46545 "mouseover" : true,
46548 * The raw mouseout event for the entire grid.
46549 * @param {Roo.EventObject} e
46554 * The raw keypress event for the entire grid.
46555 * @param {Roo.EventObject} e
46560 * The raw keydown event for the entire grid.
46561 * @param {Roo.EventObject} e
46569 * Fires when a cell is clicked
46570 * @param {Grid} this
46571 * @param {Number} rowIndex
46572 * @param {Number} columnIndex
46573 * @param {Roo.EventObject} e
46575 "cellclick" : true,
46577 * @event celldblclick
46578 * Fires when a cell is double clicked
46579 * @param {Grid} this
46580 * @param {Number} rowIndex
46581 * @param {Number} columnIndex
46582 * @param {Roo.EventObject} e
46584 "celldblclick" : true,
46587 * Fires when a row is clicked
46588 * @param {Grid} this
46589 * @param {Number} rowIndex
46590 * @param {Roo.EventObject} e
46594 * @event rowdblclick
46595 * Fires when a row is double clicked
46596 * @param {Grid} this
46597 * @param {Number} rowIndex
46598 * @param {Roo.EventObject} e
46600 "rowdblclick" : true,
46602 * @event headerclick
46603 * Fires when a header is clicked
46604 * @param {Grid} this
46605 * @param {Number} columnIndex
46606 * @param {Roo.EventObject} e
46608 "headerclick" : true,
46610 * @event headerdblclick
46611 * Fires when a header cell is double clicked
46612 * @param {Grid} this
46613 * @param {Number} columnIndex
46614 * @param {Roo.EventObject} e
46616 "headerdblclick" : true,
46618 * @event rowcontextmenu
46619 * Fires when a row is right clicked
46620 * @param {Grid} this
46621 * @param {Number} rowIndex
46622 * @param {Roo.EventObject} e
46624 "rowcontextmenu" : true,
46626 * @event cellcontextmenu
46627 * Fires when a cell is right clicked
46628 * @param {Grid} this
46629 * @param {Number} rowIndex
46630 * @param {Number} cellIndex
46631 * @param {Roo.EventObject} e
46633 "cellcontextmenu" : true,
46635 * @event headercontextmenu
46636 * Fires when a header is right clicked
46637 * @param {Grid} this
46638 * @param {Number} columnIndex
46639 * @param {Roo.EventObject} e
46641 "headercontextmenu" : true,
46643 * @event bodyscroll
46644 * Fires when the body element is scrolled
46645 * @param {Number} scrollLeft
46646 * @param {Number} scrollTop
46648 "bodyscroll" : true,
46650 * @event columnresize
46651 * Fires when the user resizes a column
46652 * @param {Number} columnIndex
46653 * @param {Number} newSize
46655 "columnresize" : true,
46657 * @event columnmove
46658 * Fires when the user moves a column
46659 * @param {Number} oldIndex
46660 * @param {Number} newIndex
46662 "columnmove" : true,
46665 * Fires when row(s) start being dragged
46666 * @param {Grid} this
46667 * @param {Roo.GridDD} dd The drag drop object
46668 * @param {event} e The raw browser event
46670 "startdrag" : true,
46673 * Fires when a drag operation is complete
46674 * @param {Grid} this
46675 * @param {Roo.GridDD} dd The drag drop object
46676 * @param {event} e The raw browser event
46681 * Fires when dragged row(s) are dropped on a valid DD target
46682 * @param {Grid} this
46683 * @param {Roo.GridDD} dd The drag drop object
46684 * @param {String} targetId The target drag drop object
46685 * @param {event} e The raw browser event
46690 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
46691 * @param {Grid} this
46692 * @param {Roo.GridDD} dd The drag drop object
46693 * @param {String} targetId The target drag drop object
46694 * @param {event} e The raw browser event
46699 * Fires when the dragged row(s) first cross another DD target while being dragged
46700 * @param {Grid} this
46701 * @param {Roo.GridDD} dd The drag drop object
46702 * @param {String} targetId The target drag drop object
46703 * @param {event} e The raw browser event
46705 "dragenter" : true,
46708 * Fires when the dragged row(s) leave another DD target while being dragged
46709 * @param {Grid} this
46710 * @param {Roo.GridDD} dd The drag drop object
46711 * @param {String} targetId The target drag drop object
46712 * @param {event} e The raw browser event
46717 * Fires when a row is rendered, so you can change add a style to it.
46718 * @param {GridView} gridview The grid view
46719 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
46725 * Fires when the grid is rendered
46726 * @param {Grid} grid
46731 Roo.grid.Grid.superclass.constructor.call(this);
46733 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
46736 * @cfg {String} ddGroup - drag drop group.
46740 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
46742 minColumnWidth : 25,
46745 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
46746 * <b>on initial render.</b> It is more efficient to explicitly size the columns
46747 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
46749 autoSizeColumns : false,
46752 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
46754 autoSizeHeaders : true,
46757 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
46759 monitorWindowResize : true,
46762 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
46763 * rows measured to get a columns size. Default is 0 (all rows).
46765 maxRowsToMeasure : 0,
46768 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
46770 trackMouseOver : true,
46773 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
46777 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
46779 enableDragDrop : false,
46782 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
46784 enableColumnMove : true,
46787 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
46789 enableColumnHide : true,
46792 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
46794 enableRowHeightSync : false,
46797 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
46802 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
46804 autoHeight : false,
46807 * @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.
46809 autoExpandColumn : false,
46812 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
46815 autoExpandMin : 50,
46818 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
46820 autoExpandMax : 1000,
46823 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
46828 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
46832 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
46842 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
46843 * of a fixed width. Default is false.
46846 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
46849 * Called once after all setup has been completed and the grid is ready to be rendered.
46850 * @return {Roo.grid.Grid} this
46852 render : function()
46854 var c = this.container;
46855 // try to detect autoHeight/width mode
46856 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
46857 this.autoHeight = true;
46859 var view = this.getView();
46862 c.on("click", this.onClick, this);
46863 c.on("dblclick", this.onDblClick, this);
46864 c.on("contextmenu", this.onContextMenu, this);
46865 c.on("keydown", this.onKeyDown, this);
46867 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
46869 this.getSelectionModel().init(this);
46874 this.loadMask = new Roo.LoadMask(this.container,
46875 Roo.apply({store:this.dataSource}, this.loadMask));
46879 if (this.toolbar && this.toolbar.xtype) {
46880 this.toolbar.container = this.getView().getHeaderPanel(true);
46881 this.toolbar = new Roo.Toolbar(this.toolbar);
46883 if (this.footer && this.footer.xtype) {
46884 this.footer.dataSource = this.getDataSource();
46885 this.footer.container = this.getView().getFooterPanel(true);
46886 this.footer = Roo.factory(this.footer, Roo);
46888 if (this.dropTarget && this.dropTarget.xtype) {
46889 delete this.dropTarget.xtype;
46890 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
46894 this.rendered = true;
46895 this.fireEvent('render', this);
46900 * Reconfigures the grid to use a different Store and Column Model.
46901 * The View will be bound to the new objects and refreshed.
46902 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
46903 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
46905 reconfigure : function(dataSource, colModel){
46907 this.loadMask.destroy();
46908 this.loadMask = new Roo.LoadMask(this.container,
46909 Roo.apply({store:dataSource}, this.loadMask));
46911 this.view.bind(dataSource, colModel);
46912 this.dataSource = dataSource;
46913 this.colModel = colModel;
46914 this.view.refresh(true);
46918 onKeyDown : function(e){
46919 this.fireEvent("keydown", e);
46923 * Destroy this grid.
46924 * @param {Boolean} removeEl True to remove the element
46926 destroy : function(removeEl, keepListeners){
46928 this.loadMask.destroy();
46930 var c = this.container;
46931 c.removeAllListeners();
46932 this.view.destroy();
46933 this.colModel.purgeListeners();
46934 if(!keepListeners){
46935 this.purgeListeners();
46938 if(removeEl === true){
46944 processEvent : function(name, e){
46945 this.fireEvent(name, e);
46946 var t = e.getTarget();
46948 var header = v.findHeaderIndex(t);
46949 if(header !== false){
46950 this.fireEvent("header" + name, this, header, e);
46952 var row = v.findRowIndex(t);
46953 var cell = v.findCellIndex(t);
46955 this.fireEvent("row" + name, this, row, e);
46956 if(cell !== false){
46957 this.fireEvent("cell" + name, this, row, cell, e);
46964 onClick : function(e){
46965 this.processEvent("click", e);
46969 onContextMenu : function(e, t){
46970 this.processEvent("contextmenu", e);
46974 onDblClick : function(e){
46975 this.processEvent("dblclick", e);
46979 walkCells : function(row, col, step, fn, scope){
46980 var cm = this.colModel, clen = cm.getColumnCount();
46981 var ds = this.dataSource, rlen = ds.getCount(), first = true;
46993 if(fn.call(scope || this, row, col, cm) === true){
47011 if(fn.call(scope || this, row, col, cm) === true){
47023 getSelections : function(){
47024 return this.selModel.getSelections();
47028 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
47029 * but if manual update is required this method will initiate it.
47031 autoSize : function(){
47033 this.view.layout();
47034 if(this.view.adjustForScroll){
47035 this.view.adjustForScroll();
47041 * Returns the grid's underlying element.
47042 * @return {Element} The element
47044 getGridEl : function(){
47045 return this.container;
47048 // private for compatibility, overridden by editor grid
47049 stopEditing : function(){},
47052 * Returns the grid's SelectionModel.
47053 * @return {SelectionModel}
47055 getSelectionModel : function(){
47056 if(!this.selModel){
47057 this.selModel = new Roo.grid.RowSelectionModel();
47059 return this.selModel;
47063 * Returns the grid's DataSource.
47064 * @return {DataSource}
47066 getDataSource : function(){
47067 return this.dataSource;
47071 * Returns the grid's ColumnModel.
47072 * @return {ColumnModel}
47074 getColumnModel : function(){
47075 return this.colModel;
47079 * Returns the grid's GridView object.
47080 * @return {GridView}
47082 getView : function(){
47084 this.view = new Roo.grid.GridView(this.viewConfig);
47089 * Called to get grid's drag proxy text, by default returns this.ddText.
47092 getDragDropText : function(){
47093 var count = this.selModel.getCount();
47094 return String.format(this.ddText, count, count == 1 ? '' : 's');
47098 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
47099 * %0 is replaced with the number of selected rows.
47102 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
47104 * Ext JS Library 1.1.1
47105 * Copyright(c) 2006-2007, Ext JS, LLC.
47107 * Originally Released Under LGPL - original licence link has changed is not relivant.
47110 * <script type="text/javascript">
47113 Roo.grid.AbstractGridView = function(){
47117 "beforerowremoved" : true,
47118 "beforerowsinserted" : true,
47119 "beforerefresh" : true,
47120 "rowremoved" : true,
47121 "rowsinserted" : true,
47122 "rowupdated" : true,
47125 Roo.grid.AbstractGridView.superclass.constructor.call(this);
47128 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
47129 rowClass : "x-grid-row",
47130 cellClass : "x-grid-cell",
47131 tdClass : "x-grid-td",
47132 hdClass : "x-grid-hd",
47133 splitClass : "x-grid-hd-split",
47135 init: function(grid){
47137 var cid = this.grid.getGridEl().id;
47138 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
47139 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
47140 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
47141 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
47144 getColumnRenderers : function(){
47145 var renderers = [];
47146 var cm = this.grid.colModel;
47147 var colCount = cm.getColumnCount();
47148 for(var i = 0; i < colCount; i++){
47149 renderers[i] = cm.getRenderer(i);
47154 getColumnIds : function(){
47156 var cm = this.grid.colModel;
47157 var colCount = cm.getColumnCount();
47158 for(var i = 0; i < colCount; i++){
47159 ids[i] = cm.getColumnId(i);
47164 getDataIndexes : function(){
47165 if(!this.indexMap){
47166 this.indexMap = this.buildIndexMap();
47168 return this.indexMap.colToData;
47171 getColumnIndexByDataIndex : function(dataIndex){
47172 if(!this.indexMap){
47173 this.indexMap = this.buildIndexMap();
47175 return this.indexMap.dataToCol[dataIndex];
47179 * Set a css style for a column dynamically.
47180 * @param {Number} colIndex The index of the column
47181 * @param {String} name The css property name
47182 * @param {String} value The css value
47184 setCSSStyle : function(colIndex, name, value){
47185 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
47186 Roo.util.CSS.updateRule(selector, name, value);
47189 generateRules : function(cm){
47190 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
47191 Roo.util.CSS.removeStyleSheet(rulesId);
47192 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47193 var cid = cm.getColumnId(i);
47194 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
47195 this.tdSelector, cid, " {\n}\n",
47196 this.hdSelector, cid, " {\n}\n",
47197 this.splitSelector, cid, " {\n}\n");
47199 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
47203 * Ext JS Library 1.1.1
47204 * Copyright(c) 2006-2007, Ext JS, LLC.
47206 * Originally Released Under LGPL - original licence link has changed is not relivant.
47209 * <script type="text/javascript">
47213 // This is a support class used internally by the Grid components
47214 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
47216 this.view = grid.getView();
47217 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
47218 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
47220 this.setHandleElId(Roo.id(hd));
47221 this.setOuterHandleElId(Roo.id(hd2));
47223 this.scroll = false;
47225 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
47227 getDragData : function(e){
47228 var t = Roo.lib.Event.getTarget(e);
47229 var h = this.view.findHeaderCell(t);
47231 return {ddel: h.firstChild, header:h};
47236 onInitDrag : function(e){
47237 this.view.headersDisabled = true;
47238 var clone = this.dragData.ddel.cloneNode(true);
47239 clone.id = Roo.id();
47240 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
47241 this.proxy.update(clone);
47245 afterValidDrop : function(){
47247 setTimeout(function(){
47248 v.headersDisabled = false;
47252 afterInvalidDrop : function(){
47254 setTimeout(function(){
47255 v.headersDisabled = false;
47261 * Ext JS Library 1.1.1
47262 * Copyright(c) 2006-2007, Ext JS, LLC.
47264 * Originally Released Under LGPL - original licence link has changed is not relivant.
47267 * <script type="text/javascript">
47270 // This is a support class used internally by the Grid components
47271 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
47273 this.view = grid.getView();
47274 // split the proxies so they don't interfere with mouse events
47275 this.proxyTop = Roo.DomHelper.append(document.body, {
47276 cls:"col-move-top", html:" "
47278 this.proxyBottom = Roo.DomHelper.append(document.body, {
47279 cls:"col-move-bottom", html:" "
47281 this.proxyTop.hide = this.proxyBottom.hide = function(){
47282 this.setLeftTop(-100,-100);
47283 this.setStyle("visibility", "hidden");
47285 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
47286 // temporarily disabled
47287 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
47288 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
47290 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
47291 proxyOffsets : [-4, -9],
47292 fly: Roo.Element.fly,
47294 getTargetFromEvent : function(e){
47295 var t = Roo.lib.Event.getTarget(e);
47296 var cindex = this.view.findCellIndex(t);
47297 if(cindex !== false){
47298 return this.view.getHeaderCell(cindex);
47303 nextVisible : function(h){
47304 var v = this.view, cm = this.grid.colModel;
47307 if(!cm.isHidden(v.getCellIndex(h))){
47315 prevVisible : function(h){
47316 var v = this.view, cm = this.grid.colModel;
47319 if(!cm.isHidden(v.getCellIndex(h))){
47327 positionIndicator : function(h, n, e){
47328 var x = Roo.lib.Event.getPageX(e);
47329 var r = Roo.lib.Dom.getRegion(n.firstChild);
47330 var px, pt, py = r.top + this.proxyOffsets[1];
47331 if((r.right - x) <= (r.right-r.left)/2){
47332 px = r.right+this.view.borderWidth;
47338 var oldIndex = this.view.getCellIndex(h);
47339 var newIndex = this.view.getCellIndex(n);
47341 if(this.grid.colModel.isFixed(newIndex)){
47345 var locked = this.grid.colModel.isLocked(newIndex);
47350 if(oldIndex < newIndex){
47353 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
47356 px += this.proxyOffsets[0];
47357 this.proxyTop.setLeftTop(px, py);
47358 this.proxyTop.show();
47359 if(!this.bottomOffset){
47360 this.bottomOffset = this.view.mainHd.getHeight();
47362 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
47363 this.proxyBottom.show();
47367 onNodeEnter : function(n, dd, e, data){
47368 if(data.header != n){
47369 this.positionIndicator(data.header, n, e);
47373 onNodeOver : function(n, dd, e, data){
47374 var result = false;
47375 if(data.header != n){
47376 result = this.positionIndicator(data.header, n, e);
47379 this.proxyTop.hide();
47380 this.proxyBottom.hide();
47382 return result ? this.dropAllowed : this.dropNotAllowed;
47385 onNodeOut : function(n, dd, e, data){
47386 this.proxyTop.hide();
47387 this.proxyBottom.hide();
47390 onNodeDrop : function(n, dd, e, data){
47391 var h = data.header;
47393 var cm = this.grid.colModel;
47394 var x = Roo.lib.Event.getPageX(e);
47395 var r = Roo.lib.Dom.getRegion(n.firstChild);
47396 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
47397 var oldIndex = this.view.getCellIndex(h);
47398 var newIndex = this.view.getCellIndex(n);
47399 var locked = cm.isLocked(newIndex);
47403 if(oldIndex < newIndex){
47406 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
47409 cm.setLocked(oldIndex, locked, true);
47410 cm.moveColumn(oldIndex, newIndex);
47411 this.grid.fireEvent("columnmove", oldIndex, newIndex);
47419 * Ext JS Library 1.1.1
47420 * Copyright(c) 2006-2007, Ext JS, LLC.
47422 * Originally Released Under LGPL - original licence link has changed is not relivant.
47425 * <script type="text/javascript">
47429 * @class Roo.grid.GridView
47430 * @extends Roo.util.Observable
47433 * @param {Object} config
47435 Roo.grid.GridView = function(config){
47436 Roo.grid.GridView.superclass.constructor.call(this);
47439 Roo.apply(this, config);
47442 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
47445 * Override this function to apply custom css classes to rows during rendering
47446 * @param {Record} record The record
47447 * @param {Number} index
47448 * @method getRowClass
47450 rowClass : "x-grid-row",
47452 cellClass : "x-grid-col",
47454 tdClass : "x-grid-td",
47456 hdClass : "x-grid-hd",
47458 splitClass : "x-grid-split",
47460 sortClasses : ["sort-asc", "sort-desc"],
47462 enableMoveAnim : false,
47466 dh : Roo.DomHelper,
47468 fly : Roo.Element.fly,
47470 css : Roo.util.CSS,
47476 scrollIncrement : 22,
47478 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
47480 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
47482 bind : function(ds, cm){
47484 this.ds.un("load", this.onLoad, this);
47485 this.ds.un("datachanged", this.onDataChange, this);
47486 this.ds.un("add", this.onAdd, this);
47487 this.ds.un("remove", this.onRemove, this);
47488 this.ds.un("update", this.onUpdate, this);
47489 this.ds.un("clear", this.onClear, this);
47492 ds.on("load", this.onLoad, this);
47493 ds.on("datachanged", this.onDataChange, this);
47494 ds.on("add", this.onAdd, this);
47495 ds.on("remove", this.onRemove, this);
47496 ds.on("update", this.onUpdate, this);
47497 ds.on("clear", this.onClear, this);
47502 this.cm.un("widthchange", this.onColWidthChange, this);
47503 this.cm.un("headerchange", this.onHeaderChange, this);
47504 this.cm.un("hiddenchange", this.onHiddenChange, this);
47505 this.cm.un("columnmoved", this.onColumnMove, this);
47506 this.cm.un("columnlockchange", this.onColumnLock, this);
47509 this.generateRules(cm);
47510 cm.on("widthchange", this.onColWidthChange, this);
47511 cm.on("headerchange", this.onHeaderChange, this);
47512 cm.on("hiddenchange", this.onHiddenChange, this);
47513 cm.on("columnmoved", this.onColumnMove, this);
47514 cm.on("columnlockchange", this.onColumnLock, this);
47519 init: function(grid){
47520 Roo.grid.GridView.superclass.init.call(this, grid);
47522 this.bind(grid.dataSource, grid.colModel);
47524 grid.on("headerclick", this.handleHeaderClick, this);
47526 if(grid.trackMouseOver){
47527 grid.on("mouseover", this.onRowOver, this);
47528 grid.on("mouseout", this.onRowOut, this);
47530 grid.cancelTextSelection = function(){};
47531 this.gridId = grid.id;
47533 var tpls = this.templates || {};
47536 tpls.master = new Roo.Template(
47537 '<div class="x-grid" hidefocus="true">',
47538 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
47539 '<div class="x-grid-topbar"></div>',
47540 '<div class="x-grid-scroller"><div></div></div>',
47541 '<div class="x-grid-locked">',
47542 '<div class="x-grid-header">{lockedHeader}</div>',
47543 '<div class="x-grid-body">{lockedBody}</div>',
47545 '<div class="x-grid-viewport">',
47546 '<div class="x-grid-header">{header}</div>',
47547 '<div class="x-grid-body">{body}</div>',
47549 '<div class="x-grid-bottombar"></div>',
47551 '<div class="x-grid-resize-proxy"> </div>',
47554 tpls.master.disableformats = true;
47558 tpls.header = new Roo.Template(
47559 '<table border="0" cellspacing="0" cellpadding="0">',
47560 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
47563 tpls.header.disableformats = true;
47565 tpls.header.compile();
47568 tpls.hcell = new Roo.Template(
47569 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
47570 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
47573 tpls.hcell.disableFormats = true;
47575 tpls.hcell.compile();
47578 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
47579 tpls.hsplit.disableFormats = true;
47581 tpls.hsplit.compile();
47584 tpls.body = new Roo.Template(
47585 '<table border="0" cellspacing="0" cellpadding="0">',
47586 "<tbody>{rows}</tbody>",
47589 tpls.body.disableFormats = true;
47591 tpls.body.compile();
47594 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
47595 tpls.row.disableFormats = true;
47597 tpls.row.compile();
47600 tpls.cell = new Roo.Template(
47601 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
47602 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
47605 tpls.cell.disableFormats = true;
47607 tpls.cell.compile();
47609 this.templates = tpls;
47612 // remap these for backwards compat
47613 onColWidthChange : function(){
47614 this.updateColumns.apply(this, arguments);
47616 onHeaderChange : function(){
47617 this.updateHeaders.apply(this, arguments);
47619 onHiddenChange : function(){
47620 this.handleHiddenChange.apply(this, arguments);
47622 onColumnMove : function(){
47623 this.handleColumnMove.apply(this, arguments);
47625 onColumnLock : function(){
47626 this.handleLockChange.apply(this, arguments);
47629 onDataChange : function(){
47631 this.updateHeaderSortState();
47634 onClear : function(){
47638 onUpdate : function(ds, record){
47639 this.refreshRow(record);
47642 refreshRow : function(record){
47643 var ds = this.ds, index;
47644 if(typeof record == 'number'){
47646 record = ds.getAt(index);
47648 index = ds.indexOf(record);
47650 this.insertRows(ds, index, index, true);
47651 this.onRemove(ds, record, index+1, true);
47652 this.syncRowHeights(index, index);
47654 this.fireEvent("rowupdated", this, index, record);
47657 onAdd : function(ds, records, index){
47658 this.insertRows(ds, index, index + (records.length-1));
47661 onRemove : function(ds, record, index, isUpdate){
47662 if(isUpdate !== true){
47663 this.fireEvent("beforerowremoved", this, index, record);
47665 var bt = this.getBodyTable(), lt = this.getLockedTable();
47666 if(bt.rows[index]){
47667 bt.firstChild.removeChild(bt.rows[index]);
47669 if(lt.rows[index]){
47670 lt.firstChild.removeChild(lt.rows[index]);
47672 if(isUpdate !== true){
47673 this.stripeRows(index);
47674 this.syncRowHeights(index, index);
47676 this.fireEvent("rowremoved", this, index, record);
47680 onLoad : function(){
47681 this.scrollToTop();
47685 * Scrolls the grid to the top
47687 scrollToTop : function(){
47689 this.scroller.dom.scrollTop = 0;
47695 * Gets a panel in the header of the grid that can be used for toolbars etc.
47696 * After modifying the contents of this panel a call to grid.autoSize() may be
47697 * required to register any changes in size.
47698 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
47699 * @return Roo.Element
47701 getHeaderPanel : function(doShow){
47703 this.headerPanel.show();
47705 return this.headerPanel;
47709 * Gets a panel in the footer of the grid that can be used for toolbars etc.
47710 * After modifying the contents of this panel a call to grid.autoSize() may be
47711 * required to register any changes in size.
47712 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
47713 * @return Roo.Element
47715 getFooterPanel : function(doShow){
47717 this.footerPanel.show();
47719 return this.footerPanel;
47722 initElements : function(){
47723 var E = Roo.Element;
47724 var el = this.grid.getGridEl().dom.firstChild;
47725 var cs = el.childNodes;
47727 this.el = new E(el);
47729 this.focusEl = new E(el.firstChild);
47730 this.focusEl.swallowEvent("click", true);
47732 this.headerPanel = new E(cs[1]);
47733 this.headerPanel.enableDisplayMode("block");
47735 this.scroller = new E(cs[2]);
47736 this.scrollSizer = new E(this.scroller.dom.firstChild);
47738 this.lockedWrap = new E(cs[3]);
47739 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
47740 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
47742 this.mainWrap = new E(cs[4]);
47743 this.mainHd = new E(this.mainWrap.dom.firstChild);
47744 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
47746 this.footerPanel = new E(cs[5]);
47747 this.footerPanel.enableDisplayMode("block");
47749 this.resizeProxy = new E(cs[6]);
47751 this.headerSelector = String.format(
47752 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
47753 this.lockedHd.id, this.mainHd.id
47756 this.splitterSelector = String.format(
47757 '#{0} div.x-grid-split, #{1} div.x-grid-split',
47758 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
47761 idToCssName : function(s)
47763 return s.replace(/[^a-z0-9]+/ig, '-');
47766 getHeaderCell : function(index){
47767 return Roo.DomQuery.select(this.headerSelector)[index];
47770 getHeaderCellMeasure : function(index){
47771 return this.getHeaderCell(index).firstChild;
47774 getHeaderCellText : function(index){
47775 return this.getHeaderCell(index).firstChild.firstChild;
47778 getLockedTable : function(){
47779 return this.lockedBody.dom.firstChild;
47782 getBodyTable : function(){
47783 return this.mainBody.dom.firstChild;
47786 getLockedRow : function(index){
47787 return this.getLockedTable().rows[index];
47790 getRow : function(index){
47791 return this.getBodyTable().rows[index];
47794 getRowComposite : function(index){
47796 this.rowEl = new Roo.CompositeElementLite();
47798 var els = [], lrow, mrow;
47799 if(lrow = this.getLockedRow(index)){
47802 if(mrow = this.getRow(index)){
47805 this.rowEl.elements = els;
47809 getCell : function(rowIndex, colIndex){
47810 var locked = this.cm.getLockedCount();
47812 if(colIndex < locked){
47813 source = this.lockedBody.dom.firstChild;
47815 source = this.mainBody.dom.firstChild;
47816 colIndex -= locked;
47818 return source.rows[rowIndex].childNodes[colIndex];
47821 getCellText : function(rowIndex, colIndex){
47822 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
47825 getCellBox : function(cell){
47826 var b = this.fly(cell).getBox();
47827 if(Roo.isOpera){ // opera fails to report the Y
47828 b.y = cell.offsetTop + this.mainBody.getY();
47833 getCellIndex : function(cell){
47834 var id = String(cell.className).match(this.cellRE);
47836 return parseInt(id[1], 10);
47841 findHeaderIndex : function(n){
47842 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47843 return r ? this.getCellIndex(r) : false;
47846 findHeaderCell : function(n){
47847 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47848 return r ? r : false;
47851 findRowIndex : function(n){
47855 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
47856 return r ? r.rowIndex : false;
47859 findCellIndex : function(node){
47860 var stop = this.el.dom;
47861 while(node && node != stop){
47862 if(this.findRE.test(node.className)){
47863 return this.getCellIndex(node);
47865 node = node.parentNode;
47870 getColumnId : function(index){
47871 return this.cm.getColumnId(index);
47874 getSplitters : function()
47876 if(this.splitterSelector){
47877 return Roo.DomQuery.select(this.splitterSelector);
47883 getSplitter : function(index){
47884 return this.getSplitters()[index];
47887 onRowOver : function(e, t){
47889 if((row = this.findRowIndex(t)) !== false){
47890 this.getRowComposite(row).addClass("x-grid-row-over");
47894 onRowOut : function(e, t){
47896 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
47897 this.getRowComposite(row).removeClass("x-grid-row-over");
47901 renderHeaders : function(){
47903 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
47904 var cb = [], lb = [], sb = [], lsb = [], p = {};
47905 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47906 p.cellId = "x-grid-hd-0-" + i;
47907 p.splitId = "x-grid-csplit-0-" + i;
47908 p.id = cm.getColumnId(i);
47909 p.title = cm.getColumnTooltip(i) || "";
47910 p.value = cm.getColumnHeader(i) || "";
47911 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
47912 if(!cm.isLocked(i)){
47913 cb[cb.length] = ct.apply(p);
47914 sb[sb.length] = st.apply(p);
47916 lb[lb.length] = ct.apply(p);
47917 lsb[lsb.length] = st.apply(p);
47920 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
47921 ht.apply({cells: cb.join(""), splits:sb.join("")})];
47924 updateHeaders : function(){
47925 var html = this.renderHeaders();
47926 this.lockedHd.update(html[0]);
47927 this.mainHd.update(html[1]);
47931 * Focuses the specified row.
47932 * @param {Number} row The row index
47934 focusRow : function(row)
47936 //Roo.log('GridView.focusRow');
47937 var x = this.scroller.dom.scrollLeft;
47938 this.focusCell(row, 0, false);
47939 this.scroller.dom.scrollLeft = x;
47943 * Focuses the specified cell.
47944 * @param {Number} row The row index
47945 * @param {Number} col The column index
47946 * @param {Boolean} hscroll false to disable horizontal scrolling
47948 focusCell : function(row, col, hscroll)
47950 //Roo.log('GridView.focusCell');
47951 var el = this.ensureVisible(row, col, hscroll);
47952 this.focusEl.alignTo(el, "tl-tl");
47954 this.focusEl.focus();
47956 this.focusEl.focus.defer(1, this.focusEl);
47961 * Scrolls the specified cell into view
47962 * @param {Number} row The row index
47963 * @param {Number} col The column index
47964 * @param {Boolean} hscroll false to disable horizontal scrolling
47966 ensureVisible : function(row, col, hscroll)
47968 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
47969 //return null; //disable for testing.
47970 if(typeof row != "number"){
47971 row = row.rowIndex;
47973 if(row < 0 && row >= this.ds.getCount()){
47976 col = (col !== undefined ? col : 0);
47977 var cm = this.grid.colModel;
47978 while(cm.isHidden(col)){
47982 var el = this.getCell(row, col);
47986 var c = this.scroller.dom;
47988 var ctop = parseInt(el.offsetTop, 10);
47989 var cleft = parseInt(el.offsetLeft, 10);
47990 var cbot = ctop + el.offsetHeight;
47991 var cright = cleft + el.offsetWidth;
47993 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
47994 var stop = parseInt(c.scrollTop, 10);
47995 var sleft = parseInt(c.scrollLeft, 10);
47996 var sbot = stop + ch;
47997 var sright = sleft + c.clientWidth;
47999 Roo.log('GridView.ensureVisible:' +
48001 ' c.clientHeight:' + c.clientHeight +
48002 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
48010 c.scrollTop = ctop;
48011 //Roo.log("set scrolltop to ctop DISABLE?");
48012 }else if(cbot > sbot){
48013 //Roo.log("set scrolltop to cbot-ch");
48014 c.scrollTop = cbot-ch;
48017 if(hscroll !== false){
48019 c.scrollLeft = cleft;
48020 }else if(cright > sright){
48021 c.scrollLeft = cright-c.clientWidth;
48028 updateColumns : function(){
48029 this.grid.stopEditing();
48030 var cm = this.grid.colModel, colIds = this.getColumnIds();
48031 //var totalWidth = cm.getTotalWidth();
48033 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48034 //if(cm.isHidden(i)) continue;
48035 var w = cm.getColumnWidth(i);
48036 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48037 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48039 this.updateSplitters();
48042 generateRules : function(cm){
48043 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
48044 Roo.util.CSS.removeStyleSheet(rulesId);
48045 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48046 var cid = cm.getColumnId(i);
48048 if(cm.config[i].align){
48049 align = 'text-align:'+cm.config[i].align+';';
48052 if(cm.isHidden(i)){
48053 hidden = 'display:none;';
48055 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
48057 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
48058 this.hdSelector, cid, " {\n", align, width, "}\n",
48059 this.tdSelector, cid, " {\n",hidden,"\n}\n",
48060 this.splitSelector, cid, " {\n", hidden , "\n}\n");
48062 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
48065 updateSplitters : function(){
48066 var cm = this.cm, s = this.getSplitters();
48067 if(s){ // splitters not created yet
48068 var pos = 0, locked = true;
48069 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48070 if(cm.isHidden(i)) continue;
48071 var w = cm.getColumnWidth(i); // make sure it's a number
48072 if(!cm.isLocked(i) && locked){
48077 s[i].style.left = (pos-this.splitOffset) + "px";
48082 handleHiddenChange : function(colModel, colIndex, hidden){
48084 this.hideColumn(colIndex);
48086 this.unhideColumn(colIndex);
48090 hideColumn : function(colIndex){
48091 var cid = this.getColumnId(colIndex);
48092 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
48093 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
48095 this.updateHeaders();
48097 this.updateSplitters();
48101 unhideColumn : function(colIndex){
48102 var cid = this.getColumnId(colIndex);
48103 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
48104 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
48107 this.updateHeaders();
48109 this.updateSplitters();
48113 insertRows : function(dm, firstRow, lastRow, isUpdate){
48114 if(firstRow == 0 && lastRow == dm.getCount()-1){
48118 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
48120 var s = this.getScrollState();
48121 var markup = this.renderRows(firstRow, lastRow);
48122 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
48123 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
48124 this.restoreScroll(s);
48126 this.fireEvent("rowsinserted", this, firstRow, lastRow);
48127 this.syncRowHeights(firstRow, lastRow);
48128 this.stripeRows(firstRow);
48134 bufferRows : function(markup, target, index){
48135 var before = null, trows = target.rows, tbody = target.tBodies[0];
48136 if(index < trows.length){
48137 before = trows[index];
48139 var b = document.createElement("div");
48140 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
48141 var rows = b.firstChild.rows;
48142 for(var i = 0, len = rows.length; i < len; i++){
48144 tbody.insertBefore(rows[0], before);
48146 tbody.appendChild(rows[0]);
48153 deleteRows : function(dm, firstRow, lastRow){
48154 if(dm.getRowCount()<1){
48155 this.fireEvent("beforerefresh", this);
48156 this.mainBody.update("");
48157 this.lockedBody.update("");
48158 this.fireEvent("refresh", this);
48160 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
48161 var bt = this.getBodyTable();
48162 var tbody = bt.firstChild;
48163 var rows = bt.rows;
48164 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
48165 tbody.removeChild(rows[firstRow]);
48167 this.stripeRows(firstRow);
48168 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
48172 updateRows : function(dataSource, firstRow, lastRow){
48173 var s = this.getScrollState();
48175 this.restoreScroll(s);
48178 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
48182 this.updateHeaderSortState();
48185 getScrollState : function(){
48187 var sb = this.scroller.dom;
48188 return {left: sb.scrollLeft, top: sb.scrollTop};
48191 stripeRows : function(startRow){
48192 if(!this.grid.stripeRows || this.ds.getCount() < 1){
48195 startRow = startRow || 0;
48196 var rows = this.getBodyTable().rows;
48197 var lrows = this.getLockedTable().rows;
48198 var cls = ' x-grid-row-alt ';
48199 for(var i = startRow, len = rows.length; i < len; i++){
48200 var row = rows[i], lrow = lrows[i];
48201 var isAlt = ((i+1) % 2 == 0);
48202 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
48203 if(isAlt == hasAlt){
48207 row.className += " x-grid-row-alt";
48209 row.className = row.className.replace("x-grid-row-alt", "");
48212 lrow.className = row.className;
48217 restoreScroll : function(state){
48218 //Roo.log('GridView.restoreScroll');
48219 var sb = this.scroller.dom;
48220 sb.scrollLeft = state.left;
48221 sb.scrollTop = state.top;
48225 syncScroll : function(){
48226 //Roo.log('GridView.syncScroll');
48227 var sb = this.scroller.dom;
48228 var sh = this.mainHd.dom;
48229 var bs = this.mainBody.dom;
48230 var lv = this.lockedBody.dom;
48231 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
48232 lv.scrollTop = bs.scrollTop = sb.scrollTop;
48235 handleScroll : function(e){
48237 var sb = this.scroller.dom;
48238 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
48242 handleWheel : function(e){
48243 var d = e.getWheelDelta();
48244 this.scroller.dom.scrollTop -= d*22;
48245 // set this here to prevent jumpy scrolling on large tables
48246 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
48250 renderRows : function(startRow, endRow){
48251 // pull in all the crap needed to render rows
48252 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
48253 var colCount = cm.getColumnCount();
48255 if(ds.getCount() < 1){
48259 // build a map for all the columns
48261 for(var i = 0; i < colCount; i++){
48262 var name = cm.getDataIndex(i);
48264 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
48265 renderer : cm.getRenderer(i),
48266 id : cm.getColumnId(i),
48267 locked : cm.isLocked(i)
48271 startRow = startRow || 0;
48272 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
48274 // records to render
48275 var rs = ds.getRange(startRow, endRow);
48277 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
48280 // As much as I hate to duplicate code, this was branched because FireFox really hates
48281 // [].join("") on strings. The performance difference was substantial enough to
48282 // branch this function
48283 doRender : Roo.isGecko ?
48284 function(cs, rs, ds, startRow, colCount, stripe){
48285 var ts = this.templates, ct = ts.cell, rt = ts.row;
48287 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
48289 var hasListener = this.grid.hasListener('rowclass');
48291 for(var j = 0, len = rs.length; j < len; j++){
48292 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
48293 for(var i = 0; i < colCount; i++){
48295 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
48297 p.css = p.attr = "";
48298 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
48299 if(p.value == undefined || p.value === "") p.value = " ";
48300 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
48301 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
48303 var markup = ct.apply(p);
48311 if(stripe && ((rowIndex+1) % 2 == 0)){
48312 alt.push("x-grid-row-alt")
48315 alt.push( " x-grid-dirty-row");
48318 if(this.getRowClass){
48319 alt.push(this.getRowClass(r, rowIndex));
48325 rowIndex : rowIndex,
48328 this.grid.fireEvent('rowclass', this, rowcfg);
48329 alt.push(rowcfg.rowClass);
48331 rp.alt = alt.join(" ");
48332 lbuf+= rt.apply(rp);
48334 buf+= rt.apply(rp);
48336 return [lbuf, buf];
48338 function(cs, rs, ds, startRow, colCount, stripe){
48339 var ts = this.templates, ct = ts.cell, rt = ts.row;
48341 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
48342 var hasListener = this.grid.hasListener('rowclass');
48344 for(var j = 0, len = rs.length; j < len; j++){
48345 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
48346 for(var i = 0; i < colCount; i++){
48348 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
48350 p.css = p.attr = "";
48351 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
48352 if(p.value == undefined || p.value === "") p.value = " ";
48353 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
48354 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
48356 var markup = ct.apply(p);
48358 cb[cb.length] = markup;
48360 lcb[lcb.length] = markup;
48364 if(stripe && ((rowIndex+1) % 2 == 0)){
48365 alt.push( "x-grid-row-alt");
48368 alt.push(" x-grid-dirty-row");
48371 if(this.getRowClass){
48372 alt.push( this.getRowClass(r, rowIndex));
48378 rowIndex : rowIndex,
48381 this.grid.fireEvent('rowclass', this, rowcfg);
48382 alt.push(rowcfg.rowClass);
48384 rp.alt = alt.join(" ");
48385 rp.cells = lcb.join("");
48386 lbuf[lbuf.length] = rt.apply(rp);
48387 rp.cells = cb.join("");
48388 buf[buf.length] = rt.apply(rp);
48390 return [lbuf.join(""), buf.join("")];
48393 renderBody : function(){
48394 var markup = this.renderRows();
48395 var bt = this.templates.body;
48396 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
48400 * Refreshes the grid
48401 * @param {Boolean} headersToo
48403 refresh : function(headersToo){
48404 this.fireEvent("beforerefresh", this);
48405 this.grid.stopEditing();
48406 var result = this.renderBody();
48407 this.lockedBody.update(result[0]);
48408 this.mainBody.update(result[1]);
48409 if(headersToo === true){
48410 this.updateHeaders();
48411 this.updateColumns();
48412 this.updateSplitters();
48413 this.updateHeaderSortState();
48415 this.syncRowHeights();
48417 this.fireEvent("refresh", this);
48420 handleColumnMove : function(cm, oldIndex, newIndex){
48421 this.indexMap = null;
48422 var s = this.getScrollState();
48423 this.refresh(true);
48424 this.restoreScroll(s);
48425 this.afterMove(newIndex);
48428 afterMove : function(colIndex){
48429 if(this.enableMoveAnim && Roo.enableFx){
48430 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
48432 // if multisort - fix sortOrder, and reload..
48433 if (this.grid.dataSource.multiSort) {
48434 // the we can call sort again..
48435 var dm = this.grid.dataSource;
48436 var cm = this.grid.colModel;
48438 for(var i = 0; i < cm.config.length; i++ ) {
48440 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
48441 continue; // dont' bother, it's not in sort list or being set.
48444 so.push(cm.config[i].dataIndex);
48447 dm.load(dm.lastOptions);
48454 updateCell : function(dm, rowIndex, dataIndex){
48455 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
48456 if(typeof colIndex == "undefined"){ // not present in grid
48459 var cm = this.grid.colModel;
48460 var cell = this.getCell(rowIndex, colIndex);
48461 var cellText = this.getCellText(rowIndex, colIndex);
48464 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
48465 id : cm.getColumnId(colIndex),
48466 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
48468 var renderer = cm.getRenderer(colIndex);
48469 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
48470 if(typeof val == "undefined" || val === "") val = " ";
48471 cellText.innerHTML = val;
48472 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
48473 this.syncRowHeights(rowIndex, rowIndex);
48476 calcColumnWidth : function(colIndex, maxRowsToMeasure){
48478 if(this.grid.autoSizeHeaders){
48479 var h = this.getHeaderCellMeasure(colIndex);
48480 maxWidth = Math.max(maxWidth, h.scrollWidth);
48483 if(this.cm.isLocked(colIndex)){
48484 tb = this.getLockedTable();
48487 tb = this.getBodyTable();
48488 index = colIndex - this.cm.getLockedCount();
48491 var rows = tb.rows;
48492 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
48493 for(var i = 0; i < stopIndex; i++){
48494 var cell = rows[i].childNodes[index].firstChild;
48495 maxWidth = Math.max(maxWidth, cell.scrollWidth);
48498 return maxWidth + /*margin for error in IE*/ 5;
48501 * Autofit a column to its content.
48502 * @param {Number} colIndex
48503 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
48505 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
48506 if(this.cm.isHidden(colIndex)){
48507 return; // can't calc a hidden column
48510 var cid = this.cm.getColumnId(colIndex);
48511 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
48512 if(this.grid.autoSizeHeaders){
48513 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
48516 var newWidth = this.calcColumnWidth(colIndex);
48517 this.cm.setColumnWidth(colIndex,
48518 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
48519 if(!suppressEvent){
48520 this.grid.fireEvent("columnresize", colIndex, newWidth);
48525 * Autofits all columns to their content and then expands to fit any extra space in the grid
48527 autoSizeColumns : function(){
48528 var cm = this.grid.colModel;
48529 var colCount = cm.getColumnCount();
48530 for(var i = 0; i < colCount; i++){
48531 this.autoSizeColumn(i, true, true);
48533 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
48536 this.updateColumns();
48542 * Autofits all columns to the grid's width proportionate with their current size
48543 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
48545 fitColumns : function(reserveScrollSpace){
48546 var cm = this.grid.colModel;
48547 var colCount = cm.getColumnCount();
48551 for (i = 0; i < colCount; i++){
48552 if(!cm.isHidden(i) && !cm.isFixed(i)){
48553 w = cm.getColumnWidth(i);
48559 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
48560 if(reserveScrollSpace){
48563 var frac = (avail - cm.getTotalWidth())/width;
48564 while (cols.length){
48567 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
48569 this.updateColumns();
48573 onRowSelect : function(rowIndex){
48574 var row = this.getRowComposite(rowIndex);
48575 row.addClass("x-grid-row-selected");
48578 onRowDeselect : function(rowIndex){
48579 var row = this.getRowComposite(rowIndex);
48580 row.removeClass("x-grid-row-selected");
48583 onCellSelect : function(row, col){
48584 var cell = this.getCell(row, col);
48586 Roo.fly(cell).addClass("x-grid-cell-selected");
48590 onCellDeselect : function(row, col){
48591 var cell = this.getCell(row, col);
48593 Roo.fly(cell).removeClass("x-grid-cell-selected");
48597 updateHeaderSortState : function(){
48599 // sort state can be single { field: xxx, direction : yyy}
48600 // or { xxx=>ASC , yyy : DESC ..... }
48603 if (!this.ds.multiSort) {
48604 var state = this.ds.getSortState();
48608 mstate[state.field] = state.direction;
48609 // FIXME... - this is not used here.. but might be elsewhere..
48610 this.sortState = state;
48613 mstate = this.ds.sortToggle;
48615 //remove existing sort classes..
48617 var sc = this.sortClasses;
48618 var hds = this.el.select(this.headerSelector).removeClass(sc);
48620 for(var f in mstate) {
48622 var sortColumn = this.cm.findColumnIndex(f);
48624 if(sortColumn != -1){
48625 var sortDir = mstate[f];
48626 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
48635 handleHeaderClick : function(g, index){
48636 if(this.headersDisabled){
48639 var dm = g.dataSource, cm = g.colModel;
48640 if(!cm.isSortable(index)){
48645 if (dm.multiSort) {
48646 // update the sortOrder
48648 for(var i = 0; i < cm.config.length; i++ ) {
48650 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
48651 continue; // dont' bother, it's not in sort list or being set.
48654 so.push(cm.config[i].dataIndex);
48660 dm.sort(cm.getDataIndex(index));
48664 destroy : function(){
48666 this.colMenu.removeAll();
48667 Roo.menu.MenuMgr.unregister(this.colMenu);
48668 this.colMenu.getEl().remove();
48669 delete this.colMenu;
48672 this.hmenu.removeAll();
48673 Roo.menu.MenuMgr.unregister(this.hmenu);
48674 this.hmenu.getEl().remove();
48677 if(this.grid.enableColumnMove){
48678 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48680 for(var dd in dds){
48681 if(!dds[dd].config.isTarget && dds[dd].dragElId){
48682 var elid = dds[dd].dragElId;
48684 Roo.get(elid).remove();
48685 } else if(dds[dd].config.isTarget){
48686 dds[dd].proxyTop.remove();
48687 dds[dd].proxyBottom.remove();
48690 if(Roo.dd.DDM.locationCache[dd]){
48691 delete Roo.dd.DDM.locationCache[dd];
48694 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48697 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
48698 this.bind(null, null);
48699 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
48702 handleLockChange : function(){
48703 this.refresh(true);
48706 onDenyColumnLock : function(){
48710 onDenyColumnHide : function(){
48714 handleHdMenuClick : function(item){
48715 var index = this.hdCtxIndex;
48716 var cm = this.cm, ds = this.ds;
48719 ds.sort(cm.getDataIndex(index), "ASC");
48722 ds.sort(cm.getDataIndex(index), "DESC");
48725 var lc = cm.getLockedCount();
48726 if(cm.getColumnCount(true) <= lc+1){
48727 this.onDenyColumnLock();
48731 cm.setLocked(index, true, true);
48732 cm.moveColumn(index, lc);
48733 this.grid.fireEvent("columnmove", index, lc);
48735 cm.setLocked(index, true);
48739 var lc = cm.getLockedCount();
48740 if((lc-1) != index){
48741 cm.setLocked(index, false, true);
48742 cm.moveColumn(index, lc-1);
48743 this.grid.fireEvent("columnmove", index, lc-1);
48745 cm.setLocked(index, false);
48749 index = cm.getIndexById(item.id.substr(4));
48751 if(item.checked && cm.getColumnCount(true) <= 1){
48752 this.onDenyColumnHide();
48755 cm.setHidden(index, item.checked);
48761 beforeColMenuShow : function(){
48762 var cm = this.cm, colCount = cm.getColumnCount();
48763 this.colMenu.removeAll();
48764 for(var i = 0; i < colCount; i++){
48765 this.colMenu.add(new Roo.menu.CheckItem({
48766 id: "col-"+cm.getColumnId(i),
48767 text: cm.getColumnHeader(i),
48768 checked: !cm.isHidden(i),
48774 handleHdCtx : function(g, index, e){
48776 var hd = this.getHeaderCell(index);
48777 this.hdCtxIndex = index;
48778 var ms = this.hmenu.items, cm = this.cm;
48779 ms.get("asc").setDisabled(!cm.isSortable(index));
48780 ms.get("desc").setDisabled(!cm.isSortable(index));
48781 if(this.grid.enableColLock !== false){
48782 ms.get("lock").setDisabled(cm.isLocked(index));
48783 ms.get("unlock").setDisabled(!cm.isLocked(index));
48785 this.hmenu.show(hd, "tl-bl");
48788 handleHdOver : function(e){
48789 var hd = this.findHeaderCell(e.getTarget());
48790 if(hd && !this.headersDisabled){
48791 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
48792 this.fly(hd).addClass("x-grid-hd-over");
48797 handleHdOut : function(e){
48798 var hd = this.findHeaderCell(e.getTarget());
48800 this.fly(hd).removeClass("x-grid-hd-over");
48804 handleSplitDblClick : function(e, t){
48805 var i = this.getCellIndex(t);
48806 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
48807 this.autoSizeColumn(i, true);
48812 render : function(){
48815 var colCount = cm.getColumnCount();
48817 if(this.grid.monitorWindowResize === true){
48818 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48820 var header = this.renderHeaders();
48821 var body = this.templates.body.apply({rows:""});
48822 var html = this.templates.master.apply({
48825 lockedHeader: header[0],
48829 //this.updateColumns();
48831 this.grid.getGridEl().dom.innerHTML = html;
48833 this.initElements();
48835 // a kludge to fix the random scolling effect in webkit
48836 this.el.on("scroll", function() {
48837 this.el.dom.scrollTop=0; // hopefully not recursive..
48840 this.scroller.on("scroll", this.handleScroll, this);
48841 this.lockedBody.on("mousewheel", this.handleWheel, this);
48842 this.mainBody.on("mousewheel", this.handleWheel, this);
48844 this.mainHd.on("mouseover", this.handleHdOver, this);
48845 this.mainHd.on("mouseout", this.handleHdOut, this);
48846 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
48847 {delegate: "."+this.splitClass});
48849 this.lockedHd.on("mouseover", this.handleHdOver, this);
48850 this.lockedHd.on("mouseout", this.handleHdOut, this);
48851 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
48852 {delegate: "."+this.splitClass});
48854 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
48855 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48858 this.updateSplitters();
48860 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
48861 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48862 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48865 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
48866 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
48868 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
48869 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
48871 if(this.grid.enableColLock !== false){
48872 this.hmenu.add('-',
48873 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
48874 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
48877 if(this.grid.enableColumnHide !== false){
48879 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
48880 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
48881 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
48883 this.hmenu.add('-',
48884 {id:"columns", text: this.columnsText, menu: this.colMenu}
48887 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
48889 this.grid.on("headercontextmenu", this.handleHdCtx, this);
48892 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
48893 this.dd = new Roo.grid.GridDragZone(this.grid, {
48894 ddGroup : this.grid.ddGroup || 'GridDD'
48899 for(var i = 0; i < colCount; i++){
48900 if(cm.isHidden(i)){
48901 this.hideColumn(i);
48903 if(cm.config[i].align){
48904 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
48905 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
48909 this.updateHeaderSortState();
48911 this.beforeInitialResize();
48914 // two part rendering gives faster view to the user
48915 this.renderPhase2.defer(1, this);
48918 renderPhase2 : function(){
48919 // render the rows now
48921 if(this.grid.autoSizeColumns){
48922 this.autoSizeColumns();
48926 beforeInitialResize : function(){
48930 onColumnSplitterMoved : function(i, w){
48931 this.userResized = true;
48932 var cm = this.grid.colModel;
48933 cm.setColumnWidth(i, w, true);
48934 var cid = cm.getColumnId(i);
48935 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48936 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48937 this.updateSplitters();
48939 this.grid.fireEvent("columnresize", i, w);
48942 syncRowHeights : function(startIndex, endIndex){
48943 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
48944 startIndex = startIndex || 0;
48945 var mrows = this.getBodyTable().rows;
48946 var lrows = this.getLockedTable().rows;
48947 var len = mrows.length-1;
48948 endIndex = Math.min(endIndex || len, len);
48949 for(var i = startIndex; i <= endIndex; i++){
48950 var m = mrows[i], l = lrows[i];
48951 var h = Math.max(m.offsetHeight, l.offsetHeight);
48952 m.style.height = l.style.height = h + "px";
48957 layout : function(initialRender, is2ndPass){
48959 var auto = g.autoHeight;
48960 var scrollOffset = 16;
48961 var c = g.getGridEl(), cm = this.cm,
48962 expandCol = g.autoExpandColumn,
48964 //c.beginMeasure();
48966 if(!c.dom.offsetWidth){ // display:none?
48968 this.lockedWrap.show();
48969 this.mainWrap.show();
48974 var hasLock = this.cm.isLocked(0);
48976 var tbh = this.headerPanel.getHeight();
48977 var bbh = this.footerPanel.getHeight();
48980 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
48981 var newHeight = ch + c.getBorderWidth("tb");
48983 newHeight = Math.min(g.maxHeight, newHeight);
48985 c.setHeight(newHeight);
48989 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
48992 var s = this.scroller;
48994 var csize = c.getSize(true);
48996 this.el.setSize(csize.width, csize.height);
48998 this.headerPanel.setWidth(csize.width);
48999 this.footerPanel.setWidth(csize.width);
49001 var hdHeight = this.mainHd.getHeight();
49002 var vw = csize.width;
49003 var vh = csize.height - (tbh + bbh);
49007 var bt = this.getBodyTable();
49008 var ltWidth = hasLock ?
49009 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
49011 var scrollHeight = bt.offsetHeight;
49012 var scrollWidth = ltWidth + bt.offsetWidth;
49013 var vscroll = false, hscroll = false;
49015 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
49017 var lw = this.lockedWrap, mw = this.mainWrap;
49018 var lb = this.lockedBody, mb = this.mainBody;
49020 setTimeout(function(){
49021 var t = s.dom.offsetTop;
49022 var w = s.dom.clientWidth,
49023 h = s.dom.clientHeight;
49026 lw.setSize(ltWidth, h);
49028 mw.setLeftTop(ltWidth, t);
49029 mw.setSize(w-ltWidth, h);
49031 lb.setHeight(h-hdHeight);
49032 mb.setHeight(h-hdHeight);
49034 if(is2ndPass !== true && !gv.userResized && expandCol){
49035 // high speed resize without full column calculation
49037 var ci = cm.getIndexById(expandCol);
49039 ci = cm.findColumnIndex(expandCol);
49041 ci = Math.max(0, ci); // make sure it's got at least the first col.
49042 var expandId = cm.getColumnId(ci);
49043 var tw = cm.getTotalWidth(false);
49044 var currentWidth = cm.getColumnWidth(ci);
49045 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
49046 if(currentWidth != cw){
49047 cm.setColumnWidth(ci, cw, true);
49048 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
49049 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
49050 gv.updateSplitters();
49051 gv.layout(false, true);
49063 onWindowResize : function(){
49064 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
49070 appendFooter : function(parentEl){
49074 sortAscText : "Sort Ascending",
49075 sortDescText : "Sort Descending",
49076 lockText : "Lock Column",
49077 unlockText : "Unlock Column",
49078 columnsText : "Columns"
49082 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
49083 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
49084 this.proxy.el.addClass('x-grid3-col-dd');
49087 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
49088 handleMouseDown : function(e){
49092 callHandleMouseDown : function(e){
49093 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
49098 * Ext JS Library 1.1.1
49099 * Copyright(c) 2006-2007, Ext JS, LLC.
49101 * Originally Released Under LGPL - original licence link has changed is not relivant.
49104 * <script type="text/javascript">
49108 // This is a support class used internally by the Grid components
49109 Roo.grid.SplitDragZone = function(grid, hd, hd2){
49111 this.view = grid.getView();
49112 this.proxy = this.view.resizeProxy;
49113 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
49114 "gridSplitters" + this.grid.getGridEl().id, {
49115 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
49117 this.setHandleElId(Roo.id(hd));
49118 this.setOuterHandleElId(Roo.id(hd2));
49119 this.scroll = false;
49121 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
49122 fly: Roo.Element.fly,
49124 b4StartDrag : function(x, y){
49125 this.view.headersDisabled = true;
49126 this.proxy.setHeight(this.view.mainWrap.getHeight());
49127 var w = this.cm.getColumnWidth(this.cellIndex);
49128 var minw = Math.max(w-this.grid.minColumnWidth, 0);
49129 this.resetConstraints();
49130 this.setXConstraint(minw, 1000);
49131 this.setYConstraint(0, 0);
49132 this.minX = x - minw;
49133 this.maxX = x + 1000;
49135 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
49139 handleMouseDown : function(e){
49140 ev = Roo.EventObject.setEvent(e);
49141 var t = this.fly(ev.getTarget());
49142 if(t.hasClass("x-grid-split")){
49143 this.cellIndex = this.view.getCellIndex(t.dom);
49144 this.split = t.dom;
49145 this.cm = this.grid.colModel;
49146 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
49147 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
49152 endDrag : function(e){
49153 this.view.headersDisabled = false;
49154 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
49155 var diff = endX - this.startPos;
49156 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
49159 autoOffset : function(){
49160 this.setDelta(0,0);
49164 * Ext JS Library 1.1.1
49165 * Copyright(c) 2006-2007, Ext JS, LLC.
49167 * Originally Released Under LGPL - original licence link has changed is not relivant.
49170 * <script type="text/javascript">
49174 // This is a support class used internally by the Grid components
49175 Roo.grid.GridDragZone = function(grid, config){
49176 this.view = grid.getView();
49177 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
49178 if(this.view.lockedBody){
49179 this.setHandleElId(Roo.id(this.view.mainBody.dom));
49180 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
49182 this.scroll = false;
49184 this.ddel = document.createElement('div');
49185 this.ddel.className = 'x-grid-dd-wrap';
49188 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
49189 ddGroup : "GridDD",
49191 getDragData : function(e){
49192 var t = Roo.lib.Event.getTarget(e);
49193 var rowIndex = this.view.findRowIndex(t);
49194 if(rowIndex !== false){
49195 var sm = this.grid.selModel;
49196 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
49197 // sm.mouseDown(e, t);
49199 if (e.hasModifier()){
49200 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
49202 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
49207 onInitDrag : function(e){
49208 var data = this.dragData;
49209 this.ddel.innerHTML = this.grid.getDragDropText();
49210 this.proxy.update(this.ddel);
49211 // fire start drag?
49214 afterRepair : function(){
49215 this.dragging = false;
49218 getRepairXY : function(e, data){
49222 onEndDrag : function(data, e){
49226 onValidDrop : function(dd, e, id){
49231 beforeInvalidDrop : function(e, id){
49236 * Ext JS Library 1.1.1
49237 * Copyright(c) 2006-2007, Ext JS, LLC.
49239 * Originally Released Under LGPL - original licence link has changed is not relivant.
49242 * <script type="text/javascript">
49247 * @class Roo.grid.ColumnModel
49248 * @extends Roo.util.Observable
49249 * This is the default implementation of a ColumnModel used by the Grid. It defines
49250 * the columns in the grid.
49253 var colModel = new Roo.grid.ColumnModel([
49254 {header: "Ticker", width: 60, sortable: true, locked: true},
49255 {header: "Company Name", width: 150, sortable: true},
49256 {header: "Market Cap.", width: 100, sortable: true},
49257 {header: "$ Sales", width: 100, sortable: true, renderer: money},
49258 {header: "Employees", width: 100, sortable: true, resizable: false}
49263 * The config options listed for this class are options which may appear in each
49264 * individual column definition.
49265 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
49267 * @param {Object} config An Array of column config objects. See this class's
49268 * config objects for details.
49270 Roo.grid.ColumnModel = function(config){
49272 * The config passed into the constructor
49274 this.config = config;
49277 // if no id, create one
49278 // if the column does not have a dataIndex mapping,
49279 // map it to the order it is in the config
49280 for(var i = 0, len = config.length; i < len; i++){
49282 if(typeof c.dataIndex == "undefined"){
49285 if(typeof c.renderer == "string"){
49286 c.renderer = Roo.util.Format[c.renderer];
49288 if(typeof c.id == "undefined"){
49291 if(c.editor && c.editor.xtype){
49292 c.editor = Roo.factory(c.editor, Roo.grid);
49294 if(c.editor && c.editor.isFormField){
49295 c.editor = new Roo.grid.GridEditor(c.editor);
49297 this.lookup[c.id] = c;
49301 * The width of columns which have no width specified (defaults to 100)
49304 this.defaultWidth = 100;
49307 * Default sortable of columns which have no sortable specified (defaults to false)
49310 this.defaultSortable = false;
49314 * @event widthchange
49315 * Fires when the width of a column changes.
49316 * @param {ColumnModel} this
49317 * @param {Number} columnIndex The column index
49318 * @param {Number} newWidth The new width
49320 "widthchange": true,
49322 * @event headerchange
49323 * Fires when the text of a header changes.
49324 * @param {ColumnModel} this
49325 * @param {Number} columnIndex The column index
49326 * @param {Number} newText The new header text
49328 "headerchange": true,
49330 * @event hiddenchange
49331 * Fires when a column is hidden or "unhidden".
49332 * @param {ColumnModel} this
49333 * @param {Number} columnIndex The column index
49334 * @param {Boolean} hidden true if hidden, false otherwise
49336 "hiddenchange": true,
49338 * @event columnmoved
49339 * Fires when a column is moved.
49340 * @param {ColumnModel} this
49341 * @param {Number} oldIndex
49342 * @param {Number} newIndex
49344 "columnmoved" : true,
49346 * @event columlockchange
49347 * Fires when a column's locked state is changed
49348 * @param {ColumnModel} this
49349 * @param {Number} colIndex
49350 * @param {Boolean} locked true if locked
49352 "columnlockchange" : true
49354 Roo.grid.ColumnModel.superclass.constructor.call(this);
49356 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
49358 * @cfg {String} header The header text to display in the Grid view.
49361 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
49362 * {@link Roo.data.Record} definition from which to draw the column's value. If not
49363 * specified, the column's index is used as an index into the Record's data Array.
49366 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
49367 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
49370 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
49371 * Defaults to the value of the {@link #defaultSortable} property.
49372 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
49375 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
49378 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
49381 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
49384 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
49387 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
49388 * given the cell's data value. See {@link #setRenderer}. If not specified, the
49389 * default renderer uses the raw data value.
49392 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
49395 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
49399 * Returns the id of the column at the specified index.
49400 * @param {Number} index The column index
49401 * @return {String} the id
49403 getColumnId : function(index){
49404 return this.config[index].id;
49408 * Returns the column for a specified id.
49409 * @param {String} id The column id
49410 * @return {Object} the column
49412 getColumnById : function(id){
49413 return this.lookup[id];
49418 * Returns the column for a specified dataIndex.
49419 * @param {String} dataIndex The column dataIndex
49420 * @return {Object|Boolean} the column or false if not found
49422 getColumnByDataIndex: function(dataIndex){
49423 var index = this.findColumnIndex(dataIndex);
49424 return index > -1 ? this.config[index] : false;
49428 * Returns the index for a specified column id.
49429 * @param {String} id The column id
49430 * @return {Number} the index, or -1 if not found
49432 getIndexById : function(id){
49433 for(var i = 0, len = this.config.length; i < len; i++){
49434 if(this.config[i].id == id){
49442 * Returns the index for a specified column dataIndex.
49443 * @param {String} dataIndex The column dataIndex
49444 * @return {Number} the index, or -1 if not found
49447 findColumnIndex : function(dataIndex){
49448 for(var i = 0, len = this.config.length; i < len; i++){
49449 if(this.config[i].dataIndex == dataIndex){
49457 moveColumn : function(oldIndex, newIndex){
49458 var c = this.config[oldIndex];
49459 this.config.splice(oldIndex, 1);
49460 this.config.splice(newIndex, 0, c);
49461 this.dataMap = null;
49462 this.fireEvent("columnmoved", this, oldIndex, newIndex);
49465 isLocked : function(colIndex){
49466 return this.config[colIndex].locked === true;
49469 setLocked : function(colIndex, value, suppressEvent){
49470 if(this.isLocked(colIndex) == value){
49473 this.config[colIndex].locked = value;
49474 if(!suppressEvent){
49475 this.fireEvent("columnlockchange", this, colIndex, value);
49479 getTotalLockedWidth : function(){
49480 var totalWidth = 0;
49481 for(var i = 0; i < this.config.length; i++){
49482 if(this.isLocked(i) && !this.isHidden(i)){
49483 this.totalWidth += this.getColumnWidth(i);
49489 getLockedCount : function(){
49490 for(var i = 0, len = this.config.length; i < len; i++){
49491 if(!this.isLocked(i)){
49498 * Returns the number of columns.
49501 getColumnCount : function(visibleOnly){
49502 if(visibleOnly === true){
49504 for(var i = 0, len = this.config.length; i < len; i++){
49505 if(!this.isHidden(i)){
49511 return this.config.length;
49515 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
49516 * @param {Function} fn
49517 * @param {Object} scope (optional)
49518 * @return {Array} result
49520 getColumnsBy : function(fn, scope){
49522 for(var i = 0, len = this.config.length; i < len; i++){
49523 var c = this.config[i];
49524 if(fn.call(scope||this, c, i) === true){
49532 * Returns true if the specified column is sortable.
49533 * @param {Number} col The column index
49534 * @return {Boolean}
49536 isSortable : function(col){
49537 if(typeof this.config[col].sortable == "undefined"){
49538 return this.defaultSortable;
49540 return this.config[col].sortable;
49544 * Returns the rendering (formatting) function defined for the column.
49545 * @param {Number} col The column index.
49546 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
49548 getRenderer : function(col){
49549 if(!this.config[col].renderer){
49550 return Roo.grid.ColumnModel.defaultRenderer;
49552 return this.config[col].renderer;
49556 * Sets the rendering (formatting) function for a column.
49557 * @param {Number} col The column index
49558 * @param {Function} fn The function to use to process the cell's raw data
49559 * to return HTML markup for the grid view. The render function is called with
49560 * the following parameters:<ul>
49561 * <li>Data value.</li>
49562 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
49563 * <li>css A CSS style string to apply to the table cell.</li>
49564 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
49565 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
49566 * <li>Row index</li>
49567 * <li>Column index</li>
49568 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
49570 setRenderer : function(col, fn){
49571 this.config[col].renderer = fn;
49575 * Returns the width for the specified column.
49576 * @param {Number} col The column index
49579 getColumnWidth : function(col){
49580 return this.config[col].width * 1 || this.defaultWidth;
49584 * Sets the width for a column.
49585 * @param {Number} col The column index
49586 * @param {Number} width The new width
49588 setColumnWidth : function(col, width, suppressEvent){
49589 this.config[col].width = width;
49590 this.totalWidth = null;
49591 if(!suppressEvent){
49592 this.fireEvent("widthchange", this, col, width);
49597 * Returns the total width of all columns.
49598 * @param {Boolean} includeHidden True to include hidden column widths
49601 getTotalWidth : function(includeHidden){
49602 if(!this.totalWidth){
49603 this.totalWidth = 0;
49604 for(var i = 0, len = this.config.length; i < len; i++){
49605 if(includeHidden || !this.isHidden(i)){
49606 this.totalWidth += this.getColumnWidth(i);
49610 return this.totalWidth;
49614 * Returns the header for the specified column.
49615 * @param {Number} col The column index
49618 getColumnHeader : function(col){
49619 return this.config[col].header;
49623 * Sets the header for a column.
49624 * @param {Number} col The column index
49625 * @param {String} header The new header
49627 setColumnHeader : function(col, header){
49628 this.config[col].header = header;
49629 this.fireEvent("headerchange", this, col, header);
49633 * Returns the tooltip for the specified column.
49634 * @param {Number} col The column index
49637 getColumnTooltip : function(col){
49638 return this.config[col].tooltip;
49641 * Sets the tooltip for a column.
49642 * @param {Number} col The column index
49643 * @param {String} tooltip The new tooltip
49645 setColumnTooltip : function(col, tooltip){
49646 this.config[col].tooltip = tooltip;
49650 * Returns the dataIndex for the specified column.
49651 * @param {Number} col The column index
49654 getDataIndex : function(col){
49655 return this.config[col].dataIndex;
49659 * Sets the dataIndex for a column.
49660 * @param {Number} col The column index
49661 * @param {Number} dataIndex The new dataIndex
49663 setDataIndex : function(col, dataIndex){
49664 this.config[col].dataIndex = dataIndex;
49670 * Returns true if the cell is editable.
49671 * @param {Number} colIndex The column index
49672 * @param {Number} rowIndex The row index
49673 * @return {Boolean}
49675 isCellEditable : function(colIndex, rowIndex){
49676 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
49680 * Returns the editor defined for the cell/column.
49681 * return false or null to disable editing.
49682 * @param {Number} colIndex The column index
49683 * @param {Number} rowIndex The row index
49686 getCellEditor : function(colIndex, rowIndex){
49687 return this.config[colIndex].editor;
49691 * Sets if a column is editable.
49692 * @param {Number} col The column index
49693 * @param {Boolean} editable True if the column is editable
49695 setEditable : function(col, editable){
49696 this.config[col].editable = editable;
49701 * Returns true if the column is hidden.
49702 * @param {Number} colIndex The column index
49703 * @return {Boolean}
49705 isHidden : function(colIndex){
49706 return this.config[colIndex].hidden;
49711 * Returns true if the column width cannot be changed
49713 isFixed : function(colIndex){
49714 return this.config[colIndex].fixed;
49718 * Returns true if the column can be resized
49719 * @return {Boolean}
49721 isResizable : function(colIndex){
49722 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
49725 * Sets if a column is hidden.
49726 * @param {Number} colIndex The column index
49727 * @param {Boolean} hidden True if the column is hidden
49729 setHidden : function(colIndex, hidden){
49730 this.config[colIndex].hidden = hidden;
49731 this.totalWidth = null;
49732 this.fireEvent("hiddenchange", this, colIndex, hidden);
49736 * Sets the editor for a column.
49737 * @param {Number} col The column index
49738 * @param {Object} editor The editor object
49740 setEditor : function(col, editor){
49741 this.config[col].editor = editor;
49745 Roo.grid.ColumnModel.defaultRenderer = function(value){
49746 if(typeof value == "string" && value.length < 1){
49752 // Alias for backwards compatibility
49753 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
49756 * Ext JS Library 1.1.1
49757 * Copyright(c) 2006-2007, Ext JS, LLC.
49759 * Originally Released Under LGPL - original licence link has changed is not relivant.
49762 * <script type="text/javascript">
49766 * @class Roo.grid.AbstractSelectionModel
49767 * @extends Roo.util.Observable
49768 * Abstract base class for grid SelectionModels. It provides the interface that should be
49769 * implemented by descendant classes. This class should not be directly instantiated.
49772 Roo.grid.AbstractSelectionModel = function(){
49773 this.locked = false;
49774 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
49777 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
49778 /** @ignore Called by the grid automatically. Do not call directly. */
49779 init : function(grid){
49785 * Locks the selections.
49788 this.locked = true;
49792 * Unlocks the selections.
49794 unlock : function(){
49795 this.locked = false;
49799 * Returns true if the selections are locked.
49800 * @return {Boolean}
49802 isLocked : function(){
49803 return this.locked;
49807 * Ext JS Library 1.1.1
49808 * Copyright(c) 2006-2007, Ext JS, LLC.
49810 * Originally Released Under LGPL - original licence link has changed is not relivant.
49813 * <script type="text/javascript">
49816 * @extends Roo.grid.AbstractSelectionModel
49817 * @class Roo.grid.RowSelectionModel
49818 * The default SelectionModel used by {@link Roo.grid.Grid}.
49819 * It supports multiple selections and keyboard selection/navigation.
49821 * @param {Object} config
49823 Roo.grid.RowSelectionModel = function(config){
49824 Roo.apply(this, config);
49825 this.selections = new Roo.util.MixedCollection(false, function(o){
49830 this.lastActive = false;
49834 * @event selectionchange
49835 * Fires when the selection changes
49836 * @param {SelectionModel} this
49838 "selectionchange" : true,
49840 * @event afterselectionchange
49841 * Fires after the selection changes (eg. by key press or clicking)
49842 * @param {SelectionModel} this
49844 "afterselectionchange" : true,
49846 * @event beforerowselect
49847 * Fires when a row is selected being selected, return false to cancel.
49848 * @param {SelectionModel} this
49849 * @param {Number} rowIndex The selected index
49850 * @param {Boolean} keepExisting False if other selections will be cleared
49852 "beforerowselect" : true,
49855 * Fires when a row is selected.
49856 * @param {SelectionModel} this
49857 * @param {Number} rowIndex The selected index
49858 * @param {Roo.data.Record} r The record
49860 "rowselect" : true,
49862 * @event rowdeselect
49863 * Fires when a row is deselected.
49864 * @param {SelectionModel} this
49865 * @param {Number} rowIndex The selected index
49867 "rowdeselect" : true
49869 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
49870 this.locked = false;
49873 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
49875 * @cfg {Boolean} singleSelect
49876 * True to allow selection of only one row at a time (defaults to false)
49878 singleSelect : false,
49881 initEvents : function(){
49883 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
49884 this.grid.on("mousedown", this.handleMouseDown, this);
49885 }else{ // allow click to work like normal
49886 this.grid.on("rowclick", this.handleDragableRowClick, this);
49889 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
49890 "up" : function(e){
49892 this.selectPrevious(e.shiftKey);
49893 }else if(this.last !== false && this.lastActive !== false){
49894 var last = this.last;
49895 this.selectRange(this.last, this.lastActive-1);
49896 this.grid.getView().focusRow(this.lastActive);
49897 if(last !== false){
49901 this.selectFirstRow();
49903 this.fireEvent("afterselectionchange", this);
49905 "down" : function(e){
49907 this.selectNext(e.shiftKey);
49908 }else if(this.last !== false && this.lastActive !== false){
49909 var last = this.last;
49910 this.selectRange(this.last, this.lastActive+1);
49911 this.grid.getView().focusRow(this.lastActive);
49912 if(last !== false){
49916 this.selectFirstRow();
49918 this.fireEvent("afterselectionchange", this);
49923 var view = this.grid.view;
49924 view.on("refresh", this.onRefresh, this);
49925 view.on("rowupdated", this.onRowUpdated, this);
49926 view.on("rowremoved", this.onRemove, this);
49930 onRefresh : function(){
49931 var ds = this.grid.dataSource, i, v = this.grid.view;
49932 var s = this.selections;
49933 s.each(function(r){
49934 if((i = ds.indexOfId(r.id)) != -1){
49943 onRemove : function(v, index, r){
49944 this.selections.remove(r);
49948 onRowUpdated : function(v, index, r){
49949 if(this.isSelected(r)){
49950 v.onRowSelect(index);
49956 * @param {Array} records The records to select
49957 * @param {Boolean} keepExisting (optional) True to keep existing selections
49959 selectRecords : function(records, keepExisting){
49961 this.clearSelections();
49963 var ds = this.grid.dataSource;
49964 for(var i = 0, len = records.length; i < len; i++){
49965 this.selectRow(ds.indexOf(records[i]), true);
49970 * Gets the number of selected rows.
49973 getCount : function(){
49974 return this.selections.length;
49978 * Selects the first row in the grid.
49980 selectFirstRow : function(){
49985 * Select the last row.
49986 * @param {Boolean} keepExisting (optional) True to keep existing selections
49988 selectLastRow : function(keepExisting){
49989 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
49993 * Selects the row immediately following the last selected row.
49994 * @param {Boolean} keepExisting (optional) True to keep existing selections
49996 selectNext : function(keepExisting){
49997 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
49998 this.selectRow(this.last+1, keepExisting);
49999 this.grid.getView().focusRow(this.last);
50004 * Selects the row that precedes the last selected row.
50005 * @param {Boolean} keepExisting (optional) True to keep existing selections
50007 selectPrevious : function(keepExisting){
50009 this.selectRow(this.last-1, keepExisting);
50010 this.grid.getView().focusRow(this.last);
50015 * Returns the selected records
50016 * @return {Array} Array of selected records
50018 getSelections : function(){
50019 return [].concat(this.selections.items);
50023 * Returns the first selected record.
50026 getSelected : function(){
50027 return this.selections.itemAt(0);
50032 * Clears all selections.
50034 clearSelections : function(fast){
50035 if(this.locked) return;
50037 var ds = this.grid.dataSource;
50038 var s = this.selections;
50039 s.each(function(r){
50040 this.deselectRow(ds.indexOfId(r.id));
50044 this.selections.clear();
50051 * Selects all rows.
50053 selectAll : function(){
50054 if(this.locked) return;
50055 this.selections.clear();
50056 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
50057 this.selectRow(i, true);
50062 * Returns True if there is a selection.
50063 * @return {Boolean}
50065 hasSelection : function(){
50066 return this.selections.length > 0;
50070 * Returns True if the specified row is selected.
50071 * @param {Number/Record} record The record or index of the record to check
50072 * @return {Boolean}
50074 isSelected : function(index){
50075 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
50076 return (r && this.selections.key(r.id) ? true : false);
50080 * Returns True if the specified record id is selected.
50081 * @param {String} id The id of record to check
50082 * @return {Boolean}
50084 isIdSelected : function(id){
50085 return (this.selections.key(id) ? true : false);
50089 handleMouseDown : function(e, t){
50090 var view = this.grid.getView(), rowIndex;
50091 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
50094 if(e.shiftKey && this.last !== false){
50095 var last = this.last;
50096 this.selectRange(last, rowIndex, e.ctrlKey);
50097 this.last = last; // reset the last
50098 view.focusRow(rowIndex);
50100 var isSelected = this.isSelected(rowIndex);
50101 if(e.button !== 0 && isSelected){
50102 view.focusRow(rowIndex);
50103 }else if(e.ctrlKey && isSelected){
50104 this.deselectRow(rowIndex);
50105 }else if(!isSelected){
50106 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
50107 view.focusRow(rowIndex);
50110 this.fireEvent("afterselectionchange", this);
50113 handleDragableRowClick : function(grid, rowIndex, e)
50115 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
50116 this.selectRow(rowIndex, false);
50117 grid.view.focusRow(rowIndex);
50118 this.fireEvent("afterselectionchange", this);
50123 * Selects multiple rows.
50124 * @param {Array} rows Array of the indexes of the row to select
50125 * @param {Boolean} keepExisting (optional) True to keep existing selections
50127 selectRows : function(rows, keepExisting){
50129 this.clearSelections();
50131 for(var i = 0, len = rows.length; i < len; i++){
50132 this.selectRow(rows[i], true);
50137 * Selects a range of rows. All rows in between startRow and endRow are also selected.
50138 * @param {Number} startRow The index of the first row in the range
50139 * @param {Number} endRow The index of the last row in the range
50140 * @param {Boolean} keepExisting (optional) True to retain existing selections
50142 selectRange : function(startRow, endRow, keepExisting){
50143 if(this.locked) return;
50145 this.clearSelections();
50147 if(startRow <= endRow){
50148 for(var i = startRow; i <= endRow; i++){
50149 this.selectRow(i, true);
50152 for(var i = startRow; i >= endRow; i--){
50153 this.selectRow(i, true);
50159 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
50160 * @param {Number} startRow The index of the first row in the range
50161 * @param {Number} endRow The index of the last row in the range
50163 deselectRange : function(startRow, endRow, preventViewNotify){
50164 if(this.locked) return;
50165 for(var i = startRow; i <= endRow; i++){
50166 this.deselectRow(i, preventViewNotify);
50172 * @param {Number} row The index of the row to select
50173 * @param {Boolean} keepExisting (optional) True to keep existing selections
50175 selectRow : function(index, keepExisting, preventViewNotify){
50176 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
50177 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
50178 if(!keepExisting || this.singleSelect){
50179 this.clearSelections();
50181 var r = this.grid.dataSource.getAt(index);
50182 this.selections.add(r);
50183 this.last = this.lastActive = index;
50184 if(!preventViewNotify){
50185 this.grid.getView().onRowSelect(index);
50187 this.fireEvent("rowselect", this, index, r);
50188 this.fireEvent("selectionchange", this);
50194 * @param {Number} row The index of the row to deselect
50196 deselectRow : function(index, preventViewNotify){
50197 if(this.locked) return;
50198 if(this.last == index){
50201 if(this.lastActive == index){
50202 this.lastActive = false;
50204 var r = this.grid.dataSource.getAt(index);
50205 this.selections.remove(r);
50206 if(!preventViewNotify){
50207 this.grid.getView().onRowDeselect(index);
50209 this.fireEvent("rowdeselect", this, index);
50210 this.fireEvent("selectionchange", this);
50214 restoreLast : function(){
50216 this.last = this._last;
50221 acceptsNav : function(row, col, cm){
50222 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50226 onEditorKey : function(field, e){
50227 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50232 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50234 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50236 }else if(k == e.ENTER && !e.ctrlKey){
50240 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
50242 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
50244 }else if(k == e.ESC){
50248 g.startEditing(newCell[0], newCell[1]);
50253 * Ext JS Library 1.1.1
50254 * Copyright(c) 2006-2007, Ext JS, LLC.
50256 * Originally Released Under LGPL - original licence link has changed is not relivant.
50259 * <script type="text/javascript">
50262 * @class Roo.grid.CellSelectionModel
50263 * @extends Roo.grid.AbstractSelectionModel
50264 * This class provides the basic implementation for cell selection in a grid.
50266 * @param {Object} config The object containing the configuration of this model.
50268 Roo.grid.CellSelectionModel = function(config){
50269 Roo.apply(this, config);
50271 this.selection = null;
50275 * @event beforerowselect
50276 * Fires before a cell is selected.
50277 * @param {SelectionModel} this
50278 * @param {Number} rowIndex The selected row index
50279 * @param {Number} colIndex The selected cell index
50281 "beforecellselect" : true,
50283 * @event cellselect
50284 * Fires when a cell is selected.
50285 * @param {SelectionModel} this
50286 * @param {Number} rowIndex The selected row index
50287 * @param {Number} colIndex The selected cell index
50289 "cellselect" : true,
50291 * @event selectionchange
50292 * Fires when the active selection changes.
50293 * @param {SelectionModel} this
50294 * @param {Object} selection null for no selection or an object (o) with two properties
50296 <li>o.record: the record object for the row the selection is in</li>
50297 <li>o.cell: An array of [rowIndex, columnIndex]</li>
50300 "selectionchange" : true
50302 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
50305 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
50308 initEvents : function(){
50309 this.grid.on("mousedown", this.handleMouseDown, this);
50310 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
50311 var view = this.grid.view;
50312 view.on("refresh", this.onViewChange, this);
50313 view.on("rowupdated", this.onRowUpdated, this);
50314 view.on("beforerowremoved", this.clearSelections, this);
50315 view.on("beforerowsinserted", this.clearSelections, this);
50316 if(this.grid.isEditor){
50317 this.grid.on("beforeedit", this.beforeEdit, this);
50322 beforeEdit : function(e){
50323 this.select(e.row, e.column, false, true, e.record);
50327 onRowUpdated : function(v, index, r){
50328 if(this.selection && this.selection.record == r){
50329 v.onCellSelect(index, this.selection.cell[1]);
50334 onViewChange : function(){
50335 this.clearSelections(true);
50339 * Returns the currently selected cell,.
50340 * @return {Array} The selected cell (row, column) or null if none selected.
50342 getSelectedCell : function(){
50343 return this.selection ? this.selection.cell : null;
50347 * Clears all selections.
50348 * @param {Boolean} true to prevent the gridview from being notified about the change.
50350 clearSelections : function(preventNotify){
50351 var s = this.selection;
50353 if(preventNotify !== true){
50354 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
50356 this.selection = null;
50357 this.fireEvent("selectionchange", this, null);
50362 * Returns true if there is a selection.
50363 * @return {Boolean}
50365 hasSelection : function(){
50366 return this.selection ? true : false;
50370 handleMouseDown : function(e, t){
50371 var v = this.grid.getView();
50372 if(this.isLocked()){
50375 var row = v.findRowIndex(t);
50376 var cell = v.findCellIndex(t);
50377 if(row !== false && cell !== false){
50378 this.select(row, cell);
50384 * @param {Number} rowIndex
50385 * @param {Number} collIndex
50387 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
50388 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
50389 this.clearSelections();
50390 r = r || this.grid.dataSource.getAt(rowIndex);
50393 cell : [rowIndex, colIndex]
50395 if(!preventViewNotify){
50396 var v = this.grid.getView();
50397 v.onCellSelect(rowIndex, colIndex);
50398 if(preventFocus !== true){
50399 v.focusCell(rowIndex, colIndex);
50402 this.fireEvent("cellselect", this, rowIndex, colIndex);
50403 this.fireEvent("selectionchange", this, this.selection);
50408 isSelectable : function(rowIndex, colIndex, cm){
50409 return !cm.isHidden(colIndex);
50413 handleKeyDown : function(e){
50414 Roo.log('Cell Sel Model handleKeyDown');
50415 if(!e.isNavKeyPress()){
50418 var g = this.grid, s = this.selection;
50421 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
50423 this.select(cell[0], cell[1]);
50428 var walk = function(row, col, step){
50429 return g.walkCells(row, col, step, sm.isSelectable, sm);
50431 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
50436 // handled by onEditorKey
50437 if (g.isEditor && g.editing) {
50441 newCell = walk(r, c-1, -1);
50443 newCell = walk(r, c+1, 1);
50447 newCell = walk(r+1, c, 1);
50450 newCell = walk(r-1, c, -1);
50453 newCell = walk(r, c+1, 1);
50456 newCell = walk(r, c-1, -1);
50459 if(g.isEditor && !g.editing){
50460 g.startEditing(r, c);
50467 this.select(newCell[0], newCell[1]);
50472 acceptsNav : function(row, col, cm){
50473 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50476 onEditorKey : function(field, e){
50478 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50479 ///Roo.log('onEditorKey' + k);
50483 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50485 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50488 }else if(k == e.ENTER && !e.ctrlKey){
50491 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50492 }else if(k == e.ESC){
50498 //Roo.log('next cell after edit');
50499 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
50504 * Ext JS Library 1.1.1
50505 * Copyright(c) 2006-2007, Ext JS, LLC.
50507 * Originally Released Under LGPL - original licence link has changed is not relivant.
50510 * <script type="text/javascript">
50514 * @class Roo.grid.EditorGrid
50515 * @extends Roo.grid.Grid
50516 * Class for creating and editable grid.
50517 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50518 * The container MUST have some type of size defined for the grid to fill. The container will be
50519 * automatically set to position relative if it isn't already.
50520 * @param {Object} dataSource The data model to bind to
50521 * @param {Object} colModel The column model with info about this grid's columns
50523 Roo.grid.EditorGrid = function(container, config){
50524 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
50525 this.getGridEl().addClass("xedit-grid");
50527 if(!this.selModel){
50528 this.selModel = new Roo.grid.CellSelectionModel();
50531 this.activeEditor = null;
50535 * @event beforeedit
50536 * Fires before cell editing is triggered. The edit event object has the following properties <br />
50537 * <ul style="padding:5px;padding-left:16px;">
50538 * <li>grid - This grid</li>
50539 * <li>record - The record being edited</li>
50540 * <li>field - The field name being edited</li>
50541 * <li>value - The value for the field being edited.</li>
50542 * <li>row - The grid row index</li>
50543 * <li>column - The grid column index</li>
50544 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50546 * @param {Object} e An edit event (see above for description)
50548 "beforeedit" : true,
50551 * Fires after a cell is edited. <br />
50552 * <ul style="padding:5px;padding-left:16px;">
50553 * <li>grid - This grid</li>
50554 * <li>record - The record being edited</li>
50555 * <li>field - The field name being edited</li>
50556 * <li>value - The value being set</li>
50557 * <li>originalValue - The original value for the field, before the edit.</li>
50558 * <li>row - The grid row index</li>
50559 * <li>column - The grid column index</li>
50561 * @param {Object} e An edit event (see above for description)
50563 "afteredit" : true,
50565 * @event validateedit
50566 * Fires after a cell is edited, but before the value is set in the record.
50567 * You can use this to modify the value being set in the field, Return false
50568 * to cancel the change. The edit event object has the following properties <br />
50569 * <ul style="padding:5px;padding-left:16px;">
50570 * <li>editor - This editor</li>
50571 * <li>grid - This grid</li>
50572 * <li>record - The record being edited</li>
50573 * <li>field - The field name being edited</li>
50574 * <li>value - The value being set</li>
50575 * <li>originalValue - The original value for the field, before the edit.</li>
50576 * <li>row - The grid row index</li>
50577 * <li>column - The grid column index</li>
50578 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50580 * @param {Object} e An edit event (see above for description)
50582 "validateedit" : true
50584 this.on("bodyscroll", this.stopEditing, this);
50585 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
50588 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
50590 * @cfg {Number} clicksToEdit
50591 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
50598 trackMouseOver: false, // causes very odd FF errors
50600 onCellDblClick : function(g, row, col){
50601 this.startEditing(row, col);
50604 onEditComplete : function(ed, value, startValue){
50605 this.editing = false;
50606 this.activeEditor = null;
50607 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
50609 var field = this.colModel.getDataIndex(ed.col);
50614 originalValue: startValue,
50621 if(String(value) !== String(startValue)){
50623 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
50624 r.set(field, e.value);
50625 // if we are dealing with a combo box..
50626 // then we also set the 'name' colum to be the displayField
50627 if (ed.field.displayField && ed.field.name) {
50628 r.set(ed.field.name, ed.field.el.dom.value);
50631 delete e.cancel; //?? why!!!
50632 this.fireEvent("afteredit", e);
50635 this.fireEvent("afteredit", e); // always fire it!
50637 this.view.focusCell(ed.row, ed.col);
50641 * Starts editing the specified for the specified row/column
50642 * @param {Number} rowIndex
50643 * @param {Number} colIndex
50645 startEditing : function(row, col){
50646 this.stopEditing();
50647 if(this.colModel.isCellEditable(col, row)){
50648 this.view.ensureVisible(row, col, true);
50649 var r = this.dataSource.getAt(row);
50650 var field = this.colModel.getDataIndex(col);
50655 value: r.data[field],
50660 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
50661 this.editing = true;
50662 var ed = this.colModel.getCellEditor(col, row);
50668 ed.render(ed.parentEl || document.body);
50671 (function(){ // complex but required for focus issues in safari, ie and opera
50675 ed.on("complete", this.onEditComplete, this, {single: true});
50676 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
50677 this.activeEditor = ed;
50678 var v = r.data[field];
50679 ed.startEdit(this.view.getCell(row, col), v);
50680 // combo's with 'displayField and name set
50681 if (ed.field.displayField && ed.field.name) {
50682 ed.field.el.dom.value = r.data[ed.field.name];
50686 }).defer(50, this);
50692 * Stops any active editing
50694 stopEditing : function(){
50695 if(this.activeEditor){
50696 this.activeEditor.completeEdit();
50698 this.activeEditor = null;
50702 * Ext JS Library 1.1.1
50703 * Copyright(c) 2006-2007, Ext JS, LLC.
50705 * Originally Released Under LGPL - original licence link has changed is not relivant.
50708 * <script type="text/javascript">
50711 // private - not really -- you end up using it !
50712 // This is a support class used internally by the Grid components
50715 * @class Roo.grid.GridEditor
50716 * @extends Roo.Editor
50717 * Class for creating and editable grid elements.
50718 * @param {Object} config any settings (must include field)
50720 Roo.grid.GridEditor = function(field, config){
50721 if (!config && field.field) {
50723 field = Roo.factory(config.field, Roo.form);
50725 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
50726 field.monitorTab = false;
50729 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
50732 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
50735 alignment: "tl-tl",
50738 cls: "x-small-editor x-grid-editor",
50743 * Ext JS Library 1.1.1
50744 * Copyright(c) 2006-2007, Ext JS, LLC.
50746 * Originally Released Under LGPL - original licence link has changed is not relivant.
50749 * <script type="text/javascript">
50754 Roo.grid.PropertyRecord = Roo.data.Record.create([
50755 {name:'name',type:'string'}, 'value'
50759 Roo.grid.PropertyStore = function(grid, source){
50761 this.store = new Roo.data.Store({
50762 recordType : Roo.grid.PropertyRecord
50764 this.store.on('update', this.onUpdate, this);
50766 this.setSource(source);
50768 Roo.grid.PropertyStore.superclass.constructor.call(this);
50773 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
50774 setSource : function(o){
50776 this.store.removeAll();
50779 if(this.isEditableValue(o[k])){
50780 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
50783 this.store.loadRecords({records: data}, {}, true);
50786 onUpdate : function(ds, record, type){
50787 if(type == Roo.data.Record.EDIT){
50788 var v = record.data['value'];
50789 var oldValue = record.modified['value'];
50790 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
50791 this.source[record.id] = v;
50793 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
50800 getProperty : function(row){
50801 return this.store.getAt(row);
50804 isEditableValue: function(val){
50805 if(val && val instanceof Date){
50807 }else if(typeof val == 'object' || typeof val == 'function'){
50813 setValue : function(prop, value){
50814 this.source[prop] = value;
50815 this.store.getById(prop).set('value', value);
50818 getSource : function(){
50819 return this.source;
50823 Roo.grid.PropertyColumnModel = function(grid, store){
50826 g.PropertyColumnModel.superclass.constructor.call(this, [
50827 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
50828 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
50830 this.store = store;
50831 this.bselect = Roo.DomHelper.append(document.body, {
50832 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
50833 {tag: 'option', value: 'true', html: 'true'},
50834 {tag: 'option', value: 'false', html: 'false'}
50837 Roo.id(this.bselect);
50840 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
50841 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
50842 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
50843 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
50844 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
50846 this.renderCellDelegate = this.renderCell.createDelegate(this);
50847 this.renderPropDelegate = this.renderProp.createDelegate(this);
50850 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
50854 valueText : 'Value',
50856 dateFormat : 'm/j/Y',
50859 renderDate : function(dateVal){
50860 return dateVal.dateFormat(this.dateFormat);
50863 renderBool : function(bVal){
50864 return bVal ? 'true' : 'false';
50867 isCellEditable : function(colIndex, rowIndex){
50868 return colIndex == 1;
50871 getRenderer : function(col){
50873 this.renderCellDelegate : this.renderPropDelegate;
50876 renderProp : function(v){
50877 return this.getPropertyName(v);
50880 renderCell : function(val){
50882 if(val instanceof Date){
50883 rv = this.renderDate(val);
50884 }else if(typeof val == 'boolean'){
50885 rv = this.renderBool(val);
50887 return Roo.util.Format.htmlEncode(rv);
50890 getPropertyName : function(name){
50891 var pn = this.grid.propertyNames;
50892 return pn && pn[name] ? pn[name] : name;
50895 getCellEditor : function(colIndex, rowIndex){
50896 var p = this.store.getProperty(rowIndex);
50897 var n = p.data['name'], val = p.data['value'];
50899 if(typeof(this.grid.customEditors[n]) == 'string'){
50900 return this.editors[this.grid.customEditors[n]];
50902 if(typeof(this.grid.customEditors[n]) != 'undefined'){
50903 return this.grid.customEditors[n];
50905 if(val instanceof Date){
50906 return this.editors['date'];
50907 }else if(typeof val == 'number'){
50908 return this.editors['number'];
50909 }else if(typeof val == 'boolean'){
50910 return this.editors['boolean'];
50912 return this.editors['string'];
50918 * @class Roo.grid.PropertyGrid
50919 * @extends Roo.grid.EditorGrid
50920 * This class represents the interface of a component based property grid control.
50921 * <br><br>Usage:<pre><code>
50922 var grid = new Roo.grid.PropertyGrid("my-container-id", {
50930 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50931 * The container MUST have some type of size defined for the grid to fill. The container will be
50932 * automatically set to position relative if it isn't already.
50933 * @param {Object} config A config object that sets properties on this grid.
50935 Roo.grid.PropertyGrid = function(container, config){
50936 config = config || {};
50937 var store = new Roo.grid.PropertyStore(this);
50938 this.store = store;
50939 var cm = new Roo.grid.PropertyColumnModel(this, store);
50940 store.store.sort('name', 'ASC');
50941 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
50944 enableColLock:false,
50945 enableColumnMove:false,
50947 trackMouseOver: false,
50950 this.getGridEl().addClass('x-props-grid');
50951 this.lastEditRow = null;
50952 this.on('columnresize', this.onColumnResize, this);
50955 * @event beforepropertychange
50956 * Fires before a property changes (return false to stop?)
50957 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50958 * @param {String} id Record Id
50959 * @param {String} newval New Value
50960 * @param {String} oldval Old Value
50962 "beforepropertychange": true,
50964 * @event propertychange
50965 * Fires after a property changes
50966 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50967 * @param {String} id Record Id
50968 * @param {String} newval New Value
50969 * @param {String} oldval Old Value
50971 "propertychange": true
50973 this.customEditors = this.customEditors || {};
50975 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
50978 * @cfg {Object} customEditors map of colnames=> custom editors.
50979 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
50980 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
50981 * false disables editing of the field.
50985 * @cfg {Object} propertyNames map of property Names to their displayed value
50988 render : function(){
50989 Roo.grid.PropertyGrid.superclass.render.call(this);
50990 this.autoSize.defer(100, this);
50993 autoSize : function(){
50994 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
50996 this.view.fitColumns();
51000 onColumnResize : function(){
51001 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
51005 * Sets the data for the Grid
51006 * accepts a Key => Value object of all the elements avaiable.
51007 * @param {Object} data to appear in grid.
51009 setSource : function(source){
51010 this.store.setSource(source);
51014 * Gets all the data from the grid.
51015 * @return {Object} data data stored in grid
51017 getSource : function(){
51018 return this.store.getSource();
51022 * Ext JS Library 1.1.1
51023 * Copyright(c) 2006-2007, Ext JS, LLC.
51025 * Originally Released Under LGPL - original licence link has changed is not relivant.
51028 * <script type="text/javascript">
51032 * @class Roo.LoadMask
51033 * A simple utility class for generically masking elements while loading data. If the element being masked has
51034 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
51035 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
51036 * element's UpdateManager load indicator and will be destroyed after the initial load.
51038 * Create a new LoadMask
51039 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
51040 * @param {Object} config The config object
51042 Roo.LoadMask = function(el, config){
51043 this.el = Roo.get(el);
51044 Roo.apply(this, config);
51046 this.store.on('beforeload', this.onBeforeLoad, this);
51047 this.store.on('load', this.onLoad, this);
51048 this.store.on('loadexception', this.onLoad, this);
51049 this.removeMask = false;
51051 var um = this.el.getUpdateManager();
51052 um.showLoadIndicator = false; // disable the default indicator
51053 um.on('beforeupdate', this.onBeforeLoad, this);
51054 um.on('update', this.onLoad, this);
51055 um.on('failure', this.onLoad, this);
51056 this.removeMask = true;
51060 Roo.LoadMask.prototype = {
51062 * @cfg {Boolean} removeMask
51063 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
51064 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
51067 * @cfg {String} msg
51068 * The text to display in a centered loading message box (defaults to 'Loading...')
51070 msg : 'Loading...',
51072 * @cfg {String} msgCls
51073 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
51075 msgCls : 'x-mask-loading',
51078 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
51084 * Disables the mask to prevent it from being displayed
51086 disable : function(){
51087 this.disabled = true;
51091 * Enables the mask so that it can be displayed
51093 enable : function(){
51094 this.disabled = false;
51098 onLoad : function(){
51099 this.el.unmask(this.removeMask);
51103 onBeforeLoad : function(){
51104 if(!this.disabled){
51105 this.el.mask(this.msg, this.msgCls);
51110 destroy : function(){
51112 this.store.un('beforeload', this.onBeforeLoad, this);
51113 this.store.un('load', this.onLoad, this);
51114 this.store.un('loadexception', this.onLoad, this);
51116 var um = this.el.getUpdateManager();
51117 um.un('beforeupdate', this.onBeforeLoad, this);
51118 um.un('update', this.onLoad, this);
51119 um.un('failure', this.onLoad, this);
51124 * Ext JS Library 1.1.1
51125 * Copyright(c) 2006-2007, Ext JS, LLC.
51127 * Originally Released Under LGPL - original licence link has changed is not relivant.
51130 * <script type="text/javascript">
51132 Roo.XTemplate = function(){
51133 Roo.XTemplate.superclass.constructor.apply(this, arguments);
51136 s = ['<tpl>', s, '</tpl>'].join('');
51138 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
51140 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
51141 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
51142 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
51146 while(m = s.match(re)){
51147 var m2 = m[0].match(nameRe);
51148 var m3 = m[0].match(ifRe);
51149 var m4 = m[0].match(execRe);
51150 var exp = null, fn = null, exec = null;
51151 var name = m2 && m2[1] ? m2[1] : '';
51153 exp = m3 && m3[1] ? m3[1] : null;
51155 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
51159 exp = m4 && m4[1] ? m4[1] : null;
51161 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
51166 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
51167 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
51168 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
51178 s = s.replace(m[0], '{xtpl'+ id + '}');
51181 for(var i = tpls.length-1; i >= 0; --i){
51182 this.compileTpl(tpls[i]);
51184 this.master = tpls[tpls.length-1];
51187 Roo.extend(Roo.XTemplate, Roo.Template, {
51189 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
51191 applySubTemplate : function(id, values, parent){
51192 var t = this.tpls[id];
51193 if(t.test && !t.test.call(this, values, parent)){
51196 if(t.exec && t.exec.call(this, values, parent)){
51199 var vs = t.target ? t.target.call(this, values, parent) : values;
51200 parent = t.target ? values : parent;
51201 if(t.target && vs instanceof Array){
51203 for(var i = 0, len = vs.length; i < len; i++){
51204 buf[buf.length] = t.compiled.call(this, vs[i], parent);
51206 return buf.join('');
51208 return t.compiled.call(this, vs, parent);
51211 compileTpl : function(tpl){
51212 var fm = Roo.util.Format;
51213 var useF = this.disableFormats !== true;
51214 var sep = Roo.isGecko ? "+" : ",";
51215 var fn = function(m, name, format, args){
51216 if(name.substr(0, 4) == 'xtpl'){
51217 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
51220 if(name.indexOf('.') != -1){
51223 v = "values['" + name + "']";
51225 if(format && useF){
51226 args = args ? ',' + args : "";
51227 if(format.substr(0, 5) != "this."){
51228 format = "fm." + format + '(';
51230 format = 'this.call("'+ format.substr(5) + '", ';
51234 args= ''; format = "("+v+" === undefined ? '' : ";
51236 return "'"+ sep + format + v + args + ")"+sep+"'";
51239 // branched to use + in gecko and [].join() in others
51241 body = "tpl.compiled = function(values, parent){ return '" +
51242 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
51245 body = ["tpl.compiled = function(values, parent){ return ['"];
51246 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
51247 body.push("'].join('');};");
51248 body = body.join('');
51250 /** eval:var:zzzzzzz */
51255 applyTemplate : function(values){
51256 return this.master.compiled.call(this, values, {});
51260 apply : function(){
51261 return this.applyTemplate.apply(this, arguments);
51264 compile : function(){return this;}
51267 Roo.XTemplate.from = function(el){
51268 el = Roo.getDom(el);
51269 return new Roo.XTemplate(el.value || el.innerHTML);
51271 * Original code for Roojs - LGPL
51272 * <script type="text/javascript">
51276 * @class Roo.XComponent
51277 * A delayed Element creator...
51278 * Or a way to group chunks of interface together.
51280 * Mypart.xyx = new Roo.XComponent({
51282 parent : 'Mypart.xyz', // empty == document.element.!!
51286 disabled : function() {}
51288 tree : function() { // return an tree of xtype declared components
51292 xtype : 'NestedLayoutPanel',
51299 * It can be used to build a big heiracy, with parent etc.
51300 * or you can just use this to render a single compoent to a dom element
51301 * MYPART.render(Roo.Element | String(id) | dom_element )
51303 * @extends Roo.util.Observable
51305 * @param cfg {Object} configuration of component
51308 Roo.XComponent = function(cfg) {
51309 Roo.apply(this, cfg);
51313 * Fires when this the componnt is built
51314 * @param {Roo.XComponent} c the component
51318 * @event buildcomplete
51319 * Fires on the top level element when all elements have been built
51320 * @param {Roo.XComponent} c the top level component.
51322 'buildcomplete' : true
51325 this.region = this.region || 'center'; // default..
51326 Roo.XComponent.register(this);
51327 this.modules = false;
51328 this.el = false; // where the layout goes..
51332 Roo.extend(Roo.XComponent, Roo.util.Observable, {
51335 * The created element (with Roo.factory())
51336 * @type {Roo.Layout}
51342 * for BC - use el in new code
51343 * @type {Roo.Layout}
51349 * for BC - use el in new code
51350 * @type {Roo.Layout}
51355 * @cfg {Function|boolean} disabled
51356 * If this module is disabled by some rule, return true from the funtion
51361 * @cfg {String} parent
51362 * Name of parent element which it get xtype added to..
51367 * @cfg {String} order
51368 * Used to set the order in which elements are created (usefull for multiple tabs)
51373 * @cfg {String} name
51374 * String to display while loading.
51378 * @cfg {String} region
51379 * Region to render component to (defaults to center)
51384 * @cfg {Array} items
51385 * A single item array - the first element is the root of the tree..
51386 * It's done this way to stay compatible with the Xtype system...
51393 * render element to dom or tree
51394 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
51397 render : function(el)
51402 if (!el && typeof(this.parent) == 'string' && this.parent[0] == '#') {
51403 // if parent is a '#.....' string, then let's use that..
51404 var ename = this.parent.substr(1)
51405 this.parent = false;
51406 el = Roo.get(ename);
51408 Roo.log("Warning - element can not be found :#" + ename );
51412 if (!this.parent) {
51414 el = el ? Roo.get(el) : false;
51416 // it's a top level one..
51418 el : new Roo.BorderLayout(el || document.body, {
51424 tabPosition: 'top',
51425 //resizeTabs: true,
51426 alwaysShowTabs: el ? false : true,
51427 hideTabs: el ? true : false,
51436 var tree = this.tree();
51437 tree.region = tree.region || this.region;
51438 this.el = this.parent.el.addxtype(tree);
51439 this.fireEvent('built', this);
51441 this.panel = this.el;
51442 this.layout = this.panel.layout;
51448 Roo.apply(Roo.XComponent, {
51451 * @property buildCompleted
51452 * True when the builder has completed building the interface.
51455 buildCompleted : false,
51458 * @property topModule
51459 * the upper most module - uses document.element as it's constructor.
51466 * @property modules
51467 * array of modules to be created by registration system.
51468 * @type {Array} of Roo.XComponent
51473 * @property elmodules
51474 * array of modules to be created by which use #ID
51475 * @type {Array} of Roo.XComponent
51482 * Register components to be built later.
51484 * This solves the following issues
51485 * - Building is not done on page load, but after an authentication process has occured.
51486 * - Interface elements are registered on page load
51487 * - Parent Interface elements may not be loaded before child, so this handles that..
51494 module : 'Pman.Tab.projectMgr',
51496 parent : 'Pman.layout',
51497 disabled : false, // or use a function..
51500 * * @param {Object} details about module
51502 register : function(obj) {
51503 this.modules.push(obj);
51507 * convert a string to an object..
51508 * eg. 'AAA.BBB' -> finds AAA.BBB
51512 toObject : function(str)
51514 if (!str || typeof(str) == 'object') {
51521 var ar = str.split('.');
51525 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
51527 throw "Module not found : " + str;
51529 Roo.each(ar, function(e) {
51530 if (typeof(o[e]) == 'undefined') {
51531 throw "Module not found : " + str;
51541 * move modules into their correct place in the tree..
51544 preBuild : function ()
51547 Roo.each(this.modules , function (obj)
51549 obj.parent = this.toObject(obj.parent);
51552 this.topModule = obj;
51555 if (typeof(obj.parent) == 'string') {
51556 this.elmodules.push(obj);
51560 if (!obj.parent.modules) {
51561 obj.parent.modules = new Roo.util.MixedCollection(false,
51562 function(o) { return o.order + '' }
51566 obj.parent.modules.add(obj);
51571 * make a list of modules to build.
51572 * @return {Array} list of modules.
51575 buildOrder : function()
51578 var cmp = function(a,b) {
51579 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
51581 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
51582 throw "No top level modules to build";
51585 // make a flat list in order of modules to build.
51586 var mods = this.topModule ? [ this.topModule ] : [];
51587 Roo.each(this.elmodules,function(e) { mods.push(e) });
51590 // add modules to their parents..
51591 var addMod = function(m) {
51592 // Roo.debug && Roo.log(m.modKey);
51596 m.modules.keySort('ASC', cmp );
51597 m.modules.each(addMod);
51599 // not sure if this is used any more..
51601 m.finalize.name = m.name + " (clean up) ";
51602 mods.push(m.finalize);
51606 if (this.topModule) {
51607 this.topModule.modules.keySort('ASC', cmp );
51608 this.topModule.modules.each(addMod);
51614 * Build the registered modules.
51615 * @param {Object} parent element.
51616 * @param {Function} optional method to call after module has been added.
51624 var mods = this.buildOrder();
51626 //this.allmods = mods;
51627 //Roo.debug && Roo.log(mods);
51629 if (!mods.length) { // should not happen
51630 throw "NO modules!!!";
51635 // flash it up as modal - so we store the mask!?
51636 Roo.MessageBox.show({ title: 'loading' });
51637 Roo.MessageBox.show({
51638 title: "Please wait...",
51639 msg: "Building Interface...",
51646 var total = mods.length;
51649 var progressRun = function() {
51650 if (!mods.length) {
51651 Roo.debug && Roo.log('hide?');
51652 Roo.MessageBox.hide();
51653 if (_this.topModule) {
51654 _this.topModule.fireEvent('buildcomplete', _this.topModule);
51660 var m = mods.shift();
51663 Roo.debug && Roo.log(m);
51664 // not sure if this is supported any more.. - modules that are are just function
51665 if (typeof(m) == 'function') {
51667 return progressRun.defer(10, _this);
51672 Roo.MessageBox.updateProgress(
51673 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
51675 (m.name ? (' - ' + m.name) : '')
51679 // is the module disabled?
51680 var disabled = (typeof(m.disabled) == 'function') ?
51681 m.disabled.call(m.module.disabled) : m.disabled;
51685 return progressRun(); // we do not update the display!
51691 // it's 10 on top level, and 1 on others??? why...
51692 return progressRun.defer(10, _this);
51695 progressRun.defer(1, _this);
51706 //<script type="text/javascript">
51711 * @extends Roo.LayoutDialog
51712 * A generic Login Dialog..... - only one needed in theory!?!?
51714 * Fires XComponent builder on success...
51717 * username,password, lang = for login actions.
51718 * check = 1 for periodic checking that sesion is valid.
51719 * passwordRequest = email request password
51720 * logout = 1 = to logout
51722 * Affects: (this id="????" elements)
51723 * loading (removed) (used to indicate application is loading)
51724 * loading-mask (hides) (used to hide application when it's building loading)
51730 * Myapp.login = Roo.Login({
51746 Roo.Login = function(cfg)
51752 Roo.apply(this,cfg);
51754 Roo.onReady(function() {
51760 Roo.Login.superclass.constructor.call(this, this);
51761 //this.addxtype(this.items[0]);
51767 Roo.extend(Roo.Login, Roo.LayoutDialog, {
51770 * @cfg {String} method
51771 * Method used to query for login details.
51776 * @cfg {String} url
51777 * URL to query login data. - eg. baseURL + '/Login.php'
51783 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
51788 * @property checkFails
51789 * Number of times we have attempted to get authentication check, and failed.
51794 * @property intervalID
51795 * The window interval that does the constant login checking.
51801 onLoad : function() // called on page load...
51805 if (Roo.get('loading')) { // clear any loading indicator..
51806 Roo.get('loading').remove();
51809 //this.switchLang('en'); // set the language to english..
51812 success: function(response, opts) { // check successfull...
51814 var res = this.processResponse(response);
51815 this.checkFails =0;
51816 if (!res.success) { // error!
51817 this.checkFails = 5;
51818 //console.log('call failure');
51819 return this.failure(response,opts);
51822 if (!res.data.id) { // id=0 == login failure.
51823 return this.show();
51827 //console.log(success);
51828 this.fillAuth(res.data);
51829 this.checkFails =0;
51830 Roo.XComponent.build();
51832 failure : this.show
51838 check: function(cfg) // called every so often to refresh cookie etc..
51840 if (cfg.again) { // could be undefined..
51843 this.checkFails = 0;
51846 if (this.sending) {
51847 if ( this.checkFails > 4) {
51848 Roo.MessageBox.alert("Error",
51849 "Error getting authentication status. - try reloading, or wait a while", function() {
51850 _this.sending = false;
51855 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
51858 this.sending = true;
51865 method: this.method,
51866 success: cfg.success || this.success,
51867 failure : cfg.failure || this.failure,
51877 window.onbeforeunload = function() { }; // false does not work for IE..
51887 failure : function() {
51888 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
51889 document.location = document.location.toString() + '?ts=' + Math.random();
51893 success : function() {
51894 _this.user = false;
51895 this.checkFails =0;
51897 document.location = document.location.toString() + '?ts=' + Math.random();
51904 processResponse : function (response)
51908 res = Roo.decode(response.responseText);
51910 if (typeof(res) != 'object') {
51911 res = { success : false, errorMsg : res, errors : true };
51913 if (typeof(res.success) == 'undefined') {
51914 res.success = false;
51918 res = { success : false, errorMsg : response.responseText, errors : true };
51923 success : function(response, opts) // check successfull...
51925 this.sending = false;
51926 var res = this.processResponse(response);
51927 if (!res.success) {
51928 return this.failure(response, opts);
51930 if (!res.data || !res.data.id) {
51931 return this.failure(response,opts);
51933 //console.log(res);
51934 this.fillAuth(res.data);
51936 this.checkFails =0;
51941 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
51943 this.authUser = -1;
51944 this.sending = false;
51945 var res = this.processResponse(response);
51946 //console.log(res);
51947 if ( this.checkFails > 2) {
51949 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
51950 "Error getting authentication status. - try reloading");
51953 opts.callCfg.again = true;
51954 this.check.defer(1000, this, [ opts.callCfg ]);
51960 fillAuth: function(au) {
51961 this.startAuthCheck();
51962 this.authUserId = au.id;
51963 this.authUser = au;
51964 this.lastChecked = new Date();
51965 this.fireEvent('refreshed', au);
51966 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
51967 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
51968 au.lang = au.lang || 'en';
51969 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
51970 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
51971 this.switchLang(au.lang );
51974 // open system... - -on setyp..
51975 if (this.authUserId < 0) {
51976 Roo.MessageBox.alert("Warning",
51977 "This is an open system - please set up a admin user with a password.");
51980 //Pman.onload(); // which should do nothing if it's a re-auth result...
51985 startAuthCheck : function() // starter for timeout checking..
51987 if (this.intervalID) { // timer already in place...
51991 this.intervalID = window.setInterval(function() {
51992 _this.check(false);
51993 }, 120000); // every 120 secs = 2mins..
51999 switchLang : function (lang)
52001 _T = typeof(_T) == 'undefined' ? false : _T;
52002 if (!_T || !lang.length) {
52006 if (!_T && lang != 'en') {
52007 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
52011 if (typeof(_T.en) == 'undefined') {
52013 Roo.apply(_T.en, _T);
52016 if (typeof(_T[lang]) == 'undefined') {
52017 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
52022 Roo.apply(_T, _T[lang]);
52023 // just need to set the text values for everything...
52025 /* this will not work ...
52029 function formLabel(name, val) {
52030 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
52033 formLabel('password', "Password"+':');
52034 formLabel('username', "Email Address"+':');
52035 formLabel('lang', "Language"+':');
52036 this.dialog.setTitle("Login");
52037 this.dialog.buttons[0].setText("Forgot Password");
52038 this.dialog.buttons[1].setText("Login");
52057 collapsible: false,
52059 center: { // needed??
52062 // tabPosition: 'top',
52065 alwaysShowTabs: false
52069 show : function(dlg)
52071 //console.log(this);
52072 this.form = this.layout.getRegion('center').activePanel.form;
52073 this.form.dialog = dlg;
52074 this.buttons[0].form = this.form;
52075 this.buttons[0].dialog = dlg;
52076 this.buttons[1].form = this.form;
52077 this.buttons[1].dialog = dlg;
52079 //this.resizeToLogo.defer(1000,this);
52080 // this is all related to resizing for logos..
52081 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
52083 // this.resizeToLogo.defer(1000,this);
52086 //var w = Ext.lib.Dom.getViewWidth() - 100;
52087 //var h = Ext.lib.Dom.getViewHeight() - 100;
52088 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
52090 if (this.disabled) {
52095 if (this.user.id < 0) { // used for inital setup situations.
52099 if (this.intervalID) {
52100 // remove the timer
52101 window.clearInterval(this.intervalID);
52102 this.intervalID = false;
52106 if (Roo.get('loading')) {
52107 Roo.get('loading').remove();
52109 if (Roo.get('loading-mask')) {
52110 Roo.get('loading-mask').hide();
52113 //incomming._node = tnode;
52115 //this.dialog.modal = !modal;
52116 //this.dialog.show();
52120 this.form.setValues({
52121 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
52122 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
52125 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
52126 if (this.form.findField('username').getValue().length > 0 ){
52127 this.form.findField('password').focus();
52129 this.form.findField('username').focus();
52137 xtype : 'ContentPanel',
52149 style : 'margin: 10px;',
52152 actionfailed : function(f, act) {
52153 // form can return { errors: .... }
52155 //act.result.errors // invalid form element list...
52156 //act.result.errorMsg// invalid form element list...
52158 this.dialog.el.unmask();
52159 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
52160 "Login failed - communication error - try again.");
52163 actioncomplete: function(re, act) {
52165 Roo.state.Manager.set(
52166 this.dialog.realm + '.username',
52167 this.findField('username').getValue()
52169 Roo.state.Manager.set(
52170 this.dialog.realm + '.lang',
52171 this.findField('lang').getValue()
52174 this.dialog.fillAuth(act.result.data);
52176 this.dialog.hide();
52178 if (Roo.get('loading-mask')) {
52179 Roo.get('loading-mask').show();
52181 Roo.XComponent.build();
52189 xtype : 'TextField',
52191 fieldLabel: "Email Address",
52194 autoCreate : {tag: "input", type: "text", size: "20"}
52197 xtype : 'TextField',
52199 fieldLabel: "Password",
52200 inputType: 'password',
52203 autoCreate : {tag: "input", type: "text", size: "20"},
52205 specialkey : function(e,ev) {
52206 if (ev.keyCode == 13) {
52207 this.form.dialog.el.mask("Logging in");
52208 this.form.doAction('submit', {
52209 url: this.form.dialog.url,
52210 method: this.form.dialog.method
52217 xtype : 'ComboBox',
52219 fieldLabel: "Language",
52222 xtype : 'SimpleStore',
52223 fields: ['lang', 'ldisp'],
52225 [ 'en', 'English' ],
52226 [ 'zh_HK' , '\u7E41\u4E2D' ],
52227 [ 'zh_CN', '\u7C21\u4E2D' ]
52231 valueField : 'lang',
52232 hiddenName: 'lang',
52234 displayField:'ldisp',
52238 triggerAction: 'all',
52239 emptyText:'Select a Language...',
52240 selectOnFocus:true,
52242 select : function(cb, rec, ix) {
52243 this.form.switchLang(rec.data.lang);
52259 text : "Forgot Password",
52261 click : function() {
52262 //console.log(this);
52263 var n = this.form.findField('username').getValue();
52265 Roo.MessageBox.alert("Error", "Fill in your email address");
52269 url: this.dialog.url,
52273 method: this.dialog.method,
52274 success: function(response, opts) { // check successfull...
52276 var res = this.dialog.processResponse(response);
52277 if (!res.success) { // error!
52278 Roo.MessageBox.alert("Error" ,
52279 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
52282 Roo.MessageBox.alert("Notice" ,
52283 "Please check you email for the Password Reset message");
52285 failure : function() {
52286 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
52299 click : function () {
52301 this.dialog.el.mask("Logging in");
52302 this.form.doAction('submit', {
52303 url: this.dialog.url,
52304 method: this.dialog.method