4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
89 * Turn on debugging output (currently only the factory uses this)
96 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
99 enableGarbageCollector : true,
102 * True to automatically purge event listeners after uncaching an element (defaults to false).
103 * Note: this only happens if enableGarbageCollector is true.
106 enableListenerCollection:false,
109 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110 * the IE insecure content warning (defaults to javascript:false).
113 SSL_SECURE_URL : "javascript:false",
116 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
120 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
122 emptyFn : function(){},
125 * Copies all the properties of config to obj if they don't already exist.
126 * @param {Object} obj The receiver of the properties
127 * @param {Object} config The source of the properties
128 * @return {Object} returns obj
130 applyIf : function(o, c){
133 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
140 * Applies event listeners to elements by selectors when the document is ready.
141 * The event name is specified with an @ suffix.
144 // add a listener for click on all anchors in element with id foo
145 '#foo a@click' : function(e, t){
149 // add the same listener to multiple selectors (separated by comma BEFORE the @)
150 '#foo a, #bar span.some-class@mouseover' : function(){
155 * @param {Object} obj The list of behaviors to apply
157 addBehaviors : function(o){
159 Roo.onReady(function(){
164 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
166 var parts = b.split('@');
167 if(parts[1]){ // for Object prototype breakers
170 cache[s] = Roo.select(s);
172 cache[s].on(parts[1], o[b]);
179 * Generates unique ids. If the element already has an id, it is unchanged
180 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182 * @return {String} The generated Id.
184 id : function(el, prefix){
185 prefix = prefix || "roo-gen";
187 var id = prefix + (++idSeed);
188 return el ? (el.id ? el.id : (el.id = id)) : id;
193 * Extends one class with another class and optionally overrides members with the passed literal. This class
194 * also adds the function "override()" to the class that can be used to override
195 * members on an instance.
196 * @param {Object} subclass The class inheriting the functionality
197 * @param {Object} superclass The class being extended
198 * @param {Object} overrides (optional) A literal with members
203 var io = function(o){
208 return function(sb, sp, overrides){
209 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
212 sb = function(){sp.apply(this, arguments);};
214 var F = function(){}, sbp, spp = sp.prototype;
216 sbp = sb.prototype = new F();
220 if(spp.constructor == Object.prototype.constructor){
225 sb.override = function(o){
229 Roo.override(sb, overrides);
235 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
237 Roo.override(MyClass, {
238 newMethod1: function(){
241 newMethod2: function(foo){
246 * @param {Object} origclass The class to override
247 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
248 * containing one or more methods.
251 override : function(origclass, overrides){
253 var p = origclass.prototype;
254 for(var method in overrides){
255 p[method] = overrides[method];
260 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
266 * @param {String} namespace1
267 * @param {String} namespace2
268 * @param {String} etc
271 namespace : function(){
272 var a=arguments, o=null, i, j, d, rt;
273 for (i=0; i<a.length; ++i) {
277 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278 for (j=1; j<d.length; ++j) {
279 o[d[j]]=o[d[j]] || {};
285 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
290 * @param {String} classname
291 * @param {String} namespace (optional)
295 factory : function(c, ns)
297 // no xtype, no ns or c.xns - or forced off by c.xns
298 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
301 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302 if (c.constructor == ns[c.xtype]) {// already created...
306 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307 var ret = new ns[c.xtype](c);
311 c.xns = false; // prevent recursion..
315 * Logs to console if it can.
317 * @param {String|Object} string
322 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
329 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
333 urlEncode : function(o){
339 var ov = o[key], k = Roo.encodeURIComponent(key);
340 var type = typeof ov;
341 if(type == 'undefined'){
343 }else if(type != "function" && type != "object"){
344 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345 }else if(ov instanceof Array){
347 for(var i = 0, len = ov.length; i < len; i++) {
348 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
359 * Safe version of encodeURIComponent
360 * @param {String} data
364 encodeURIComponent : function (data)
367 return encodeURIComponent(data);
368 } catch(e) {} // should be an uri encode error.
370 if (data == '' || data == null){
373 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374 function nibble_to_hex(nibble){
375 var chars = '0123456789ABCDEF';
376 return chars.charAt(nibble);
378 data = data.toString();
380 for(var i=0; i<data.length; i++){
381 var c = data.charCodeAt(i);
382 var bs = new Array();
385 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388 bs[3] = 0x80 | (c & 0x3F);
389 }else if (c > 0x800){
391 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393 bs[2] = 0x80 | (c & 0x3F);
396 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397 bs[1] = 0x80 | (c & 0x3F);
402 for(var j=0; j<bs.length; j++){
404 var hex = nibble_to_hex((b & 0xF0) >>> 4)
405 + nibble_to_hex(b &0x0F);
414 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415 * @param {String} string
416 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417 * @return {Object} A literal with members
419 urlDecode : function(string, overwrite){
420 if(!string || !string.length){
424 var pairs = string.split('&');
425 var pair, name, value;
426 for(var i = 0, len = pairs.length; i < len; i++){
427 pair = pairs[i].split('=');
428 name = decodeURIComponent(pair[0]);
429 value = decodeURIComponent(pair[1]);
430 if(overwrite !== true){
431 if(typeof obj[name] == "undefined"){
433 }else if(typeof obj[name] == "string"){
434 obj[name] = [obj[name]];
435 obj[name].push(value);
437 obj[name].push(value);
447 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448 * passed array is not really an array, your function is called once with it.
449 * The supplied function is called with (Object item, Number index, Array allItems).
450 * @param {Array/NodeList/Mixed} array
451 * @param {Function} fn
452 * @param {Object} scope
454 each : function(array, fn, scope){
455 if(typeof array.length == "undefined" || typeof array == "string"){
458 for(var i = 0, len = array.length; i < len; i++){
459 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
464 combine : function(){
465 var as = arguments, l = as.length, r = [];
466 for(var i = 0; i < l; i++){
468 if(a instanceof Array){
470 }else if(a.length !== undefined && !a.substr){
471 r = r.concat(Array.prototype.slice.call(a, 0));
480 * Escapes the passed string for use in a regular expression
481 * @param {String} str
484 escapeRe : function(s) {
485 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
489 callback : function(cb, scope, args, delay){
490 if(typeof cb == "function"){
492 cb.defer(delay, scope, args || []);
494 cb.apply(scope, args || []);
500 * Return the dom node for the passed string (id), dom node, or Roo.Element
501 * @param {String/HTMLElement/Roo.Element} el
502 * @return HTMLElement
504 getDom : function(el){
508 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
512 * Shorthand for {@link Roo.ComponentMgr#get}
514 * @return Roo.Component
516 getCmp : function(id){
517 return Roo.ComponentMgr.get(id);
520 num : function(v, defaultValue){
521 if(typeof v != 'number'){
527 destroy : function(){
528 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
532 as.removeAllListeners();
536 if(typeof as.purgeListeners == 'function'){
539 if(typeof as.destroy == 'function'){
546 // inpired by a similar function in mootools library
548 * Returns the type of object that is passed in. If the object passed in is null or undefined it
549 * return false otherwise it returns one of the following values:<ul>
550 * <li><b>string</b>: If the object passed is a string</li>
551 * <li><b>number</b>: If the object passed is a number</li>
552 * <li><b>boolean</b>: If the object passed is a boolean value</li>
553 * <li><b>function</b>: If the object passed is a function reference</li>
554 * <li><b>object</b>: If the object passed is an object</li>
555 * <li><b>array</b>: If the object passed is an array</li>
556 * <li><b>regexp</b>: If the object passed is a regular expression</li>
557 * <li><b>element</b>: If the object passed is a DOM Element</li>
558 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561 * @param {Mixed} object
565 if(o === undefined || o === null){
572 if(t == 'object' && o.nodeName) {
574 case 1: return 'element';
575 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
578 if(t == 'object' || t == 'function') {
579 switch(o.constructor) {
580 case Array: return 'array';
581 case RegExp: return 'regexp';
583 if(typeof o.length == 'number' && typeof o.item == 'function') {
591 * Returns true if the passed value is null, undefined or an empty string (optional).
592 * @param {Mixed} value The value to test
593 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
596 isEmpty : function(v, allowBlank){
597 return v === null || v === undefined || (!allowBlank ? v === '' : false);
611 isBorderBox : isBorderBox,
613 isWindows : isWindows,
620 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
621 * you may want to set this to true.
624 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
629 * Selects a single element as a Roo Element
630 * This is about as close as you can get to jQuery's $('do crazy stuff')
631 * @param {String} selector The selector/xpath query
632 * @param {Node} root (optional) The start of the query (defaults to document).
633 * @return {Roo.Element}
635 selectNode : function(selector, root)
637 var node = Roo.DomQuery.selectNode(selector,root);
638 return node ? Roo.get(node) : new Roo.Element(false);
646 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
647 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
650 * Ext JS Library 1.1.1
651 * Copyright(c) 2006-2007, Ext JS, LLC.
653 * Originally Released Under LGPL - original licence link has changed is not relivant.
656 * <script type="text/javascript">
660 // wrappedn so fnCleanup is not in global scope...
662 function fnCleanUp() {
663 var p = Function.prototype;
664 delete p.createSequence;
666 delete p.createDelegate;
667 delete p.createCallback;
668 delete p.createInterceptor;
670 window.detachEvent("onunload", fnCleanUp);
672 window.attachEvent("onunload", fnCleanUp);
679 * These functions are available on every Function object (any JavaScript function).
681 Roo.apply(Function.prototype, {
683 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
684 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
685 * Will create a function that is bound to those 2 args.
686 * @return {Function} The new function
688 createCallback : function(/*args...*/){
689 // make args available, in function below
690 var args = arguments;
693 return method.apply(window, args);
698 * Creates a delegate (callback) that sets the scope to obj.
699 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
700 * Will create a function that is automatically scoped to this.
701 * @param {Object} obj (optional) The object for which the scope is set
702 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
703 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
704 * if a number the args are inserted at the specified position
705 * @return {Function} The new function
707 createDelegate : function(obj, args, appendArgs){
710 var callArgs = args || arguments;
711 if(appendArgs === true){
712 callArgs = Array.prototype.slice.call(arguments, 0);
713 callArgs = callArgs.concat(args);
714 }else if(typeof appendArgs == "number"){
715 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
716 var applyArgs = [appendArgs, 0].concat(args); // create method call params
717 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
719 return method.apply(obj || window, callArgs);
724 * Calls this function after the number of millseconds specified.
725 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
726 * @param {Object} obj (optional) The object for which the scope is set
727 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
728 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
729 * if a number the args are inserted at the specified position
730 * @return {Number} The timeout id that can be used with clearTimeout
732 defer : function(millis, obj, args, appendArgs){
733 var fn = this.createDelegate(obj, args, appendArgs);
735 return setTimeout(fn, millis);
741 * Create a combined function call sequence of the original function + the passed function.
742 * The resulting function returns the results of the original function.
743 * The passed fcn is called with the parameters of the original function
744 * @param {Function} fcn The function to sequence
745 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
746 * @return {Function} The new function
748 createSequence : function(fcn, scope){
749 if(typeof fcn != "function"){
754 var retval = method.apply(this || window, arguments);
755 fcn.apply(scope || this || window, arguments);
761 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
762 * The resulting function returns the results of the original function.
763 * The passed fcn is called with the parameters of the original function.
765 * @param {Function} fcn The function to call before the original
766 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
767 * @return {Function} The new function
769 createInterceptor : function(fcn, scope){
770 if(typeof fcn != "function"){
777 if(fcn.apply(scope || this || window, arguments) === false){
780 return method.apply(this || window, arguments);
786 * Ext JS Library 1.1.1
787 * Copyright(c) 2006-2007, Ext JS, LLC.
789 * Originally Released Under LGPL - original licence link has changed is not relivant.
792 * <script type="text/javascript">
795 Roo.applyIf(String, {
800 * Escapes the passed string for ' and \
801 * @param {String} string The string to escape
802 * @return {String} The escaped string
805 escape : function(string) {
806 return string.replace(/('|\\)/g, "\\$1");
810 * Pads the left side of a string with a specified character. This is especially useful
811 * for normalizing number and date strings. Example usage:
813 var s = String.leftPad('123', 5, '0');
814 // s now contains the string: '00123'
816 * @param {String} string The original string
817 * @param {Number} size The total length of the output string
818 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
819 * @return {String} The padded string
822 leftPad : function (val, size, ch) {
823 var result = new String(val);
824 if(ch === null || ch === undefined || ch === '') {
827 while (result.length < size) {
828 result = ch + result;
834 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
835 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
837 var cls = 'my-class', text = 'Some text';
838 var s = String.format('<div class="{0}">{1}</div>', cls, text);
839 // s now contains the string: '<div class="my-class">Some text</div>'
841 * @param {String} string The tokenized string to be formatted
842 * @param {String} value1 The value to replace token {0}
843 * @param {String} value2 Etc...
844 * @return {String} The formatted string
847 format : function(format){
848 var args = Array.prototype.slice.call(arguments, 1);
849 return format.replace(/\{(\d+)\}/g, function(m, i){
850 return Roo.util.Format.htmlEncode(args[i]);
856 * Utility function that allows you to easily switch a string between two alternating values. The passed value
857 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
858 * they are already different, the first value passed in is returned. Note that this method returns the new value
859 * but does not change the current string.
861 // alternate sort directions
862 sort = sort.toggle('ASC', 'DESC');
864 // instead of conditional logic:
865 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
867 * @param {String} value The value to compare to the current string
868 * @param {String} other The new value to use if the string already equals the first value passed in
869 * @return {String} The new value
872 String.prototype.toggle = function(value, other){
873 return this == value ? other : value;
876 * Ext JS Library 1.1.1
877 * Copyright(c) 2006-2007, Ext JS, LLC.
879 * Originally Released Under LGPL - original licence link has changed is not relivant.
882 * <script type="text/javascript">
888 Roo.applyIf(Number.prototype, {
890 * Checks whether or not the current number is within a desired range. If the number is already within the
891 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
892 * exceeded. Note that this method returns the constrained value but does not change the current number.
893 * @param {Number} min The minimum number in the range
894 * @param {Number} max The maximum number in the range
895 * @return {Number} The constrained value if outside the range, otherwise the current value
897 constrain : function(min, max){
898 return Math.min(Math.max(this, min), max);
902 * Ext JS Library 1.1.1
903 * Copyright(c) 2006-2007, Ext JS, LLC.
905 * Originally Released Under LGPL - original licence link has changed is not relivant.
908 * <script type="text/javascript">
913 Roo.applyIf(Array.prototype, {
915 * Checks whether or not the specified object exists in the array.
916 * @param {Object} o The object to check for
917 * @return {Number} The index of o in the array (or -1 if it is not found)
919 indexOf : function(o){
920 for (var i = 0, len = this.length; i < len; i++){
921 if(this[i] == o) return i;
927 * Removes the specified object from the array. If the object is not found nothing happens.
928 * @param {Object} o The object to remove
930 remove : function(o){
931 var index = this.indexOf(o);
933 this.splice(index, 1);
937 * Map (JS 1.6 compatibility)
938 * @param {Function} function to call
942 var len = this.length >>> 0;
943 if (typeof fun != "function")
944 throw new TypeError();
946 var res = new Array(len);
947 var thisp = arguments[1];
948 for (var i = 0; i < len; i++)
951 res[i] = fun.call(thisp, this[i], i, this);
962 * Ext JS Library 1.1.1
963 * Copyright(c) 2006-2007, Ext JS, LLC.
965 * Originally Released Under LGPL - original licence link has changed is not relivant.
968 * <script type="text/javascript">
974 * The date parsing and format syntax is a subset of
975 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
976 * supported will provide results equivalent to their PHP versions.
978 * Following is the list of all currently supported formats:
981 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
983 Format Output Description
984 ------ ---------- --------------------------------------------------------------
985 d 10 Day of the month, 2 digits with leading zeros
986 D Wed A textual representation of a day, three letters
987 j 10 Day of the month without leading zeros
988 l Wednesday A full textual representation of the day of the week
989 S th English ordinal day of month suffix, 2 chars (use with j)
990 w 3 Numeric representation of the day of the week
991 z 9 The julian date, or day of the year (0-365)
992 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
993 F January A full textual representation of the month
994 m 01 Numeric representation of a month, with leading zeros
995 M Jan Month name abbreviation, three letters
996 n 1 Numeric representation of a month, without leading zeros
997 t 31 Number of days in the given month
998 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
999 Y 2007 A full numeric representation of a year, 4 digits
1000 y 07 A two digit representation of a year
1001 a pm Lowercase Ante meridiem and Post meridiem
1002 A PM Uppercase Ante meridiem and Post meridiem
1003 g 3 12-hour format of an hour without leading zeros
1004 G 15 24-hour format of an hour without leading zeros
1005 h 03 12-hour format of an hour with leading zeros
1006 H 15 24-hour format of an hour with leading zeros
1007 i 05 Minutes with leading zeros
1008 s 01 Seconds, with leading zeros
1009 O -0600 Difference to Greenwich time (GMT) in hours
1010 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1011 T CST Timezone setting of the machine running the code
1012 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1015 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1017 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1018 document.write(dt.format('Y-m-d')); //2007-01-10
1019 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1020 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1023 * Here are some standard date/time patterns that you might find helpful. They
1024 * are not part of the source of Date.js, but to use them you can simply copy this
1025 * block of code into any script that is included after Date.js and they will also become
1026 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1029 ISO8601Long:"Y-m-d H:i:s",
1030 ISO8601Short:"Y-m-d",
1032 LongDate: "l, F d, Y",
1033 FullDateTime: "l, F d, Y g:i:s A",
1036 LongTime: "g:i:s A",
1037 SortableDateTime: "Y-m-d\\TH:i:s",
1038 UniversalSortableDateTime: "Y-m-d H:i:sO",
1045 var dt = new Date();
1046 document.write(dt.format(Date.patterns.ShortDate));
1051 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1052 * They generate precompiled functions from date formats instead of parsing and
1053 * processing the pattern every time you format a date. These functions are available
1054 * on every Date object (any javascript function).
1056 * The original article and download are here:
1057 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1064 Returns the number of milliseconds between this date and date
1065 @param {Date} date (optional) Defaults to now
1066 @return {Number} The diff in milliseconds
1067 @member Date getElapsed
1069 Date.prototype.getElapsed = function(date) {
1070 return Math.abs((date || new Date()).getTime()-this.getTime());
1072 // was in date file..
1076 Date.parseFunctions = {count:0};
1078 Date.parseRegexes = [];
1080 Date.formatFunctions = {count:0};
1083 Date.prototype.dateFormat = function(format) {
1084 if (Date.formatFunctions[format] == null) {
1085 Date.createNewFormat(format);
1087 var func = Date.formatFunctions[format];
1088 return this[func]();
1093 * Formats a date given the supplied format string
1094 * @param {String} format The format string
1095 * @return {String} The formatted date
1098 Date.prototype.format = Date.prototype.dateFormat;
1101 Date.createNewFormat = function(format) {
1102 var funcName = "format" + Date.formatFunctions.count++;
1103 Date.formatFunctions[format] = funcName;
1104 var code = "Date.prototype." + funcName + " = function(){return ";
1105 var special = false;
1107 for (var i = 0; i < format.length; ++i) {
1108 ch = format.charAt(i);
1109 if (!special && ch == "\\") {
1114 code += "'" + String.escape(ch) + "' + ";
1117 code += Date.getFormatCode(ch);
1120 /** eval:var:zzzzzzzzzzzzz */
1121 eval(code.substring(0, code.length - 3) + ";}");
1125 Date.getFormatCode = function(character) {
1126 switch (character) {
1128 return "String.leftPad(this.getDate(), 2, '0') + ";
1130 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1132 return "this.getDate() + ";
1134 return "Date.dayNames[this.getDay()] + ";
1136 return "this.getSuffix() + ";
1138 return "this.getDay() + ";
1140 return "this.getDayOfYear() + ";
1142 return "this.getWeekOfYear() + ";
1144 return "Date.monthNames[this.getMonth()] + ";
1146 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1148 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1150 return "(this.getMonth() + 1) + ";
1152 return "this.getDaysInMonth() + ";
1154 return "(this.isLeapYear() ? 1 : 0) + ";
1156 return "this.getFullYear() + ";
1158 return "('' + this.getFullYear()).substring(2, 4) + ";
1160 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1162 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1164 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1166 return "this.getHours() + ";
1168 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1170 return "String.leftPad(this.getHours(), 2, '0') + ";
1172 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1174 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1176 return "this.getGMTOffset() + ";
1178 return "this.getGMTColonOffset() + ";
1180 return "this.getTimezone() + ";
1182 return "(this.getTimezoneOffset() * -60) + ";
1184 return "'" + String.escape(character) + "' + ";
1189 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1190 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1191 * the date format that is not specified will default to the current date value for that part. Time parts can also
1192 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1193 * string or the parse operation will fail.
1196 //dt = Fri May 25 2007 (current date)
1197 var dt = new Date();
1199 //dt = Thu May 25 2006 (today's month/day in 2006)
1200 dt = Date.parseDate("2006", "Y");
1202 //dt = Sun Jan 15 2006 (all date parts specified)
1203 dt = Date.parseDate("2006-1-15", "Y-m-d");
1205 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1206 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1208 * @param {String} input The unparsed date as a string
1209 * @param {String} format The format the date is in
1210 * @return {Date} The parsed date
1213 Date.parseDate = function(input, format) {
1214 if (Date.parseFunctions[format] == null) {
1215 Date.createParser(format);
1217 var func = Date.parseFunctions[format];
1218 return Date[func](input);
1223 Date.createParser = function(format) {
1224 var funcName = "parse" + Date.parseFunctions.count++;
1225 var regexNum = Date.parseRegexes.length;
1226 var currentGroup = 1;
1227 Date.parseFunctions[format] = funcName;
1229 var code = "Date." + funcName + " = function(input){\n"
1230 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1231 + "var d = new Date();\n"
1232 + "y = d.getFullYear();\n"
1233 + "m = d.getMonth();\n"
1234 + "d = d.getDate();\n"
1235 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1236 + "if (results && results.length > 0) {";
1239 var special = false;
1241 for (var i = 0; i < format.length; ++i) {
1242 ch = format.charAt(i);
1243 if (!special && ch == "\\") {
1248 regex += String.escape(ch);
1251 var obj = Date.formatCodeToRegex(ch, currentGroup);
1252 currentGroup += obj.g;
1254 if (obj.g && obj.c) {
1260 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1261 + "{v = new Date(y, m, d, h, i, s);}\n"
1262 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1263 + "{v = new Date(y, m, d, h, i);}\n"
1264 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1265 + "{v = new Date(y, m, d, h);}\n"
1266 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1267 + "{v = new Date(y, m, d);}\n"
1268 + "else if (y >= 0 && m >= 0)\n"
1269 + "{v = new Date(y, m);}\n"
1270 + "else if (y >= 0)\n"
1271 + "{v = new Date(y);}\n"
1272 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1273 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1274 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1277 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1278 /** eval:var:zzzzzzzzzzzzz */
1283 Date.formatCodeToRegex = function(character, currentGroup) {
1284 switch (character) {
1288 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1291 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1292 s:"(\\d{1,2})"}; // day of month without leading zeroes
1295 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1296 s:"(\\d{2})"}; // day of month with leading zeroes
1300 s:"(?:" + Date.dayNames.join("|") + ")"};
1304 s:"(?:st|nd|rd|th)"};
1319 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1320 s:"(" + Date.monthNames.join("|") + ")"};
1323 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1324 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1327 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1328 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1331 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1332 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1343 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1347 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1348 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1352 c:"if (results[" + currentGroup + "] == 'am') {\n"
1353 + "if (h == 12) { h = 0; }\n"
1354 + "} else { if (h < 12) { h += 12; }}",
1358 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1359 + "if (h == 12) { h = 0; }\n"
1360 + "} else { if (h < 12) { h += 12; }}",
1365 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1366 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1370 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1371 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1374 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1378 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1383 "o = results[", currentGroup, "];\n",
1384 "var sn = o.substring(0,1);\n", // get + / - sign
1385 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1386 "var mn = o.substring(3,5) % 60;\n", // get minutes
1387 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1388 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1394 "o = results[", currentGroup, "];\n",
1395 "var sn = o.substring(0,1);\n",
1396 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1397 "var mn = o.substring(4,6) % 60;\n",
1398 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1399 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1405 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1408 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1409 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1410 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1414 s:String.escape(character)};
1419 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1420 * @return {String} The abbreviated timezone name (e.g. 'CST')
1422 Date.prototype.getTimezone = function() {
1423 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1427 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1428 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1430 Date.prototype.getGMTOffset = function() {
1431 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1432 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1433 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1437 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1438 * @return {String} 2-characters representing hours and 2-characters representing minutes
1439 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1441 Date.prototype.getGMTColonOffset = function() {
1442 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1443 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1445 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1449 * Get the numeric day number of the year, adjusted for leap year.
1450 * @return {Number} 0 through 364 (365 in leap years)
1452 Date.prototype.getDayOfYear = function() {
1454 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1455 for (var i = 0; i < this.getMonth(); ++i) {
1456 num += Date.daysInMonth[i];
1458 return num + this.getDate() - 1;
1462 * Get the string representation of the numeric week number of the year
1463 * (equivalent to the format specifier 'W').
1464 * @return {String} '00' through '52'
1466 Date.prototype.getWeekOfYear = function() {
1467 // Skip to Thursday of this week
1468 var now = this.getDayOfYear() + (4 - this.getDay());
1469 // Find the first Thursday of the year
1470 var jan1 = new Date(this.getFullYear(), 0, 1);
1471 var then = (7 - jan1.getDay() + 4);
1472 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1476 * Whether or not the current date is in a leap year.
1477 * @return {Boolean} True if the current date is in a leap year, else false
1479 Date.prototype.isLeapYear = function() {
1480 var year = this.getFullYear();
1481 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1485 * Get the first day of the current month, adjusted for leap year. The returned value
1486 * is the numeric day index within the week (0-6) which can be used in conjunction with
1487 * the {@link #monthNames} array to retrieve the textual day name.
1490 var dt = new Date('1/10/2007');
1491 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1493 * @return {Number} The day number (0-6)
1495 Date.prototype.getFirstDayOfMonth = function() {
1496 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1497 return (day < 0) ? (day + 7) : day;
1501 * Get the last day of the current month, adjusted for leap year. The returned value
1502 * is the numeric day index within the week (0-6) which can be used in conjunction with
1503 * the {@link #monthNames} array to retrieve the textual day name.
1506 var dt = new Date('1/10/2007');
1507 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1509 * @return {Number} The day number (0-6)
1511 Date.prototype.getLastDayOfMonth = function() {
1512 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1513 return (day < 0) ? (day + 7) : day;
1518 * Get the first date of this date's month
1521 Date.prototype.getFirstDateOfMonth = function() {
1522 return new Date(this.getFullYear(), this.getMonth(), 1);
1526 * Get the last date of this date's month
1529 Date.prototype.getLastDateOfMonth = function() {
1530 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1533 * Get the number of days in the current month, adjusted for leap year.
1534 * @return {Number} The number of days in the month
1536 Date.prototype.getDaysInMonth = function() {
1537 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1538 return Date.daysInMonth[this.getMonth()];
1542 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1543 * @return {String} 'st, 'nd', 'rd' or 'th'
1545 Date.prototype.getSuffix = function() {
1546 switch (this.getDate()) {
1563 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1566 * An array of textual month names.
1567 * Override these values for international dates, for example...
1568 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1587 * An array of textual day names.
1588 * Override these values for international dates, for example...
1589 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1605 Date.monthNumbers = {
1620 * Creates and returns a new Date instance with the exact same date value as the called instance.
1621 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1622 * variable will also be changed. When the intention is to create a new variable that will not
1623 * modify the original instance, you should create a clone.
1625 * Example of correctly cloning a date:
1628 var orig = new Date('10/1/2006');
1631 document.write(orig); //returns 'Thu Oct 05 2006'!
1634 var orig = new Date('10/1/2006');
1635 var copy = orig.clone();
1637 document.write(orig); //returns 'Thu Oct 01 2006'
1639 * @return {Date} The new Date instance
1641 Date.prototype.clone = function() {
1642 return new Date(this.getTime());
1646 * Clears any time information from this date
1647 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1648 @return {Date} this or the clone
1650 Date.prototype.clearTime = function(clone){
1652 return this.clone().clearTime();
1657 this.setMilliseconds(0);
1662 // safari setMonth is broken
1664 Date.brokenSetMonth = Date.prototype.setMonth;
1665 Date.prototype.setMonth = function(num){
1667 var n = Math.ceil(-num);
1668 var back_year = Math.ceil(n/12);
1669 var month = (n % 12) ? 12 - n % 12 : 0 ;
1670 this.setFullYear(this.getFullYear() - back_year);
1671 return Date.brokenSetMonth.call(this, month);
1673 return Date.brokenSetMonth.apply(this, arguments);
1678 /** Date interval constant
1682 /** Date interval constant
1686 /** Date interval constant
1690 /** Date interval constant
1694 /** Date interval constant
1698 /** Date interval constant
1702 /** Date interval constant
1708 * Provides a convenient method of performing basic date arithmetic. This method
1709 * does not modify the Date instance being called - it creates and returns
1710 * a new Date instance containing the resulting date value.
1715 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1716 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1718 //Negative values will subtract correctly:
1719 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1720 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1722 //You can even chain several calls together in one line!
1723 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1724 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1727 * @param {String} interval A valid date interval enum value
1728 * @param {Number} value The amount to add to the current date
1729 * @return {Date} The new Date instance
1731 Date.prototype.add = function(interval, value){
1732 var d = this.clone();
1733 if (!interval || value === 0) return d;
1734 switch(interval.toLowerCase()){
1736 d.setMilliseconds(this.getMilliseconds() + value);
1739 d.setSeconds(this.getSeconds() + value);
1742 d.setMinutes(this.getMinutes() + value);
1745 d.setHours(this.getHours() + value);
1748 d.setDate(this.getDate() + value);
1751 var day = this.getDate();
1753 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1756 d.setMonth(this.getMonth() + value);
1759 d.setFullYear(this.getFullYear() + value);
1766 * Ext JS Library 1.1.1
1767 * Copyright(c) 2006-2007, Ext JS, LLC.
1769 * Originally Released Under LGPL - original licence link has changed is not relivant.
1772 * <script type="text/javascript">
1776 getViewWidth : function(full) {
1777 return full ? this.getDocumentWidth() : this.getViewportWidth();
1780 getViewHeight : function(full) {
1781 return full ? this.getDocumentHeight() : this.getViewportHeight();
1784 getDocumentHeight: function() {
1785 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1786 return Math.max(scrollHeight, this.getViewportHeight());
1789 getDocumentWidth: function() {
1790 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1791 return Math.max(scrollWidth, this.getViewportWidth());
1794 getViewportHeight: function() {
1795 var height = self.innerHeight;
1796 var mode = document.compatMode;
1798 if ((mode || Roo.isIE) && !Roo.isOpera) {
1799 height = (mode == "CSS1Compat") ?
1800 document.documentElement.clientHeight :
1801 document.body.clientHeight;
1807 getViewportWidth: function() {
1808 var width = self.innerWidth;
1809 var mode = document.compatMode;
1811 if (mode || Roo.isIE) {
1812 width = (mode == "CSS1Compat") ?
1813 document.documentElement.clientWidth :
1814 document.body.clientWidth;
1819 isAncestor : function(p, c) {
1826 if (p.contains && !Roo.isSafari) {
1827 return p.contains(c);
1828 } else if (p.compareDocumentPosition) {
1829 return !!(p.compareDocumentPosition(c) & 16);
1831 var parent = c.parentNode;
1836 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1839 parent = parent.parentNode;
1845 getRegion : function(el) {
1846 return Roo.lib.Region.getRegion(el);
1849 getY : function(el) {
1850 return this.getXY(el)[1];
1853 getX : function(el) {
1854 return this.getXY(el)[0];
1857 getXY : function(el) {
1858 var p, pe, b, scroll, bd = document.body;
1859 el = Roo.getDom(el);
1860 var fly = Roo.lib.AnimBase.fly;
1861 if (el.getBoundingClientRect) {
1862 b = el.getBoundingClientRect();
1863 scroll = fly(document).getScroll();
1864 return [b.left + scroll.left, b.top + scroll.top];
1870 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1877 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1884 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1885 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1892 if (p != el && pe.getStyle('overflow') != 'visible') {
1900 if (Roo.isSafari && hasAbsolute) {
1905 if (Roo.isGecko && !hasAbsolute) {
1907 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1908 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1912 while (p && p != bd) {
1913 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1925 setXY : function(el, xy) {
1926 el = Roo.fly(el, '_setXY');
1928 var pts = el.translatePoints(xy);
1929 if (xy[0] !== false) {
1930 el.dom.style.left = pts.left + "px";
1932 if (xy[1] !== false) {
1933 el.dom.style.top = pts.top + "px";
1937 setX : function(el, x) {
1938 this.setXY(el, [x, false]);
1941 setY : function(el, y) {
1942 this.setXY(el, [false, y]);
1946 * Portions of this file are based on pieces of Yahoo User Interface Library
1947 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1948 * YUI licensed under the BSD License:
1949 * http://developer.yahoo.net/yui/license.txt
1950 * <script type="text/javascript">
1954 Roo.lib.Event = function() {
1955 var loadComplete = false;
1957 var unloadListeners = [];
1959 var onAvailStack = [];
1961 var lastError = null;
1974 startInterval: function() {
1975 if (!this._interval) {
1977 var callback = function() {
1978 self._tryPreloadAttach();
1980 this._interval = setInterval(callback, this.POLL_INTERVAL);
1985 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1986 onAvailStack.push({ id: p_id,
1989 override: p_override,
1990 checkReady: false });
1992 retryCount = this.POLL_RETRYS;
1993 this.startInterval();
1997 addListener: function(el, eventName, fn) {
1998 el = Roo.getDom(el);
2003 if ("unload" == eventName) {
2004 unloadListeners[unloadListeners.length] =
2005 [el, eventName, fn];
2009 var wrappedFn = function(e) {
2010 return fn(Roo.lib.Event.getEvent(e));
2013 var li = [el, eventName, fn, wrappedFn];
2015 var index = listeners.length;
2016 listeners[index] = li;
2018 this.doAdd(el, eventName, wrappedFn, false);
2024 removeListener: function(el, eventName, fn) {
2027 el = Roo.getDom(el);
2030 return this.purgeElement(el, false, eventName);
2034 if ("unload" == eventName) {
2036 for (i = 0,len = unloadListeners.length; i < len; i++) {
2037 var li = unloadListeners[i];
2040 li[1] == eventName &&
2042 unloadListeners.splice(i, 1);
2050 var cacheItem = null;
2053 var index = arguments[3];
2055 if ("undefined" == typeof index) {
2056 index = this._getCacheIndex(el, eventName, fn);
2060 cacheItem = listeners[index];
2063 if (!el || !cacheItem) {
2067 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2069 delete listeners[index][this.WFN];
2070 delete listeners[index][this.FN];
2071 listeners.splice(index, 1);
2078 getTarget: function(ev, resolveTextNode) {
2079 ev = ev.browserEvent || ev;
2080 var t = ev.target || ev.srcElement;
2081 return this.resolveTextNode(t);
2085 resolveTextNode: function(node) {
2086 if (Roo.isSafari && node && 3 == node.nodeType) {
2087 return node.parentNode;
2094 getPageX: function(ev) {
2095 ev = ev.browserEvent || ev;
2097 if (!x && 0 !== x) {
2098 x = ev.clientX || 0;
2101 x += this.getScroll()[1];
2109 getPageY: function(ev) {
2110 ev = ev.browserEvent || ev;
2112 if (!y && 0 !== y) {
2113 y = ev.clientY || 0;
2116 y += this.getScroll()[0];
2125 getXY: function(ev) {
2126 ev = ev.browserEvent || ev;
2127 return [this.getPageX(ev), this.getPageY(ev)];
2131 getRelatedTarget: function(ev) {
2132 ev = ev.browserEvent || ev;
2133 var t = ev.relatedTarget;
2135 if (ev.type == "mouseout") {
2137 } else if (ev.type == "mouseover") {
2142 return this.resolveTextNode(t);
2146 getTime: function(ev) {
2147 ev = ev.browserEvent || ev;
2149 var t = new Date().getTime();
2153 this.lastError = ex;
2162 stopEvent: function(ev) {
2163 this.stopPropagation(ev);
2164 this.preventDefault(ev);
2168 stopPropagation: function(ev) {
2169 ev = ev.browserEvent || ev;
2170 if (ev.stopPropagation) {
2171 ev.stopPropagation();
2173 ev.cancelBubble = true;
2178 preventDefault: function(ev) {
2179 ev = ev.browserEvent || ev;
2180 if(ev.preventDefault) {
2181 ev.preventDefault();
2183 ev.returnValue = false;
2188 getEvent: function(e) {
2189 var ev = e || window.event;
2191 var c = this.getEvent.caller;
2193 ev = c.arguments[0];
2194 if (ev && Event == ev.constructor) {
2204 getCharCode: function(ev) {
2205 ev = ev.browserEvent || ev;
2206 return ev.charCode || ev.keyCode || 0;
2210 _getCacheIndex: function(el, eventName, fn) {
2211 for (var i = 0,len = listeners.length; i < len; ++i) {
2212 var li = listeners[i];
2214 li[this.FN] == fn &&
2215 li[this.EL] == el &&
2216 li[this.TYPE] == eventName) {
2228 getEl: function(id) {
2229 return document.getElementById(id);
2233 clearCache: function() {
2237 _load: function(e) {
2238 loadComplete = true;
2239 var EU = Roo.lib.Event;
2243 EU.doRemove(window, "load", EU._load);
2248 _tryPreloadAttach: function() {
2257 var tryAgain = !loadComplete;
2259 tryAgain = (retryCount > 0);
2264 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2265 var item = onAvailStack[i];
2267 var el = this.getEl(item.id);
2270 if (!item.checkReady ||
2273 (document && document.body)) {
2276 if (item.override) {
2277 if (item.override === true) {
2280 scope = item.override;
2283 item.fn.call(scope, item.obj);
2284 onAvailStack[i] = null;
2287 notAvail.push(item);
2292 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2296 this.startInterval();
2298 clearInterval(this._interval);
2299 this._interval = null;
2302 this.locked = false;
2309 purgeElement: function(el, recurse, eventName) {
2310 var elListeners = this.getListeners(el, eventName);
2312 for (var i = 0,len = elListeners.length; i < len; ++i) {
2313 var l = elListeners[i];
2314 this.removeListener(el, l.type, l.fn);
2318 if (recurse && el && el.childNodes) {
2319 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2320 this.purgeElement(el.childNodes[i], recurse, eventName);
2326 getListeners: function(el, eventName) {
2327 var results = [], searchLists;
2329 searchLists = [listeners, unloadListeners];
2330 } else if (eventName == "unload") {
2331 searchLists = [unloadListeners];
2333 searchLists = [listeners];
2336 for (var j = 0; j < searchLists.length; ++j) {
2337 var searchList = searchLists[j];
2338 if (searchList && searchList.length > 0) {
2339 for (var i = 0,len = searchList.length; i < len; ++i) {
2340 var l = searchList[i];
2341 if (l && l[this.EL] === el &&
2342 (!eventName || eventName === l[this.TYPE])) {
2347 adjust: l[this.ADJ_SCOPE],
2355 return (results.length) ? results : null;
2359 _unload: function(e) {
2361 var EU = Roo.lib.Event, i, j, l, len, index;
2363 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2364 l = unloadListeners[i];
2367 if (l[EU.ADJ_SCOPE]) {
2368 if (l[EU.ADJ_SCOPE] === true) {
2371 scope = l[EU.ADJ_SCOPE];
2374 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2375 unloadListeners[i] = null;
2381 unloadListeners = null;
2383 if (listeners && listeners.length > 0) {
2384 j = listeners.length;
2387 l = listeners[index];
2389 EU.removeListener(l[EU.EL], l[EU.TYPE],
2399 EU.doRemove(window, "unload", EU._unload);
2404 getScroll: function() {
2405 var dd = document.documentElement, db = document.body;
2406 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2407 return [dd.scrollTop, dd.scrollLeft];
2409 return [db.scrollTop, db.scrollLeft];
2416 doAdd: function () {
2417 if (window.addEventListener) {
2418 return function(el, eventName, fn, capture) {
2419 el.addEventListener(eventName, fn, (capture));
2421 } else if (window.attachEvent) {
2422 return function(el, eventName, fn, capture) {
2423 el.attachEvent("on" + eventName, fn);
2432 doRemove: function() {
2433 if (window.removeEventListener) {
2434 return function (el, eventName, fn, capture) {
2435 el.removeEventListener(eventName, fn, (capture));
2437 } else if (window.detachEvent) {
2438 return function (el, eventName, fn) {
2439 el.detachEvent("on" + eventName, fn);
2451 var E = Roo.lib.Event;
2452 E.on = E.addListener;
2453 E.un = E.removeListener;
2455 if (document && document.body) {
2458 E.doAdd(window, "load", E._load);
2460 E.doAdd(window, "unload", E._unload);
2461 E._tryPreloadAttach();
2465 * Portions of this file are based on pieces of Yahoo User Interface Library
2466 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2467 * YUI licensed under the BSD License:
2468 * http://developer.yahoo.net/yui/license.txt
2469 * <script type="text/javascript">
2475 * @class Roo.lib.Ajax
2482 request : function(method, uri, cb, data, options) {
2484 var hs = options.headers;
2487 if(hs.hasOwnProperty(h)){
2488 this.initHeader(h, hs[h], false);
2492 if(options.xmlData){
2493 this.initHeader('Content-Type', 'text/xml', false);
2495 data = options.xmlData;
2499 return this.asyncRequest(method, uri, cb, data);
2502 serializeForm : function(form) {
2503 if(typeof form == 'string') {
2504 form = (document.getElementById(form) || document.forms[form]);
2507 var el, name, val, disabled, data = '', hasSubmit = false;
2508 for (var i = 0; i < form.elements.length; i++) {
2509 el = form.elements[i];
2510 disabled = form.elements[i].disabled;
2511 name = form.elements[i].name;
2512 val = form.elements[i].value;
2514 if (!disabled && name){
2518 case 'select-multiple':
2519 for (var j = 0; j < el.options.length; j++) {
2520 if (el.options[j].selected) {
2522 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2525 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2533 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2546 if(hasSubmit == false) {
2547 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2552 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2557 data = data.substr(0, data.length - 1);
2565 useDefaultHeader:true,
2567 defaultPostHeader:'application/x-www-form-urlencoded',
2569 useDefaultXhrHeader:true,
2571 defaultXhrHeader:'XMLHttpRequest',
2573 hasDefaultHeaders:true,
2585 setProgId:function(id)
2587 this.activeX.unshift(id);
2590 setDefaultPostHeader:function(b)
2592 this.useDefaultHeader = b;
2595 setDefaultXhrHeader:function(b)
2597 this.useDefaultXhrHeader = b;
2600 setPollingInterval:function(i)
2602 if (typeof i == 'number' && isFinite(i)) {
2603 this.pollInterval = i;
2607 createXhrObject:function(transactionId)
2613 http = new XMLHttpRequest();
2615 obj = { conn:http, tId:transactionId };
2619 for (var i = 0; i < this.activeX.length; ++i) {
2623 http = new ActiveXObject(this.activeX[i]);
2625 obj = { conn:http, tId:transactionId };
2638 getConnectionObject:function()
2641 var tId = this.transactionId;
2645 o = this.createXhrObject(tId);
2647 this.transactionId++;
2658 asyncRequest:function(method, uri, callback, postData)
2660 var o = this.getConnectionObject();
2666 o.conn.open(method, uri, true);
2668 if (this.useDefaultXhrHeader) {
2669 if (!this.defaultHeaders['X-Requested-With']) {
2670 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2674 if(postData && this.useDefaultHeader){
2675 this.initHeader('Content-Type', this.defaultPostHeader);
2678 if (this.hasDefaultHeaders || this.hasHeaders) {
2682 this.handleReadyState(o, callback);
2683 o.conn.send(postData || null);
2689 handleReadyState:function(o, callback)
2693 if (callback && callback.timeout) {
2694 this.timeout[o.tId] = window.setTimeout(function() {
2695 oConn.abort(o, callback, true);
2696 }, callback.timeout);
2699 this.poll[o.tId] = window.setInterval(
2701 if (o.conn && o.conn.readyState == 4) {
2702 window.clearInterval(oConn.poll[o.tId]);
2703 delete oConn.poll[o.tId];
2705 if(callback && callback.timeout) {
2706 window.clearTimeout(oConn.timeout[o.tId]);
2707 delete oConn.timeout[o.tId];
2710 oConn.handleTransactionResponse(o, callback);
2713 , this.pollInterval);
2716 handleTransactionResponse:function(o, callback, isAbort)
2720 this.releaseObject(o);
2724 var httpStatus, responseObject;
2728 if (o.conn.status !== undefined && o.conn.status != 0) {
2729 httpStatus = o.conn.status;
2741 if (httpStatus >= 200 && httpStatus < 300) {
2742 responseObject = this.createResponseObject(o, callback.argument);
2743 if (callback.success) {
2744 if (!callback.scope) {
2745 callback.success(responseObject);
2750 callback.success.apply(callback.scope, [responseObject]);
2755 switch (httpStatus) {
2763 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2764 if (callback.failure) {
2765 if (!callback.scope) {
2766 callback.failure(responseObject);
2769 callback.failure.apply(callback.scope, [responseObject]);
2774 responseObject = this.createResponseObject(o, callback.argument);
2775 if (callback.failure) {
2776 if (!callback.scope) {
2777 callback.failure(responseObject);
2780 callback.failure.apply(callback.scope, [responseObject]);
2786 this.releaseObject(o);
2787 responseObject = null;
2790 createResponseObject:function(o, callbackArg)
2797 var headerStr = o.conn.getAllResponseHeaders();
2798 var header = headerStr.split('\n');
2799 for (var i = 0; i < header.length; i++) {
2800 var delimitPos = header[i].indexOf(':');
2801 if (delimitPos != -1) {
2802 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2810 obj.status = o.conn.status;
2811 obj.statusText = o.conn.statusText;
2812 obj.getResponseHeader = headerObj;
2813 obj.getAllResponseHeaders = headerStr;
2814 obj.responseText = o.conn.responseText;
2815 obj.responseXML = o.conn.responseXML;
2817 if (typeof callbackArg !== undefined) {
2818 obj.argument = callbackArg;
2824 createExceptionObject:function(tId, callbackArg, isAbort)
2827 var COMM_ERROR = 'communication failure';
2828 var ABORT_CODE = -1;
2829 var ABORT_ERROR = 'transaction aborted';
2835 obj.status = ABORT_CODE;
2836 obj.statusText = ABORT_ERROR;
2839 obj.status = COMM_CODE;
2840 obj.statusText = COMM_ERROR;
2844 obj.argument = callbackArg;
2850 initHeader:function(label, value, isDefault)
2852 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2854 if (headerObj[label] === undefined) {
2855 headerObj[label] = value;
2860 headerObj[label] = value + "," + headerObj[label];
2864 this.hasDefaultHeaders = true;
2867 this.hasHeaders = true;
2872 setHeader:function(o)
2874 if (this.hasDefaultHeaders) {
2875 for (var prop in this.defaultHeaders) {
2876 if (this.defaultHeaders.hasOwnProperty(prop)) {
2877 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2882 if (this.hasHeaders) {
2883 for (var prop in this.headers) {
2884 if (this.headers.hasOwnProperty(prop)) {
2885 o.conn.setRequestHeader(prop, this.headers[prop]);
2889 this.hasHeaders = false;
2893 resetDefaultHeaders:function() {
2894 delete this.defaultHeaders;
2895 this.defaultHeaders = {};
2896 this.hasDefaultHeaders = false;
2899 abort:function(o, callback, isTimeout)
2901 if(this.isCallInProgress(o)) {
2903 window.clearInterval(this.poll[o.tId]);
2904 delete this.poll[o.tId];
2906 delete this.timeout[o.tId];
2909 this.handleTransactionResponse(o, callback, true);
2919 isCallInProgress:function(o)
2922 return o.conn.readyState != 4 && o.conn.readyState != 0;
2931 releaseObject:function(o)
2940 'MSXML2.XMLHTTP.3.0',
2948 * Portions of this file are based on pieces of Yahoo User Interface Library
2949 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2950 * YUI licensed under the BSD License:
2951 * http://developer.yahoo.net/yui/license.txt
2952 * <script type="text/javascript">
2956 Roo.lib.Region = function(t, r, b, l) {
2966 Roo.lib.Region.prototype = {
2967 contains : function(region) {
2968 return ( region.left >= this.left &&
2969 region.right <= this.right &&
2970 region.top >= this.top &&
2971 region.bottom <= this.bottom );
2975 getArea : function() {
2976 return ( (this.bottom - this.top) * (this.right - this.left) );
2979 intersect : function(region) {
2980 var t = Math.max(this.top, region.top);
2981 var r = Math.min(this.right, region.right);
2982 var b = Math.min(this.bottom, region.bottom);
2983 var l = Math.max(this.left, region.left);
2985 if (b >= t && r >= l) {
2986 return new Roo.lib.Region(t, r, b, l);
2991 union : function(region) {
2992 var t = Math.min(this.top, region.top);
2993 var r = Math.max(this.right, region.right);
2994 var b = Math.max(this.bottom, region.bottom);
2995 var l = Math.min(this.left, region.left);
2997 return new Roo.lib.Region(t, r, b, l);
3000 adjust : function(t, l, b, r) {
3009 Roo.lib.Region.getRegion = function(el) {
3010 var p = Roo.lib.Dom.getXY(el);
3013 var r = p[0] + el.offsetWidth;
3014 var b = p[1] + el.offsetHeight;
3017 return new Roo.lib.Region(t, r, b, l);
3020 * Portions of this file are based on pieces of Yahoo User Interface Library
3021 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3022 * YUI licensed under the BSD License:
3023 * http://developer.yahoo.net/yui/license.txt
3024 * <script type="text/javascript">
3027 //@@dep Roo.lib.Region
3030 Roo.lib.Point = function(x, y) {
3031 if (x instanceof Array) {
3035 this.x = this.right = this.left = this[0] = x;
3036 this.y = this.top = this.bottom = this[1] = y;
3039 Roo.lib.Point.prototype = new Roo.lib.Region();
3041 * Portions of this file are based on pieces of Yahoo User Interface Library
3042 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3043 * YUI licensed under the BSD License:
3044 * http://developer.yahoo.net/yui/license.txt
3045 * <script type="text/javascript">
3052 scroll : function(el, args, duration, easing, cb, scope) {
3053 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3056 motion : function(el, args, duration, easing, cb, scope) {
3057 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3060 color : function(el, args, duration, easing, cb, scope) {
3061 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3064 run : function(el, args, duration, easing, cb, scope, type) {
3065 type = type || Roo.lib.AnimBase;
3066 if (typeof easing == "string") {
3067 easing = Roo.lib.Easing[easing];
3069 var anim = new type(el, args, duration, easing);
3070 anim.animateX(function() {
3071 Roo.callback(cb, scope);
3077 * Portions of this file are based on pieces of Yahoo User Interface Library
3078 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3079 * YUI licensed under the BSD License:
3080 * http://developer.yahoo.net/yui/license.txt
3081 * <script type="text/javascript">
3089 if (!libFlyweight) {
3090 libFlyweight = new Roo.Element.Flyweight();
3092 libFlyweight.dom = el;
3093 return libFlyweight;
3096 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3100 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3102 this.init(el, attributes, duration, method);
3106 Roo.lib.AnimBase.fly = fly;
3110 Roo.lib.AnimBase.prototype = {
3112 toString: function() {
3113 var el = this.getEl();
3114 var id = el.id || el.tagName;
3115 return ("Anim " + id);
3119 noNegatives: /width|height|opacity|padding/i,
3120 offsetAttribute: /^((width|height)|(top|left))$/,
3121 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3122 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3126 doMethod: function(attr, start, end) {
3127 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3131 setAttribute: function(attr, val, unit) {
3132 if (this.patterns.noNegatives.test(attr)) {
3133 val = (val > 0) ? val : 0;
3136 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3140 getAttribute: function(attr) {
3141 var el = this.getEl();
3142 var val = fly(el).getStyle(attr);
3144 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3145 return parseFloat(val);
3148 var a = this.patterns.offsetAttribute.exec(attr) || [];
3149 var pos = !!( a[3] );
3150 var box = !!( a[2] );
3153 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3154 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3163 getDefaultUnit: function(attr) {
3164 if (this.patterns.defaultUnit.test(attr)) {
3171 animateX : function(callback, scope) {
3172 var f = function() {
3173 this.onComplete.removeListener(f);
3174 if (typeof callback == "function") {
3175 callback.call(scope || this, this);
3178 this.onComplete.addListener(f, this);
3183 setRuntimeAttribute: function(attr) {
3186 var attributes = this.attributes;
3188 this.runtimeAttributes[attr] = {};
3190 var isset = function(prop) {
3191 return (typeof prop !== 'undefined');
3194 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3198 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3201 if (isset(attributes[attr]['to'])) {
3202 end = attributes[attr]['to'];
3203 } else if (isset(attributes[attr]['by'])) {
3204 if (start.constructor == Array) {
3206 for (var i = 0, len = start.length; i < len; ++i) {
3207 end[i] = start[i] + attributes[attr]['by'][i];
3210 end = start + attributes[attr]['by'];
3214 this.runtimeAttributes[attr].start = start;
3215 this.runtimeAttributes[attr].end = end;
3218 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3222 init: function(el, attributes, duration, method) {
3224 var isAnimated = false;
3227 var startTime = null;
3230 var actualFrames = 0;
3233 el = Roo.getDom(el);
3236 this.attributes = attributes || {};
3239 this.duration = duration || 1;
3242 this.method = method || Roo.lib.Easing.easeNone;
3245 this.useSeconds = true;
3248 this.currentFrame = 0;
3251 this.totalFrames = Roo.lib.AnimMgr.fps;
3254 this.getEl = function() {
3259 this.isAnimated = function() {
3264 this.getStartTime = function() {
3268 this.runtimeAttributes = {};
3271 this.animate = function() {
3272 if (this.isAnimated()) {
3276 this.currentFrame = 0;
3278 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3280 Roo.lib.AnimMgr.registerElement(this);
3284 this.stop = function(finish) {
3286 this.currentFrame = this.totalFrames;
3287 this._onTween.fire();
3289 Roo.lib.AnimMgr.stop(this);
3292 var onStart = function() {
3293 this.onStart.fire();
3295 this.runtimeAttributes = {};
3296 for (var attr in this.attributes) {
3297 this.setRuntimeAttribute(attr);
3302 startTime = new Date();
3306 var onTween = function() {
3308 duration: new Date() - this.getStartTime(),
3309 currentFrame: this.currentFrame
3312 data.toString = function() {
3314 'duration: ' + data.duration +
3315 ', currentFrame: ' + data.currentFrame
3319 this.onTween.fire(data);
3321 var runtimeAttributes = this.runtimeAttributes;
3323 for (var attr in runtimeAttributes) {
3324 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3330 var onComplete = function() {
3331 var actual_duration = (new Date() - startTime) / 1000 ;
3334 duration: actual_duration,
3335 frames: actualFrames,
3336 fps: actualFrames / actual_duration
3339 data.toString = function() {
3341 'duration: ' + data.duration +
3342 ', frames: ' + data.frames +
3343 ', fps: ' + data.fps
3349 this.onComplete.fire(data);
3353 this._onStart = new Roo.util.Event(this);
3354 this.onStart = new Roo.util.Event(this);
3355 this.onTween = new Roo.util.Event(this);
3356 this._onTween = new Roo.util.Event(this);
3357 this.onComplete = new Roo.util.Event(this);
3358 this._onComplete = new Roo.util.Event(this);
3359 this._onStart.addListener(onStart);
3360 this._onTween.addListener(onTween);
3361 this._onComplete.addListener(onComplete);
3366 * Portions of this file are based on pieces of Yahoo User Interface Library
3367 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3368 * YUI licensed under the BSD License:
3369 * http://developer.yahoo.net/yui/license.txt
3370 * <script type="text/javascript">
3374 Roo.lib.AnimMgr = new function() {
3391 this.registerElement = function(tween) {
3392 queue[queue.length] = tween;
3394 tween._onStart.fire();
3399 this.unRegister = function(tween, index) {
3400 tween._onComplete.fire();
3401 index = index || getIndex(tween);
3403 queue.splice(index, 1);
3407 if (tweenCount <= 0) {
3413 this.start = function() {
3414 if (thread === null) {
3415 thread = setInterval(this.run, this.delay);
3420 this.stop = function(tween) {
3422 clearInterval(thread);
3424 for (var i = 0, len = queue.length; i < len; ++i) {
3425 if (queue[0].isAnimated()) {
3426 this.unRegister(queue[0], 0);
3435 this.unRegister(tween);
3440 this.run = function() {
3441 for (var i = 0, len = queue.length; i < len; ++i) {
3442 var tween = queue[i];
3443 if (!tween || !tween.isAnimated()) {
3447 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3449 tween.currentFrame += 1;
3451 if (tween.useSeconds) {
3452 correctFrame(tween);
3454 tween._onTween.fire();
3457 Roo.lib.AnimMgr.stop(tween, i);
3462 var getIndex = function(anim) {
3463 for (var i = 0, len = queue.length; i < len; ++i) {
3464 if (queue[i] == anim) {
3472 var correctFrame = function(tween) {
3473 var frames = tween.totalFrames;
3474 var frame = tween.currentFrame;
3475 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3476 var elapsed = (new Date() - tween.getStartTime());
3479 if (elapsed < tween.duration * 1000) {
3480 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3482 tweak = frames - (frame + 1);
3484 if (tweak > 0 && isFinite(tweak)) {
3485 if (tween.currentFrame + tweak >= frames) {
3486 tweak = frames - (frame + 1);
3489 tween.currentFrame += tweak;
3493 * Portions of this file are based on pieces of Yahoo User Interface Library
3494 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3495 * YUI licensed under the BSD License:
3496 * http://developer.yahoo.net/yui/license.txt
3497 * <script type="text/javascript">
3500 Roo.lib.Bezier = new function() {
3502 this.getPosition = function(points, t) {
3503 var n = points.length;
3506 for (var i = 0; i < n; ++i) {
3507 tmp[i] = [points[i][0], points[i][1]];
3510 for (var j = 1; j < n; ++j) {
3511 for (i = 0; i < n - j; ++i) {
3512 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3513 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3517 return [ tmp[0][0], tmp[0][1] ];
3521 * Portions of this file are based on pieces of Yahoo User Interface Library
3522 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3523 * YUI licensed under the BSD License:
3524 * http://developer.yahoo.net/yui/license.txt
3525 * <script type="text/javascript">
3530 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3531 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3534 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3536 var fly = Roo.lib.AnimBase.fly;
3538 var superclass = Y.ColorAnim.superclass;
3539 var proto = Y.ColorAnim.prototype;
3541 proto.toString = function() {
3542 var el = this.getEl();
3543 var id = el.id || el.tagName;
3544 return ("ColorAnim " + id);
3547 proto.patterns.color = /color$/i;
3548 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3549 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3550 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3551 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3554 proto.parseColor = function(s) {
3555 if (s.length == 3) {
3559 var c = this.patterns.hex.exec(s);
3560 if (c && c.length == 4) {
3561 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3564 c = this.patterns.rgb.exec(s);
3565 if (c && c.length == 4) {
3566 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3569 c = this.patterns.hex3.exec(s);
3570 if (c && c.length == 4) {
3571 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3576 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3577 proto.getAttribute = function(attr) {
3578 var el = this.getEl();
3579 if (this.patterns.color.test(attr)) {
3580 var val = fly(el).getStyle(attr);
3582 if (this.patterns.transparent.test(val)) {
3583 var parent = el.parentNode;
3584 val = fly(parent).getStyle(attr);
3586 while (parent && this.patterns.transparent.test(val)) {
3587 parent = parent.parentNode;
3588 val = fly(parent).getStyle(attr);
3589 if (parent.tagName.toUpperCase() == 'HTML') {
3595 val = superclass.getAttribute.call(this, attr);
3600 proto.getAttribute = function(attr) {
3601 var el = this.getEl();
3602 if (this.patterns.color.test(attr)) {
3603 var val = fly(el).getStyle(attr);
3605 if (this.patterns.transparent.test(val)) {
3606 var parent = el.parentNode;
3607 val = fly(parent).getStyle(attr);
3609 while (parent && this.patterns.transparent.test(val)) {
3610 parent = parent.parentNode;
3611 val = fly(parent).getStyle(attr);
3612 if (parent.tagName.toUpperCase() == 'HTML') {
3618 val = superclass.getAttribute.call(this, attr);
3624 proto.doMethod = function(attr, start, end) {
3627 if (this.patterns.color.test(attr)) {
3629 for (var i = 0, len = start.length; i < len; ++i) {
3630 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3633 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3636 val = superclass.doMethod.call(this, attr, start, end);
3642 proto.setRuntimeAttribute = function(attr) {
3643 superclass.setRuntimeAttribute.call(this, attr);
3645 if (this.patterns.color.test(attr)) {
3646 var attributes = this.attributes;
3647 var start = this.parseColor(this.runtimeAttributes[attr].start);
3648 var end = this.parseColor(this.runtimeAttributes[attr].end);
3650 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3651 end = this.parseColor(attributes[attr].by);
3653 for (var i = 0, len = start.length; i < len; ++i) {
3654 end[i] = start[i] + end[i];
3658 this.runtimeAttributes[attr].start = start;
3659 this.runtimeAttributes[attr].end = end;
3665 * Portions of this file are based on pieces of Yahoo User Interface Library
3666 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3667 * YUI licensed under the BSD License:
3668 * http://developer.yahoo.net/yui/license.txt
3669 * <script type="text/javascript">
3675 easeNone: function (t, b, c, d) {
3676 return c * t / d + b;
3680 easeIn: function (t, b, c, d) {
3681 return c * (t /= d) * t + b;
3685 easeOut: function (t, b, c, d) {
3686 return -c * (t /= d) * (t - 2) + b;
3690 easeBoth: function (t, b, c, d) {
3691 if ((t /= d / 2) < 1) {
3692 return c / 2 * t * t + b;
3695 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3699 easeInStrong: function (t, b, c, d) {
3700 return c * (t /= d) * t * t * t + b;
3704 easeOutStrong: function (t, b, c, d) {
3705 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3709 easeBothStrong: function (t, b, c, d) {
3710 if ((t /= d / 2) < 1) {
3711 return c / 2 * t * t * t * t + b;
3714 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3719 elasticIn: function (t, b, c, d, a, p) {
3723 if ((t /= d) == 1) {
3730 if (!a || a < Math.abs(c)) {
3735 var s = p / (2 * Math.PI) * Math.asin(c / a);
3738 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3742 elasticOut: function (t, b, c, d, a, p) {
3746 if ((t /= d) == 1) {
3753 if (!a || a < Math.abs(c)) {
3758 var s = p / (2 * Math.PI) * Math.asin(c / a);
3761 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3765 elasticBoth: function (t, b, c, d, a, p) {
3770 if ((t /= d / 2) == 2) {
3778 if (!a || a < Math.abs(c)) {
3783 var s = p / (2 * Math.PI) * Math.asin(c / a);
3787 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3788 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3790 return a * Math.pow(2, -10 * (t -= 1)) *
3791 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3796 backIn: function (t, b, c, d, s) {
3797 if (typeof s == 'undefined') {
3800 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3804 backOut: function (t, b, c, d, s) {
3805 if (typeof s == 'undefined') {
3808 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3812 backBoth: function (t, b, c, d, s) {
3813 if (typeof s == 'undefined') {
3817 if ((t /= d / 2 ) < 1) {
3818 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3820 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3824 bounceIn: function (t, b, c, d) {
3825 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3829 bounceOut: function (t, b, c, d) {
3830 if ((t /= d) < (1 / 2.75)) {
3831 return c * (7.5625 * t * t) + b;
3832 } else if (t < (2 / 2.75)) {
3833 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3834 } else if (t < (2.5 / 2.75)) {
3835 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3837 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3841 bounceBoth: function (t, b, c, d) {
3843 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3845 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3848 * Portions of this file are based on pieces of Yahoo User Interface Library
3849 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3850 * YUI licensed under the BSD License:
3851 * http://developer.yahoo.net/yui/license.txt
3852 * <script type="text/javascript">
3856 Roo.lib.Motion = function(el, attributes, duration, method) {
3858 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3862 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3866 var superclass = Y.Motion.superclass;
3867 var proto = Y.Motion.prototype;
3869 proto.toString = function() {
3870 var el = this.getEl();
3871 var id = el.id || el.tagName;
3872 return ("Motion " + id);
3875 proto.patterns.points = /^points$/i;
3877 proto.setAttribute = function(attr, val, unit) {
3878 if (this.patterns.points.test(attr)) {
3879 unit = unit || 'px';
3880 superclass.setAttribute.call(this, 'left', val[0], unit);
3881 superclass.setAttribute.call(this, 'top', val[1], unit);
3883 superclass.setAttribute.call(this, attr, val, unit);
3887 proto.getAttribute = function(attr) {
3888 if (this.patterns.points.test(attr)) {
3890 superclass.getAttribute.call(this, 'left'),
3891 superclass.getAttribute.call(this, 'top')
3894 val = superclass.getAttribute.call(this, attr);
3900 proto.doMethod = function(attr, start, end) {
3903 if (this.patterns.points.test(attr)) {
3904 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3905 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3907 val = superclass.doMethod.call(this, attr, start, end);
3912 proto.setRuntimeAttribute = function(attr) {
3913 if (this.patterns.points.test(attr)) {
3914 var el = this.getEl();
3915 var attributes = this.attributes;
3917 var control = attributes['points']['control'] || [];
3921 if (control.length > 0 && !(control[0] instanceof Array)) {
3922 control = [control];
3925 for (i = 0,len = control.length; i < len; ++i) {
3926 tmp[i] = control[i];
3931 Roo.fly(el).position();
3933 if (isset(attributes['points']['from'])) {
3934 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3937 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3940 start = this.getAttribute('points');
3943 if (isset(attributes['points']['to'])) {
3944 end = translateValues.call(this, attributes['points']['to'], start);
3946 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3947 for (i = 0,len = control.length; i < len; ++i) {
3948 control[i] = translateValues.call(this, control[i], start);
3952 } else if (isset(attributes['points']['by'])) {
3953 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3955 for (i = 0,len = control.length; i < len; ++i) {
3956 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3960 this.runtimeAttributes[attr] = [start];
3962 if (control.length > 0) {
3963 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3966 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3969 superclass.setRuntimeAttribute.call(this, attr);
3973 var translateValues = function(val, start) {
3974 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3975 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3980 var isset = function(prop) {
3981 return (typeof prop !== 'undefined');
3985 * Portions of this file are based on pieces of Yahoo User Interface Library
3986 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3987 * YUI licensed under the BSD License:
3988 * http://developer.yahoo.net/yui/license.txt
3989 * <script type="text/javascript">
3993 Roo.lib.Scroll = function(el, attributes, duration, method) {
3995 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3999 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4003 var superclass = Y.Scroll.superclass;
4004 var proto = Y.Scroll.prototype;
4006 proto.toString = function() {
4007 var el = this.getEl();
4008 var id = el.id || el.tagName;
4009 return ("Scroll " + id);
4012 proto.doMethod = function(attr, start, end) {
4015 if (attr == 'scroll') {
4017 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4018 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4022 val = superclass.doMethod.call(this, attr, start, end);
4027 proto.getAttribute = function(attr) {
4029 var el = this.getEl();
4031 if (attr == 'scroll') {
4032 val = [ el.scrollLeft, el.scrollTop ];
4034 val = superclass.getAttribute.call(this, attr);
4040 proto.setAttribute = function(attr, val, unit) {
4041 var el = this.getEl();
4043 if (attr == 'scroll') {
4044 el.scrollLeft = val[0];
4045 el.scrollTop = val[1];
4047 superclass.setAttribute.call(this, attr, val, unit);
4053 * Ext JS Library 1.1.1
4054 * Copyright(c) 2006-2007, Ext JS, LLC.
4056 * Originally Released Under LGPL - original licence link has changed is not relivant.
4059 * <script type="text/javascript">
4063 // nasty IE9 hack - what a pile of crap that is..
4065 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4066 Range.prototype.createContextualFragment = function (html) {
4067 var doc = window.document;
4068 var container = doc.createElement("div");
4069 container.innerHTML = html;
4070 var frag = doc.createDocumentFragment(), n;
4071 while ((n = container.firstChild)) {
4072 frag.appendChild(n);
4079 * @class Roo.DomHelper
4080 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4081 * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4084 Roo.DomHelper = function(){
4085 var tempTableEl = null;
4086 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4087 var tableRe = /^table|tbody|tr|td$/i;
4089 // build as innerHTML where available
4091 var createHtml = function(o){
4092 if(typeof o == 'string'){
4101 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4102 if(attr == "style"){
4104 if(typeof s == "function"){
4107 if(typeof s == "string"){
4108 b += ' style="' + s + '"';
4109 }else if(typeof s == "object"){
4112 if(typeof s[key] != "function"){
4113 b += key + ":" + s[key] + ";";
4120 b += ' class="' + o["cls"] + '"';
4121 }else if(attr == "htmlFor"){
4122 b += ' for="' + o["htmlFor"] + '"';
4124 b += " " + attr + '="' + o[attr] + '"';
4128 if(emptyTags.test(o.tag)){
4132 var cn = o.children || o.cn;
4134 //http://bugs.kde.org/show_bug.cgi?id=71506
4135 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4136 for(var i = 0, len = cn.length; i < len; i++) {
4137 b += createHtml(cn[i], b);
4140 b += createHtml(cn, b);
4146 b += "</" + o.tag + ">";
4153 var createDom = function(o, parentNode){
4155 // defininition craeted..
4157 if (o.ns && o.ns != 'html') {
4159 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4160 xmlns[o.ns] = o.xmlns;
4163 if (typeof(xmlns[o.ns]) == 'undefined') {
4164 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4170 if (typeof(o) == 'string') {
4171 return parentNode.appendChild(document.createTextNode(o));
4173 o.tag = o.tag || div;
4174 if (o.ns && Roo.isIE) {
4176 o.tag = o.ns + ':' + o.tag;
4179 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4180 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4183 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4184 attr == "style" || typeof o[attr] == "function") continue;
4186 if(attr=="cls" && Roo.isIE){
4187 el.className = o["cls"];
4189 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4190 else el[attr] = o[attr];
4193 Roo.DomHelper.applyStyles(el, o.style);
4194 var cn = o.children || o.cn;
4196 //http://bugs.kde.org/show_bug.cgi?id=71506
4197 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4198 for(var i = 0, len = cn.length; i < len; i++) {
4199 createDom(cn[i], el);
4206 el.innerHTML = o.html;
4209 parentNode.appendChild(el);
4214 var ieTable = function(depth, s, h, e){
4215 tempTableEl.innerHTML = [s, h, e].join('');
4216 var i = -1, el = tempTableEl;
4223 // kill repeat to save bytes
4227 tbe = '</tbody>'+te,
4233 * Nasty code for IE's broken table implementation
4235 var insertIntoTable = function(tag, where, el, html){
4237 tempTableEl = document.createElement('div');
4242 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4245 if(where == 'beforebegin'){
4249 before = el.nextSibling;
4252 node = ieTable(4, trs, html, tre);
4254 else if(tag == 'tr'){
4255 if(where == 'beforebegin'){
4258 node = ieTable(3, tbs, html, tbe);
4259 } else if(where == 'afterend'){
4260 before = el.nextSibling;
4262 node = ieTable(3, tbs, html, tbe);
4263 } else{ // INTO a TR
4264 if(where == 'afterbegin'){
4265 before = el.firstChild;
4267 node = ieTable(4, trs, html, tre);
4269 } else if(tag == 'tbody'){
4270 if(where == 'beforebegin'){
4273 node = ieTable(2, ts, html, te);
4274 } else if(where == 'afterend'){
4275 before = el.nextSibling;
4277 node = ieTable(2, ts, html, te);
4279 if(where == 'afterbegin'){
4280 before = el.firstChild;
4282 node = ieTable(3, tbs, html, tbe);
4285 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4288 if(where == 'afterbegin'){
4289 before = el.firstChild;
4291 node = ieTable(2, ts, html, te);
4293 el.insertBefore(node, before);
4298 /** True to force the use of DOM instead of html fragments @type Boolean */
4302 * Returns the markup for the passed Element(s) config
4303 * @param {Object} o The Dom object spec (and children)
4306 markup : function(o){
4307 return createHtml(o);
4311 * Applies a style specification to an element
4312 * @param {String/HTMLElement} el The element to apply styles to
4313 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4314 * a function which returns such a specification.
4316 applyStyles : function(el, styles){
4319 if(typeof styles == "string"){
4320 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4322 while ((matches = re.exec(styles)) != null){
4323 el.setStyle(matches[1], matches[2]);
4325 }else if (typeof styles == "object"){
4326 for (var style in styles){
4327 el.setStyle(style, styles[style]);
4329 }else if (typeof styles == "function"){
4330 Roo.DomHelper.applyStyles(el, styles.call());
4336 * Inserts an HTML fragment into the Dom
4337 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4338 * @param {HTMLElement} el The context element
4339 * @param {String} html The HTML fragmenet
4340 * @return {HTMLElement} The new node
4342 insertHtml : function(where, el, html){
4343 where = where.toLowerCase();
4344 if(el.insertAdjacentHTML){
4345 if(tableRe.test(el.tagName)){
4347 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4353 el.insertAdjacentHTML('BeforeBegin', html);
4354 return el.previousSibling;
4356 el.insertAdjacentHTML('AfterBegin', html);
4357 return el.firstChild;
4359 el.insertAdjacentHTML('BeforeEnd', html);
4360 return el.lastChild;
4362 el.insertAdjacentHTML('AfterEnd', html);
4363 return el.nextSibling;
4365 throw 'Illegal insertion point -> "' + where + '"';
4367 var range = el.ownerDocument.createRange();
4371 range.setStartBefore(el);
4372 frag = range.createContextualFragment(html);
4373 el.parentNode.insertBefore(frag, el);
4374 return el.previousSibling;
4377 range.setStartBefore(el.firstChild);
4378 frag = range.createContextualFragment(html);
4379 el.insertBefore(frag, el.firstChild);
4380 return el.firstChild;
4382 el.innerHTML = html;
4383 return el.firstChild;
4387 range.setStartAfter(el.lastChild);
4388 frag = range.createContextualFragment(html);
4389 el.appendChild(frag);
4390 return el.lastChild;
4392 el.innerHTML = html;
4393 return el.lastChild;
4396 range.setStartAfter(el);
4397 frag = range.createContextualFragment(html);
4398 el.parentNode.insertBefore(frag, el.nextSibling);
4399 return el.nextSibling;
4401 throw 'Illegal insertion point -> "' + where + '"';
4405 * Creates new Dom element(s) and inserts them before el
4406 * @param {String/HTMLElement/Element} el The context element
4407 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4408 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4409 * @return {HTMLElement/Roo.Element} The new node
4411 insertBefore : function(el, o, returnElement){
4412 return this.doInsert(el, o, returnElement, "beforeBegin");
4416 * Creates new Dom element(s) and inserts them after el
4417 * @param {String/HTMLElement/Element} el The context element
4418 * @param {Object} o The Dom object spec (and children)
4419 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4420 * @return {HTMLElement/Roo.Element} The new node
4422 insertAfter : function(el, o, returnElement){
4423 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4427 * Creates new Dom element(s) and inserts them as the first child of el
4428 * @param {String/HTMLElement/Element} el The context element
4429 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4430 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4431 * @return {HTMLElement/Roo.Element} The new node
4433 insertFirst : function(el, o, returnElement){
4434 return this.doInsert(el, o, returnElement, "afterBegin");
4438 doInsert : function(el, o, returnElement, pos, sibling){
4439 el = Roo.getDom(el);
4441 if(this.useDom || o.ns){
4442 newNode = createDom(o, null);
4443 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4445 var html = createHtml(o);
4446 newNode = this.insertHtml(pos, el, html);
4448 return returnElement ? Roo.get(newNode, true) : newNode;
4452 * Creates new Dom element(s) and appends them to el
4453 * @param {String/HTMLElement/Element} el The context element
4454 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4455 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4456 * @return {HTMLElement/Roo.Element} The new node
4458 append : function(el, o, returnElement){
4459 el = Roo.getDom(el);
4461 if(this.useDom || o.ns){
4462 newNode = createDom(o, null);
4463 el.appendChild(newNode);
4465 var html = createHtml(o);
4466 newNode = this.insertHtml("beforeEnd", el, html);
4468 return returnElement ? Roo.get(newNode, true) : newNode;
4472 * Creates new Dom element(s) and overwrites the contents of el with them
4473 * @param {String/HTMLElement/Element} el The context element
4474 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4475 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4476 * @return {HTMLElement/Roo.Element} The new node
4478 overwrite : function(el, o, returnElement){
4479 el = Roo.getDom(el);
4482 while (el.childNodes.length) {
4483 el.removeChild(el.firstChild);
4487 el.innerHTML = createHtml(o);
4490 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4494 * Creates a new Roo.DomHelper.Template from the Dom object spec
4495 * @param {Object} o The Dom object spec (and children)
4496 * @return {Roo.DomHelper.Template} The new template
4498 createTemplate : function(o){
4499 var html = createHtml(o);
4500 return new Roo.Template(html);
4506 * Ext JS Library 1.1.1
4507 * Copyright(c) 2006-2007, Ext JS, LLC.
4509 * Originally Released Under LGPL - original licence link has changed is not relivant.
4512 * <script type="text/javascript">
4516 * @class Roo.Template
4517 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4518 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4521 var t = new Roo.Template({
4522 html : '<div name="{id}">' +
4523 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4525 myformat: function (value, allValues) {
4526 return 'XX' + value;
4529 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4531 * For more information see this blog post with examples: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>.
4533 * @param {Object} cfg - Configuration object.
4535 Roo.Template = function(cfg){
4537 if(cfg instanceof Array){
4539 }else if(arguments.length > 1){
4540 cfg = Array.prototype.join.call(arguments, "");
4544 if (typeof(cfg) == 'object') {
4553 Roo.Template.prototype = {
4556 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4560 * Returns an HTML fragment of this template with the specified values applied.
4561 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4562 * @return {String} The HTML fragment
4564 applyTemplate : function(values){
4568 return this.compiled(values);
4570 var useF = this.disableFormats !== true;
4571 var fm = Roo.util.Format, tpl = this;
4572 var fn = function(m, name, format, args){
4574 if(format.substr(0, 5) == "this."){
4575 return tpl.call(format.substr(5), values[name], values);
4578 // quoted values are required for strings in compiled templates,
4579 // but for non compiled we need to strip them
4580 // quoted reversed for jsmin
4581 var re = /^\s*['"](.*)["']\s*$/;
4582 args = args.split(',');
4583 for(var i = 0, len = args.length; i < len; i++){
4584 args[i] = args[i].replace(re, "$1");
4586 args = [values[name]].concat(args);
4588 args = [values[name]];
4590 return fm[format].apply(fm, args);
4593 return values[name] !== undefined ? values[name] : "";
4596 return this.html.replace(this.re, fn);
4605 * Sets the HTML used as the template and optionally compiles it.
4606 * @param {String} html
4607 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4608 * @return {Roo.Template} this
4610 set : function(html, compile){
4612 this.compiled = null;
4620 * True to disable format functions (defaults to false)
4623 disableFormats : false,
4626 * The regular expression used to match template variables
4630 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4633 * Compiles the template into an internal function, eliminating the RegEx overhead.
4634 * @return {Roo.Template} this
4636 compile : function(){
4637 var fm = Roo.util.Format;
4638 var useF = this.disableFormats !== true;
4639 var sep = Roo.isGecko ? "+" : ",";
4640 var fn = function(m, name, format, args){
4642 args = args ? ',' + args : "";
4643 if(format.substr(0, 5) != "this."){
4644 format = "fm." + format + '(';
4646 format = 'this.call("'+ format.substr(5) + '", ';
4650 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4652 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4655 // branched to use + in gecko and [].join() in others
4657 body = "this.compiled = function(values){ return '" +
4658 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4661 body = ["this.compiled = function(values){ return ['"];
4662 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4663 body.push("'].join('');};");
4664 body = body.join('');
4674 // private function used to call members
4675 call : function(fnName, value, allValues){
4676 return this[fnName](value, allValues);
4680 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4681 * @param {String/HTMLElement/Roo.Element} el The context element
4682 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4683 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4684 * @return {HTMLElement/Roo.Element} The new node or Element
4686 insertFirst: function(el, values, returnElement){
4687 return this.doInsert('afterBegin', el, values, returnElement);
4691 * Applies the supplied values to the template and inserts the new node(s) before el.
4692 * @param {String/HTMLElement/Roo.Element} el The context element
4693 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4694 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4695 * @return {HTMLElement/Roo.Element} The new node or Element
4697 insertBefore: function(el, values, returnElement){
4698 return this.doInsert('beforeBegin', el, values, returnElement);
4702 * Applies the supplied values to the template and inserts the new node(s) after el.
4703 * @param {String/HTMLElement/Roo.Element} el The context element
4704 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4705 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4706 * @return {HTMLElement/Roo.Element} The new node or Element
4708 insertAfter : function(el, values, returnElement){
4709 return this.doInsert('afterEnd', el, values, returnElement);
4713 * Applies the supplied values to the template and appends the new node(s) to el.
4714 * @param {String/HTMLElement/Roo.Element} el The context element
4715 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4716 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4717 * @return {HTMLElement/Roo.Element} The new node or Element
4719 append : function(el, values, returnElement){
4720 return this.doInsert('beforeEnd', el, values, returnElement);
4723 doInsert : function(where, el, values, returnEl){
4724 el = Roo.getDom(el);
4725 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4726 return returnEl ? Roo.get(newNode, true) : newNode;
4730 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4731 * @param {String/HTMLElement/Roo.Element} el The context element
4732 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4733 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4734 * @return {HTMLElement/Roo.Element} The new node or Element
4736 overwrite : function(el, values, returnElement){
4737 el = Roo.getDom(el);
4738 el.innerHTML = this.applyTemplate(values);
4739 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4743 * Alias for {@link #applyTemplate}
4746 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4749 Roo.DomHelper.Template = Roo.Template;
4752 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4753 * @param {String/HTMLElement} el A DOM element or its id
4754 * @returns {Roo.Template} The created template
4757 Roo.Template.from = function(el){
4758 el = Roo.getDom(el);
4759 return new Roo.Template(el.value || el.innerHTML);
4762 * Ext JS Library 1.1.1
4763 * Copyright(c) 2006-2007, Ext JS, LLC.
4765 * Originally Released Under LGPL - original licence link has changed is not relivant.
4768 * <script type="text/javascript">
4773 * This is code is also distributed under MIT license for use
4774 * with jQuery and prototype JavaScript libraries.
4777 * @class Roo.DomQuery
4778 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4780 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4783 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4785 <h4>Element Selectors:</h4>
4787 <li> <b>*</b> any element</li>
4788 <li> <b>E</b> an element with the tag E</li>
4789 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4790 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4791 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4792 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4794 <h4>Attribute Selectors:</h4>
4795 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4797 <li> <b>E[foo]</b> has an attribute "foo"</li>
4798 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4799 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4800 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4801 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4802 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4803 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4805 <h4>Pseudo Classes:</h4>
4807 <li> <b>E:first-child</b> E is the first child of its parent</li>
4808 <li> <b>E:last-child</b> E is the last child of its parent</li>
4809 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4810 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4811 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4812 <li> <b>E:only-child</b> E is the only child of its parent</li>
4813 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4814 <li> <b>E:first</b> the first E in the resultset</li>
4815 <li> <b>E:last</b> the last E in the resultset</li>
4816 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4817 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4818 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4819 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4820 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4821 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4822 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4823 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4824 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4826 <h4>CSS Value Selectors:</h4>
4828 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4829 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4830 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4831 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4832 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4833 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4837 Roo.DomQuery = function(){
4838 var cache = {}, simpleCache = {}, valueCache = {};
4839 var nonSpace = /\S/;
4840 var trimRe = /^\s+|\s+$/g;
4841 var tplRe = /\{(\d+)\}/g;
4842 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4843 var tagTokenRe = /^(#)?([\w-\*]+)/;
4844 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4846 function child(p, index){
4848 var n = p.firstChild;
4850 if(n.nodeType == 1){
4861 while((n = n.nextSibling) && n.nodeType != 1);
4866 while((n = n.previousSibling) && n.nodeType != 1);
4870 function children(d){
4871 var n = d.firstChild, ni = -1;
4873 var nx = n.nextSibling;
4874 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4884 function byClassName(c, a, v){
4888 var r = [], ri = -1, cn;
4889 for(var i = 0, ci; ci = c[i]; i++){
4890 if((' '+ci.className+' ').indexOf(v) != -1){
4897 function attrValue(n, attr){
4898 if(!n.tagName && typeof n.length != "undefined"){
4907 if(attr == "class" || attr == "className"){
4910 return n.getAttribute(attr) || n[attr];
4914 function getNodes(ns, mode, tagName){
4915 var result = [], ri = -1, cs;
4919 tagName = tagName || "*";
4920 if(typeof ns.getElementsByTagName != "undefined"){
4924 for(var i = 0, ni; ni = ns[i]; i++){
4925 cs = ni.getElementsByTagName(tagName);
4926 for(var j = 0, ci; ci = cs[j]; j++){
4930 }else if(mode == "/" || mode == ">"){
4931 var utag = tagName.toUpperCase();
4932 for(var i = 0, ni, cn; ni = ns[i]; i++){
4933 cn = ni.children || ni.childNodes;
4934 for(var j = 0, cj; cj = cn[j]; j++){
4935 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4940 }else if(mode == "+"){
4941 var utag = tagName.toUpperCase();
4942 for(var i = 0, n; n = ns[i]; i++){
4943 while((n = n.nextSibling) && n.nodeType != 1);
4944 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4948 }else if(mode == "~"){
4949 for(var i = 0, n; n = ns[i]; i++){
4950 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4959 function concat(a, b){
4963 for(var i = 0, l = b.length; i < l; i++){
4969 function byTag(cs, tagName){
4970 if(cs.tagName || cs == document){
4976 var r = [], ri = -1;
4977 tagName = tagName.toLowerCase();
4978 for(var i = 0, ci; ci = cs[i]; i++){
4979 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4986 function byId(cs, attr, id){
4987 if(cs.tagName || cs == document){
4993 var r = [], ri = -1;
4994 for(var i = 0,ci; ci = cs[i]; i++){
4995 if(ci && ci.id == id){
5003 function byAttribute(cs, attr, value, op, custom){
5004 var r = [], ri = -1, st = custom=="{";
5005 var f = Roo.DomQuery.operators[op];
5006 for(var i = 0, ci; ci = cs[i]; i++){
5009 a = Roo.DomQuery.getStyle(ci, attr);
5011 else if(attr == "class" || attr == "className"){
5013 }else if(attr == "for"){
5015 }else if(attr == "href"){
5016 a = ci.getAttribute("href", 2);
5018 a = ci.getAttribute(attr);
5020 if((f && f(a, value)) || (!f && a)){
5027 function byPseudo(cs, name, value){
5028 return Roo.DomQuery.pseudos[name](cs, value);
5031 // This is for IE MSXML which does not support expandos.
5032 // IE runs the same speed using setAttribute, however FF slows way down
5033 // and Safari completely fails so they need to continue to use expandos.
5034 var isIE = window.ActiveXObject ? true : false;
5036 // this eval is stop the compressor from
5037 // renaming the variable to something shorter
5039 /** eval:var:batch */
5044 function nodupIEXml(cs){
5046 cs[0].setAttribute("_nodup", d);
5048 for(var i = 1, len = cs.length; i < len; i++){
5050 if(!c.getAttribute("_nodup") != d){
5051 c.setAttribute("_nodup", d);
5055 for(var i = 0, len = cs.length; i < len; i++){
5056 cs[i].removeAttribute("_nodup");
5065 var len = cs.length, c, i, r = cs, cj, ri = -1;
5066 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5069 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5070 return nodupIEXml(cs);
5074 for(i = 1; c = cs[i]; i++){
5079 for(var j = 0; j < i; j++){
5082 for(j = i+1; cj = cs[j]; j++){
5094 function quickDiffIEXml(c1, c2){
5096 for(var i = 0, len = c1.length; i < len; i++){
5097 c1[i].setAttribute("_qdiff", d);
5100 for(var i = 0, len = c2.length; i < len; i++){
5101 if(c2[i].getAttribute("_qdiff") != d){
5102 r[r.length] = c2[i];
5105 for(var i = 0, len = c1.length; i < len; i++){
5106 c1[i].removeAttribute("_qdiff");
5111 function quickDiff(c1, c2){
5112 var len1 = c1.length;
5116 if(isIE && c1[0].selectSingleNode){
5117 return quickDiffIEXml(c1, c2);
5120 for(var i = 0; i < len1; i++){
5124 for(var i = 0, len = c2.length; i < len; i++){
5125 if(c2[i]._qdiff != d){
5126 r[r.length] = c2[i];
5132 function quickId(ns, mode, root, id){
5134 var d = root.ownerDocument || root;
5135 return d.getElementById(id);
5137 ns = getNodes(ns, mode, "*");
5138 return byId(ns, null, id);
5142 getStyle : function(el, name){
5143 return Roo.fly(el).getStyle(name);
5146 * Compiles a selector/xpath query into a reusable function. The returned function
5147 * takes one parameter "root" (optional), which is the context node from where the query should start.
5148 * @param {String} selector The selector/xpath query
5149 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5150 * @return {Function}
5152 compile : function(path, type){
5153 type = type || "select";
5155 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5156 var q = path, mode, lq;
5157 var tk = Roo.DomQuery.matchers;
5158 var tklen = tk.length;
5161 // accept leading mode switch
5162 var lmode = q.match(modeRe);
5163 if(lmode && lmode[1]){
5164 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5165 q = q.replace(lmode[1], "");
5167 // strip leading slashes
5168 while(path.substr(0, 1)=="/"){
5169 path = path.substr(1);
5172 while(q && lq != q){
5174 var tm = q.match(tagTokenRe);
5175 if(type == "select"){
5178 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5180 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5182 q = q.replace(tm[0], "");
5183 }else if(q.substr(0, 1) != '@'){
5184 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5189 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5191 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5193 q = q.replace(tm[0], "");
5196 while(!(mm = q.match(modeRe))){
5197 var matched = false;
5198 for(var j = 0; j < tklen; j++){
5200 var m = q.match(t.re);
5202 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5205 q = q.replace(m[0], "");
5210 // prevent infinite loop on bad selector
5212 throw 'Error parsing selector, parsing failed at "' + q + '"';
5216 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5217 q = q.replace(mm[1], "");
5220 fn[fn.length] = "return nodup(n);\n}";
5223 * list of variables that need from compression as they are used by eval.
5233 * eval:var:byClassName
5235 * eval:var:byAttribute
5236 * eval:var:attrValue
5244 * Selects a group of elements.
5245 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5246 * @param {Node} root (optional) The start of the query (defaults to document).
5249 select : function(path, root, type){
5250 if(!root || root == document){
5253 if(typeof root == "string"){
5254 root = document.getElementById(root);
5256 var paths = path.split(",");
5258 for(var i = 0, len = paths.length; i < len; i++){
5259 var p = paths[i].replace(trimRe, "");
5261 cache[p] = Roo.DomQuery.compile(p);
5263 throw p + " is not a valid selector";
5266 var result = cache[p](root);
5267 if(result && result != document){
5268 results = results.concat(result);
5271 if(paths.length > 1){
5272 return nodup(results);
5278 * Selects a single element.
5279 * @param {String} selector The selector/xpath query
5280 * @param {Node} root (optional) The start of the query (defaults to document).
5283 selectNode : function(path, root){
5284 return Roo.DomQuery.select(path, root)[0];
5288 * Selects the value of a node, optionally replacing null with the defaultValue.
5289 * @param {String} selector The selector/xpath query
5290 * @param {Node} root (optional) The start of the query (defaults to document).
5291 * @param {String} defaultValue
5293 selectValue : function(path, root, defaultValue){
5294 path = path.replace(trimRe, "");
5295 if(!valueCache[path]){
5296 valueCache[path] = Roo.DomQuery.compile(path, "select");
5298 var n = valueCache[path](root);
5299 n = n[0] ? n[0] : n;
5300 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5301 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5305 * Selects the value of a node, parsing integers and floats.
5306 * @param {String} selector The selector/xpath query
5307 * @param {Node} root (optional) The start of the query (defaults to document).
5308 * @param {Number} defaultValue
5311 selectNumber : function(path, root, defaultValue){
5312 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5313 return parseFloat(v);
5317 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5318 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5319 * @param {String} selector The simple selector to test
5322 is : function(el, ss){
5323 if(typeof el == "string"){
5324 el = document.getElementById(el);
5326 var isArray = (el instanceof Array);
5327 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5328 return isArray ? (result.length == el.length) : (result.length > 0);
5332 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5333 * @param {Array} el An array of elements to filter
5334 * @param {String} selector The simple selector to test
5335 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5336 * the selector instead of the ones that match
5339 filter : function(els, ss, nonMatches){
5340 ss = ss.replace(trimRe, "");
5341 if(!simpleCache[ss]){
5342 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5344 var result = simpleCache[ss](els);
5345 return nonMatches ? quickDiff(result, els) : result;
5349 * Collection of matching regular expressions and code snippets.
5353 select: 'n = byClassName(n, null, " {1} ");'
5355 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5356 select: 'n = byPseudo(n, "{1}", "{2}");'
5358 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5359 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5362 select: 'n = byId(n, null, "{1}");'
5365 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5370 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5371 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5374 "=" : function(a, v){
5377 "!=" : function(a, v){
5380 "^=" : function(a, v){
5381 return a && a.substr(0, v.length) == v;
5383 "$=" : function(a, v){
5384 return a && a.substr(a.length-v.length) == v;
5386 "*=" : function(a, v){
5387 return a && a.indexOf(v) !== -1;
5389 "%=" : function(a, v){
5390 return (a % v) == 0;
5392 "|=" : function(a, v){
5393 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5395 "~=" : function(a, v){
5396 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5401 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5402 * and the argument (if any) supplied in the selector.
5405 "first-child" : function(c){
5406 var r = [], ri = -1, n;
5407 for(var i = 0, ci; ci = n = c[i]; i++){
5408 while((n = n.previousSibling) && n.nodeType != 1);
5416 "last-child" : function(c){
5417 var r = [], ri = -1, n;
5418 for(var i = 0, ci; ci = n = c[i]; i++){
5419 while((n = n.nextSibling) && n.nodeType != 1);
5427 "nth-child" : function(c, a) {
5428 var r = [], ri = -1;
5429 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5430 var f = (m[1] || 1) - 0, l = m[2] - 0;
5431 for(var i = 0, n; n = c[i]; i++){
5432 var pn = n.parentNode;
5433 if (batch != pn._batch) {
5435 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5436 if(cn.nodeType == 1){
5443 if (l == 0 || n.nodeIndex == l){
5446 } else if ((n.nodeIndex + l) % f == 0){
5454 "only-child" : function(c){
5455 var r = [], ri = -1;;
5456 for(var i = 0, ci; ci = c[i]; i++){
5457 if(!prev(ci) && !next(ci)){
5464 "empty" : function(c){
5465 var r = [], ri = -1;
5466 for(var i = 0, ci; ci = c[i]; i++){
5467 var cns = ci.childNodes, j = 0, cn, empty = true;
5470 if(cn.nodeType == 1 || cn.nodeType == 3){
5482 "contains" : function(c, v){
5483 var r = [], ri = -1;
5484 for(var i = 0, ci; ci = c[i]; i++){
5485 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5492 "nodeValue" : function(c, v){
5493 var r = [], ri = -1;
5494 for(var i = 0, ci; ci = c[i]; i++){
5495 if(ci.firstChild && ci.firstChild.nodeValue == v){
5502 "checked" : function(c){
5503 var r = [], ri = -1;
5504 for(var i = 0, ci; ci = c[i]; i++){
5505 if(ci.checked == true){
5512 "not" : function(c, ss){
5513 return Roo.DomQuery.filter(c, ss, true);
5516 "odd" : function(c){
5517 return this["nth-child"](c, "odd");
5520 "even" : function(c){
5521 return this["nth-child"](c, "even");
5524 "nth" : function(c, a){
5525 return c[a-1] || [];
5528 "first" : function(c){
5532 "last" : function(c){
5533 return c[c.length-1] || [];
5536 "has" : function(c, ss){
5537 var s = Roo.DomQuery.select;
5538 var r = [], ri = -1;
5539 for(var i = 0, ci; ci = c[i]; i++){
5540 if(s(ss, ci).length > 0){
5547 "next" : function(c, ss){
5548 var is = Roo.DomQuery.is;
5549 var r = [], ri = -1;
5550 for(var i = 0, ci; ci = c[i]; i++){
5559 "prev" : function(c, ss){
5560 var is = Roo.DomQuery.is;
5561 var r = [], ri = -1;
5562 for(var i = 0, ci; ci = c[i]; i++){
5575 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5576 * @param {String} path The selector/xpath query
5577 * @param {Node} root (optional) The start of the query (defaults to document).
5582 Roo.query = Roo.DomQuery.select;
5585 * Ext JS Library 1.1.1
5586 * Copyright(c) 2006-2007, Ext JS, LLC.
5588 * Originally Released Under LGPL - original licence link has changed is not relivant.
5591 * <script type="text/javascript">
5595 * @class Roo.util.Observable
5596 * Base class that provides a common interface for publishing events. Subclasses are expected to
5597 * to have a property "events" with all the events defined.<br>
5600 Employee = function(name){
5607 Roo.extend(Employee, Roo.util.Observable);
5609 * @param {Object} config properties to use (incuding events / listeners)
5612 Roo.util.Observable = function(cfg){
5615 this.addEvents(cfg.events || {});
5617 delete cfg.events; // make sure
5620 Roo.apply(this, cfg);
5623 this.on(this.listeners);
5624 delete this.listeners;
5627 Roo.util.Observable.prototype = {
5629 * @cfg {Object} listeners list of events and functions to call for this object,
5633 'click' : function(e) {
5643 * Fires the specified event with the passed parameters (minus the event name).
5644 * @param {String} eventName
5645 * @param {Object...} args Variable number of parameters are passed to handlers
5646 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5648 fireEvent : function(){
5649 var ce = this.events[arguments[0].toLowerCase()];
5650 if(typeof ce == "object"){
5651 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5658 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5661 * Appends an event handler to this component
5662 * @param {String} eventName The type of event to listen for
5663 * @param {Function} handler The method the event invokes
5664 * @param {Object} scope (optional) The scope in which to execute the handler
5665 * function. The handler function's "this" context.
5666 * @param {Object} options (optional) An object containing handler configuration
5667 * properties. This may contain any of the following properties:<ul>
5668 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5669 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5670 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5671 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5672 * by the specified number of milliseconds. If the event fires again within that time, the original
5673 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5676 * <b>Combining Options</b><br>
5677 * Using the options argument, it is possible to combine different types of listeners:<br>
5679 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5681 el.on('click', this.onClick, this, {
5688 * <b>Attaching multiple handlers in 1 call</b><br>
5689 * The method also allows for a single argument to be passed which is a config object containing properties
5690 * which specify multiple handlers.
5699 fn: this.onMouseOver,
5703 fn: this.onMouseOut,
5709 * Or a shorthand syntax which passes the same scope object to all handlers:
5712 'click': this.onClick,
5713 'mouseover': this.onMouseOver,
5714 'mouseout': this.onMouseOut,
5719 addListener : function(eventName, fn, scope, o){
5720 if(typeof eventName == "object"){
5723 if(this.filterOptRe.test(e)){
5726 if(typeof o[e] == "function"){
5728 this.addListener(e, o[e], o.scope, o);
5730 // individual options
5731 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5736 o = (!o || typeof o == "boolean") ? {} : o;
5737 eventName = eventName.toLowerCase();
5738 var ce = this.events[eventName] || true;
5739 if(typeof ce == "boolean"){
5740 ce = new Roo.util.Event(this, eventName);
5741 this.events[eventName] = ce;
5743 ce.addListener(fn, scope, o);
5747 * Removes a listener
5748 * @param {String} eventName The type of event to listen for
5749 * @param {Function} handler The handler to remove
5750 * @param {Object} scope (optional) The scope (this object) for the handler
5752 removeListener : function(eventName, fn, scope){
5753 var ce = this.events[eventName.toLowerCase()];
5754 if(typeof ce == "object"){
5755 ce.removeListener(fn, scope);
5760 * Removes all listeners for this object
5762 purgeListeners : function(){
5763 for(var evt in this.events){
5764 if(typeof this.events[evt] == "object"){
5765 this.events[evt].clearListeners();
5770 relayEvents : function(o, events){
5771 var createHandler = function(ename){
5773 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5776 for(var i = 0, len = events.length; i < len; i++){
5777 var ename = events[i];
5778 if(!this.events[ename]){ this.events[ename] = true; };
5779 o.on(ename, createHandler(ename), this);
5784 * Used to define events on this Observable
5785 * @param {Object} object The object with the events defined
5787 addEvents : function(o){
5791 Roo.applyIf(this.events, o);
5795 * Checks to see if this object has any listeners for a specified event
5796 * @param {String} eventName The name of the event to check for
5797 * @return {Boolean} True if the event is being listened for, else false
5799 hasListener : function(eventName){
5800 var e = this.events[eventName];
5801 return typeof e == "object" && e.listeners.length > 0;
5805 * Appends an event handler to this element (shorthand for addListener)
5806 * @param {String} eventName The type of event to listen for
5807 * @param {Function} handler The method the event invokes
5808 * @param {Object} scope (optional) The scope in which to execute the handler
5809 * function. The handler function's "this" context.
5810 * @param {Object} options (optional)
5813 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5815 * Removes a listener (shorthand for removeListener)
5816 * @param {String} eventName The type of event to listen for
5817 * @param {Function} handler The handler to remove
5818 * @param {Object} scope (optional) The scope (this object) for the handler
5821 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5824 * Starts capture on the specified Observable. All events will be passed
5825 * to the supplied function with the event name + standard signature of the event
5826 * <b>before</b> the event is fired. If the supplied function returns false,
5827 * the event will not fire.
5828 * @param {Observable} o The Observable to capture
5829 * @param {Function} fn The function to call
5830 * @param {Object} scope (optional) The scope (this object) for the fn
5833 Roo.util.Observable.capture = function(o, fn, scope){
5834 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5838 * Removes <b>all</b> added captures from the Observable.
5839 * @param {Observable} o The Observable to release
5842 Roo.util.Observable.releaseCapture = function(o){
5843 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5848 var createBuffered = function(h, o, scope){
5849 var task = new Roo.util.DelayedTask();
5851 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5855 var createSingle = function(h, e, fn, scope){
5857 e.removeListener(fn, scope);
5858 return h.apply(scope, arguments);
5862 var createDelayed = function(h, o, scope){
5864 var args = Array.prototype.slice.call(arguments, 0);
5865 setTimeout(function(){
5866 h.apply(scope, args);
5871 Roo.util.Event = function(obj, name){
5874 this.listeners = [];
5877 Roo.util.Event.prototype = {
5878 addListener : function(fn, scope, options){
5879 var o = options || {};
5880 scope = scope || this.obj;
5881 if(!this.isListening(fn, scope)){
5882 var l = {fn: fn, scope: scope, options: o};
5885 h = createDelayed(h, o, scope);
5888 h = createSingle(h, this, fn, scope);
5891 h = createBuffered(h, o, scope);
5894 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5895 this.listeners.push(l);
5897 this.listeners = this.listeners.slice(0);
5898 this.listeners.push(l);
5903 findListener : function(fn, scope){
5904 scope = scope || this.obj;
5905 var ls = this.listeners;
5906 for(var i = 0, len = ls.length; i < len; i++){
5908 if(l.fn == fn && l.scope == scope){
5915 isListening : function(fn, scope){
5916 return this.findListener(fn, scope) != -1;
5919 removeListener : function(fn, scope){
5921 if((index = this.findListener(fn, scope)) != -1){
5923 this.listeners.splice(index, 1);
5925 this.listeners = this.listeners.slice(0);
5926 this.listeners.splice(index, 1);
5933 clearListeners : function(){
5934 this.listeners = [];
5938 var ls = this.listeners, scope, len = ls.length;
5941 var args = Array.prototype.slice.call(arguments, 0);
5942 for(var i = 0; i < len; i++){
5944 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5945 this.firing = false;
5949 this.firing = false;
5956 * Ext JS Library 1.1.1
5957 * Copyright(c) 2006-2007, Ext JS, LLC.
5959 * Originally Released Under LGPL - original licence link has changed is not relivant.
5962 * <script type="text/javascript">
5966 * @class Roo.EventManager
5967 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5968 * several useful events directly.
5969 * See {@link Roo.EventObject} for more details on normalized event objects.
5972 Roo.EventManager = function(){
5973 var docReadyEvent, docReadyProcId, docReadyState = false;
5974 var resizeEvent, resizeTask, textEvent, textSize;
5975 var E = Roo.lib.Event;
5976 var D = Roo.lib.Dom;
5979 var fireDocReady = function(){
5981 docReadyState = true;
5984 clearInterval(docReadyProcId);
5986 if(Roo.isGecko || Roo.isOpera) {
5987 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5990 var defer = document.getElementById("ie-deferred-loader");
5992 defer.onreadystatechange = null;
5993 defer.parentNode.removeChild(defer);
5997 docReadyEvent.fire();
5998 docReadyEvent.clearListeners();
6003 var initDocReady = function(){
6004 docReadyEvent = new Roo.util.Event();
6005 if(Roo.isGecko || Roo.isOpera) {
6006 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6008 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6009 var defer = document.getElementById("ie-deferred-loader");
6010 defer.onreadystatechange = function(){
6011 if(this.readyState == "complete"){
6015 }else if(Roo.isSafari){
6016 docReadyProcId = setInterval(function(){
6017 var rs = document.readyState;
6018 if(rs == "complete") {
6023 // no matter what, make sure it fires on load
6024 E.on(window, "load", fireDocReady);
6027 var createBuffered = function(h, o){
6028 var task = new Roo.util.DelayedTask(h);
6030 // create new event object impl so new events don't wipe out properties
6031 e = new Roo.EventObjectImpl(e);
6032 task.delay(o.buffer, h, null, [e]);
6036 var createSingle = function(h, el, ename, fn){
6038 Roo.EventManager.removeListener(el, ename, fn);
6043 var createDelayed = function(h, o){
6045 // create new event object impl so new events don't wipe out properties
6046 e = new Roo.EventObjectImpl(e);
6047 setTimeout(function(){
6053 var listen = function(element, ename, opt, fn, scope){
6054 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6055 fn = fn || o.fn; scope = scope || o.scope;
6056 var el = Roo.getDom(element);
6058 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6060 var h = function(e){
6061 e = Roo.EventObject.setEvent(e);
6064 t = e.getTarget(o.delegate, el);
6071 if(o.stopEvent === true){
6074 if(o.preventDefault === true){
6077 if(o.stopPropagation === true){
6078 e.stopPropagation();
6081 if(o.normalized === false){
6085 fn.call(scope || el, e, t, o);
6088 h = createDelayed(h, o);
6091 h = createSingle(h, el, ename, fn);
6094 h = createBuffered(h, o);
6096 fn._handlers = fn._handlers || [];
6097 fn._handlers.push([Roo.id(el), ename, h]);
6100 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6101 el.addEventListener("DOMMouseScroll", h, false);
6102 E.on(window, 'unload', function(){
6103 el.removeEventListener("DOMMouseScroll", h, false);
6106 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6107 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6112 var stopListening = function(el, ename, fn){
6113 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6115 for(var i = 0, len = hds.length; i < len; i++){
6117 if(h[0] == id && h[1] == ename){
6124 E.un(el, ename, hd);
6125 el = Roo.getDom(el);
6126 if(ename == "mousewheel" && el.addEventListener){
6127 el.removeEventListener("DOMMouseScroll", hd, false);
6129 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6130 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6134 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6141 * @scope Roo.EventManager
6146 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6147 * object with a Roo.EventObject
6148 * @param {Function} fn The method the event invokes
6149 * @param {Object} scope An object that becomes the scope of the handler
6150 * @param {boolean} override If true, the obj passed in becomes
6151 * the execution scope of the listener
6152 * @return {Function} The wrapped function
6155 wrap : function(fn, scope, override){
6157 Roo.EventObject.setEvent(e);
6158 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6163 * Appends an event handler to an element (shorthand for addListener)
6164 * @param {String/HTMLElement} element The html element or id to assign the
6165 * @param {String} eventName The type of event to listen for
6166 * @param {Function} handler The method the event invokes
6167 * @param {Object} scope (optional) The scope in which to execute the handler
6168 * function. The handler function's "this" context.
6169 * @param {Object} options (optional) An object containing handler configuration
6170 * properties. This may contain any of the following properties:<ul>
6171 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6172 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6173 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6174 * <li>preventDefault {Boolean} True to prevent the default action</li>
6175 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6176 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6177 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6178 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6179 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6180 * by the specified number of milliseconds. If the event fires again within that time, the original
6181 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6184 * <b>Combining Options</b><br>
6185 * Using the options argument, it is possible to combine different types of listeners:<br>
6187 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6189 el.on('click', this.onClick, this, {
6196 * <b>Attaching multiple handlers in 1 call</b><br>
6197 * The method also allows for a single argument to be passed which is a config object containing properties
6198 * which specify multiple handlers.
6208 fn: this.onMouseOver
6217 * Or a shorthand syntax:<br>
6220 'click' : this.onClick,
6221 'mouseover' : this.onMouseOver,
6222 'mouseout' : this.onMouseOut
6226 addListener : function(element, eventName, fn, scope, options){
6227 if(typeof eventName == "object"){
6233 if(typeof o[e] == "function"){
6235 listen(element, e, o, o[e], o.scope);
6237 // individual options
6238 listen(element, e, o[e]);
6243 return listen(element, eventName, options, fn, scope);
6247 * Removes an event handler
6249 * @param {String/HTMLElement} element The id or html element to remove the
6251 * @param {String} eventName The type of event
6252 * @param {Function} fn
6253 * @return {Boolean} True if a listener was actually removed
6255 removeListener : function(element, eventName, fn){
6256 return stopListening(element, eventName, fn);
6260 * Fires when the document is ready (before onload and before images are loaded). Can be
6261 * accessed shorthanded Roo.onReady().
6262 * @param {Function} fn The method the event invokes
6263 * @param {Object} scope An object that becomes the scope of the handler
6264 * @param {boolean} options
6266 onDocumentReady : function(fn, scope, options){
6267 if(docReadyState){ // if it already fired
6268 docReadyEvent.addListener(fn, scope, options);
6269 docReadyEvent.fire();
6270 docReadyEvent.clearListeners();
6276 docReadyEvent.addListener(fn, scope, options);
6280 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6281 * @param {Function} fn The method the event invokes
6282 * @param {Object} scope An object that becomes the scope of the handler
6283 * @param {boolean} options
6285 onWindowResize : function(fn, scope, options){
6287 resizeEvent = new Roo.util.Event();
6288 resizeTask = new Roo.util.DelayedTask(function(){
6289 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6291 E.on(window, "resize", function(){
6293 resizeTask.delay(50);
6295 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6299 resizeEvent.addListener(fn, scope, options);
6303 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6304 * @param {Function} fn The method the event invokes
6305 * @param {Object} scope An object that becomes the scope of the handler
6306 * @param {boolean} options
6308 onTextResize : function(fn, scope, options){
6310 textEvent = new Roo.util.Event();
6311 var textEl = new Roo.Element(document.createElement('div'));
6312 textEl.dom.className = 'x-text-resize';
6313 textEl.dom.innerHTML = 'X';
6314 textEl.appendTo(document.body);
6315 textSize = textEl.dom.offsetHeight;
6316 setInterval(function(){
6317 if(textEl.dom.offsetHeight != textSize){
6318 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6320 }, this.textResizeInterval);
6322 textEvent.addListener(fn, scope, options);
6326 * Removes the passed window resize listener.
6327 * @param {Function} fn The method the event invokes
6328 * @param {Object} scope The scope of handler
6330 removeResizeListener : function(fn, scope){
6332 resizeEvent.removeListener(fn, scope);
6337 fireResize : function(){
6339 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6343 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6347 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6349 textResizeInterval : 50
6354 * @scopeAlias pub=Roo.EventManager
6358 * Appends an event handler to an element (shorthand for addListener)
6359 * @param {String/HTMLElement} element The html element or id to assign the
6360 * @param {String} eventName The type of event to listen for
6361 * @param {Function} handler The method the event invokes
6362 * @param {Object} scope (optional) The scope in which to execute the handler
6363 * function. The handler function's "this" context.
6364 * @param {Object} options (optional) An object containing handler configuration
6365 * properties. This may contain any of the following properties:<ul>
6366 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6367 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6368 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6369 * <li>preventDefault {Boolean} True to prevent the default action</li>
6370 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6371 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6372 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6373 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6374 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6375 * by the specified number of milliseconds. If the event fires again within that time, the original
6376 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6379 * <b>Combining Options</b><br>
6380 * Using the options argument, it is possible to combine different types of listeners:<br>
6382 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6384 el.on('click', this.onClick, this, {
6391 * <b>Attaching multiple handlers in 1 call</b><br>
6392 * The method also allows for a single argument to be passed which is a config object containing properties
6393 * which specify multiple handlers.
6403 fn: this.onMouseOver
6412 * Or a shorthand syntax:<br>
6415 'click' : this.onClick,
6416 'mouseover' : this.onMouseOver,
6417 'mouseout' : this.onMouseOut
6421 pub.on = pub.addListener;
6422 pub.un = pub.removeListener;
6424 pub.stoppedMouseDownEvent = new Roo.util.Event();
6428 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6429 * @param {Function} fn The method the event invokes
6430 * @param {Object} scope An object that becomes the scope of the handler
6431 * @param {boolean} override If true, the obj passed in becomes
6432 * the execution scope of the listener
6436 Roo.onReady = Roo.EventManager.onDocumentReady;
6438 Roo.onReady(function(){
6439 var bd = Roo.get(document.body);
6444 : Roo.isGecko ? "roo-gecko"
6445 : Roo.isOpera ? "roo-opera"
6446 : Roo.isSafari ? "roo-safari" : ""];
6449 cls.push("roo-mac");
6452 cls.push("roo-linux");
6454 if(Roo.isBorderBox){
6455 cls.push('roo-border-box');
6457 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6458 var p = bd.dom.parentNode;
6460 p.className += ' roo-strict';
6463 bd.addClass(cls.join(' '));
6467 * @class Roo.EventObject
6468 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6469 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6472 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6474 var target = e.getTarget();
6477 var myDiv = Roo.get("myDiv");
6478 myDiv.on("click", handleClick);
6480 Roo.EventManager.on("myDiv", 'click', handleClick);
6481 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6485 Roo.EventObject = function(){
6487 var E = Roo.lib.Event;
6489 // safari keypress events for special keys return bad keycodes
6492 63235 : 39, // right
6495 63276 : 33, // page up
6496 63277 : 34, // page down
6497 63272 : 46, // delete
6502 // normalize button clicks
6503 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6504 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6506 Roo.EventObjectImpl = function(e){
6508 this.setEvent(e.browserEvent || e);
6511 Roo.EventObjectImpl.prototype = {
6513 * Used to fix doc tools.
6514 * @scope Roo.EventObject.prototype
6520 /** The normal browser event */
6521 browserEvent : null,
6522 /** The button pressed in a mouse event */
6524 /** True if the shift key was down during the event */
6526 /** True if the control key was down during the event */
6528 /** True if the alt key was down during the event */
6587 setEvent : function(e){
6588 if(e == this || (e && e.browserEvent)){ // already wrapped
6591 this.browserEvent = e;
6593 // normalize buttons
6594 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6595 if(e.type == 'click' && this.button == -1){
6599 this.shiftKey = e.shiftKey;
6600 // mac metaKey behaves like ctrlKey
6601 this.ctrlKey = e.ctrlKey || e.metaKey;
6602 this.altKey = e.altKey;
6603 // in getKey these will be normalized for the mac
6604 this.keyCode = e.keyCode;
6605 // keyup warnings on firefox.
6606 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6607 // cache the target for the delayed and or buffered events
6608 this.target = E.getTarget(e);
6610 this.xy = E.getXY(e);
6613 this.shiftKey = false;
6614 this.ctrlKey = false;
6615 this.altKey = false;
6625 * Stop the event (preventDefault and stopPropagation)
6627 stopEvent : function(){
6628 if(this.browserEvent){
6629 if(this.browserEvent.type == 'mousedown'){
6630 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6632 E.stopEvent(this.browserEvent);
6637 * Prevents the browsers default handling of the event.
6639 preventDefault : function(){
6640 if(this.browserEvent){
6641 E.preventDefault(this.browserEvent);
6646 isNavKeyPress : function(){
6647 var k = this.keyCode;
6648 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6649 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6652 isSpecialKey : function(){
6653 var k = this.keyCode;
6654 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6655 (k == 16) || (k == 17) ||
6656 (k >= 18 && k <= 20) ||
6657 (k >= 33 && k <= 35) ||
6658 (k >= 36 && k <= 39) ||
6659 (k >= 44 && k <= 45);
6662 * Cancels bubbling of the event.
6664 stopPropagation : function(){
6665 if(this.browserEvent){
6666 if(this.type == 'mousedown'){
6667 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6669 E.stopPropagation(this.browserEvent);
6674 * Gets the key code for the event.
6677 getCharCode : function(){
6678 return this.charCode || this.keyCode;
6682 * Returns a normalized keyCode for the event.
6683 * @return {Number} The key code
6685 getKey : function(){
6686 var k = this.keyCode || this.charCode;
6687 return Roo.isSafari ? (safariKeys[k] || k) : k;
6691 * Gets the x coordinate of the event.
6694 getPageX : function(){
6699 * Gets the y coordinate of the event.
6702 getPageY : function(){
6707 * Gets the time of the event.
6710 getTime : function(){
6711 if(this.browserEvent){
6712 return E.getTime(this.browserEvent);
6718 * Gets the page coordinates of the event.
6719 * @return {Array} The xy values like [x, y]
6726 * Gets the target for the event.
6727 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6728 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6729 search as a number or element (defaults to 10 || document.body)
6730 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6731 * @return {HTMLelement}
6733 getTarget : function(selector, maxDepth, returnEl){
6734 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6737 * Gets the related target.
6738 * @return {HTMLElement}
6740 getRelatedTarget : function(){
6741 if(this.browserEvent){
6742 return E.getRelatedTarget(this.browserEvent);
6748 * Normalizes mouse wheel delta across browsers
6749 * @return {Number} The delta
6751 getWheelDelta : function(){
6752 var e = this.browserEvent;
6754 if(e.wheelDelta){ /* IE/Opera. */
6755 delta = e.wheelDelta/120;
6756 }else if(e.detail){ /* Mozilla case. */
6757 delta = -e.detail/3;
6763 * Returns true if the control, meta, shift or alt key was pressed during this event.
6766 hasModifier : function(){
6767 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6771 * Returns true if the target of this event equals el or is a child of el
6772 * @param {String/HTMLElement/Element} el
6773 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6776 within : function(el, related){
6777 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6778 return t && Roo.fly(el).contains(t);
6781 getPoint : function(){
6782 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6786 return new Roo.EventObjectImpl();
6791 * Ext JS Library 1.1.1
6792 * Copyright(c) 2006-2007, Ext JS, LLC.
6794 * Originally Released Under LGPL - original licence link has changed is not relivant.
6797 * <script type="text/javascript">
6801 // was in Composite Element!??!?!
6804 var D = Roo.lib.Dom;
6805 var E = Roo.lib.Event;
6806 var A = Roo.lib.Anim;
6808 // local style camelizing for speed
6810 var camelRe = /(-[a-z])/gi;
6811 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6812 var view = document.defaultView;
6815 * @class Roo.Element
6816 * Represents an Element in the DOM.<br><br>
6819 var el = Roo.get("my-div");
6822 var el = getEl("my-div");
6824 // or with a DOM element
6825 var el = Roo.get(myDivElement);
6827 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6828 * each call instead of constructing a new one.<br><br>
6829 * <b>Animations</b><br />
6830 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6831 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6833 Option Default Description
6834 --------- -------- ---------------------------------------------
6835 duration .35 The duration of the animation in seconds
6836 easing easeOut The YUI easing method
6837 callback none A function to execute when the anim completes
6838 scope this The scope (this) of the callback function
6840 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6841 * manipulate the animation. Here's an example:
6843 var el = Roo.get("my-div");
6848 // default animation
6849 el.setWidth(100, true);
6851 // animation with some options set
6858 // using the "anim" property to get the Anim object
6864 el.setWidth(100, opt);
6866 if(opt.anim.isAnimated()){
6870 * <b> Composite (Collections of) Elements</b><br />
6871 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6872 * @constructor Create a new Element directly.
6873 * @param {String/HTMLElement} element
6874 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6876 Roo.Element = function(element, forceNew){
6877 var dom = typeof element == "string" ?
6878 document.getElementById(element) : element;
6879 if(!dom){ // invalid id/element
6883 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6884 return Roo.Element.cache[id];
6894 * The DOM element ID
6897 this.id = id || Roo.id(dom);
6900 var El = Roo.Element;
6904 * The element's default display mode (defaults to "")
6907 originalDisplay : "",
6911 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6916 * Sets the element's visibility mode. When setVisible() is called it
6917 * will use this to determine whether to set the visibility or the display property.
6918 * @param visMode Element.VISIBILITY or Element.DISPLAY
6919 * @return {Roo.Element} this
6921 setVisibilityMode : function(visMode){
6922 this.visibilityMode = visMode;
6926 * Convenience method for setVisibilityMode(Element.DISPLAY)
6927 * @param {String} display (optional) What to set display to when visible
6928 * @return {Roo.Element} this
6930 enableDisplayMode : function(display){
6931 this.setVisibilityMode(El.DISPLAY);
6932 if(typeof display != "undefined") this.originalDisplay = display;
6937 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6938 * @param {String} selector The simple selector to test
6939 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6940 search as a number or element (defaults to 10 || document.body)
6941 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6942 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6944 findParent : function(simpleSelector, maxDepth, returnEl){
6945 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6946 maxDepth = maxDepth || 50;
6947 if(typeof maxDepth != "number"){
6948 stopEl = Roo.getDom(maxDepth);
6951 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6952 if(dq.is(p, simpleSelector)){
6953 return returnEl ? Roo.get(p) : p;
6963 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6964 * @param {String} selector The simple selector to test
6965 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6966 search as a number or element (defaults to 10 || document.body)
6967 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6968 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6970 findParentNode : function(simpleSelector, maxDepth, returnEl){
6971 var p = Roo.fly(this.dom.parentNode, '_internal');
6972 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6976 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6977 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6978 * @param {String} selector The simple selector to test
6979 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6980 search as a number or element (defaults to 10 || document.body)
6981 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6983 up : function(simpleSelector, maxDepth){
6984 return this.findParentNode(simpleSelector, maxDepth, true);
6990 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6991 * @param {String} selector The simple selector to test
6992 * @return {Boolean} True if this element matches the selector, else false
6994 is : function(simpleSelector){
6995 return Roo.DomQuery.is(this.dom, simpleSelector);
6999 * Perform animation on this element.
7000 * @param {Object} args The YUI animation control args
7001 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7002 * @param {Function} onComplete (optional) Function to call when animation completes
7003 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7004 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7005 * @return {Roo.Element} this
7007 animate : function(args, duration, onComplete, easing, animType){
7008 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7013 * @private Internal animation call
7015 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7016 animType = animType || 'run';
7018 var anim = Roo.lib.Anim[animType](
7020 (opt.duration || defaultDur) || .35,
7021 (opt.easing || defaultEase) || 'easeOut',
7023 Roo.callback(cb, this);
7024 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7032 // private legacy anim prep
7033 preanim : function(a, i){
7034 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7038 * Removes worthless text nodes
7039 * @param {Boolean} forceReclean (optional) By default the element
7040 * keeps track if it has been cleaned already so
7041 * you can call this over and over. However, if you update the element and
7042 * need to force a reclean, you can pass true.
7044 clean : function(forceReclean){
7045 if(this.isCleaned && forceReclean !== true){
7049 var d = this.dom, n = d.firstChild, ni = -1;
7051 var nx = n.nextSibling;
7052 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7059 this.isCleaned = true;
7064 calcOffsetsTo : function(el){
7067 var restorePos = false;
7068 if(el.getStyle('position') == 'static'){
7069 el.position('relative');
7074 while(op && op != d && op.tagName != 'HTML'){
7077 op = op.offsetParent;
7080 el.position('static');
7086 * Scrolls this element into view within the passed container.
7087 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7088 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7089 * @return {Roo.Element} this
7091 scrollIntoView : function(container, hscroll){
7092 var c = Roo.getDom(container) || document.body;
7095 var o = this.calcOffsetsTo(c),
7098 b = t+el.offsetHeight,
7099 r = l+el.offsetWidth;
7101 var ch = c.clientHeight;
7102 var ct = parseInt(c.scrollTop, 10);
7103 var cl = parseInt(c.scrollLeft, 10);
7105 var cr = cl + c.clientWidth;
7113 if(hscroll !== false){
7117 c.scrollLeft = r-c.clientWidth;
7124 scrollChildIntoView : function(child, hscroll){
7125 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7129 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7130 * the new height may not be available immediately.
7131 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7132 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7133 * @param {Function} onComplete (optional) Function to call when animation completes
7134 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7135 * @return {Roo.Element} this
7137 autoHeight : function(animate, duration, onComplete, easing){
7138 var oldHeight = this.getHeight();
7140 this.setHeight(1); // force clipping
7141 setTimeout(function(){
7142 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7144 this.setHeight(height);
7146 if(typeof onComplete == "function"){
7150 this.setHeight(oldHeight); // restore original height
7151 this.setHeight(height, animate, duration, function(){
7153 if(typeof onComplete == "function") onComplete();
7154 }.createDelegate(this), easing);
7156 }.createDelegate(this), 0);
7161 * Returns true if this element is an ancestor of the passed element
7162 * @param {HTMLElement/String} el The element to check
7163 * @return {Boolean} True if this element is an ancestor of el, else false
7165 contains : function(el){
7166 if(!el){return false;}
7167 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7171 * Checks whether the element is currently visible using both visibility and display properties.
7172 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7173 * @return {Boolean} True if the element is currently visible, else false
7175 isVisible : function(deep) {
7176 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7177 if(deep !== true || !vis){
7180 var p = this.dom.parentNode;
7181 while(p && p.tagName.toLowerCase() != "body"){
7182 if(!Roo.fly(p, '_isVisible').isVisible()){
7191 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7192 * @param {String} selector The CSS selector
7193 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7194 * @return {CompositeElement/CompositeElementLite} The composite element
7196 select : function(selector, unique){
7197 return El.select(selector, unique, this.dom);
7201 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7202 * @param {String} selector The CSS selector
7203 * @return {Array} An array of the matched nodes
7205 query : function(selector, unique){
7206 return Roo.DomQuery.select(selector, this.dom);
7210 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7211 * @param {String} selector The CSS selector
7212 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7213 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7215 child : function(selector, returnDom){
7216 var n = Roo.DomQuery.selectNode(selector, this.dom);
7217 return returnDom ? n : Roo.get(n);
7221 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7222 * @param {String} selector The CSS selector
7223 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7224 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7226 down : function(selector, returnDom){
7227 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7228 return returnDom ? n : Roo.get(n);
7232 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7233 * @param {String} group The group the DD object is member of
7234 * @param {Object} config The DD config object
7235 * @param {Object} overrides An object containing methods to override/implement on the DD object
7236 * @return {Roo.dd.DD} The DD object
7238 initDD : function(group, config, overrides){
7239 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7240 return Roo.apply(dd, overrides);
7244 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7245 * @param {String} group The group the DDProxy object is member of
7246 * @param {Object} config The DDProxy config object
7247 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7248 * @return {Roo.dd.DDProxy} The DDProxy object
7250 initDDProxy : function(group, config, overrides){
7251 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7252 return Roo.apply(dd, overrides);
7256 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7257 * @param {String} group The group the DDTarget object is member of
7258 * @param {Object} config The DDTarget config object
7259 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7260 * @return {Roo.dd.DDTarget} The DDTarget object
7262 initDDTarget : function(group, config, overrides){
7263 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7264 return Roo.apply(dd, overrides);
7268 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7269 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7270 * @param {Boolean} visible Whether the element is visible
7271 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7272 * @return {Roo.Element} this
7274 setVisible : function(visible, animate){
7276 if(this.visibilityMode == El.DISPLAY){
7277 this.setDisplayed(visible);
7280 this.dom.style.visibility = visible ? "visible" : "hidden";
7283 // closure for composites
7285 var visMode = this.visibilityMode;
7287 this.setOpacity(.01);
7288 this.setVisible(true);
7290 this.anim({opacity: { to: (visible?1:0) }},
7291 this.preanim(arguments, 1),
7292 null, .35, 'easeIn', function(){
7294 if(visMode == El.DISPLAY){
7295 dom.style.display = "none";
7297 dom.style.visibility = "hidden";
7299 Roo.get(dom).setOpacity(1);
7307 * Returns true if display is not "none"
7310 isDisplayed : function() {
7311 return this.getStyle("display") != "none";
7315 * Toggles the element's visibility or display, depending on visibility mode.
7316 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7317 * @return {Roo.Element} this
7319 toggle : function(animate){
7320 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7325 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7326 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7327 * @return {Roo.Element} this
7329 setDisplayed : function(value) {
7330 if(typeof value == "boolean"){
7331 value = value ? this.originalDisplay : "none";
7333 this.setStyle("display", value);
7338 * Tries to focus the element. Any exceptions are caught and ignored.
7339 * @return {Roo.Element} this
7341 focus : function() {
7349 * Tries to blur the element. Any exceptions are caught and ignored.
7350 * @return {Roo.Element} this
7360 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7361 * @param {String/Array} className The CSS class to add, or an array of classes
7362 * @return {Roo.Element} this
7364 addClass : function(className){
7365 if(className instanceof Array){
7366 for(var i = 0, len = className.length; i < len; i++) {
7367 this.addClass(className[i]);
7370 if(className && !this.hasClass(className)){
7371 this.dom.className = this.dom.className + " " + className;
7378 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7379 * @param {String/Array} className The CSS class to add, or an array of classes
7380 * @return {Roo.Element} this
7382 radioClass : function(className){
7383 var siblings = this.dom.parentNode.childNodes;
7384 for(var i = 0; i < siblings.length; i++) {
7385 var s = siblings[i];
7386 if(s.nodeType == 1){
7387 Roo.get(s).removeClass(className);
7390 this.addClass(className);
7395 * Removes one or more CSS classes from the element.
7396 * @param {String/Array} className The CSS class to remove, or an array of classes
7397 * @return {Roo.Element} this
7399 removeClass : function(className){
7400 if(!className || !this.dom.className){
7403 if(className instanceof Array){
7404 for(var i = 0, len = className.length; i < len; i++) {
7405 this.removeClass(className[i]);
7408 if(this.hasClass(className)){
7409 var re = this.classReCache[className];
7411 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7412 this.classReCache[className] = re;
7414 this.dom.className =
7415 this.dom.className.replace(re, " ");
7425 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7426 * @param {String} className The CSS class to toggle
7427 * @return {Roo.Element} this
7429 toggleClass : function(className){
7430 if(this.hasClass(className)){
7431 this.removeClass(className);
7433 this.addClass(className);
7439 * Checks if the specified CSS class exists on this element's DOM node.
7440 * @param {String} className The CSS class to check for
7441 * @return {Boolean} True if the class exists, else false
7443 hasClass : function(className){
7444 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7448 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7449 * @param {String} oldClassName The CSS class to replace
7450 * @param {String} newClassName The replacement CSS class
7451 * @return {Roo.Element} this
7453 replaceClass : function(oldClassName, newClassName){
7454 this.removeClass(oldClassName);
7455 this.addClass(newClassName);
7460 * Returns an object with properties matching the styles requested.
7461 * For example, el.getStyles('color', 'font-size', 'width') might return
7462 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7463 * @param {String} style1 A style name
7464 * @param {String} style2 A style name
7465 * @param {String} etc.
7466 * @return {Object} The style object
7468 getStyles : function(){
7469 var a = arguments, len = a.length, r = {};
7470 for(var i = 0; i < len; i++){
7471 r[a[i]] = this.getStyle(a[i]);
7477 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7478 * @param {String} property The style property whose value is returned.
7479 * @return {String} The current value of the style property for this element.
7481 getStyle : function(){
7482 return view && view.getComputedStyle ?
7484 var el = this.dom, v, cs, camel;
7485 if(prop == 'float'){
7488 if(el.style && (v = el.style[prop])){
7491 if(cs = view.getComputedStyle(el, "")){
7492 if(!(camel = propCache[prop])){
7493 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7500 var el = this.dom, v, cs, camel;
7501 if(prop == 'opacity'){
7502 if(typeof el.style.filter == 'string'){
7503 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7505 var fv = parseFloat(m[1]);
7507 return fv ? fv / 100 : 0;
7512 }else if(prop == 'float'){
7513 prop = "styleFloat";
7515 if(!(camel = propCache[prop])){
7516 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7518 if(v = el.style[camel]){
7521 if(cs = el.currentStyle){
7529 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7530 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7531 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7532 * @return {Roo.Element} this
7534 setStyle : function(prop, value){
7535 if(typeof prop == "string"){
7537 if (prop == 'float') {
7538 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7543 if(!(camel = propCache[prop])){
7544 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7547 if(camel == 'opacity') {
7548 this.setOpacity(value);
7550 this.dom.style[camel] = value;
7553 for(var style in prop){
7554 if(typeof prop[style] != "function"){
7555 this.setStyle(style, prop[style]);
7563 * More flexible version of {@link #setStyle} for setting style properties.
7564 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7565 * a function which returns such a specification.
7566 * @return {Roo.Element} this
7568 applyStyles : function(style){
7569 Roo.DomHelper.applyStyles(this.dom, style);
7574 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7575 * @return {Number} The X position of the element
7578 return D.getX(this.dom);
7582 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7583 * @return {Number} The Y position of the element
7586 return D.getY(this.dom);
7590 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7591 * @return {Array} The XY position of the element
7594 return D.getXY(this.dom);
7598 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7599 * @param {Number} The X position of the element
7600 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7601 * @return {Roo.Element} this
7603 setX : function(x, animate){
7605 D.setX(this.dom, x);
7607 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7613 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7614 * @param {Number} The Y position of the element
7615 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7616 * @return {Roo.Element} this
7618 setY : function(y, animate){
7620 D.setY(this.dom, y);
7622 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7628 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7629 * @param {String} left The left CSS property value
7630 * @return {Roo.Element} this
7632 setLeft : function(left){
7633 this.setStyle("left", this.addUnits(left));
7638 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7639 * @param {String} top The top CSS property value
7640 * @return {Roo.Element} this
7642 setTop : function(top){
7643 this.setStyle("top", this.addUnits(top));
7648 * Sets the element's CSS right style.
7649 * @param {String} right The right CSS property value
7650 * @return {Roo.Element} this
7652 setRight : function(right){
7653 this.setStyle("right", this.addUnits(right));
7658 * Sets the element's CSS bottom style.
7659 * @param {String} bottom The bottom CSS property value
7660 * @return {Roo.Element} this
7662 setBottom : function(bottom){
7663 this.setStyle("bottom", this.addUnits(bottom));
7668 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7669 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7670 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7671 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7672 * @return {Roo.Element} this
7674 setXY : function(pos, animate){
7676 D.setXY(this.dom, pos);
7678 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7684 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7685 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7686 * @param {Number} x X value for new position (coordinates are page-based)
7687 * @param {Number} y Y value for new position (coordinates are page-based)
7688 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7689 * @return {Roo.Element} this
7691 setLocation : function(x, y, animate){
7692 this.setXY([x, y], this.preanim(arguments, 2));
7697 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7698 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7699 * @param {Number} x X value for new position (coordinates are page-based)
7700 * @param {Number} y Y value for new position (coordinates are page-based)
7701 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7702 * @return {Roo.Element} this
7704 moveTo : function(x, y, animate){
7705 this.setXY([x, y], this.preanim(arguments, 2));
7710 * Returns the region of the given element.
7711 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7712 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7714 getRegion : function(){
7715 return D.getRegion(this.dom);
7719 * Returns the offset height of the element
7720 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7721 * @return {Number} The element's height
7723 getHeight : function(contentHeight){
7724 var h = this.dom.offsetHeight || 0;
7725 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7729 * Returns the offset width of the element
7730 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7731 * @return {Number} The element's width
7733 getWidth : function(contentWidth){
7734 var w = this.dom.offsetWidth || 0;
7735 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7739 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7740 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7741 * if a height has not been set using CSS.
7744 getComputedHeight : function(){
7745 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7747 h = parseInt(this.getStyle('height'), 10) || 0;
7748 if(!this.isBorderBox()){
7749 h += this.getFrameWidth('tb');
7756 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7757 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7758 * if a width has not been set using CSS.
7761 getComputedWidth : function(){
7762 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7764 w = parseInt(this.getStyle('width'), 10) || 0;
7765 if(!this.isBorderBox()){
7766 w += this.getFrameWidth('lr');
7773 * Returns the size of the element.
7774 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7775 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7777 getSize : function(contentSize){
7778 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7782 * Returns the width and height of the viewport.
7783 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7785 getViewSize : function(){
7786 var d = this.dom, doc = document, aw = 0, ah = 0;
7787 if(d == doc || d == doc.body){
7788 return {width : D.getViewWidth(), height: D.getViewHeight()};
7791 width : d.clientWidth,
7792 height: d.clientHeight
7798 * Returns the value of the "value" attribute
7799 * @param {Boolean} asNumber true to parse the value as a number
7800 * @return {String/Number}
7802 getValue : function(asNumber){
7803 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7807 adjustWidth : function(width){
7808 if(typeof width == "number"){
7809 if(this.autoBoxAdjust && !this.isBorderBox()){
7810 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7820 adjustHeight : function(height){
7821 if(typeof height == "number"){
7822 if(this.autoBoxAdjust && !this.isBorderBox()){
7823 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7833 * Set the width of the element
7834 * @param {Number} width The new width
7835 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7836 * @return {Roo.Element} this
7838 setWidth : function(width, animate){
7839 width = this.adjustWidth(width);
7841 this.dom.style.width = this.addUnits(width);
7843 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7849 * Set the height of the element
7850 * @param {Number} height The new height
7851 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7852 * @return {Roo.Element} this
7854 setHeight : function(height, animate){
7855 height = this.adjustHeight(height);
7857 this.dom.style.height = this.addUnits(height);
7859 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7865 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7866 * @param {Number} width The new width
7867 * @param {Number} height The new height
7868 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7869 * @return {Roo.Element} this
7871 setSize : function(width, height, animate){
7872 if(typeof width == "object"){ // in case of object from getSize()
7873 height = width.height; width = width.width;
7875 width = this.adjustWidth(width); height = this.adjustHeight(height);
7877 this.dom.style.width = this.addUnits(width);
7878 this.dom.style.height = this.addUnits(height);
7880 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7886 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7887 * @param {Number} x X value for new position (coordinates are page-based)
7888 * @param {Number} y Y value for new position (coordinates are page-based)
7889 * @param {Number} width The new width
7890 * @param {Number} height The new height
7891 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7892 * @return {Roo.Element} this
7894 setBounds : function(x, y, width, height, animate){
7896 this.setSize(width, height);
7897 this.setLocation(x, y);
7899 width = this.adjustWidth(width); height = this.adjustHeight(height);
7900 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7901 this.preanim(arguments, 4), 'motion');
7907 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
7908 * @param {Roo.lib.Region} region The region to fill
7909 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7910 * @return {Roo.Element} this
7912 setRegion : function(region, animate){
7913 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7918 * Appends an event handler
7920 * @param {String} eventName The type of event to append
7921 * @param {Function} fn The method the event invokes
7922 * @param {Object} scope (optional) The scope (this object) of the fn
7923 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7925 addListener : function(eventName, fn, scope, options){
7927 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7932 * Removes an event handler from this element
7933 * @param {String} eventName the type of event to remove
7934 * @param {Function} fn the method the event invokes
7935 * @return {Roo.Element} this
7937 removeListener : function(eventName, fn){
7938 Roo.EventManager.removeListener(this.dom, eventName, fn);
7943 * Removes all previous added listeners from this element
7944 * @return {Roo.Element} this
7946 removeAllListeners : function(){
7947 E.purgeElement(this.dom);
7951 relayEvent : function(eventName, observable){
7952 this.on(eventName, function(e){
7953 observable.fireEvent(eventName, e);
7958 * Set the opacity of the element
7959 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7960 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7961 * @return {Roo.Element} this
7963 setOpacity : function(opacity, animate){
7965 var s = this.dom.style;
7968 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7969 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7971 s.opacity = opacity;
7974 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7980 * Gets the left X coordinate
7981 * @param {Boolean} local True to get the local css position instead of page coordinate
7984 getLeft : function(local){
7988 return parseInt(this.getStyle("left"), 10) || 0;
7993 * Gets the right X coordinate of the element (element X position + element width)
7994 * @param {Boolean} local True to get the local css position instead of page coordinate
7997 getRight : function(local){
7999 return this.getX() + this.getWidth();
8001 return (this.getLeft(true) + this.getWidth()) || 0;
8006 * Gets the top Y coordinate
8007 * @param {Boolean} local True to get the local css position instead of page coordinate
8010 getTop : function(local) {
8014 return parseInt(this.getStyle("top"), 10) || 0;
8019 * Gets the bottom Y coordinate of the element (element Y position + element height)
8020 * @param {Boolean} local True to get the local css position instead of page coordinate
8023 getBottom : function(local){
8025 return this.getY() + this.getHeight();
8027 return (this.getTop(true) + this.getHeight()) || 0;
8032 * Initializes positioning on this element. If a desired position is not passed, it will make the
8033 * the element positioned relative IF it is not already positioned.
8034 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8035 * @param {Number} zIndex (optional) The zIndex to apply
8036 * @param {Number} x (optional) Set the page X position
8037 * @param {Number} y (optional) Set the page Y position
8039 position : function(pos, zIndex, x, y){
8041 if(this.getStyle('position') == 'static'){
8042 this.setStyle('position', 'relative');
8045 this.setStyle("position", pos);
8048 this.setStyle("z-index", zIndex);
8050 if(x !== undefined && y !== undefined){
8052 }else if(x !== undefined){
8054 }else if(y !== undefined){
8060 * Clear positioning back to the default when the document was loaded
8061 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8062 * @return {Roo.Element} this
8064 clearPositioning : function(value){
8072 "position" : "static"
8078 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8079 * snapshot before performing an update and then restoring the element.
8082 getPositioning : function(){
8083 var l = this.getStyle("left");
8084 var t = this.getStyle("top");
8086 "position" : this.getStyle("position"),
8088 "right" : l ? "" : this.getStyle("right"),
8090 "bottom" : t ? "" : this.getStyle("bottom"),
8091 "z-index" : this.getStyle("z-index")
8096 * Gets the width of the border(s) for the specified side(s)
8097 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8098 * passing lr would get the border (l)eft width + the border (r)ight width.
8099 * @return {Number} The width of the sides passed added together
8101 getBorderWidth : function(side){
8102 return this.addStyles(side, El.borders);
8106 * Gets the width of the padding(s) for the specified side(s)
8107 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8108 * passing lr would get the padding (l)eft + the padding (r)ight.
8109 * @return {Number} The padding of the sides passed added together
8111 getPadding : function(side){
8112 return this.addStyles(side, El.paddings);
8116 * Set positioning with an object returned by getPositioning().
8117 * @param {Object} posCfg
8118 * @return {Roo.Element} this
8120 setPositioning : function(pc){
8121 this.applyStyles(pc);
8122 if(pc.right == "auto"){
8123 this.dom.style.right = "";
8125 if(pc.bottom == "auto"){
8126 this.dom.style.bottom = "";
8132 fixDisplay : function(){
8133 if(this.getStyle("display") == "none"){
8134 this.setStyle("visibility", "hidden");
8135 this.setStyle("display", this.originalDisplay); // first try reverting to default
8136 if(this.getStyle("display") == "none"){ // if that fails, default to block
8137 this.setStyle("display", "block");
8143 * Quick set left and top adding default units
8144 * @param {String} left The left CSS property value
8145 * @param {String} top The top CSS property value
8146 * @return {Roo.Element} this
8148 setLeftTop : function(left, top){
8149 this.dom.style.left = this.addUnits(left);
8150 this.dom.style.top = this.addUnits(top);
8155 * Move this element relative to its current position.
8156 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8157 * @param {Number} distance How far to move the element in pixels
8158 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8159 * @return {Roo.Element} this
8161 move : function(direction, distance, animate){
8162 var xy = this.getXY();
8163 direction = direction.toLowerCase();
8167 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8171 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8176 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8181 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8188 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8189 * @return {Roo.Element} this
8192 if(!this.isClipped){
8193 this.isClipped = true;
8194 this.originalClip = {
8195 "o": this.getStyle("overflow"),
8196 "x": this.getStyle("overflow-x"),
8197 "y": this.getStyle("overflow-y")
8199 this.setStyle("overflow", "hidden");
8200 this.setStyle("overflow-x", "hidden");
8201 this.setStyle("overflow-y", "hidden");
8207 * Return clipping (overflow) to original clipping before clip() was called
8208 * @return {Roo.Element} this
8210 unclip : function(){
8212 this.isClipped = false;
8213 var o = this.originalClip;
8214 if(o.o){this.setStyle("overflow", o.o);}
8215 if(o.x){this.setStyle("overflow-x", o.x);}
8216 if(o.y){this.setStyle("overflow-y", o.y);}
8223 * Gets the x,y coordinates specified by the anchor position on the element.
8224 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8225 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8226 * {width: (target width), height: (target height)} (defaults to the element's current size)
8227 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8228 * @return {Array} [x, y] An array containing the element's x and y coordinates
8230 getAnchorXY : function(anchor, local, s){
8231 //Passing a different size is useful for pre-calculating anchors,
8232 //especially for anchored animations that change the el size.
8234 var w, h, vp = false;
8237 if(d == document.body || d == document){
8239 w = D.getViewWidth(); h = D.getViewHeight();
8241 w = this.getWidth(); h = this.getHeight();
8244 w = s.width; h = s.height;
8246 var x = 0, y = 0, r = Math.round;
8247 switch((anchor || "tl").toLowerCase()){
8289 var sc = this.getScroll();
8290 return [x + sc.left, y + sc.top];
8292 //Add the element's offset xy
8293 var o = this.getXY();
8294 return [x+o[0], y+o[1]];
8298 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8299 * supported position values.
8300 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8301 * @param {String} position The position to align to.
8302 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8303 * @return {Array} [x, y]
8305 getAlignToXY : function(el, p, o){
8309 throw "Element.alignTo with an element that doesn't exist";
8311 var c = false; //constrain to viewport
8312 var p1 = "", p2 = "";
8319 }else if(p.indexOf("-") == -1){
8322 p = p.toLowerCase();
8323 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8325 throw "Element.alignTo with an invalid alignment " + p;
8327 p1 = m[1]; p2 = m[2]; c = !!m[3];
8329 //Subtract the aligned el's internal xy from the target's offset xy
8330 //plus custom offset to get the aligned el's new offset xy
8331 var a1 = this.getAnchorXY(p1, true);
8332 var a2 = el.getAnchorXY(p2, false);
8333 var x = a2[0] - a1[0] + o[0];
8334 var y = a2[1] - a1[1] + o[1];
8336 //constrain the aligned el to viewport if necessary
8337 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8338 // 5px of margin for ie
8339 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8341 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8342 //perpendicular to the vp border, allow the aligned el to slide on that border,
8343 //otherwise swap the aligned el to the opposite border of the target.
8344 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8345 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8346 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8347 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8350 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8351 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8353 if((x+w) > dw + scrollX){
8354 x = swapX ? r.left-w : dw+scrollX-w;
8357 x = swapX ? r.right : scrollX;
8359 if((y+h) > dh + scrollY){
8360 y = swapY ? r.top-h : dh+scrollY-h;
8363 y = swapY ? r.bottom : scrollY;
8370 getConstrainToXY : function(){
8371 var os = {top:0, left:0, bottom:0, right: 0};
8373 return function(el, local, offsets, proposedXY){
8375 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8377 var vw, vh, vx = 0, vy = 0;
8378 if(el.dom == document.body || el.dom == document){
8379 vw = Roo.lib.Dom.getViewWidth();
8380 vh = Roo.lib.Dom.getViewHeight();
8382 vw = el.dom.clientWidth;
8383 vh = el.dom.clientHeight;
8385 var vxy = el.getXY();
8391 var s = el.getScroll();
8393 vx += offsets.left + s.left;
8394 vy += offsets.top + s.top;
8396 vw -= offsets.right;
8397 vh -= offsets.bottom;
8402 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8403 var x = xy[0], y = xy[1];
8404 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8406 // only move it if it needs it
8409 // first validate right/bottom
8418 // then make sure top/left isn't negative
8427 return moved ? [x, y] : false;
8432 adjustForConstraints : function(xy, parent, offsets){
8433 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8437 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8438 * document it aligns it to the viewport.
8439 * The position parameter is optional, and can be specified in any one of the following formats:
8441 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8442 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8443 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8444 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8445 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8446 * element's anchor point, and the second value is used as the target's anchor point.</li>
8448 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8449 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8450 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8451 * that specified in order to enforce the viewport constraints.
8452 * Following are all of the supported anchor positions:
8455 ----- -----------------------------
8456 tl The top left corner (default)
8457 t The center of the top edge
8458 tr The top right corner
8459 l The center of the left edge
8460 c In the center of the element
8461 r The center of the right edge
8462 bl The bottom left corner
8463 b The center of the bottom edge
8464 br The bottom right corner
8468 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8469 el.alignTo("other-el");
8471 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8472 el.alignTo("other-el", "tr?");
8474 // align the bottom right corner of el with the center left edge of other-el
8475 el.alignTo("other-el", "br-l?");
8477 // align the center of el with the bottom left corner of other-el and
8478 // adjust the x position by -6 pixels (and the y position by 0)
8479 el.alignTo("other-el", "c-bl", [-6, 0]);
8481 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8482 * @param {String} position The position to align to.
8483 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8484 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8485 * @return {Roo.Element} this
8487 alignTo : function(element, position, offsets, animate){
8488 var xy = this.getAlignToXY(element, position, offsets);
8489 this.setXY(xy, this.preanim(arguments, 3));
8494 * Anchors an element to another element and realigns it when the window is resized.
8495 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8496 * @param {String} position The position to align to.
8497 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8498 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8499 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8500 * is a number, it is used as the buffer delay (defaults to 50ms).
8501 * @param {Function} callback The function to call after the animation finishes
8502 * @return {Roo.Element} this
8504 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8505 var action = function(){
8506 this.alignTo(el, alignment, offsets, animate);
8507 Roo.callback(callback, this);
8509 Roo.EventManager.onWindowResize(action, this);
8510 var tm = typeof monitorScroll;
8511 if(tm != 'undefined'){
8512 Roo.EventManager.on(window, 'scroll', action, this,
8513 {buffer: tm == 'number' ? monitorScroll : 50});
8515 action.call(this); // align immediately
8519 * Clears any opacity settings from this element. Required in some cases for IE.
8520 * @return {Roo.Element} this
8522 clearOpacity : function(){
8523 if (window.ActiveXObject) {
8524 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8525 this.dom.style.filter = "";
8528 this.dom.style.opacity = "";
8529 this.dom.style["-moz-opacity"] = "";
8530 this.dom.style["-khtml-opacity"] = "";
8536 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8537 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8538 * @return {Roo.Element} this
8540 hide : function(animate){
8541 this.setVisible(false, this.preanim(arguments, 0));
8546 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8547 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8548 * @return {Roo.Element} this
8550 show : function(animate){
8551 this.setVisible(true, this.preanim(arguments, 0));
8556 * @private Test if size has a unit, otherwise appends the default
8558 addUnits : function(size){
8559 return Roo.Element.addUnits(size, this.defaultUnit);
8563 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8564 * @return {Roo.Element} this
8566 beginMeasure : function(){
8568 if(el.offsetWidth || el.offsetHeight){
8569 return this; // offsets work already
8572 var p = this.dom, b = document.body; // start with this element
8573 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8574 var pe = Roo.get(p);
8575 if(pe.getStyle('display') == 'none'){
8576 changed.push({el: p, visibility: pe.getStyle("visibility")});
8577 p.style.visibility = "hidden";
8578 p.style.display = "block";
8582 this._measureChanged = changed;
8588 * Restores displays to before beginMeasure was called
8589 * @return {Roo.Element} this
8591 endMeasure : function(){
8592 var changed = this._measureChanged;
8594 for(var i = 0, len = changed.length; i < len; i++) {
8596 r.el.style.visibility = r.visibility;
8597 r.el.style.display = "none";
8599 this._measureChanged = null;
8605 * Update the innerHTML of this element, optionally searching for and processing scripts
8606 * @param {String} html The new HTML
8607 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8608 * @param {Function} callback For async script loading you can be noticed when the update completes
8609 * @return {Roo.Element} this
8611 update : function(html, loadScripts, callback){
8612 if(typeof html == "undefined"){
8615 if(loadScripts !== true){
8616 this.dom.innerHTML = html;
8617 if(typeof callback == "function"){
8625 html += '<span id="' + id + '"></span>';
8627 E.onAvailable(id, function(){
8628 var hd = document.getElementsByTagName("head")[0];
8629 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8630 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8631 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8634 while(match = re.exec(html)){
8635 var attrs = match[1];
8636 var srcMatch = attrs ? attrs.match(srcRe) : false;
8637 if(srcMatch && srcMatch[2]){
8638 var s = document.createElement("script");
8639 s.src = srcMatch[2];
8640 var typeMatch = attrs.match(typeRe);
8641 if(typeMatch && typeMatch[2]){
8642 s.type = typeMatch[2];
8645 }else if(match[2] && match[2].length > 0){
8646 if(window.execScript) {
8647 window.execScript(match[2]);
8655 window.eval(match[2]);
8659 var el = document.getElementById(id);
8660 if(el){el.parentNode.removeChild(el);}
8661 if(typeof callback == "function"){
8665 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8670 * Direct access to the UpdateManager update() method (takes the same parameters).
8671 * @param {String/Function} url The url for this request or a function to call to get the url
8672 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8673 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8674 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8675 * @return {Roo.Element} this
8678 var um = this.getUpdateManager();
8679 um.update.apply(um, arguments);
8684 * Gets this element's UpdateManager
8685 * @return {Roo.UpdateManager} The UpdateManager
8687 getUpdateManager : function(){
8688 if(!this.updateManager){
8689 this.updateManager = new Roo.UpdateManager(this);
8691 return this.updateManager;
8695 * Disables text selection for this element (normalized across browsers)
8696 * @return {Roo.Element} this
8698 unselectable : function(){
8699 this.dom.unselectable = "on";
8700 this.swallowEvent("selectstart", true);
8701 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8702 this.addClass("x-unselectable");
8707 * Calculates the x, y to center this element on the screen
8708 * @return {Array} The x, y values [x, y]
8710 getCenterXY : function(){
8711 return this.getAlignToXY(document, 'c-c');
8715 * Centers the Element in either the viewport, or another Element.
8716 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8718 center : function(centerIn){
8719 this.alignTo(centerIn || document, 'c-c');
8724 * Tests various css rules/browsers to determine if this element uses a border box
8727 isBorderBox : function(){
8728 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8732 * Return a box {x, y, width, height} that can be used to set another elements
8733 * size/location to match this element.
8734 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8735 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8736 * @return {Object} box An object in the format {x, y, width, height}
8738 getBox : function(contentBox, local){
8743 var left = parseInt(this.getStyle("left"), 10) || 0;
8744 var top = parseInt(this.getStyle("top"), 10) || 0;
8747 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8749 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8751 var l = this.getBorderWidth("l")+this.getPadding("l");
8752 var r = this.getBorderWidth("r")+this.getPadding("r");
8753 var t = this.getBorderWidth("t")+this.getPadding("t");
8754 var b = this.getBorderWidth("b")+this.getPadding("b");
8755 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8757 bx.right = bx.x + bx.width;
8758 bx.bottom = bx.y + bx.height;
8763 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8764 for more information about the sides.
8765 * @param {String} sides
8768 getFrameWidth : function(sides, onlyContentBox){
8769 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8773 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8774 * @param {Object} box The box to fill {x, y, width, height}
8775 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8776 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8777 * @return {Roo.Element} this
8779 setBox : function(box, adjust, animate){
8780 var w = box.width, h = box.height;
8781 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8782 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8783 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8785 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8790 * Forces the browser to repaint this element
8791 * @return {Roo.Element} this
8793 repaint : function(){
8795 this.addClass("x-repaint");
8796 setTimeout(function(){
8797 Roo.get(dom).removeClass("x-repaint");
8803 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8804 * then it returns the calculated width of the sides (see getPadding)
8805 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8806 * @return {Object/Number}
8808 getMargins : function(side){
8811 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8812 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8813 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8814 right: parseInt(this.getStyle("margin-right"), 10) || 0
8817 return this.addStyles(side, El.margins);
8822 addStyles : function(sides, styles){
8824 for(var i = 0, len = sides.length; i < len; i++){
8825 v = this.getStyle(styles[sides.charAt(i)]);
8827 w = parseInt(v, 10);
8835 * Creates a proxy element of this element
8836 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8837 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8838 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8839 * @return {Roo.Element} The new proxy element
8841 createProxy : function(config, renderTo, matchBox){
8843 renderTo = Roo.getDom(renderTo);
8845 renderTo = document.body;
8847 config = typeof config == "object" ?
8848 config : {tag : "div", cls: config};
8849 var proxy = Roo.DomHelper.append(renderTo, config, true);
8851 proxy.setBox(this.getBox());
8857 * Puts a mask over this element to disable user interaction. Requires core.css.
8858 * This method can only be applied to elements which accept child nodes.
8859 * @param {String} msg (optional) A message to display in the mask
8860 * @param {String} msgCls (optional) A css class to apply to the msg element
8861 * @return {Element} The mask element
8863 mask : function(msg, msgCls){
8864 if(this.getStyle("position") == "static"){
8865 this.setStyle("position", "relative");
8868 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8870 this.addClass("x-masked");
8871 this._mask.setDisplayed(true);
8872 if(typeof msg == 'string'){
8874 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8876 var mm = this._maskMsg;
8877 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8878 mm.dom.firstChild.innerHTML = msg;
8879 mm.setDisplayed(true);
8882 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8883 this._mask.setHeight(this.getHeight());
8889 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8890 * it is cached for reuse.
8892 unmask : function(removeEl){
8894 if(removeEl === true){
8895 this._mask.remove();
8898 this._maskMsg.remove();
8899 delete this._maskMsg;
8902 this._mask.setDisplayed(false);
8904 this._maskMsg.setDisplayed(false);
8908 this.removeClass("x-masked");
8912 * Returns true if this element is masked
8915 isMasked : function(){
8916 return this._mask && this._mask.isVisible();
8920 * Creates an iframe shim for this element to keep selects and other windowed objects from
8922 * @return {Roo.Element} The new shim element
8924 createShim : function(){
8925 var el = document.createElement('iframe');
8926 el.frameBorder = 'no';
8927 el.className = 'roo-shim';
8928 if(Roo.isIE && Roo.isSecure){
8929 el.src = Roo.SSL_SECURE_URL;
8931 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8932 shim.autoBoxAdjust = false;
8937 * Removes this element from the DOM and deletes it from the cache
8939 remove : function(){
8940 if(this.dom.parentNode){
8941 this.dom.parentNode.removeChild(this.dom);
8943 delete El.cache[this.dom.id];
8947 * Sets up event handlers to add and remove a css class when the mouse is over this element
8948 * @param {String} className
8949 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8950 * mouseout events for children elements
8951 * @return {Roo.Element} this
8953 addClassOnOver : function(className, preventFlicker){
8954 this.on("mouseover", function(){
8955 Roo.fly(this, '_internal').addClass(className);
8957 var removeFn = function(e){
8958 if(preventFlicker !== true || !e.within(this, true)){
8959 Roo.fly(this, '_internal').removeClass(className);
8962 this.on("mouseout", removeFn, this.dom);
8967 * Sets up event handlers to add and remove a css class when this element has the focus
8968 * @param {String} className
8969 * @return {Roo.Element} this
8971 addClassOnFocus : function(className){
8972 this.on("focus", function(){
8973 Roo.fly(this, '_internal').addClass(className);
8975 this.on("blur", function(){
8976 Roo.fly(this, '_internal').removeClass(className);
8981 * 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)
8982 * @param {String} className
8983 * @return {Roo.Element} this
8985 addClassOnClick : function(className){
8987 this.on("mousedown", function(){
8988 Roo.fly(dom, '_internal').addClass(className);
8989 var d = Roo.get(document);
8990 var fn = function(){
8991 Roo.fly(dom, '_internal').removeClass(className);
8992 d.removeListener("mouseup", fn);
8994 d.on("mouseup", fn);
9000 * Stops the specified event from bubbling and optionally prevents the default action
9001 * @param {String} eventName
9002 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9003 * @return {Roo.Element} this
9005 swallowEvent : function(eventName, preventDefault){
9006 var fn = function(e){
9007 e.stopPropagation();
9012 if(eventName instanceof Array){
9013 for(var i = 0, len = eventName.length; i < len; i++){
9014 this.on(eventName[i], fn);
9018 this.on(eventName, fn);
9025 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9028 * Sizes this element to its parent element's dimensions performing
9029 * neccessary box adjustments.
9030 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9031 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9032 * @return {Roo.Element} this
9034 fitToParent : function(monitorResize, targetParent) {
9035 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9036 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9037 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9040 var p = Roo.get(targetParent || this.dom.parentNode);
9041 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9042 if (monitorResize === true) {
9043 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9044 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9050 * Gets the next sibling, skipping text nodes
9051 * @return {HTMLElement} The next sibling or null
9053 getNextSibling : function(){
9054 var n = this.dom.nextSibling;
9055 while(n && n.nodeType != 1){
9062 * Gets the previous sibling, skipping text nodes
9063 * @return {HTMLElement} The previous sibling or null
9065 getPrevSibling : function(){
9066 var n = this.dom.previousSibling;
9067 while(n && n.nodeType != 1){
9068 n = n.previousSibling;
9075 * Appends the passed element(s) to this element
9076 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9077 * @return {Roo.Element} this
9079 appendChild: function(el){
9086 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9087 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9088 * automatically generated with the specified attributes.
9089 * @param {HTMLElement} insertBefore (optional) a child element of this element
9090 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9091 * @return {Roo.Element} The new child element
9093 createChild: function(config, insertBefore, returnDom){
9094 config = config || {tag:'div'};
9096 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9098 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9102 * Appends this element to the passed element
9103 * @param {String/HTMLElement/Element} el The new parent element
9104 * @return {Roo.Element} this
9106 appendTo: function(el){
9107 el = Roo.getDom(el);
9108 el.appendChild(this.dom);
9113 * Inserts this element before the passed element in the DOM
9114 * @param {String/HTMLElement/Element} el The element to insert before
9115 * @return {Roo.Element} this
9117 insertBefore: function(el){
9118 el = Roo.getDom(el);
9119 el.parentNode.insertBefore(this.dom, el);
9124 * Inserts this element after the passed element in the DOM
9125 * @param {String/HTMLElement/Element} el The element to insert after
9126 * @return {Roo.Element} this
9128 insertAfter: function(el){
9129 el = Roo.getDom(el);
9130 el.parentNode.insertBefore(this.dom, el.nextSibling);
9135 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9136 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9137 * @return {Roo.Element} The new child
9139 insertFirst: function(el, returnDom){
9141 if(typeof el == 'object' && !el.nodeType){ // dh config
9142 return this.createChild(el, this.dom.firstChild, returnDom);
9144 el = Roo.getDom(el);
9145 this.dom.insertBefore(el, this.dom.firstChild);
9146 return !returnDom ? Roo.get(el) : el;
9151 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9152 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9153 * @param {String} where (optional) 'before' or 'after' defaults to before
9154 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9155 * @return {Roo.Element} the inserted Element
9157 insertSibling: function(el, where, returnDom){
9158 where = where ? where.toLowerCase() : 'before';
9160 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9162 if(typeof el == 'object' && !el.nodeType){ // dh config
9163 if(where == 'after' && !this.dom.nextSibling){
9164 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9166 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9170 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9171 where == 'before' ? this.dom : this.dom.nextSibling);
9180 * Creates and wraps this element with another element
9181 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9182 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9183 * @return {HTMLElement/Element} The newly created wrapper element
9185 wrap: function(config, returnDom){
9187 config = {tag: "div"};
9189 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9190 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9195 * Replaces the passed element with this element
9196 * @param {String/HTMLElement/Element} el The element to replace
9197 * @return {Roo.Element} this
9199 replace: function(el){
9201 this.insertBefore(el);
9207 * Inserts an html fragment into this element
9208 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9209 * @param {String} html The HTML fragment
9210 * @param {Boolean} returnEl True to return an Roo.Element
9211 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9213 insertHtml : function(where, html, returnEl){
9214 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9215 return returnEl ? Roo.get(el) : el;
9219 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9220 * @param {Object} o The object with the attributes
9221 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9222 * @return {Roo.Element} this
9224 set : function(o, useSet){
9226 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9228 if(attr == "style" || typeof o[attr] == "function") continue;
9230 el.className = o["cls"];
9232 if(useSet) el.setAttribute(attr, o[attr]);
9233 else el[attr] = o[attr];
9237 Roo.DomHelper.applyStyles(el, o.style);
9243 * Convenience method for constructing a KeyMap
9244 * @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:
9245 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9246 * @param {Function} fn The function to call
9247 * @param {Object} scope (optional) The scope of the function
9248 * @return {Roo.KeyMap} The KeyMap created
9250 addKeyListener : function(key, fn, scope){
9252 if(typeof key != "object" || key instanceof Array){
9268 return new Roo.KeyMap(this, config);
9272 * Creates a KeyMap for this element
9273 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9274 * @return {Roo.KeyMap} The KeyMap created
9276 addKeyMap : function(config){
9277 return new Roo.KeyMap(this, config);
9281 * Returns true if this element is scrollable.
9284 isScrollable : function(){
9286 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9290 * 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().
9291 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9292 * @param {Number} value The new scroll value
9293 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9294 * @return {Element} this
9297 scrollTo : function(side, value, animate){
9298 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9300 this.dom[prop] = value;
9302 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9303 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9309 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9310 * within this element's scrollable range.
9311 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9312 * @param {Number} distance How far to scroll the element in pixels
9313 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9314 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9315 * was scrolled as far as it could go.
9317 scroll : function(direction, distance, animate){
9318 if(!this.isScrollable()){
9322 var l = el.scrollLeft, t = el.scrollTop;
9323 var w = el.scrollWidth, h = el.scrollHeight;
9324 var cw = el.clientWidth, ch = el.clientHeight;
9325 direction = direction.toLowerCase();
9326 var scrolled = false;
9327 var a = this.preanim(arguments, 2);
9332 var v = Math.min(l + distance, w-cw);
9333 this.scrollTo("left", v, a);
9340 var v = Math.max(l - distance, 0);
9341 this.scrollTo("left", v, a);
9349 var v = Math.max(t - distance, 0);
9350 this.scrollTo("top", v, a);
9358 var v = Math.min(t + distance, h-ch);
9359 this.scrollTo("top", v, a);
9368 * Translates the passed page coordinates into left/top css values for this element
9369 * @param {Number/Array} x The page x or an array containing [x, y]
9370 * @param {Number} y The page y
9371 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9373 translatePoints : function(x, y){
9374 if(typeof x == 'object' || x instanceof Array){
9377 var p = this.getStyle('position');
9378 var o = this.getXY();
9380 var l = parseInt(this.getStyle('left'), 10);
9381 var t = parseInt(this.getStyle('top'), 10);
9384 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9387 t = (p == "relative") ? 0 : this.dom.offsetTop;
9390 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9394 * Returns the current scroll position of the element.
9395 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9397 getScroll : function(){
9398 var d = this.dom, doc = document;
9399 if(d == doc || d == doc.body){
9400 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9401 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9402 return {left: l, top: t};
9404 return {left: d.scrollLeft, top: d.scrollTop};
9409 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9410 * are convert to standard 6 digit hex color.
9411 * @param {String} attr The css attribute
9412 * @param {String} defaultValue The default value to use when a valid color isn't found
9413 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9416 getColor : function(attr, defaultValue, prefix){
9417 var v = this.getStyle(attr);
9418 if(!v || v == "transparent" || v == "inherit") {
9419 return defaultValue;
9421 var color = typeof prefix == "undefined" ? "#" : prefix;
9422 if(v.substr(0, 4) == "rgb("){
9423 var rvs = v.slice(4, v.length -1).split(",");
9424 for(var i = 0; i < 3; i++){
9425 var h = parseInt(rvs[i]).toString(16);
9432 if(v.substr(0, 1) == "#"){
9434 for(var i = 1; i < 4; i++){
9435 var c = v.charAt(i);
9438 }else if(v.length == 7){
9439 color += v.substr(1);
9443 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9447 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9448 * gradient background, rounded corners and a 4-way shadow.
9449 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9450 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9451 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9452 * @return {Roo.Element} this
9454 boxWrap : function(cls){
9455 cls = cls || 'x-box';
9456 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9457 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9462 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9463 * @param {String} namespace The namespace in which to look for the attribute
9464 * @param {String} name The attribute name
9465 * @return {String} The attribute value
9467 getAttributeNS : Roo.isIE ? function(ns, name){
9469 var type = typeof d[ns+":"+name];
9470 if(type != 'undefined' && type != 'unknown'){
9471 return d[ns+":"+name];
9474 } : function(ns, name){
9476 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9480 var ep = El.prototype;
9483 * Appends an event handler (Shorthand for addListener)
9484 * @param {String} eventName The type of event to append
9485 * @param {Function} fn The method the event invokes
9486 * @param {Object} scope (optional) The scope (this object) of the fn
9487 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9490 ep.on = ep.addListener;
9492 ep.mon = ep.addListener;
9495 * Removes an event handler from this element (shorthand for removeListener)
9496 * @param {String} eventName the type of event to remove
9497 * @param {Function} fn the method the event invokes
9498 * @return {Roo.Element} this
9501 ep.un = ep.removeListener;
9504 * true to automatically adjust width and height settings for box-model issues (default to true)
9506 ep.autoBoxAdjust = true;
9509 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9512 El.addUnits = function(v, defaultUnit){
9513 if(v === "" || v == "auto"){
9516 if(v === undefined){
9519 if(typeof v == "number" || !El.unitPattern.test(v)){
9520 return v + (defaultUnit || 'px');
9525 // special markup used throughout Roo when box wrapping elements
9526 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>';
9528 * Visibility mode constant - Use visibility to hide element
9534 * Visibility mode constant - Use display to hide element
9540 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9541 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9542 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9554 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9555 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9556 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9557 * @return {Element} The Element object
9560 El.get = function(el){
9562 if(!el){ return null; }
9563 if(typeof el == "string"){ // element id
9564 if(!(elm = document.getElementById(el))){
9567 if(ex = El.cache[el]){
9570 ex = El.cache[el] = new El(elm);
9573 }else if(el.tagName){ // dom element
9577 if(ex = El.cache[id]){
9580 ex = El.cache[id] = new El(el);
9583 }else if(el instanceof El){
9585 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9586 // catch case where it hasn't been appended
9587 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9590 }else if(el.isComposite){
9592 }else if(el instanceof Array){
9593 return El.select(el);
9594 }else if(el == document){
9595 // create a bogus element object representing the document object
9597 var f = function(){};
9598 f.prototype = El.prototype;
9600 docEl.dom = document;
9608 El.uncache = function(el){
9609 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9611 delete El.cache[a[i].id || a[i]];
9617 // Garbage collection - uncache elements/purge listeners on orphaned elements
9618 // so we don't hold a reference and cause the browser to retain them
9619 El.garbageCollect = function(){
9620 if(!Roo.enableGarbageCollector){
9621 clearInterval(El.collectorThread);
9624 for(var eid in El.cache){
9625 var el = El.cache[eid], d = el.dom;
9626 // -------------------------------------------------------
9627 // Determining what is garbage:
9628 // -------------------------------------------------------
9630 // dom node is null, definitely garbage
9631 // -------------------------------------------------------
9633 // no parentNode == direct orphan, definitely garbage
9634 // -------------------------------------------------------
9635 // !d.offsetParent && !document.getElementById(eid)
9636 // display none elements have no offsetParent so we will
9637 // also try to look it up by it's id. However, check
9638 // offsetParent first so we don't do unneeded lookups.
9639 // This enables collection of elements that are not orphans
9640 // directly, but somewhere up the line they have an orphan
9642 // -------------------------------------------------------
9643 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9644 delete El.cache[eid];
9645 if(d && Roo.enableListenerCollection){
9651 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9655 El.Flyweight = function(dom){
9658 El.Flyweight.prototype = El.prototype;
9660 El._flyweights = {};
9662 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9663 * the dom node can be overwritten by other code.
9664 * @param {String/HTMLElement} el The dom node or id
9665 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9666 * prevent conflicts (e.g. internally Roo uses "_internal")
9668 * @return {Element} The shared Element object
9670 El.fly = function(el, named){
9671 named = named || '_global';
9672 el = Roo.getDom(el);
9676 if(!El._flyweights[named]){
9677 El._flyweights[named] = new El.Flyweight();
9679 El._flyweights[named].dom = el;
9680 return El._flyweights[named];
9684 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9685 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9686 * Shorthand of {@link Roo.Element#get}
9687 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9688 * @return {Element} The Element object
9694 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9695 * the dom node can be overwritten by other code.
9696 * Shorthand of {@link Roo.Element#fly}
9697 * @param {String/HTMLElement} el The dom node or id
9698 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9699 * prevent conflicts (e.g. internally Roo uses "_internal")
9701 * @return {Element} The shared Element object
9707 // speedy lookup for elements never to box adjust
9708 var noBoxAdjust = Roo.isStrict ? {
9711 input:1, select:1, textarea:1
9713 if(Roo.isIE || Roo.isGecko){
9714 noBoxAdjust['button'] = 1;
9718 Roo.EventManager.on(window, 'unload', function(){
9720 delete El._flyweights;
9728 Roo.Element.selectorFunction = Roo.DomQuery.select;
9731 Roo.Element.select = function(selector, unique, root){
9733 if(typeof selector == "string"){
9734 els = Roo.Element.selectorFunction(selector, root);
9735 }else if(selector.length !== undefined){
9738 throw "Invalid selector";
9740 if(unique === true){
9741 return new Roo.CompositeElement(els);
9743 return new Roo.CompositeElementLite(els);
9747 * Selects elements based on the passed CSS selector to enable working on them as 1.
9748 * @param {String/Array} selector The CSS selector or an array of elements
9749 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9750 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9751 * @return {CompositeElementLite/CompositeElement}
9755 Roo.select = Roo.Element.select;
9772 * Ext JS Library 1.1.1
9773 * Copyright(c) 2006-2007, Ext JS, LLC.
9775 * Originally Released Under LGPL - original licence link has changed is not relivant.
9778 * <script type="text/javascript">
9783 //Notifies Element that fx methods are available
9784 Roo.enableFx = true;
9788 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9789 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9790 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9791 * Element effects to work.</p><br/>
9793 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9794 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9795 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9796 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9797 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9798 * expected results and should be done with care.</p><br/>
9800 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9801 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9804 ----- -----------------------------
9805 tl The top left corner
9806 t The center of the top edge
9807 tr The top right corner
9808 l The center of the left edge
9809 r The center of the right edge
9810 bl The bottom left corner
9811 b The center of the bottom edge
9812 br The bottom right corner
9814 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9815 * below are common options that can be passed to any Fx method.</b>
9816 * @cfg {Function} callback A function called when the effect is finished
9817 * @cfg {Object} scope The scope of the effect function
9818 * @cfg {String} easing A valid Easing value for the effect
9819 * @cfg {String} afterCls A css class to apply after the effect
9820 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9821 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9822 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9823 * effects that end with the element being visually hidden, ignored otherwise)
9824 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9825 * a function which returns such a specification that will be applied to the Element after the effect finishes
9826 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9827 * @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
9828 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9832 * Slides the element into view. An anchor point can be optionally passed to set the point of
9833 * origin for the slide effect. This function automatically handles wrapping the element with
9834 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9837 // default: slide the element in from the top
9840 // custom: slide the element in from the right with a 2-second duration
9841 el.slideIn('r', { duration: 2 });
9843 // common config options shown with default values
9849 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9850 * @param {Object} options (optional) Object literal with any of the Fx config options
9851 * @return {Roo.Element} The Element
9853 slideIn : function(anchor, o){
9854 var el = this.getFxEl();
9857 el.queueFx(o, function(){
9859 anchor = anchor || "t";
9861 // fix display to visibility
9864 // restore values after effect
9865 var r = this.getFxRestore();
9866 var b = this.getBox();
9867 // fixed size for slide
9871 var wrap = this.fxWrap(r.pos, o, "hidden");
9873 var st = this.dom.style;
9874 st.visibility = "visible";
9875 st.position = "absolute";
9877 // clear out temp styles after slide and unwrap
9878 var after = function(){
9879 el.fxUnwrap(wrap, r.pos, o);
9881 st.height = r.height;
9884 // time to calc the positions
9885 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9887 switch(anchor.toLowerCase()){
9889 wrap.setSize(b.width, 0);
9890 st.left = st.bottom = "0";
9894 wrap.setSize(0, b.height);
9895 st.right = st.top = "0";
9899 wrap.setSize(0, b.height);
9901 st.left = st.top = "0";
9902 a = {width: bw, points: pt};
9905 wrap.setSize(b.width, 0);
9906 wrap.setY(b.bottom);
9907 st.left = st.top = "0";
9908 a = {height: bh, points: pt};
9912 st.right = st.bottom = "0";
9913 a = {width: bw, height: bh};
9917 wrap.setY(b.y+b.height);
9918 st.right = st.top = "0";
9919 a = {width: bw, height: bh, points: pt};
9923 wrap.setXY([b.right, b.bottom]);
9924 st.left = st.top = "0";
9925 a = {width: bw, height: bh, points: pt};
9929 wrap.setX(b.x+b.width);
9930 st.left = st.bottom = "0";
9931 a = {width: bw, height: bh, points: pt};
9934 this.dom.style.visibility = "visible";
9937 arguments.callee.anim = wrap.fxanim(a,
9947 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9948 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9949 * 'hidden') but block elements will still take up space in the document. The element must be removed
9950 * from the DOM using the 'remove' config option if desired. This function automatically handles
9951 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9954 // default: slide the element out to the top
9957 // custom: slide the element out to the right with a 2-second duration
9958 el.slideOut('r', { duration: 2 });
9960 // common config options shown with default values
9968 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9969 * @param {Object} options (optional) Object literal with any of the Fx config options
9970 * @return {Roo.Element} The Element
9972 slideOut : function(anchor, o){
9973 var el = this.getFxEl();
9976 el.queueFx(o, function(){
9978 anchor = anchor || "t";
9980 // restore values after effect
9981 var r = this.getFxRestore();
9983 var b = this.getBox();
9984 // fixed size for slide
9988 var wrap = this.fxWrap(r.pos, o, "visible");
9990 var st = this.dom.style;
9991 st.visibility = "visible";
9992 st.position = "absolute";
9996 var after = function(){
9998 el.setDisplayed(false);
10003 el.fxUnwrap(wrap, r.pos, o);
10005 st.width = r.width;
10006 st.height = r.height;
10011 var a, zero = {to: 0};
10012 switch(anchor.toLowerCase()){
10014 st.left = st.bottom = "0";
10015 a = {height: zero};
10018 st.right = st.top = "0";
10022 st.left = st.top = "0";
10023 a = {width: zero, points: {to:[b.right, b.y]}};
10026 st.left = st.top = "0";
10027 a = {height: zero, points: {to:[b.x, b.bottom]}};
10030 st.right = st.bottom = "0";
10031 a = {width: zero, height: zero};
10034 st.right = st.top = "0";
10035 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10038 st.left = st.top = "0";
10039 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10042 st.left = st.bottom = "0";
10043 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10047 arguments.callee.anim = wrap.fxanim(a,
10057 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10058 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10059 * The element must be removed from the DOM using the 'remove' config option if desired.
10065 // common config options shown with default values
10073 * @param {Object} options (optional) Object literal with any of the Fx config options
10074 * @return {Roo.Element} The Element
10076 puff : function(o){
10077 var el = this.getFxEl();
10080 el.queueFx(o, function(){
10081 this.clearOpacity();
10084 // restore values after effect
10085 var r = this.getFxRestore();
10086 var st = this.dom.style;
10088 var after = function(){
10090 el.setDisplayed(false);
10097 el.setPositioning(r.pos);
10098 st.width = r.width;
10099 st.height = r.height;
10104 var width = this.getWidth();
10105 var height = this.getHeight();
10107 arguments.callee.anim = this.fxanim({
10108 width : {to: this.adjustWidth(width * 2)},
10109 height : {to: this.adjustHeight(height * 2)},
10110 points : {by: [-(width * .5), -(height * .5)]},
10112 fontSize: {to:200, unit: "%"}
10123 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10124 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10125 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10131 // all config options shown with default values
10139 * @param {Object} options (optional) Object literal with any of the Fx config options
10140 * @return {Roo.Element} The Element
10142 switchOff : function(o){
10143 var el = this.getFxEl();
10146 el.queueFx(o, function(){
10147 this.clearOpacity();
10150 // restore values after effect
10151 var r = this.getFxRestore();
10152 var st = this.dom.style;
10154 var after = function(){
10156 el.setDisplayed(false);
10162 el.setPositioning(r.pos);
10163 st.width = r.width;
10164 st.height = r.height;
10169 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10170 this.clearOpacity();
10174 points:{by:[0, this.getHeight() * .5]}
10175 }, o, 'motion', 0.3, 'easeIn', after);
10176 }).defer(100, this);
10183 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10184 * changed using the "attr" config option) and then fading back to the original color. If no original
10185 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10188 // default: highlight background to yellow
10191 // custom: highlight foreground text to blue for 2 seconds
10192 el.highlight("0000ff", { attr: 'color', duration: 2 });
10194 // common config options shown with default values
10195 el.highlight("ffff9c", {
10196 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10197 endColor: (current color) or "ffffff",
10202 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10203 * @param {Object} options (optional) Object literal with any of the Fx config options
10204 * @return {Roo.Element} The Element
10206 highlight : function(color, o){
10207 var el = this.getFxEl();
10210 el.queueFx(o, function(){
10211 color = color || "ffff9c";
10212 attr = o.attr || "backgroundColor";
10214 this.clearOpacity();
10217 var origColor = this.getColor(attr);
10218 var restoreColor = this.dom.style[attr];
10219 endColor = (o.endColor || origColor) || "ffffff";
10221 var after = function(){
10222 el.dom.style[attr] = restoreColor;
10227 a[attr] = {from: color, to: endColor};
10228 arguments.callee.anim = this.fxanim(a,
10238 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10241 // default: a single light blue ripple
10244 // custom: 3 red ripples lasting 3 seconds total
10245 el.frame("ff0000", 3, { duration: 3 });
10247 // common config options shown with default values
10248 el.frame("C3DAF9", 1, {
10249 duration: 1 //duration of entire animation (not each individual ripple)
10250 // Note: Easing is not configurable and will be ignored if included
10253 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10254 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10255 * @param {Object} options (optional) Object literal with any of the Fx config options
10256 * @return {Roo.Element} The Element
10258 frame : function(color, count, o){
10259 var el = this.getFxEl();
10262 el.queueFx(o, function(){
10263 color = color || "#C3DAF9";
10264 if(color.length == 6){
10265 color = "#" + color;
10267 count = count || 1;
10268 duration = o.duration || 1;
10271 var b = this.getBox();
10272 var animFn = function(){
10273 var proxy = this.createProxy({
10276 visbility:"hidden",
10277 position:"absolute",
10278 "z-index":"35000", // yee haw
10279 border:"0px solid " + color
10282 var scale = Roo.isBorderBox ? 2 : 1;
10284 top:{from:b.y, to:b.y - 20},
10285 left:{from:b.x, to:b.x - 20},
10286 borderWidth:{from:0, to:10},
10287 opacity:{from:1, to:0},
10288 height:{from:b.height, to:(b.height + (20*scale))},
10289 width:{from:b.width, to:(b.width + (20*scale))}
10290 }, duration, function(){
10294 animFn.defer((duration/2)*1000, this);
10305 * Creates a pause before any subsequent queued effects begin. If there are
10306 * no effects queued after the pause it will have no effect.
10311 * @param {Number} seconds The length of time to pause (in seconds)
10312 * @return {Roo.Element} The Element
10314 pause : function(seconds){
10315 var el = this.getFxEl();
10318 el.queueFx(o, function(){
10319 setTimeout(function(){
10321 }, seconds * 1000);
10327 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10328 * using the "endOpacity" config option.
10331 // default: fade in from opacity 0 to 100%
10334 // custom: fade in from opacity 0 to 75% over 2 seconds
10335 el.fadeIn({ endOpacity: .75, duration: 2});
10337 // common config options shown with default values
10339 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10344 * @param {Object} options (optional) Object literal with any of the Fx config options
10345 * @return {Roo.Element} The Element
10347 fadeIn : function(o){
10348 var el = this.getFxEl();
10350 el.queueFx(o, function(){
10351 this.setOpacity(0);
10353 this.dom.style.visibility = 'visible';
10354 var to = o.endOpacity || 1;
10355 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10356 o, null, .5, "easeOut", function(){
10358 this.clearOpacity();
10367 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10368 * using the "endOpacity" config option.
10371 // default: fade out from the element's current opacity to 0
10374 // custom: fade out from the element's current opacity to 25% over 2 seconds
10375 el.fadeOut({ endOpacity: .25, duration: 2});
10377 // common config options shown with default values
10379 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10386 * @param {Object} options (optional) Object literal with any of the Fx config options
10387 * @return {Roo.Element} The Element
10389 fadeOut : function(o){
10390 var el = this.getFxEl();
10392 el.queueFx(o, function(){
10393 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10394 o, null, .5, "easeOut", function(){
10395 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10396 this.dom.style.display = "none";
10398 this.dom.style.visibility = "hidden";
10400 this.clearOpacity();
10408 * Animates the transition of an element's dimensions from a starting height/width
10409 * to an ending height/width.
10412 // change height and width to 100x100 pixels
10413 el.scale(100, 100);
10415 // common config options shown with default values. The height and width will default to
10416 // the element's existing values if passed as null.
10419 [element's height], {
10424 * @param {Number} width The new width (pass undefined to keep the original width)
10425 * @param {Number} height The new height (pass undefined to keep the original height)
10426 * @param {Object} options (optional) Object literal with any of the Fx config options
10427 * @return {Roo.Element} The Element
10429 scale : function(w, h, o){
10430 this.shift(Roo.apply({}, o, {
10438 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10439 * Any of these properties not specified in the config object will not be changed. This effect
10440 * requires that at least one new dimension, position or opacity setting must be passed in on
10441 * the config object in order for the function to have any effect.
10444 // slide the element horizontally to x position 200 while changing the height and opacity
10445 el.shift({ x: 200, height: 50, opacity: .8 });
10447 // common config options shown with default values.
10449 width: [element's width],
10450 height: [element's height],
10451 x: [element's x position],
10452 y: [element's y position],
10453 opacity: [element's opacity],
10458 * @param {Object} options Object literal with any of the Fx config options
10459 * @return {Roo.Element} The Element
10461 shift : function(o){
10462 var el = this.getFxEl();
10464 el.queueFx(o, function(){
10465 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10466 if(w !== undefined){
10467 a.width = {to: this.adjustWidth(w)};
10469 if(h !== undefined){
10470 a.height = {to: this.adjustHeight(h)};
10472 if(x !== undefined || y !== undefined){
10474 x !== undefined ? x : this.getX(),
10475 y !== undefined ? y : this.getY()
10478 if(op !== undefined){
10479 a.opacity = {to: op};
10481 if(o.xy !== undefined){
10482 a.points = {to: o.xy};
10484 arguments.callee.anim = this.fxanim(a,
10485 o, 'motion', .35, "easeOut", function(){
10493 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10494 * ending point of the effect.
10497 // default: slide the element downward while fading out
10500 // custom: slide the element out to the right with a 2-second duration
10501 el.ghost('r', { duration: 2 });
10503 // common config options shown with default values
10511 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10512 * @param {Object} options (optional) Object literal with any of the Fx config options
10513 * @return {Roo.Element} The Element
10515 ghost : function(anchor, o){
10516 var el = this.getFxEl();
10519 el.queueFx(o, function(){
10520 anchor = anchor || "b";
10522 // restore values after effect
10523 var r = this.getFxRestore();
10524 var w = this.getWidth(),
10525 h = this.getHeight();
10527 var st = this.dom.style;
10529 var after = function(){
10531 el.setDisplayed(false);
10537 el.setPositioning(r.pos);
10538 st.width = r.width;
10539 st.height = r.height;
10544 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10545 switch(anchor.toLowerCase()){
10572 arguments.callee.anim = this.fxanim(a,
10582 * Ensures that all effects queued after syncFx is called on the element are
10583 * run concurrently. This is the opposite of {@link #sequenceFx}.
10584 * @return {Roo.Element} The Element
10586 syncFx : function(){
10587 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10596 * Ensures that all effects queued after sequenceFx is called on the element are
10597 * run in sequence. This is the opposite of {@link #syncFx}.
10598 * @return {Roo.Element} The Element
10600 sequenceFx : function(){
10601 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10603 concurrent : false,
10610 nextFx : function(){
10611 var ef = this.fxQueue[0];
10618 * Returns true if the element has any effects actively running or queued, else returns false.
10619 * @return {Boolean} True if element has active effects, else false
10621 hasActiveFx : function(){
10622 return this.fxQueue && this.fxQueue[0];
10626 * Stops any running effects and clears the element's internal effects queue if it contains
10627 * any additional effects that haven't started yet.
10628 * @return {Roo.Element} The Element
10630 stopFx : function(){
10631 if(this.hasActiveFx()){
10632 var cur = this.fxQueue[0];
10633 if(cur && cur.anim && cur.anim.isAnimated()){
10634 this.fxQueue = [cur]; // clear out others
10635 cur.anim.stop(true);
10642 beforeFx : function(o){
10643 if(this.hasActiveFx() && !o.concurrent){
10654 * Returns true if the element is currently blocking so that no other effect can be queued
10655 * until this effect is finished, else returns false if blocking is not set. This is commonly
10656 * used to ensure that an effect initiated by a user action runs to completion prior to the
10657 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10658 * @return {Boolean} True if blocking, else false
10660 hasFxBlock : function(){
10661 var q = this.fxQueue;
10662 return q && q[0] && q[0].block;
10666 queueFx : function(o, fn){
10670 if(!this.hasFxBlock()){
10671 Roo.applyIf(o, this.fxDefaults);
10673 var run = this.beforeFx(o);
10674 fn.block = o.block;
10675 this.fxQueue.push(fn);
10687 fxWrap : function(pos, o, vis){
10689 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10692 wrapXY = this.getXY();
10694 var div = document.createElement("div");
10695 div.style.visibility = vis;
10696 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10697 wrap.setPositioning(pos);
10698 if(wrap.getStyle("position") == "static"){
10699 wrap.position("relative");
10701 this.clearPositioning('auto');
10703 wrap.dom.appendChild(this.dom);
10705 wrap.setXY(wrapXY);
10712 fxUnwrap : function(wrap, pos, o){
10713 this.clearPositioning();
10714 this.setPositioning(pos);
10716 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10722 getFxRestore : function(){
10723 var st = this.dom.style;
10724 return {pos: this.getPositioning(), width: st.width, height : st.height};
10728 afterFx : function(o){
10730 this.applyStyles(o.afterStyle);
10733 this.addClass(o.afterCls);
10735 if(o.remove === true){
10738 Roo.callback(o.callback, o.scope, [this]);
10740 this.fxQueue.shift();
10746 getFxEl : function(){ // support for composite element fx
10747 return Roo.get(this.dom);
10751 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10752 animType = animType || 'run';
10754 var anim = Roo.lib.Anim[animType](
10756 (opt.duration || defaultDur) || .35,
10757 (opt.easing || defaultEase) || 'easeOut',
10759 Roo.callback(cb, this);
10768 // backwords compat
10769 Roo.Fx.resize = Roo.Fx.scale;
10771 //When included, Roo.Fx is automatically applied to Element so that all basic
10772 //effects are available directly via the Element API
10773 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10775 * Ext JS Library 1.1.1
10776 * Copyright(c) 2006-2007, Ext JS, LLC.
10778 * Originally Released Under LGPL - original licence link has changed is not relivant.
10781 * <script type="text/javascript">
10786 * @class Roo.CompositeElement
10787 * Standard composite class. Creates a Roo.Element for every element in the collection.
10789 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10790 * actions will be performed on all the elements in this collection.</b>
10792 * All methods return <i>this</i> and can be chained.
10794 var els = Roo.select("#some-el div.some-class", true);
10795 // or select directly from an existing element
10796 var el = Roo.get('some-el');
10797 el.select('div.some-class', true);
10799 els.setWidth(100); // all elements become 100 width
10800 els.hide(true); // all elements fade out and hide
10802 els.setWidth(100).hide(true);
10805 Roo.CompositeElement = function(els){
10806 this.elements = [];
10807 this.addElements(els);
10809 Roo.CompositeElement.prototype = {
10811 addElements : function(els){
10812 if(!els) return this;
10813 if(typeof els == "string"){
10814 els = Roo.Element.selectorFunction(els);
10816 var yels = this.elements;
10817 var index = yels.length-1;
10818 for(var i = 0, len = els.length; i < len; i++) {
10819 yels[++index] = Roo.get(els[i]);
10825 * Clears this composite and adds the elements returned by the passed selector.
10826 * @param {String/Array} els A string CSS selector, an array of elements or an element
10827 * @return {CompositeElement} this
10829 fill : function(els){
10830 this.elements = [];
10836 * Filters this composite to only elements that match the passed selector.
10837 * @param {String} selector A string CSS selector
10838 * @return {CompositeElement} this
10840 filter : function(selector){
10842 this.each(function(el){
10843 if(el.is(selector)){
10844 els[els.length] = el.dom;
10851 invoke : function(fn, args){
10852 var els = this.elements;
10853 for(var i = 0, len = els.length; i < len; i++) {
10854 Roo.Element.prototype[fn].apply(els[i], args);
10859 * Adds elements to this composite.
10860 * @param {String/Array} els A string CSS selector, an array of elements or an element
10861 * @return {CompositeElement} this
10863 add : function(els){
10864 if(typeof els == "string"){
10865 this.addElements(Roo.Element.selectorFunction(els));
10866 }else if(els.length !== undefined){
10867 this.addElements(els);
10869 this.addElements([els]);
10874 * Calls the passed function passing (el, this, index) for each element in this composite.
10875 * @param {Function} fn The function to call
10876 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10877 * @return {CompositeElement} this
10879 each : function(fn, scope){
10880 var els = this.elements;
10881 for(var i = 0, len = els.length; i < len; i++){
10882 if(fn.call(scope || els[i], els[i], this, i) === false) {
10890 * Returns the Element object at the specified index
10891 * @param {Number} index
10892 * @return {Roo.Element}
10894 item : function(index){
10895 return this.elements[index] || null;
10899 * Returns the first Element
10900 * @return {Roo.Element}
10902 first : function(){
10903 return this.item(0);
10907 * Returns the last Element
10908 * @return {Roo.Element}
10911 return this.item(this.elements.length-1);
10915 * Returns the number of elements in this composite
10918 getCount : function(){
10919 return this.elements.length;
10923 * Returns true if this composite contains the passed element
10926 contains : function(el){
10927 return this.indexOf(el) !== -1;
10931 * Returns true if this composite contains the passed element
10934 indexOf : function(el){
10935 return this.elements.indexOf(Roo.get(el));
10940 * Removes the specified element(s).
10941 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10942 * or an array of any of those.
10943 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10944 * @return {CompositeElement} this
10946 removeElement : function(el, removeDom){
10947 if(el instanceof Array){
10948 for(var i = 0, len = el.length; i < len; i++){
10949 this.removeElement(el[i]);
10953 var index = typeof el == 'number' ? el : this.indexOf(el);
10956 var d = this.elements[index];
10960 d.parentNode.removeChild(d);
10963 this.elements.splice(index, 1);
10969 * Replaces the specified element with the passed element.
10970 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10972 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10973 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10974 * @return {CompositeElement} this
10976 replaceElement : function(el, replacement, domReplace){
10977 var index = typeof el == 'number' ? el : this.indexOf(el);
10980 this.elements[index].replaceWith(replacement);
10982 this.elements.splice(index, 1, Roo.get(replacement))
10989 * Removes all elements.
10991 clear : function(){
10992 this.elements = [];
10996 Roo.CompositeElement.createCall = function(proto, fnName){
10997 if(!proto[fnName]){
10998 proto[fnName] = function(){
10999 return this.invoke(fnName, arguments);
11003 for(var fnName in Roo.Element.prototype){
11004 if(typeof Roo.Element.prototype[fnName] == "function"){
11005 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11011 * Ext JS Library 1.1.1
11012 * Copyright(c) 2006-2007, Ext JS, LLC.
11014 * Originally Released Under LGPL - original licence link has changed is not relivant.
11017 * <script type="text/javascript">
11021 * @class Roo.CompositeElementLite
11022 * @extends Roo.CompositeElement
11023 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11025 var els = Roo.select("#some-el div.some-class");
11026 // or select directly from an existing element
11027 var el = Roo.get('some-el');
11028 el.select('div.some-class');
11030 els.setWidth(100); // all elements become 100 width
11031 els.hide(true); // all elements fade out and hide
11033 els.setWidth(100).hide(true);
11034 </code></pre><br><br>
11035 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11036 * actions will be performed on all the elements in this collection.</b>
11038 Roo.CompositeElementLite = function(els){
11039 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11040 this.el = new Roo.Element.Flyweight();
11042 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11043 addElements : function(els){
11045 if(els instanceof Array){
11046 this.elements = this.elements.concat(els);
11048 var yels = this.elements;
11049 var index = yels.length-1;
11050 for(var i = 0, len = els.length; i < len; i++) {
11051 yels[++index] = els[i];
11057 invoke : function(fn, args){
11058 var els = this.elements;
11060 for(var i = 0, len = els.length; i < len; i++) {
11062 Roo.Element.prototype[fn].apply(el, args);
11067 * Returns a flyweight Element of the dom element object at the specified index
11068 * @param {Number} index
11069 * @return {Roo.Element}
11071 item : function(index){
11072 if(!this.elements[index]){
11075 this.el.dom = this.elements[index];
11079 // fixes scope with flyweight
11080 addListener : function(eventName, handler, scope, opt){
11081 var els = this.elements;
11082 for(var i = 0, len = els.length; i < len; i++) {
11083 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11089 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11090 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11091 * a reference to the dom node, use el.dom.</b>
11092 * @param {Function} fn The function to call
11093 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11094 * @return {CompositeElement} this
11096 each : function(fn, scope){
11097 var els = this.elements;
11099 for(var i = 0, len = els.length; i < len; i++){
11101 if(fn.call(scope || el, el, this, i) === false){
11108 indexOf : function(el){
11109 return this.elements.indexOf(Roo.getDom(el));
11112 replaceElement : function(el, replacement, domReplace){
11113 var index = typeof el == 'number' ? el : this.indexOf(el);
11115 replacement = Roo.getDom(replacement);
11117 var d = this.elements[index];
11118 d.parentNode.insertBefore(replacement, d);
11119 d.parentNode.removeChild(d);
11121 this.elements.splice(index, 1, replacement);
11126 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11130 * Ext JS Library 1.1.1
11131 * Copyright(c) 2006-2007, Ext JS, LLC.
11133 * Originally Released Under LGPL - original licence link has changed is not relivant.
11136 * <script type="text/javascript">
11142 * @class Roo.data.Connection
11143 * @extends Roo.util.Observable
11144 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11145 * either to a configured URL, or to a URL specified at request time.<br><br>
11147 * Requests made by this class are asynchronous, and will return immediately. No data from
11148 * the server will be available to the statement immediately following the {@link #request} call.
11149 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11151 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11152 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11153 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11154 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11155 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11156 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11157 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11158 * standard DOM methods.
11160 * @param {Object} config a configuration object.
11162 Roo.data.Connection = function(config){
11163 Roo.apply(this, config);
11166 * @event beforerequest
11167 * Fires before a network request is made to retrieve a data object.
11168 * @param {Connection} conn This Connection object.
11169 * @param {Object} options The options config object passed to the {@link #request} method.
11171 "beforerequest" : true,
11173 * @event requestcomplete
11174 * Fires if the request was successfully completed.
11175 * @param {Connection} conn This Connection object.
11176 * @param {Object} response The XHR object containing the response data.
11177 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11178 * @param {Object} options The options config object passed to the {@link #request} method.
11180 "requestcomplete" : true,
11182 * @event requestexception
11183 * Fires if an error HTTP status was returned from the server.
11184 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11185 * @param {Connection} conn This Connection object.
11186 * @param {Object} response The XHR object containing the response data.
11187 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11188 * @param {Object} options The options config object passed to the {@link #request} method.
11190 "requestexception" : true
11192 Roo.data.Connection.superclass.constructor.call(this);
11195 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11197 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11200 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11201 * extra parameters to each request made by this object. (defaults to undefined)
11204 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11205 * to each request made by this object. (defaults to undefined)
11208 * @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)
11211 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11215 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11221 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11224 disableCaching: true,
11227 * Sends an HTTP request to a remote server.
11228 * @param {Object} options An object which may contain the following properties:<ul>
11229 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11230 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11231 * request, a url encoded string or a function to call to get either.</li>
11232 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11233 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11234 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11235 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11236 * <li>options {Object} The parameter to the request call.</li>
11237 * <li>success {Boolean} True if the request succeeded.</li>
11238 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11240 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11241 * The callback is passed the following parameters:<ul>
11242 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11243 * <li>options {Object} The parameter to the request call.</li>
11245 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11246 * The callback is passed the following parameters:<ul>
11247 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11248 * <li>options {Object} The parameter to the request call.</li>
11250 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11251 * for the callback function. Defaults to the browser window.</li>
11252 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11253 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11254 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11255 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11256 * params for the post data. Any params will be appended to the URL.</li>
11257 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11259 * @return {Number} transactionId
11261 request : function(o){
11262 if(this.fireEvent("beforerequest", this, o) !== false){
11265 if(typeof p == "function"){
11266 p = p.call(o.scope||window, o);
11268 if(typeof p == "object"){
11269 p = Roo.urlEncode(o.params);
11271 if(this.extraParams){
11272 var extras = Roo.urlEncode(this.extraParams);
11273 p = p ? (p + '&' + extras) : extras;
11276 var url = o.url || this.url;
11277 if(typeof url == 'function'){
11278 url = url.call(o.scope||window, o);
11282 var form = Roo.getDom(o.form);
11283 url = url || form.action;
11285 var enctype = form.getAttribute("enctype");
11286 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11287 return this.doFormUpload(o, p, url);
11289 var f = Roo.lib.Ajax.serializeForm(form);
11290 p = p ? (p + '&' + f) : f;
11293 var hs = o.headers;
11294 if(this.defaultHeaders){
11295 hs = Roo.apply(hs || {}, this.defaultHeaders);
11302 success: this.handleResponse,
11303 failure: this.handleFailure,
11305 argument: {options: o},
11306 timeout : this.timeout
11309 var method = o.method||this.method||(p ? "POST" : "GET");
11311 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11312 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11315 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11319 }else if(this.autoAbort !== false){
11323 if((method == 'GET' && p) || o.xmlData){
11324 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11327 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11328 return this.transId;
11330 Roo.callback(o.callback, o.scope, [o, null, null]);
11336 * Determine whether this object has a request outstanding.
11337 * @param {Number} transactionId (Optional) defaults to the last transaction
11338 * @return {Boolean} True if there is an outstanding request.
11340 isLoading : function(transId){
11342 return Roo.lib.Ajax.isCallInProgress(transId);
11344 return this.transId ? true : false;
11349 * Aborts any outstanding request.
11350 * @param {Number} transactionId (Optional) defaults to the last transaction
11352 abort : function(transId){
11353 if(transId || this.isLoading()){
11354 Roo.lib.Ajax.abort(transId || this.transId);
11359 handleResponse : function(response){
11360 this.transId = false;
11361 var options = response.argument.options;
11362 response.argument = options ? options.argument : null;
11363 this.fireEvent("requestcomplete", this, response, options);
11364 Roo.callback(options.success, options.scope, [response, options]);
11365 Roo.callback(options.callback, options.scope, [options, true, response]);
11369 handleFailure : function(response, e){
11370 this.transId = false;
11371 var options = response.argument.options;
11372 response.argument = options ? options.argument : null;
11373 this.fireEvent("requestexception", this, response, options, e);
11374 Roo.callback(options.failure, options.scope, [response, options]);
11375 Roo.callback(options.callback, options.scope, [options, false, response]);
11379 doFormUpload : function(o, ps, url){
11381 var frame = document.createElement('iframe');
11384 frame.className = 'x-hidden';
11386 frame.src = Roo.SSL_SECURE_URL;
11388 document.body.appendChild(frame);
11391 document.frames[id].name = id;
11394 var form = Roo.getDom(o.form);
11396 form.method = 'POST';
11397 form.enctype = form.encoding = 'multipart/form-data';
11403 if(ps){ // add dynamic params
11405 ps = Roo.urlDecode(ps, false);
11407 if(ps.hasOwnProperty(k)){
11408 hd = document.createElement('input');
11409 hd.type = 'hidden';
11412 form.appendChild(hd);
11419 var r = { // bogus response object
11424 r.argument = o ? o.argument : null;
11429 doc = frame.contentWindow.document;
11431 doc = (frame.contentDocument || window.frames[id].document);
11433 if(doc && doc.body){
11434 r.responseText = doc.body.innerHTML;
11436 if(doc && doc.XMLDocument){
11437 r.responseXML = doc.XMLDocument;
11439 r.responseXML = doc;
11446 Roo.EventManager.removeListener(frame, 'load', cb, this);
11448 this.fireEvent("requestcomplete", this, r, o);
11449 Roo.callback(o.success, o.scope, [r, o]);
11450 Roo.callback(o.callback, o.scope, [o, true, r]);
11452 setTimeout(function(){document.body.removeChild(frame);}, 100);
11455 Roo.EventManager.on(frame, 'load', cb, this);
11458 if(hiddens){ // remove dynamic params
11459 for(var i = 0, len = hiddens.length; i < len; i++){
11460 form.removeChild(hiddens[i]);
11468 * @extends Roo.data.Connection
11469 * Global Ajax request class.
11473 Roo.Ajax = new Roo.data.Connection({
11476 * @cfg {String} url @hide
11479 * @cfg {Object} extraParams @hide
11482 * @cfg {Object} defaultHeaders @hide
11485 * @cfg {String} method (Optional) @hide
11488 * @cfg {Number} timeout (Optional) @hide
11491 * @cfg {Boolean} autoAbort (Optional) @hide
11495 * @cfg {Boolean} disableCaching (Optional) @hide
11499 * @property disableCaching
11500 * True to add a unique cache-buster param to GET requests. (defaults to true)
11505 * The default URL to be used for requests to the server. (defaults to undefined)
11509 * @property extraParams
11510 * An object containing properties which are used as
11511 * extra parameters to each request made by this object. (defaults to undefined)
11515 * @property defaultHeaders
11516 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11521 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11525 * @property timeout
11526 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11531 * @property autoAbort
11532 * Whether a new request should abort any pending requests. (defaults to false)
11538 * Serialize the passed form into a url encoded string
11539 * @param {String/HTMLElement} form
11542 serializeForm : function(form){
11543 return Roo.lib.Ajax.serializeForm(form);
11547 * Ext JS Library 1.1.1
11548 * Copyright(c) 2006-2007, Ext JS, LLC.
11550 * Originally Released Under LGPL - original licence link has changed is not relivant.
11553 * <script type="text/javascript">
11557 * Global Ajax request class.
11559 * @extends Roo.data.Connection
11560 * @instanceOf Roo.data.Connection
11562 Roo.Ajax = new Roo.data.Connection({
11571 * @cfg {String} url @hide
11574 * @cfg {Object} extraParams @hide
11577 * @cfg {Object} defaultHeaders @hide
11580 * @cfg {String} method (Optional) @hide
11583 * @cfg {Number} timeout (Optional) @hide
11586 * @cfg {Boolean} autoAbort (Optional) @hide
11590 * @cfg {Boolean} disableCaching (Optional) @hide
11594 * @property disableCaching
11595 * True to add a unique cache-buster param to GET requests. (defaults to true)
11600 * The default URL to be used for requests to the server. (defaults to undefined)
11604 * @property extraParams
11605 * An object containing properties which are used as
11606 * extra parameters to each request made by this object. (defaults to undefined)
11610 * @property defaultHeaders
11611 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11616 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11620 * @property timeout
11621 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11626 * @property autoAbort
11627 * Whether a new request should abort any pending requests. (defaults to false)
11633 * Serialize the passed form into a url encoded string
11634 * @param {String/HTMLElement} form
11637 serializeForm : function(form){
11638 return Roo.lib.Ajax.serializeForm(form);
11642 * Ext JS Library 1.1.1
11643 * Copyright(c) 2006-2007, Ext JS, LLC.
11645 * Originally Released Under LGPL - original licence link has changed is not relivant.
11648 * <script type="text/javascript">
11653 * @class Roo.UpdateManager
11654 * @extends Roo.util.Observable
11655 * Provides AJAX-style update for Element object.<br><br>
11658 * // Get it from a Roo.Element object
11659 * var el = Roo.get("foo");
11660 * var mgr = el.getUpdateManager();
11661 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11663 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11665 * // or directly (returns the same UpdateManager instance)
11666 * var mgr = new Roo.UpdateManager("myElementId");
11667 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11668 * mgr.on("update", myFcnNeedsToKnow);
11670 // short handed call directly from the element object
11671 Roo.get("foo").load({
11675 text: "Loading Foo..."
11679 * Create new UpdateManager directly.
11680 * @param {String/HTMLElement/Roo.Element} el The element to update
11681 * @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).
11683 Roo.UpdateManager = function(el, forceNew){
11685 if(!forceNew && el.updateManager){
11686 return el.updateManager;
11689 * The Element object
11690 * @type Roo.Element
11694 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11697 this.defaultUrl = null;
11701 * @event beforeupdate
11702 * Fired before an update is made, return false from your handler and the update is cancelled.
11703 * @param {Roo.Element} el
11704 * @param {String/Object/Function} url
11705 * @param {String/Object} params
11707 "beforeupdate": true,
11710 * Fired after successful update is made.
11711 * @param {Roo.Element} el
11712 * @param {Object} oResponseObject The response Object
11717 * Fired on update failure.
11718 * @param {Roo.Element} el
11719 * @param {Object} oResponseObject The response Object
11723 var d = Roo.UpdateManager.defaults;
11725 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11728 this.sslBlankUrl = d.sslBlankUrl;
11730 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11733 this.disableCaching = d.disableCaching;
11735 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11738 this.indicatorText = d.indicatorText;
11740 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11743 this.showLoadIndicator = d.showLoadIndicator;
11745 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11748 this.timeout = d.timeout;
11751 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11754 this.loadScripts = d.loadScripts;
11757 * Transaction object of current executing transaction
11759 this.transaction = null;
11764 this.autoRefreshProcId = null;
11766 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11769 this.refreshDelegate = this.refresh.createDelegate(this);
11771 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11774 this.updateDelegate = this.update.createDelegate(this);
11776 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11779 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11783 this.successDelegate = this.processSuccess.createDelegate(this);
11787 this.failureDelegate = this.processFailure.createDelegate(this);
11789 if(!this.renderer){
11791 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11793 this.renderer = new Roo.UpdateManager.BasicRenderer();
11796 Roo.UpdateManager.superclass.constructor.call(this);
11799 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11801 * Get the Element this UpdateManager is bound to
11802 * @return {Roo.Element} The element
11804 getEl : function(){
11808 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11809 * @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:
11812 url: "your-url.php",<br/>
11813 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11814 callback: yourFunction,<br/>
11815 scope: yourObject, //(optional scope) <br/>
11816 discardUrl: false, <br/>
11817 nocache: false,<br/>
11818 text: "Loading...",<br/>
11820 scripts: false<br/>
11823 * The only required property is url. The optional properties nocache, text and scripts
11824 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11825 * @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}
11826 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11827 * @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.
11829 update : function(url, params, callback, discardUrl){
11830 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11831 var method = this.method, cfg;
11832 if(typeof url == "object"){ // must be config object
11835 params = params || cfg.params;
11836 callback = callback || cfg.callback;
11837 discardUrl = discardUrl || cfg.discardUrl;
11838 if(callback && cfg.scope){
11839 callback = callback.createDelegate(cfg.scope);
11841 if(typeof cfg.method != "undefined"){method = cfg.method;};
11842 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11843 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11844 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11845 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11847 this.showLoading();
11849 this.defaultUrl = url;
11851 if(typeof url == "function"){
11852 url = url.call(this);
11855 method = method || (params ? "POST" : "GET");
11856 if(method == "GET"){
11857 url = this.prepareUrl(url);
11860 var o = Roo.apply(cfg ||{}, {
11863 success: this.successDelegate,
11864 failure: this.failureDelegate,
11865 callback: undefined,
11866 timeout: (this.timeout*1000),
11867 argument: {"url": url, "form": null, "callback": callback, "params": params}
11870 this.transaction = Roo.Ajax.request(o);
11875 * 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.
11876 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11877 * @param {String/HTMLElement} form The form Id or form element
11878 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11879 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11880 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11882 formUpdate : function(form, url, reset, callback){
11883 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11884 if(typeof url == "function"){
11885 url = url.call(this);
11887 form = Roo.getDom(form);
11888 this.transaction = Roo.Ajax.request({
11891 success: this.successDelegate,
11892 failure: this.failureDelegate,
11893 timeout: (this.timeout*1000),
11894 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11896 this.showLoading.defer(1, this);
11901 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11902 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11904 refresh : function(callback){
11905 if(this.defaultUrl == null){
11908 this.update(this.defaultUrl, null, callback, true);
11912 * Set this element to auto refresh.
11913 * @param {Number} interval How often to update (in seconds).
11914 * @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)
11915 * @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}
11916 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11917 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11919 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11921 this.update(url || this.defaultUrl, params, callback, true);
11923 if(this.autoRefreshProcId){
11924 clearInterval(this.autoRefreshProcId);
11926 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11930 * Stop auto refresh on this element.
11932 stopAutoRefresh : function(){
11933 if(this.autoRefreshProcId){
11934 clearInterval(this.autoRefreshProcId);
11935 delete this.autoRefreshProcId;
11939 isAutoRefreshing : function(){
11940 return this.autoRefreshProcId ? true : false;
11943 * Called to update the element to "Loading" state. Override to perform custom action.
11945 showLoading : function(){
11946 if(this.showLoadIndicator){
11947 this.el.update(this.indicatorText);
11952 * Adds unique parameter to query string if disableCaching = true
11955 prepareUrl : function(url){
11956 if(this.disableCaching){
11957 var append = "_dc=" + (new Date().getTime());
11958 if(url.indexOf("?") !== -1){
11959 url += "&" + append;
11961 url += "?" + append;
11970 processSuccess : function(response){
11971 this.transaction = null;
11972 if(response.argument.form && response.argument.reset){
11973 try{ // put in try/catch since some older FF releases had problems with this
11974 response.argument.form.reset();
11977 if(this.loadScripts){
11978 this.renderer.render(this.el, response, this,
11979 this.updateComplete.createDelegate(this, [response]));
11981 this.renderer.render(this.el, response, this);
11982 this.updateComplete(response);
11986 updateComplete : function(response){
11987 this.fireEvent("update", this.el, response);
11988 if(typeof response.argument.callback == "function"){
11989 response.argument.callback(this.el, true, response);
11996 processFailure : function(response){
11997 this.transaction = null;
11998 this.fireEvent("failure", this.el, response);
11999 if(typeof response.argument.callback == "function"){
12000 response.argument.callback(this.el, false, response);
12005 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12006 * @param {Object} renderer The object implementing the render() method
12008 setRenderer : function(renderer){
12009 this.renderer = renderer;
12012 getRenderer : function(){
12013 return this.renderer;
12017 * Set the defaultUrl used for updates
12018 * @param {String/Function} defaultUrl The url or a function to call to get the url
12020 setDefaultUrl : function(defaultUrl){
12021 this.defaultUrl = defaultUrl;
12025 * Aborts the executing transaction
12027 abort : function(){
12028 if(this.transaction){
12029 Roo.Ajax.abort(this.transaction);
12034 * Returns true if an update is in progress
12035 * @return {Boolean}
12037 isUpdating : function(){
12038 if(this.transaction){
12039 return Roo.Ajax.isLoading(this.transaction);
12046 * @class Roo.UpdateManager.defaults
12047 * @static (not really - but it helps the doc tool)
12048 * The defaults collection enables customizing the default properties of UpdateManager
12050 Roo.UpdateManager.defaults = {
12052 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12058 * True to process scripts by default (Defaults to false).
12061 loadScripts : false,
12064 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12067 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12069 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12072 disableCaching : false,
12074 * Whether to show indicatorText when loading (Defaults to true).
12077 showLoadIndicator : true,
12079 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12082 indicatorText : '<div class="loading-indicator">Loading...</div>'
12086 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12088 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12089 * @param {String/HTMLElement/Roo.Element} el The element to update
12090 * @param {String} url The url
12091 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12092 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12095 * @member Roo.UpdateManager
12097 Roo.UpdateManager.updateElement = function(el, url, params, options){
12098 var um = Roo.get(el, true).getUpdateManager();
12099 Roo.apply(um, options);
12100 um.update(url, params, options ? options.callback : null);
12102 // alias for backwards compat
12103 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12105 * @class Roo.UpdateManager.BasicRenderer
12106 * Default Content renderer. Updates the elements innerHTML with the responseText.
12108 Roo.UpdateManager.BasicRenderer = function(){};
12110 Roo.UpdateManager.BasicRenderer.prototype = {
12112 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12113 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12114 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12115 * @param {Roo.Element} el The element being rendered
12116 * @param {Object} response The YUI Connect response object
12117 * @param {UpdateManager} updateManager The calling update manager
12118 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12120 render : function(el, response, updateManager, callback){
12121 el.update(response.responseText, updateManager.loadScripts, callback);
12126 * Ext JS Library 1.1.1
12127 * Copyright(c) 2006-2007, Ext JS, LLC.
12129 * Originally Released Under LGPL - original licence link has changed is not relivant.
12132 * <script type="text/javascript">
12136 * @class Roo.util.DelayedTask
12137 * Provides a convenient method of performing setTimeout where a new
12138 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12139 * You can use this class to buffer
12140 * the keypress events for a certain number of milliseconds, and perform only if they stop
12141 * for that amount of time.
12142 * @constructor The parameters to this constructor serve as defaults and are not required.
12143 * @param {Function} fn (optional) The default function to timeout
12144 * @param {Object} scope (optional) The default scope of that timeout
12145 * @param {Array} args (optional) The default Array of arguments
12147 Roo.util.DelayedTask = function(fn, scope, args){
12148 var id = null, d, t;
12150 var call = function(){
12151 var now = new Date().getTime();
12155 fn.apply(scope, args || []);
12159 * Cancels any pending timeout and queues a new one
12160 * @param {Number} delay The milliseconds to delay
12161 * @param {Function} newFn (optional) Overrides function passed to constructor
12162 * @param {Object} newScope (optional) Overrides scope passed to constructor
12163 * @param {Array} newArgs (optional) Overrides args passed to constructor
12165 this.delay = function(delay, newFn, newScope, newArgs){
12166 if(id && delay != d){
12170 t = new Date().getTime();
12172 scope = newScope || scope;
12173 args = newArgs || args;
12175 id = setInterval(call, d);
12180 * Cancel the last queued timeout
12182 this.cancel = function(){
12190 * Ext JS Library 1.1.1
12191 * Copyright(c) 2006-2007, Ext JS, LLC.
12193 * Originally Released Under LGPL - original licence link has changed is not relivant.
12196 * <script type="text/javascript">
12200 Roo.util.TaskRunner = function(interval){
12201 interval = interval || 10;
12202 var tasks = [], removeQueue = [];
12204 var running = false;
12206 var stopThread = function(){
12212 var startThread = function(){
12215 id = setInterval(runTasks, interval);
12219 var removeTask = function(task){
12220 removeQueue.push(task);
12226 var runTasks = function(){
12227 if(removeQueue.length > 0){
12228 for(var i = 0, len = removeQueue.length; i < len; i++){
12229 tasks.remove(removeQueue[i]);
12232 if(tasks.length < 1){
12237 var now = new Date().getTime();
12238 for(var i = 0, len = tasks.length; i < len; ++i){
12240 var itime = now - t.taskRunTime;
12241 if(t.interval <= itime){
12242 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12243 t.taskRunTime = now;
12244 if(rt === false || t.taskRunCount === t.repeat){
12249 if(t.duration && t.duration <= (now - t.taskStartTime)){
12256 * Queues a new task.
12257 * @param {Object} task
12259 this.start = function(task){
12261 task.taskStartTime = new Date().getTime();
12262 task.taskRunTime = 0;
12263 task.taskRunCount = 0;
12268 this.stop = function(task){
12273 this.stopAll = function(){
12275 for(var i = 0, len = tasks.length; i < len; i++){
12276 if(tasks[i].onStop){
12285 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12287 * Ext JS Library 1.1.1
12288 * Copyright(c) 2006-2007, Ext JS, LLC.
12290 * Originally Released Under LGPL - original licence link has changed is not relivant.
12293 * <script type="text/javascript">
12298 * @class Roo.util.MixedCollection
12299 * @extends Roo.util.Observable
12300 * A Collection class that maintains both numeric indexes and keys and exposes events.
12302 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12303 * collection (defaults to false)
12304 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12305 * and return the key value for that item. This is used when available to look up the key on items that
12306 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12307 * equivalent to providing an implementation for the {@link #getKey} method.
12309 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12317 * Fires when the collection is cleared.
12322 * Fires when an item is added to the collection.
12323 * @param {Number} index The index at which the item was added.
12324 * @param {Object} o The item added.
12325 * @param {String} key The key associated with the added item.
12330 * Fires when an item is replaced in the collection.
12331 * @param {String} key he key associated with the new added.
12332 * @param {Object} old The item being replaced.
12333 * @param {Object} new The new item.
12338 * Fires when an item is removed from the collection.
12339 * @param {Object} o The item being removed.
12340 * @param {String} key (optional) The key associated with the removed item.
12345 this.allowFunctions = allowFunctions === true;
12347 this.getKey = keyFn;
12349 Roo.util.MixedCollection.superclass.constructor.call(this);
12352 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12353 allowFunctions : false,
12356 * Adds an item to the collection.
12357 * @param {String} key The key to associate with the item
12358 * @param {Object} o The item to add.
12359 * @return {Object} The item added.
12361 add : function(key, o){
12362 if(arguments.length == 1){
12364 key = this.getKey(o);
12366 if(typeof key == "undefined" || key === null){
12368 this.items.push(o);
12369 this.keys.push(null);
12371 var old = this.map[key];
12373 return this.replace(key, o);
12376 this.items.push(o);
12378 this.keys.push(key);
12380 this.fireEvent("add", this.length-1, o, key);
12385 * MixedCollection has a generic way to fetch keys if you implement getKey.
12388 var mc = new Roo.util.MixedCollection();
12389 mc.add(someEl.dom.id, someEl);
12390 mc.add(otherEl.dom.id, otherEl);
12394 var mc = new Roo.util.MixedCollection();
12395 mc.getKey = function(el){
12401 // or via the constructor
12402 var mc = new Roo.util.MixedCollection(false, function(el){
12408 * @param o {Object} The item for which to find the key.
12409 * @return {Object} The key for the passed item.
12411 getKey : function(o){
12416 * Replaces an item in the collection.
12417 * @param {String} key The key associated with the item to replace, or the item to replace.
12418 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12419 * @return {Object} The new item.
12421 replace : function(key, o){
12422 if(arguments.length == 1){
12424 key = this.getKey(o);
12426 var old = this.item(key);
12427 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12428 return this.add(key, o);
12430 var index = this.indexOfKey(key);
12431 this.items[index] = o;
12433 this.fireEvent("replace", key, old, o);
12438 * Adds all elements of an Array or an Object to the collection.
12439 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12440 * an Array of values, each of which are added to the collection.
12442 addAll : function(objs){
12443 if(arguments.length > 1 || objs instanceof Array){
12444 var args = arguments.length > 1 ? arguments : objs;
12445 for(var i = 0, len = args.length; i < len; i++){
12449 for(var key in objs){
12450 if(this.allowFunctions || typeof objs[key] != "function"){
12451 this.add(key, objs[key]);
12458 * Executes the specified function once for every item in the collection, passing each
12459 * item as the first and only parameter. returning false from the function will stop the iteration.
12460 * @param {Function} fn The function to execute for each item.
12461 * @param {Object} scope (optional) The scope in which to execute the function.
12463 each : function(fn, scope){
12464 var items = [].concat(this.items); // each safe for removal
12465 for(var i = 0, len = items.length; i < len; i++){
12466 if(fn.call(scope || items[i], items[i], i, len) === false){
12473 * Executes the specified function once for every key in the collection, passing each
12474 * key, and its associated item as the first two parameters.
12475 * @param {Function} fn The function to execute for each item.
12476 * @param {Object} scope (optional) The scope in which to execute the function.
12478 eachKey : function(fn, scope){
12479 for(var i = 0, len = this.keys.length; i < len; i++){
12480 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12485 * Returns the first item in the collection which elicits a true return value from the
12486 * passed selection function.
12487 * @param {Function} fn The selection function to execute for each item.
12488 * @param {Object} scope (optional) The scope in which to execute the function.
12489 * @return {Object} The first item in the collection which returned true from the selection function.
12491 find : function(fn, scope){
12492 for(var i = 0, len = this.items.length; i < len; i++){
12493 if(fn.call(scope || window, this.items[i], this.keys[i])){
12494 return this.items[i];
12501 * Inserts an item at the specified index in the collection.
12502 * @param {Number} index The index to insert the item at.
12503 * @param {String} key The key to associate with the new item, or the item itself.
12504 * @param {Object} o (optional) If the second parameter was a key, the new item.
12505 * @return {Object} The item inserted.
12507 insert : function(index, key, o){
12508 if(arguments.length == 2){
12510 key = this.getKey(o);
12512 if(index >= this.length){
12513 return this.add(key, o);
12516 this.items.splice(index, 0, o);
12517 if(typeof key != "undefined" && key != null){
12520 this.keys.splice(index, 0, key);
12521 this.fireEvent("add", index, o, key);
12526 * Removed an item from the collection.
12527 * @param {Object} o The item to remove.
12528 * @return {Object} The item removed.
12530 remove : function(o){
12531 return this.removeAt(this.indexOf(o));
12535 * Remove an item from a specified index in the collection.
12536 * @param {Number} index The index within the collection of the item to remove.
12538 removeAt : function(index){
12539 if(index < this.length && index >= 0){
12541 var o = this.items[index];
12542 this.items.splice(index, 1);
12543 var key = this.keys[index];
12544 if(typeof key != "undefined"){
12545 delete this.map[key];
12547 this.keys.splice(index, 1);
12548 this.fireEvent("remove", o, key);
12553 * Removed an item associated with the passed key fom the collection.
12554 * @param {String} key The key of the item to remove.
12556 removeKey : function(key){
12557 return this.removeAt(this.indexOfKey(key));
12561 * Returns the number of items in the collection.
12562 * @return {Number} the number of items in the collection.
12564 getCount : function(){
12565 return this.length;
12569 * Returns index within the collection of the passed Object.
12570 * @param {Object} o The item to find the index of.
12571 * @return {Number} index of the item.
12573 indexOf : function(o){
12574 if(!this.items.indexOf){
12575 for(var i = 0, len = this.items.length; i < len; i++){
12576 if(this.items[i] == o) return i;
12580 return this.items.indexOf(o);
12585 * Returns index within the collection of the passed key.
12586 * @param {String} key The key to find the index of.
12587 * @return {Number} index of the key.
12589 indexOfKey : function(key){
12590 if(!this.keys.indexOf){
12591 for(var i = 0, len = this.keys.length; i < len; i++){
12592 if(this.keys[i] == key) return i;
12596 return this.keys.indexOf(key);
12601 * Returns the item associated with the passed key OR index. Key has priority over index.
12602 * @param {String/Number} key The key or index of the item.
12603 * @return {Object} The item associated with the passed key.
12605 item : function(key){
12606 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12607 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12611 * Returns the item at the specified index.
12612 * @param {Number} index The index of the item.
12615 itemAt : function(index){
12616 return this.items[index];
12620 * Returns the item associated with the passed key.
12621 * @param {String/Number} key The key of the item.
12622 * @return {Object} The item associated with the passed key.
12624 key : function(key){
12625 return this.map[key];
12629 * Returns true if the collection contains the passed Object as an item.
12630 * @param {Object} o The Object to look for in the collection.
12631 * @return {Boolean} True if the collection contains the Object as an item.
12633 contains : function(o){
12634 return this.indexOf(o) != -1;
12638 * Returns true if the collection contains the passed Object as a key.
12639 * @param {String} key The key to look for in the collection.
12640 * @return {Boolean} True if the collection contains the Object as a key.
12642 containsKey : function(key){
12643 return typeof this.map[key] != "undefined";
12647 * Removes all items from the collection.
12649 clear : function(){
12654 this.fireEvent("clear");
12658 * Returns the first item in the collection.
12659 * @return {Object} the first item in the collection..
12661 first : function(){
12662 return this.items[0];
12666 * Returns the last item in the collection.
12667 * @return {Object} the last item in the collection..
12670 return this.items[this.length-1];
12673 _sort : function(property, dir, fn){
12674 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12675 fn = fn || function(a, b){
12678 var c = [], k = this.keys, items = this.items;
12679 for(var i = 0, len = items.length; i < len; i++){
12680 c[c.length] = {key: k[i], value: items[i], index: i};
12682 c.sort(function(a, b){
12683 var v = fn(a[property], b[property]) * dsc;
12685 v = (a.index < b.index ? -1 : 1);
12689 for(var i = 0, len = c.length; i < len; i++){
12690 items[i] = c[i].value;
12693 this.fireEvent("sort", this);
12697 * Sorts this collection with the passed comparison function
12698 * @param {String} direction (optional) "ASC" or "DESC"
12699 * @param {Function} fn (optional) comparison function
12701 sort : function(dir, fn){
12702 this._sort("value", dir, fn);
12706 * Sorts this collection by keys
12707 * @param {String} direction (optional) "ASC" or "DESC"
12708 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12710 keySort : function(dir, fn){
12711 this._sort("key", dir, fn || function(a, b){
12712 return String(a).toUpperCase()-String(b).toUpperCase();
12717 * Returns a range of items in this collection
12718 * @param {Number} startIndex (optional) defaults to 0
12719 * @param {Number} endIndex (optional) default to the last item
12720 * @return {Array} An array of items
12722 getRange : function(start, end){
12723 var items = this.items;
12724 if(items.length < 1){
12727 start = start || 0;
12728 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12731 for(var i = start; i <= end; i++) {
12732 r[r.length] = items[i];
12735 for(var i = start; i >= end; i--) {
12736 r[r.length] = items[i];
12743 * Filter the <i>objects</i> in this collection by a specific property.
12744 * Returns a new collection that has been filtered.
12745 * @param {String} property A property on your objects
12746 * @param {String/RegExp} value Either string that the property values
12747 * should start with or a RegExp to test against the property
12748 * @return {MixedCollection} The new filtered collection
12750 filter : function(property, value){
12751 if(!value.exec){ // not a regex
12752 value = String(value);
12753 if(value.length == 0){
12754 return this.clone();
12756 value = new RegExp("^" + Roo.escapeRe(value), "i");
12758 return this.filterBy(function(o){
12759 return o && value.test(o[property]);
12764 * Filter by a function. * Returns a new collection that has been filtered.
12765 * The passed function will be called with each
12766 * object in the collection. If the function returns true, the value is included
12767 * otherwise it is filtered.
12768 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12769 * @param {Object} scope (optional) The scope of the function (defaults to this)
12770 * @return {MixedCollection} The new filtered collection
12772 filterBy : function(fn, scope){
12773 var r = new Roo.util.MixedCollection();
12774 r.getKey = this.getKey;
12775 var k = this.keys, it = this.items;
12776 for(var i = 0, len = it.length; i < len; i++){
12777 if(fn.call(scope||this, it[i], k[i])){
12778 r.add(k[i], it[i]);
12785 * Creates a duplicate of this collection
12786 * @return {MixedCollection}
12788 clone : function(){
12789 var r = new Roo.util.MixedCollection();
12790 var k = this.keys, it = this.items;
12791 for(var i = 0, len = it.length; i < len; i++){
12792 r.add(k[i], it[i]);
12794 r.getKey = this.getKey;
12799 * Returns the item associated with the passed key or index.
12801 * @param {String/Number} key The key or index of the item.
12802 * @return {Object} The item associated with the passed key.
12804 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12806 * Ext JS Library 1.1.1
12807 * Copyright(c) 2006-2007, Ext JS, LLC.
12809 * Originally Released Under LGPL - original licence link has changed is not relivant.
12812 * <script type="text/javascript">
12815 * @class Roo.util.JSON
12816 * Modified version of Douglas Crockford"s json.js that doesn"t
12817 * mess with the Object prototype
12818 * http://www.json.org/js.html
12821 Roo.util.JSON = new (function(){
12822 var useHasOwn = {}.hasOwnProperty ? true : false;
12824 // crashes Safari in some instances
12825 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12827 var pad = function(n) {
12828 return n < 10 ? "0" + n : n;
12841 var encodeString = function(s){
12842 if (/["\\\x00-\x1f]/.test(s)) {
12843 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12848 c = b.charCodeAt();
12850 Math.floor(c / 16).toString(16) +
12851 (c % 16).toString(16);
12854 return '"' + s + '"';
12857 var encodeArray = function(o){
12858 var a = ["["], b, i, l = o.length, v;
12859 for (i = 0; i < l; i += 1) {
12861 switch (typeof v) {
12870 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12878 var encodeDate = function(o){
12879 return '"' + o.getFullYear() + "-" +
12880 pad(o.getMonth() + 1) + "-" +
12881 pad(o.getDate()) + "T" +
12882 pad(o.getHours()) + ":" +
12883 pad(o.getMinutes()) + ":" +
12884 pad(o.getSeconds()) + '"';
12888 * Encodes an Object, Array or other value
12889 * @param {Mixed} o The variable to encode
12890 * @return {String} The JSON string
12892 this.encode = function(o)
12894 // should this be extended to fully wrap stringify..
12896 if(typeof o == "undefined" || o === null){
12898 }else if(o instanceof Array){
12899 return encodeArray(o);
12900 }else if(o instanceof Date){
12901 return encodeDate(o);
12902 }else if(typeof o == "string"){
12903 return encodeString(o);
12904 }else if(typeof o == "number"){
12905 return isFinite(o) ? String(o) : "null";
12906 }else if(typeof o == "boolean"){
12909 var a = ["{"], b, i, v;
12911 if(!useHasOwn || o.hasOwnProperty(i)) {
12913 switch (typeof v) {
12922 a.push(this.encode(i), ":",
12923 v === null ? "null" : this.encode(v));
12934 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12935 * @param {String} json The JSON string
12936 * @return {Object} The resulting object
12938 this.decode = function(json){
12940 return /** eval:var:json */ eval("(" + json + ')');
12944 * Shorthand for {@link Roo.util.JSON#encode}
12945 * @member Roo encode
12947 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12949 * Shorthand for {@link Roo.util.JSON#decode}
12950 * @member Roo decode
12952 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12955 * Ext JS Library 1.1.1
12956 * Copyright(c) 2006-2007, Ext JS, LLC.
12958 * Originally Released Under LGPL - original licence link has changed is not relivant.
12961 * <script type="text/javascript">
12965 * @class Roo.util.Format
12966 * Reusable data formatting functions
12969 Roo.util.Format = function(){
12970 var trimRe = /^\s+|\s+$/g;
12973 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12974 * @param {String} value The string to truncate
12975 * @param {Number} length The maximum length to allow before truncating
12976 * @return {String} The converted text
12978 ellipsis : function(value, len){
12979 if(value && value.length > len){
12980 return value.substr(0, len-3)+"...";
12986 * Checks a reference and converts it to empty string if it is undefined
12987 * @param {Mixed} value Reference to check
12988 * @return {Mixed} Empty string if converted, otherwise the original value
12990 undef : function(value){
12991 return typeof value != "undefined" ? value : "";
12995 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12996 * @param {String} value The string to encode
12997 * @return {String} The encoded text
12999 htmlEncode : function(value){
13000 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13004 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13005 * @param {String} value The string to decode
13006 * @return {String} The decoded text
13008 htmlDecode : function(value){
13009 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13013 * Trims any whitespace from either side of a string
13014 * @param {String} value The text to trim
13015 * @return {String} The trimmed text
13017 trim : function(value){
13018 return String(value).replace(trimRe, "");
13022 * Returns a substring from within an original string
13023 * @param {String} value The original text
13024 * @param {Number} start The start index of the substring
13025 * @param {Number} length The length of the substring
13026 * @return {String} The substring
13028 substr : function(value, start, length){
13029 return String(value).substr(start, length);
13033 * Converts a string to all lower case letters
13034 * @param {String} value The text to convert
13035 * @return {String} The converted text
13037 lowercase : function(value){
13038 return String(value).toLowerCase();
13042 * Converts a string to all upper case letters
13043 * @param {String} value The text to convert
13044 * @return {String} The converted text
13046 uppercase : function(value){
13047 return String(value).toUpperCase();
13051 * Converts the first character only of a string to upper case
13052 * @param {String} value The text to convert
13053 * @return {String} The converted text
13055 capitalize : function(value){
13056 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13060 call : function(value, fn){
13061 if(arguments.length > 2){
13062 var args = Array.prototype.slice.call(arguments, 2);
13063 args.unshift(value);
13065 return /** eval:var:value */ eval(fn).apply(window, args);
13067 /** eval:var:value */
13068 return /** eval:var:value */ eval(fn).call(window, value);
13074 * safer version of Math.toFixed..??/
13075 * @param {Number/String} value The numeric value to format
13076 * @param {Number/String} value Decimal places
13077 * @return {String} The formatted currency string
13079 toFixed : function(v, n)
13081 // why not use to fixed - precision is buggered???
13083 return Math.round(v-0);
13085 var fact = Math.pow(10,n+1);
13086 v = (Math.round((v-0)*fact))/fact;
13087 var z = (''+fact).substring(2);
13088 if (v == Math.floor(v)) {
13089 return Math.floor(v) + '.' + z;
13092 // now just padd decimals..
13093 var ps = String(v).split('.');
13094 var fd = (ps[1] + z);
13095 var r = fd.substring(0,n);
13096 var rm = fd.substring(n);
13098 return ps[0] + '.' + r;
13100 r*=1; // turn it into a number;
13102 if (String(r).length != n) {
13105 r = String(r).substring(1); // chop the end off.
13108 return ps[0] + '.' + r;
13113 * Format a number as US currency
13114 * @param {Number/String} value The numeric value to format
13115 * @return {String} The formatted currency string
13117 usMoney : function(v){
13118 v = (Math.round((v-0)*100))/100;
13119 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13121 var ps = v.split('.');
13123 var sub = ps[1] ? '.'+ ps[1] : '.00';
13124 var r = /(\d+)(\d{3})/;
13125 while (r.test(whole)) {
13126 whole = whole.replace(r, '$1' + ',' + '$2');
13128 return "$" + whole + sub ;
13132 * Parse a value into a formatted date using the specified format pattern.
13133 * @param {Mixed} value The value to format
13134 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13135 * @return {String} The formatted date string
13137 date : function(v, format){
13141 if(!(v instanceof Date)){
13142 v = new Date(Date.parse(v));
13144 return v.dateFormat(format || "m/d/Y");
13148 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13149 * @param {String} format Any valid date format string
13150 * @return {Function} The date formatting function
13152 dateRenderer : function(format){
13153 return function(v){
13154 return Roo.util.Format.date(v, format);
13159 stripTagsRE : /<\/?[^>]+>/gi,
13162 * Strips all HTML tags
13163 * @param {Mixed} value The text from which to strip tags
13164 * @return {String} The stripped text
13166 stripTags : function(v){
13167 return !v ? v : String(v).replace(this.stripTagsRE, "");
13172 * Ext JS Library 1.1.1
13173 * Copyright(c) 2006-2007, Ext JS, LLC.
13175 * Originally Released Under LGPL - original licence link has changed is not relivant.
13178 * <script type="text/javascript">
13185 * @class Roo.MasterTemplate
13186 * @extends Roo.Template
13187 * Provides a template that can have child templates. The syntax is:
13189 var t = new Roo.MasterTemplate(
13190 '<select name="{name}">',
13191 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13194 t.add('options', {value: 'foo', text: 'bar'});
13195 // or you can add multiple child elements in one shot
13196 t.addAll('options', [
13197 {value: 'foo', text: 'bar'},
13198 {value: 'foo2', text: 'bar2'},
13199 {value: 'foo3', text: 'bar3'}
13201 // then append, applying the master template values
13202 t.append('my-form', {name: 'my-select'});
13204 * A name attribute for the child template is not required if you have only one child
13205 * template or you want to refer to them by index.
13207 Roo.MasterTemplate = function(){
13208 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13209 this.originalHtml = this.html;
13211 var m, re = this.subTemplateRe;
13214 while(m = re.exec(this.html)){
13215 var name = m[1], content = m[2];
13220 tpl : new Roo.Template(content)
13223 st[name] = st[subIndex];
13225 st[subIndex].tpl.compile();
13226 st[subIndex].tpl.call = this.call.createDelegate(this);
13229 this.subCount = subIndex;
13232 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13234 * The regular expression used to match sub templates
13238 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13241 * Applies the passed values to a child template.
13242 * @param {String/Number} name (optional) The name or index of the child template
13243 * @param {Array/Object} values The values to be applied to the template
13244 * @return {MasterTemplate} this
13246 add : function(name, values){
13247 if(arguments.length == 1){
13248 values = arguments[0];
13251 var s = this.subs[name];
13252 s.buffer[s.buffer.length] = s.tpl.apply(values);
13257 * Applies all the passed values to a child template.
13258 * @param {String/Number} name (optional) The name or index of the child template
13259 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13260 * @param {Boolean} reset (optional) True to reset the template first
13261 * @return {MasterTemplate} this
13263 fill : function(name, values, reset){
13265 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13273 for(var i = 0, len = values.length; i < len; i++){
13274 this.add(name, values[i]);
13280 * Resets the template for reuse
13281 * @return {MasterTemplate} this
13283 reset : function(){
13285 for(var i = 0; i < this.subCount; i++){
13291 applyTemplate : function(values){
13293 var replaceIndex = -1;
13294 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13295 return s[++replaceIndex].buffer.join("");
13297 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13300 apply : function(){
13301 return this.applyTemplate.apply(this, arguments);
13304 compile : function(){return this;}
13308 * Alias for fill().
13311 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13313 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13314 * var tpl = Roo.MasterTemplate.from('element-id');
13315 * @param {String/HTMLElement} el
13316 * @param {Object} config
13319 Roo.MasterTemplate.from = function(el, config){
13320 el = Roo.getDom(el);
13321 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13324 * Ext JS Library 1.1.1
13325 * Copyright(c) 2006-2007, Ext JS, LLC.
13327 * Originally Released Under LGPL - original licence link has changed is not relivant.
13330 * <script type="text/javascript">
13335 * @class Roo.util.CSS
13336 * Utility class for manipulating CSS rules
13339 Roo.util.CSS = function(){
13341 var doc = document;
13343 var camelRe = /(-[a-z])/gi;
13344 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13348 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13349 * tag and appended to the HEAD of the document.
13350 * @param {String|Object} cssText The text containing the css rules
13351 * @param {String} id An id to add to the stylesheet for later removal
13352 * @return {StyleSheet}
13354 createStyleSheet : function(cssText, id){
13356 var head = doc.getElementsByTagName("head")[0];
13357 var nrules = doc.createElement("style");
13358 nrules.setAttribute("type", "text/css");
13360 nrules.setAttribute("id", id);
13362 if (typeof(cssText) != 'string') {
13363 // support object maps..
13364 // not sure if this a good idea..
13365 // perhaps it should be merged with the general css handling
13366 // and handle js style props.
13367 var cssTextNew = [];
13368 for(var n in cssText) {
13370 for(var k in cssText[n]) {
13371 citems.push( k + ' : ' +cssText[n][k] + ';' );
13373 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13376 cssText = cssTextNew.join("\n");
13382 head.appendChild(nrules);
13383 ss = nrules.styleSheet;
13384 ss.cssText = cssText;
13387 nrules.appendChild(doc.createTextNode(cssText));
13389 nrules.cssText = cssText;
13391 head.appendChild(nrules);
13392 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13394 this.cacheStyleSheet(ss);
13399 * Removes a style or link tag by id
13400 * @param {String} id The id of the tag
13402 removeStyleSheet : function(id){
13403 var existing = doc.getElementById(id);
13405 existing.parentNode.removeChild(existing);
13410 * Dynamically swaps an existing stylesheet reference for a new one
13411 * @param {String} id The id of an existing link tag to remove
13412 * @param {String} url The href of the new stylesheet to include
13414 swapStyleSheet : function(id, url){
13415 this.removeStyleSheet(id);
13416 var ss = doc.createElement("link");
13417 ss.setAttribute("rel", "stylesheet");
13418 ss.setAttribute("type", "text/css");
13419 ss.setAttribute("id", id);
13420 ss.setAttribute("href", url);
13421 doc.getElementsByTagName("head")[0].appendChild(ss);
13425 * Refresh the rule cache if you have dynamically added stylesheets
13426 * @return {Object} An object (hash) of rules indexed by selector
13428 refreshCache : function(){
13429 return this.getRules(true);
13433 cacheStyleSheet : function(stylesheet){
13437 try{// try catch for cross domain access issue
13438 var ssRules = stylesheet.cssRules || stylesheet.rules;
13439 for(var j = ssRules.length-1; j >= 0; --j){
13440 rules[ssRules[j].selectorText] = ssRules[j];
13446 * Gets all css rules for the document
13447 * @param {Boolean} refreshCache true to refresh the internal cache
13448 * @return {Object} An object (hash) of rules indexed by selector
13450 getRules : function(refreshCache){
13451 if(rules == null || refreshCache){
13453 var ds = doc.styleSheets;
13454 for(var i =0, len = ds.length; i < len; i++){
13456 this.cacheStyleSheet(ds[i]);
13464 * Gets an an individual CSS rule by selector(s)
13465 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13466 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13467 * @return {CSSRule} The CSS rule or null if one is not found
13469 getRule : function(selector, refreshCache){
13470 var rs = this.getRules(refreshCache);
13471 if(!(selector instanceof Array)){
13472 return rs[selector];
13474 for(var i = 0; i < selector.length; i++){
13475 if(rs[selector[i]]){
13476 return rs[selector[i]];
13484 * Updates a rule property
13485 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13486 * @param {String} property The css property
13487 * @param {String} value The new value for the property
13488 * @return {Boolean} true If a rule was found and updated
13490 updateRule : function(selector, property, value){
13491 if(!(selector instanceof Array)){
13492 var rule = this.getRule(selector);
13494 rule.style[property.replace(camelRe, camelFn)] = value;
13498 for(var i = 0; i < selector.length; i++){
13499 if(this.updateRule(selector[i], property, value)){
13509 * Ext JS Library 1.1.1
13510 * Copyright(c) 2006-2007, Ext JS, LLC.
13512 * Originally Released Under LGPL - original licence link has changed is not relivant.
13515 * <script type="text/javascript">
13521 * @class Roo.util.ClickRepeater
13522 * @extends Roo.util.Observable
13524 * A wrapper class which can be applied to any element. Fires a "click" event while the
13525 * mouse is pressed. The interval between firings may be specified in the config but
13526 * defaults to 10 milliseconds.
13528 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13530 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13531 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13532 * Similar to an autorepeat key delay.
13533 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13534 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13535 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13536 * "interval" and "delay" are ignored. "immediate" is honored.
13537 * @cfg {Boolean} preventDefault True to prevent the default click event
13538 * @cfg {Boolean} stopDefault True to stop the default click event
13541 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13542 * 2007-02-02 jvs Renamed to ClickRepeater
13543 * 2007-02-03 jvs Modifications for FF Mac and Safari
13546 * @param {String/HTMLElement/Element} el The element to listen on
13547 * @param {Object} config
13549 Roo.util.ClickRepeater = function(el, config)
13551 this.el = Roo.get(el);
13552 this.el.unselectable();
13554 Roo.apply(this, config);
13559 * Fires when the mouse button is depressed.
13560 * @param {Roo.util.ClickRepeater} this
13562 "mousedown" : true,
13565 * Fires on a specified interval during the time the element is pressed.
13566 * @param {Roo.util.ClickRepeater} this
13571 * Fires when the mouse key is released.
13572 * @param {Roo.util.ClickRepeater} this
13577 this.el.on("mousedown", this.handleMouseDown, this);
13578 if(this.preventDefault || this.stopDefault){
13579 this.el.on("click", function(e){
13580 if(this.preventDefault){
13581 e.preventDefault();
13583 if(this.stopDefault){
13589 // allow inline handler
13591 this.on("click", this.handler, this.scope || this);
13594 Roo.util.ClickRepeater.superclass.constructor.call(this);
13597 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13600 preventDefault : true,
13601 stopDefault : false,
13605 handleMouseDown : function(){
13606 clearTimeout(this.timer);
13608 if(this.pressClass){
13609 this.el.addClass(this.pressClass);
13611 this.mousedownTime = new Date();
13613 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13614 this.el.on("mouseout", this.handleMouseOut, this);
13616 this.fireEvent("mousedown", this);
13617 this.fireEvent("click", this);
13619 this.timer = this.click.defer(this.delay || this.interval, this);
13623 click : function(){
13624 this.fireEvent("click", this);
13625 this.timer = this.click.defer(this.getInterval(), this);
13629 getInterval: function(){
13630 if(!this.accelerate){
13631 return this.interval;
13633 var pressTime = this.mousedownTime.getElapsed();
13634 if(pressTime < 500){
13636 }else if(pressTime < 1700){
13638 }else if(pressTime < 2600){
13640 }else if(pressTime < 3500){
13642 }else if(pressTime < 4400){
13644 }else if(pressTime < 5300){
13646 }else if(pressTime < 6200){
13654 handleMouseOut : function(){
13655 clearTimeout(this.timer);
13656 if(this.pressClass){
13657 this.el.removeClass(this.pressClass);
13659 this.el.on("mouseover", this.handleMouseReturn, this);
13663 handleMouseReturn : function(){
13664 this.el.un("mouseover", this.handleMouseReturn);
13665 if(this.pressClass){
13666 this.el.addClass(this.pressClass);
13672 handleMouseUp : function(){
13673 clearTimeout(this.timer);
13674 this.el.un("mouseover", this.handleMouseReturn);
13675 this.el.un("mouseout", this.handleMouseOut);
13676 Roo.get(document).un("mouseup", this.handleMouseUp);
13677 this.el.removeClass(this.pressClass);
13678 this.fireEvent("mouseup", this);
13682 * Ext JS Library 1.1.1
13683 * Copyright(c) 2006-2007, Ext JS, LLC.
13685 * Originally Released Under LGPL - original licence link has changed is not relivant.
13688 * <script type="text/javascript">
13693 * @class Roo.KeyNav
13694 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13695 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13696 * way to implement custom navigation schemes for any UI component.</p>
13697 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13698 * pageUp, pageDown, del, home, end. Usage:</p>
13700 var nav = new Roo.KeyNav("my-element", {
13701 "left" : function(e){
13702 this.moveLeft(e.ctrlKey);
13704 "right" : function(e){
13705 this.moveRight(e.ctrlKey);
13707 "enter" : function(e){
13714 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13715 * @param {Object} config The config
13717 Roo.KeyNav = function(el, config){
13718 this.el = Roo.get(el);
13719 Roo.apply(this, config);
13720 if(!this.disabled){
13721 this.disabled = true;
13726 Roo.KeyNav.prototype = {
13728 * @cfg {Boolean} disabled
13729 * True to disable this KeyNav instance (defaults to false)
13733 * @cfg {String} defaultEventAction
13734 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13735 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13736 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13738 defaultEventAction: "stopEvent",
13740 * @cfg {Boolean} forceKeyDown
13741 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13742 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13743 * handle keydown instead of keypress.
13745 forceKeyDown : false,
13748 prepareEvent : function(e){
13749 var k = e.getKey();
13750 var h = this.keyToHandler[k];
13751 //if(h && this[h]){
13752 // e.stopPropagation();
13754 if(Roo.isSafari && h && k >= 37 && k <= 40){
13760 relay : function(e){
13761 var k = e.getKey();
13762 var h = this.keyToHandler[k];
13764 if(this.doRelay(e, this[h], h) !== true){
13765 e[this.defaultEventAction]();
13771 doRelay : function(e, h, hname){
13772 return h.call(this.scope || this, e);
13775 // possible handlers
13789 // quick lookup hash
13806 * Enable this KeyNav
13808 enable: function(){
13810 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13811 // the EventObject will normalize Safari automatically
13812 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13813 this.el.on("keydown", this.relay, this);
13815 this.el.on("keydown", this.prepareEvent, this);
13816 this.el.on("keypress", this.relay, this);
13818 this.disabled = false;
13823 * Disable this KeyNav
13825 disable: function(){
13826 if(!this.disabled){
13827 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13828 this.el.un("keydown", this.relay);
13830 this.el.un("keydown", this.prepareEvent);
13831 this.el.un("keypress", this.relay);
13833 this.disabled = true;
13838 * Ext JS Library 1.1.1
13839 * Copyright(c) 2006-2007, Ext JS, LLC.
13841 * Originally Released Under LGPL - original licence link has changed is not relivant.
13844 * <script type="text/javascript">
13849 * @class Roo.KeyMap
13850 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13851 * The constructor accepts the same config object as defined by {@link #addBinding}.
13852 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13853 * combination it will call the function with this signature (if the match is a multi-key
13854 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13855 * A KeyMap can also handle a string representation of keys.<br />
13858 // map one key by key code
13859 var map = new Roo.KeyMap("my-element", {
13860 key: 13, // or Roo.EventObject.ENTER
13865 // map multiple keys to one action by string
13866 var map = new Roo.KeyMap("my-element", {
13872 // map multiple keys to multiple actions by strings and array of codes
13873 var map = new Roo.KeyMap("my-element", [
13876 fn: function(){ alert("Return was pressed"); }
13879 fn: function(){ alert('a, b or c was pressed'); }
13884 fn: function(){ alert('Control + shift + tab was pressed.'); }
13888 * <b>Note: A KeyMap starts enabled</b>
13890 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13891 * @param {Object} config The config (see {@link #addBinding})
13892 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13894 Roo.KeyMap = function(el, config, eventName){
13895 this.el = Roo.get(el);
13896 this.eventName = eventName || "keydown";
13897 this.bindings = [];
13899 this.addBinding(config);
13904 Roo.KeyMap.prototype = {
13906 * True to stop the event from bubbling and prevent the default browser action if the
13907 * key was handled by the KeyMap (defaults to false)
13913 * Add a new binding to this KeyMap. The following config object properties are supported:
13915 Property Type Description
13916 ---------- --------------- ----------------------------------------------------------------------
13917 key String/Array A single keycode or an array of keycodes to handle
13918 shift Boolean True to handle key only when shift is pressed (defaults to false)
13919 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13920 alt Boolean True to handle key only when alt is pressed (defaults to false)
13921 fn Function The function to call when KeyMap finds the expected key combination
13922 scope Object The scope of the callback function
13928 var map = new Roo.KeyMap(document, {
13929 key: Roo.EventObject.ENTER,
13934 //Add a new binding to the existing KeyMap later
13942 * @param {Object/Array} config A single KeyMap config or an array of configs
13944 addBinding : function(config){
13945 if(config instanceof Array){
13946 for(var i = 0, len = config.length; i < len; i++){
13947 this.addBinding(config[i]);
13951 var keyCode = config.key,
13952 shift = config.shift,
13953 ctrl = config.ctrl,
13956 scope = config.scope;
13957 if(typeof keyCode == "string"){
13959 var keyString = keyCode.toUpperCase();
13960 for(var j = 0, len = keyString.length; j < len; j++){
13961 ks.push(keyString.charCodeAt(j));
13965 var keyArray = keyCode instanceof Array;
13966 var handler = function(e){
13967 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13968 var k = e.getKey();
13970 for(var i = 0, len = keyCode.length; i < len; i++){
13971 if(keyCode[i] == k){
13972 if(this.stopEvent){
13975 fn.call(scope || window, k, e);
13981 if(this.stopEvent){
13984 fn.call(scope || window, k, e);
13989 this.bindings.push(handler);
13993 * Shorthand for adding a single key listener
13994 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13995 * following options:
13996 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13997 * @param {Function} fn The function to call
13998 * @param {Object} scope (optional) The scope of the function
14000 on : function(key, fn, scope){
14001 var keyCode, shift, ctrl, alt;
14002 if(typeof key == "object" && !(key instanceof Array)){
14021 handleKeyDown : function(e){
14022 if(this.enabled){ //just in case
14023 var b = this.bindings;
14024 for(var i = 0, len = b.length; i < len; i++){
14025 b[i].call(this, e);
14031 * Returns true if this KeyMap is enabled
14032 * @return {Boolean}
14034 isEnabled : function(){
14035 return this.enabled;
14039 * Enables this KeyMap
14041 enable: function(){
14043 this.el.on(this.eventName, this.handleKeyDown, this);
14044 this.enabled = true;
14049 * Disable this KeyMap
14051 disable: function(){
14053 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14054 this.enabled = false;
14059 * Ext JS Library 1.1.1
14060 * Copyright(c) 2006-2007, Ext JS, LLC.
14062 * Originally Released Under LGPL - original licence link has changed is not relivant.
14065 * <script type="text/javascript">
14070 * @class Roo.util.TextMetrics
14071 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14072 * wide, in pixels, a given block of text will be.
14075 Roo.util.TextMetrics = function(){
14079 * Measures the size of the specified text
14080 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14081 * that can affect the size of the rendered text
14082 * @param {String} text The text to measure
14083 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14084 * in order to accurately measure the text height
14085 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14087 measure : function(el, text, fixedWidth){
14089 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14092 shared.setFixedWidth(fixedWidth || 'auto');
14093 return shared.getSize(text);
14097 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14098 * the overhead of multiple calls to initialize the style properties on each measurement.
14099 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14100 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14101 * in order to accurately measure the text height
14102 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14104 createInstance : function(el, fixedWidth){
14105 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14112 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14113 var ml = new Roo.Element(document.createElement('div'));
14114 document.body.appendChild(ml.dom);
14115 ml.position('absolute');
14116 ml.setLeftTop(-1000, -1000);
14120 ml.setWidth(fixedWidth);
14125 * Returns the size of the specified text based on the internal element's style and width properties
14126 * @memberOf Roo.util.TextMetrics.Instance#
14127 * @param {String} text The text to measure
14128 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14130 getSize : function(text){
14132 var s = ml.getSize();
14138 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14139 * that can affect the size of the rendered text
14140 * @memberOf Roo.util.TextMetrics.Instance#
14141 * @param {String/HTMLElement} el The element, dom node or id
14143 bind : function(el){
14145 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14150 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14151 * to set a fixed width in order to accurately measure the text height.
14152 * @memberOf Roo.util.TextMetrics.Instance#
14153 * @param {Number} width The width to set on the element
14155 setFixedWidth : function(width){
14156 ml.setWidth(width);
14160 * Returns the measured width of the specified text
14161 * @memberOf Roo.util.TextMetrics.Instance#
14162 * @param {String} text The text to measure
14163 * @return {Number} width The width in pixels
14165 getWidth : function(text){
14166 ml.dom.style.width = 'auto';
14167 return this.getSize(text).width;
14171 * Returns the measured height of the specified text. For multiline text, be sure to call
14172 * {@link #setFixedWidth} if necessary.
14173 * @memberOf Roo.util.TextMetrics.Instance#
14174 * @param {String} text The text to measure
14175 * @return {Number} height The height in pixels
14177 getHeight : function(text){
14178 return this.getSize(text).height;
14182 instance.bind(bindTo);
14187 // backwards compat
14188 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14190 * Ext JS Library 1.1.1
14191 * Copyright(c) 2006-2007, Ext JS, LLC.
14193 * Originally Released Under LGPL - original licence link has changed is not relivant.
14196 * <script type="text/javascript">
14200 * @class Roo.state.Provider
14201 * Abstract base class for state provider implementations. This class provides methods
14202 * for encoding and decoding <b>typed</b> variables including dates and defines the
14203 * Provider interface.
14205 Roo.state.Provider = function(){
14207 * @event statechange
14208 * Fires when a state change occurs.
14209 * @param {Provider} this This state provider
14210 * @param {String} key The state key which was changed
14211 * @param {String} value The encoded value for the state
14214 "statechange": true
14217 Roo.state.Provider.superclass.constructor.call(this);
14219 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14221 * Returns the current value for a key
14222 * @param {String} name The key name
14223 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14224 * @return {Mixed} The state data
14226 get : function(name, defaultValue){
14227 return typeof this.state[name] == "undefined" ?
14228 defaultValue : this.state[name];
14232 * Clears a value from the state
14233 * @param {String} name The key name
14235 clear : function(name){
14236 delete this.state[name];
14237 this.fireEvent("statechange", this, name, null);
14241 * Sets the value for a key
14242 * @param {String} name The key name
14243 * @param {Mixed} value The value to set
14245 set : function(name, value){
14246 this.state[name] = value;
14247 this.fireEvent("statechange", this, name, value);
14251 * Decodes a string previously encoded with {@link #encodeValue}.
14252 * @param {String} value The value to decode
14253 * @return {Mixed} The decoded value
14255 decodeValue : function(cookie){
14256 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14257 var matches = re.exec(unescape(cookie));
14258 if(!matches || !matches[1]) return; // non state cookie
14259 var type = matches[1];
14260 var v = matches[2];
14263 return parseFloat(v);
14265 return new Date(Date.parse(v));
14270 var values = v.split("^");
14271 for(var i = 0, len = values.length; i < len; i++){
14272 all.push(this.decodeValue(values[i]));
14277 var values = v.split("^");
14278 for(var i = 0, len = values.length; i < len; i++){
14279 var kv = values[i].split("=");
14280 all[kv[0]] = this.decodeValue(kv[1]);
14289 * Encodes a value including type information. Decode with {@link #decodeValue}.
14290 * @param {Mixed} value The value to encode
14291 * @return {String} The encoded value
14293 encodeValue : function(v){
14295 if(typeof v == "number"){
14297 }else if(typeof v == "boolean"){
14298 enc = "b:" + (v ? "1" : "0");
14299 }else if(v instanceof Date){
14300 enc = "d:" + v.toGMTString();
14301 }else if(v instanceof Array){
14303 for(var i = 0, len = v.length; i < len; i++){
14304 flat += this.encodeValue(v[i]);
14305 if(i != len-1) flat += "^";
14308 }else if(typeof v == "object"){
14311 if(typeof v[key] != "function"){
14312 flat += key + "=" + this.encodeValue(v[key]) + "^";
14315 enc = "o:" + flat.substring(0, flat.length-1);
14319 return escape(enc);
14325 * Ext JS Library 1.1.1
14326 * Copyright(c) 2006-2007, Ext JS, LLC.
14328 * Originally Released Under LGPL - original licence link has changed is not relivant.
14331 * <script type="text/javascript">
14334 * @class Roo.state.Manager
14335 * This is the global state manager. By default all components that are "state aware" check this class
14336 * for state information if you don't pass them a custom state provider. In order for this class
14337 * to be useful, it must be initialized with a provider when your application initializes.
14339 // in your initialization function
14341 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14343 // supposed you have a {@link Roo.BorderLayout}
14344 var layout = new Roo.BorderLayout(...);
14345 layout.restoreState();
14346 // or a {Roo.BasicDialog}
14347 var dialog = new Roo.BasicDialog(...);
14348 dialog.restoreState();
14352 Roo.state.Manager = function(){
14353 var provider = new Roo.state.Provider();
14357 * Configures the default state provider for your application
14358 * @param {Provider} stateProvider The state provider to set
14360 setProvider : function(stateProvider){
14361 provider = stateProvider;
14365 * Returns the current value for a key
14366 * @param {String} name The key name
14367 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14368 * @return {Mixed} The state data
14370 get : function(key, defaultValue){
14371 return provider.get(key, defaultValue);
14375 * Sets the value for a key
14376 * @param {String} name The key name
14377 * @param {Mixed} value The state data
14379 set : function(key, value){
14380 provider.set(key, value);
14384 * Clears a value from the state
14385 * @param {String} name The key name
14387 clear : function(key){
14388 provider.clear(key);
14392 * Gets the currently configured state provider
14393 * @return {Provider} The state provider
14395 getProvider : function(){
14402 * Ext JS Library 1.1.1
14403 * Copyright(c) 2006-2007, Ext JS, LLC.
14405 * Originally Released Under LGPL - original licence link has changed is not relivant.
14408 * <script type="text/javascript">
14411 * @class Roo.state.CookieProvider
14412 * @extends Roo.state.Provider
14413 * The default Provider implementation which saves state via cookies.
14416 var cp = new Roo.state.CookieProvider({
14418 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14419 domain: "roojs.com"
14421 Roo.state.Manager.setProvider(cp);
14423 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14424 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14425 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14426 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14427 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14428 * domain the page is running on including the 'www' like 'www.roojs.com')
14429 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14431 * Create a new CookieProvider
14432 * @param {Object} config The configuration object
14434 Roo.state.CookieProvider = function(config){
14435 Roo.state.CookieProvider.superclass.constructor.call(this);
14437 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14438 this.domain = null;
14439 this.secure = false;
14440 Roo.apply(this, config);
14441 this.state = this.readCookies();
14444 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14446 set : function(name, value){
14447 if(typeof value == "undefined" || value === null){
14451 this.setCookie(name, value);
14452 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14456 clear : function(name){
14457 this.clearCookie(name);
14458 Roo.state.CookieProvider.superclass.clear.call(this, name);
14462 readCookies : function(){
14464 var c = document.cookie + ";";
14465 var re = /\s?(.*?)=(.*?);/g;
14467 while((matches = re.exec(c)) != null){
14468 var name = matches[1];
14469 var value = matches[2];
14470 if(name && name.substring(0,3) == "ys-"){
14471 cookies[name.substr(3)] = this.decodeValue(value);
14478 setCookie : function(name, value){
14479 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14480 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14481 ((this.path == null) ? "" : ("; path=" + this.path)) +
14482 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14483 ((this.secure == true) ? "; secure" : "");
14487 clearCookie : function(name){
14488 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14489 ((this.path == null) ? "" : ("; path=" + this.path)) +
14490 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14491 ((this.secure == true) ? "; secure" : "");
14495 * Ext JS Library 1.1.1
14496 * Copyright(c) 2006-2007, Ext JS, LLC.
14498 * Originally Released Under LGPL - original licence link has changed is not relivant.
14501 * <script type="text/javascript">
14507 * These classes are derivatives of the similarly named classes in the YUI Library.
14508 * The original license:
14509 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14510 * Code licensed under the BSD License:
14511 * http://developer.yahoo.net/yui/license.txt
14516 var Event=Roo.EventManager;
14517 var Dom=Roo.lib.Dom;
14520 * @class Roo.dd.DragDrop
14521 * @extends Roo.util.Observable
14522 * Defines the interface and base operation of items that that can be
14523 * dragged or can be drop targets. It was designed to be extended, overriding
14524 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14525 * Up to three html elements can be associated with a DragDrop instance:
14527 * <li>linked element: the element that is passed into the constructor.
14528 * This is the element which defines the boundaries for interaction with
14529 * other DragDrop objects.</li>
14530 * <li>handle element(s): The drag operation only occurs if the element that
14531 * was clicked matches a handle element. By default this is the linked
14532 * element, but there are times that you will want only a portion of the
14533 * linked element to initiate the drag operation, and the setHandleElId()
14534 * method provides a way to define this.</li>
14535 * <li>drag element: this represents the element that would be moved along
14536 * with the cursor during a drag operation. By default, this is the linked
14537 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14538 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14541 * This class should not be instantiated until the onload event to ensure that
14542 * the associated elements are available.
14543 * The following would define a DragDrop obj that would interact with any
14544 * other DragDrop obj in the "group1" group:
14546 * dd = new Roo.dd.DragDrop("div1", "group1");
14548 * Since none of the event handlers have been implemented, nothing would
14549 * actually happen if you were to run the code above. Normally you would
14550 * override this class or one of the default implementations, but you can
14551 * also override the methods you want on an instance of the class...
14553 * dd.onDragDrop = function(e, id) {
14554 * alert("dd was dropped on " + id);
14558 * @param {String} id of the element that is linked to this instance
14559 * @param {String} sGroup the group of related DragDrop objects
14560 * @param {object} config an object containing configurable attributes
14561 * Valid properties for DragDrop:
14562 * padding, isTarget, maintainOffset, primaryButtonOnly
14564 Roo.dd.DragDrop = function(id, sGroup, config) {
14566 this.init(id, sGroup, config);
14571 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
14574 * The id of the element associated with this object. This is what we
14575 * refer to as the "linked element" because the size and position of
14576 * this element is used to determine when the drag and drop objects have
14584 * Configuration attributes passed into the constructor
14591 * The id of the element that will be dragged. By default this is same
14592 * as the linked element , but could be changed to another element. Ex:
14594 * @property dragElId
14601 * the id of the element that initiates the drag operation. By default
14602 * this is the linked element, but could be changed to be a child of this
14603 * element. This lets us do things like only starting the drag when the
14604 * header element within the linked html element is clicked.
14605 * @property handleElId
14612 * An associative array of HTML tags that will be ignored if clicked.
14613 * @property invalidHandleTypes
14614 * @type {string: string}
14616 invalidHandleTypes: null,
14619 * An associative array of ids for elements that will be ignored if clicked
14620 * @property invalidHandleIds
14621 * @type {string: string}
14623 invalidHandleIds: null,
14626 * An indexted array of css class names for elements that will be ignored
14628 * @property invalidHandleClasses
14631 invalidHandleClasses: null,
14634 * The linked element's absolute X position at the time the drag was
14636 * @property startPageX
14643 * The linked element's absolute X position at the time the drag was
14645 * @property startPageY
14652 * The group defines a logical collection of DragDrop objects that are
14653 * related. Instances only get events when interacting with other
14654 * DragDrop object in the same group. This lets us define multiple
14655 * groups using a single DragDrop subclass if we want.
14657 * @type {string: string}
14662 * Individual drag/drop instances can be locked. This will prevent
14663 * onmousedown start drag.
14671 * Lock this instance
14674 lock: function() { this.locked = true; },
14677 * Unlock this instace
14680 unlock: function() { this.locked = false; },
14683 * By default, all insances can be a drop target. This can be disabled by
14684 * setting isTarget to false.
14691 * The padding configured for this drag and drop object for calculating
14692 * the drop zone intersection with this object.
14699 * Cached reference to the linked element
14700 * @property _domRef
14706 * Internal typeof flag
14707 * @property __ygDragDrop
14710 __ygDragDrop: true,
14713 * Set to true when horizontal contraints are applied
14714 * @property constrainX
14721 * Set to true when vertical contraints are applied
14722 * @property constrainY
14729 * The left constraint
14737 * The right constraint
14745 * The up constraint
14754 * The down constraint
14762 * Maintain offsets when we resetconstraints. Set to true when you want
14763 * the position of the element relative to its parent to stay the same
14764 * when the page changes
14766 * @property maintainOffset
14769 maintainOffset: false,
14772 * Array of pixel locations the element will snap to if we specified a
14773 * horizontal graduation/interval. This array is generated automatically
14774 * when you define a tick interval.
14781 * Array of pixel locations the element will snap to if we specified a
14782 * vertical graduation/interval. This array is generated automatically
14783 * when you define a tick interval.
14790 * By default the drag and drop instance will only respond to the primary
14791 * button click (left button for a right-handed mouse). Set to true to
14792 * allow drag and drop to start with any mouse click that is propogated
14794 * @property primaryButtonOnly
14797 primaryButtonOnly: true,
14800 * The availabe property is false until the linked dom element is accessible.
14801 * @property available
14807 * By default, drags can only be initiated if the mousedown occurs in the
14808 * region the linked element is. This is done in part to work around a
14809 * bug in some browsers that mis-report the mousedown if the previous
14810 * mouseup happened outside of the window. This property is set to true
14811 * if outer handles are defined.
14813 * @property hasOuterHandles
14817 hasOuterHandles: false,
14820 * Code that executes immediately before the startDrag event
14821 * @method b4StartDrag
14824 b4StartDrag: function(x, y) { },
14827 * Abstract method called after a drag/drop object is clicked
14828 * and the drag or mousedown time thresholds have beeen met.
14829 * @method startDrag
14830 * @param {int} X click location
14831 * @param {int} Y click location
14833 startDrag: function(x, y) { /* override this */ },
14836 * Code that executes immediately before the onDrag event
14840 b4Drag: function(e) { },
14843 * Abstract method called during the onMouseMove event while dragging an
14846 * @param {Event} e the mousemove event
14848 onDrag: function(e) { /* override this */ },
14851 * Abstract method called when this element fist begins hovering over
14852 * another DragDrop obj
14853 * @method onDragEnter
14854 * @param {Event} e the mousemove event
14855 * @param {String|DragDrop[]} id In POINT mode, the element
14856 * id this is hovering over. In INTERSECT mode, an array of one or more
14857 * dragdrop items being hovered over.
14859 onDragEnter: function(e, id) { /* override this */ },
14862 * Code that executes immediately before the onDragOver event
14863 * @method b4DragOver
14866 b4DragOver: function(e) { },
14869 * Abstract method called when this element is hovering over another
14871 * @method onDragOver
14872 * @param {Event} e the mousemove event
14873 * @param {String|DragDrop[]} id In POINT mode, the element
14874 * id this is hovering over. In INTERSECT mode, an array of dd items
14875 * being hovered over.
14877 onDragOver: function(e, id) { /* override this */ },
14880 * Code that executes immediately before the onDragOut event
14881 * @method b4DragOut
14884 b4DragOut: function(e) { },
14887 * Abstract method called when we are no longer hovering over an element
14888 * @method onDragOut
14889 * @param {Event} e the mousemove event
14890 * @param {String|DragDrop[]} id In POINT mode, the element
14891 * id this was hovering over. In INTERSECT mode, an array of dd items
14892 * that the mouse is no longer over.
14894 onDragOut: function(e, id) { /* override this */ },
14897 * Code that executes immediately before the onDragDrop event
14898 * @method b4DragDrop
14901 b4DragDrop: function(e) { },
14904 * Abstract method called when this item is dropped on another DragDrop
14906 * @method onDragDrop
14907 * @param {Event} e the mouseup event
14908 * @param {String|DragDrop[]} id In POINT mode, the element
14909 * id this was dropped on. In INTERSECT mode, an array of dd items this
14912 onDragDrop: function(e, id) { /* override this */ },
14915 * Abstract method called when this item is dropped on an area with no
14917 * @method onInvalidDrop
14918 * @param {Event} e the mouseup event
14920 onInvalidDrop: function(e) { /* override this */ },
14923 * Code that executes immediately before the endDrag event
14924 * @method b4EndDrag
14927 b4EndDrag: function(e) { },
14930 * Fired when we are done dragging the object
14932 * @param {Event} e the mouseup event
14934 endDrag: function(e) { /* override this */ },
14937 * Code executed immediately before the onMouseDown event
14938 * @method b4MouseDown
14939 * @param {Event} e the mousedown event
14942 b4MouseDown: function(e) { },
14945 * Event handler that fires when a drag/drop obj gets a mousedown
14946 * @method onMouseDown
14947 * @param {Event} e the mousedown event
14949 onMouseDown: function(e) { /* override this */ },
14952 * Event handler that fires when a drag/drop obj gets a mouseup
14953 * @method onMouseUp
14954 * @param {Event} e the mouseup event
14956 onMouseUp: function(e) { /* override this */ },
14959 * Override the onAvailable method to do what is needed after the initial
14960 * position was determined.
14961 * @method onAvailable
14963 onAvailable: function () {
14967 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14970 defaultPadding : {left:0, right:0, top:0, bottom:0},
14973 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14977 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14978 { dragElId: "existingProxyDiv" });
14979 dd.startDrag = function(){
14980 this.constrainTo("parent-id");
14983 * Or you can initalize it using the {@link Roo.Element} object:
14985 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14986 startDrag : function(){
14987 this.constrainTo("parent-id");
14991 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14992 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14993 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14994 * an object containing the sides to pad. For example: {right:10, bottom:10}
14995 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14997 constrainTo : function(constrainTo, pad, inContent){
14998 if(typeof pad == "number"){
14999 pad = {left: pad, right:pad, top:pad, bottom:pad};
15001 pad = pad || this.defaultPadding;
15002 var b = Roo.get(this.getEl()).getBox();
15003 var ce = Roo.get(constrainTo);
15004 var s = ce.getScroll();
15005 var c, cd = ce.dom;
15006 if(cd == document.body){
15007 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
15010 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
15014 var topSpace = b.y - c.y;
15015 var leftSpace = b.x - c.x;
15017 this.resetConstraints();
15018 this.setXConstraint(leftSpace - (pad.left||0), // left
15019 c.width - leftSpace - b.width - (pad.right||0) //right
15021 this.setYConstraint(topSpace - (pad.top||0), //top
15022 c.height - topSpace - b.height - (pad.bottom||0) //bottom
15027 * Returns a reference to the linked element
15029 * @return {HTMLElement} the html element
15031 getEl: function() {
15032 if (!this._domRef) {
15033 this._domRef = Roo.getDom(this.id);
15036 return this._domRef;
15040 * Returns a reference to the actual element to drag. By default this is
15041 * the same as the html element, but it can be assigned to another
15042 * element. An example of this can be found in Roo.dd.DDProxy
15043 * @method getDragEl
15044 * @return {HTMLElement} the html element
15046 getDragEl: function() {
15047 return Roo.getDom(this.dragElId);
15051 * Sets up the DragDrop object. Must be called in the constructor of any
15052 * Roo.dd.DragDrop subclass
15054 * @param id the id of the linked element
15055 * @param {String} sGroup the group of related items
15056 * @param {object} config configuration attributes
15058 init: function(id, sGroup, config) {
15059 this.initTarget(id, sGroup, config);
15060 Event.on(this.id, "mousedown", this.handleMouseDown, this);
15061 // Event.on(this.id, "selectstart", Event.preventDefault);
15065 * Initializes Targeting functionality only... the object does not
15066 * get a mousedown handler.
15067 * @method initTarget
15068 * @param id the id of the linked element
15069 * @param {String} sGroup the group of related items
15070 * @param {object} config configuration attributes
15072 initTarget: function(id, sGroup, config) {
15074 // configuration attributes
15075 this.config = config || {};
15077 // create a local reference to the drag and drop manager
15078 this.DDM = Roo.dd.DDM;
15079 // initialize the groups array
15082 // assume that we have an element reference instead of an id if the
15083 // parameter is not a string
15084 if (typeof id !== "string") {
15091 // add to an interaction group
15092 this.addToGroup((sGroup) ? sGroup : "default");
15094 // We don't want to register this as the handle with the manager
15095 // so we just set the id rather than calling the setter.
15096 this.handleElId = id;
15098 // the linked element is the element that gets dragged by default
15099 this.setDragElId(id);
15101 // by default, clicked anchors will not start drag operations.
15102 this.invalidHandleTypes = { A: "A" };
15103 this.invalidHandleIds = {};
15104 this.invalidHandleClasses = [];
15106 this.applyConfig();
15108 this.handleOnAvailable();
15112 * Applies the configuration parameters that were passed into the constructor.
15113 * This is supposed to happen at each level through the inheritance chain. So
15114 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15115 * DragDrop in order to get all of the parameters that are available in
15117 * @method applyConfig
15119 applyConfig: function() {
15121 // configurable properties:
15122 // padding, isTarget, maintainOffset, primaryButtonOnly
15123 this.padding = this.config.padding || [0, 0, 0, 0];
15124 this.isTarget = (this.config.isTarget !== false);
15125 this.maintainOffset = (this.config.maintainOffset);
15126 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15131 * Executed when the linked element is available
15132 * @method handleOnAvailable
15135 handleOnAvailable: function() {
15136 this.available = true;
15137 this.resetConstraints();
15138 this.onAvailable();
15142 * Configures the padding for the target zone in px. Effectively expands
15143 * (or reduces) the virtual object size for targeting calculations.
15144 * Supports css-style shorthand; if only one parameter is passed, all sides
15145 * will have that padding, and if only two are passed, the top and bottom
15146 * will have the first param, the left and right the second.
15147 * @method setPadding
15148 * @param {int} iTop Top pad
15149 * @param {int} iRight Right pad
15150 * @param {int} iBot Bot pad
15151 * @param {int} iLeft Left pad
15153 setPadding: function(iTop, iRight, iBot, iLeft) {
15154 // this.padding = [iLeft, iRight, iTop, iBot];
15155 if (!iRight && 0 !== iRight) {
15156 this.padding = [iTop, iTop, iTop, iTop];
15157 } else if (!iBot && 0 !== iBot) {
15158 this.padding = [iTop, iRight, iTop, iRight];
15160 this.padding = [iTop, iRight, iBot, iLeft];
15165 * Stores the initial placement of the linked element.
15166 * @method setInitialPosition
15167 * @param {int} diffX the X offset, default 0
15168 * @param {int} diffY the Y offset, default 0
15170 setInitPosition: function(diffX, diffY) {
15171 var el = this.getEl();
15173 if (!this.DDM.verifyEl(el)) {
15177 var dx = diffX || 0;
15178 var dy = diffY || 0;
15180 var p = Dom.getXY( el );
15182 this.initPageX = p[0] - dx;
15183 this.initPageY = p[1] - dy;
15185 this.lastPageX = p[0];
15186 this.lastPageY = p[1];
15189 this.setStartPosition(p);
15193 * Sets the start position of the element. This is set when the obj
15194 * is initialized, the reset when a drag is started.
15195 * @method setStartPosition
15196 * @param pos current position (from previous lookup)
15199 setStartPosition: function(pos) {
15200 var p = pos || Dom.getXY( this.getEl() );
15201 this.deltaSetXY = null;
15203 this.startPageX = p[0];
15204 this.startPageY = p[1];
15208 * Add this instance to a group of related drag/drop objects. All
15209 * instances belong to at least one group, and can belong to as many
15210 * groups as needed.
15211 * @method addToGroup
15212 * @param sGroup {string} the name of the group
15214 addToGroup: function(sGroup) {
15215 this.groups[sGroup] = true;
15216 this.DDM.regDragDrop(this, sGroup);
15220 * Remove's this instance from the supplied interaction group
15221 * @method removeFromGroup
15222 * @param {string} sGroup The group to drop
15224 removeFromGroup: function(sGroup) {
15225 if (this.groups[sGroup]) {
15226 delete this.groups[sGroup];
15229 this.DDM.removeDDFromGroup(this, sGroup);
15233 * Allows you to specify that an element other than the linked element
15234 * will be moved with the cursor during a drag
15235 * @method setDragElId
15236 * @param id {string} the id of the element that will be used to initiate the drag
15238 setDragElId: function(id) {
15239 this.dragElId = id;
15243 * Allows you to specify a child of the linked element that should be
15244 * used to initiate the drag operation. An example of this would be if
15245 * you have a content div with text and links. Clicking anywhere in the
15246 * content area would normally start the drag operation. Use this method
15247 * to specify that an element inside of the content div is the element
15248 * that starts the drag operation.
15249 * @method setHandleElId
15250 * @param id {string} the id of the element that will be used to
15251 * initiate the drag.
15253 setHandleElId: function(id) {
15254 if (typeof id !== "string") {
15257 this.handleElId = id;
15258 this.DDM.regHandle(this.id, id);
15262 * Allows you to set an element outside of the linked element as a drag
15264 * @method setOuterHandleElId
15265 * @param id the id of the element that will be used to initiate the drag
15267 setOuterHandleElId: function(id) {
15268 if (typeof id !== "string") {
15271 Event.on(id, "mousedown",
15272 this.handleMouseDown, this);
15273 this.setHandleElId(id);
15275 this.hasOuterHandles = true;
15279 * Remove all drag and drop hooks for this element
15282 unreg: function() {
15283 Event.un(this.id, "mousedown",
15284 this.handleMouseDown);
15285 this._domRef = null;
15286 this.DDM._remove(this);
15289 destroy : function(){
15294 * Returns true if this instance is locked, or the drag drop mgr is locked
15295 * (meaning that all drag/drop is disabled on the page.)
15297 * @return {boolean} true if this obj or all drag/drop is locked, else
15300 isLocked: function() {
15301 return (this.DDM.isLocked() || this.locked);
15305 * Fired when this object is clicked
15306 * @method handleMouseDown
15308 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15311 handleMouseDown: function(e, oDD){
15312 if (this.primaryButtonOnly && e.button != 0) {
15316 if (this.isLocked()) {
15320 this.DDM.refreshCache(this.groups);
15322 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15323 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15325 if (this.clickValidator(e)) {
15327 // set the initial element position
15328 this.setStartPosition();
15331 this.b4MouseDown(e);
15332 this.onMouseDown(e);
15334 this.DDM.handleMouseDown(e, this);
15336 this.DDM.stopEvent(e);
15344 clickValidator: function(e) {
15345 var target = e.getTarget();
15346 return ( this.isValidHandleChild(target) &&
15347 (this.id == this.handleElId ||
15348 this.DDM.handleWasClicked(target, this.id)) );
15352 * Allows you to specify a tag name that should not start a drag operation
15353 * when clicked. This is designed to facilitate embedding links within a
15354 * drag handle that do something other than start the drag.
15355 * @method addInvalidHandleType
15356 * @param {string} tagName the type of element to exclude
15358 addInvalidHandleType: function(tagName) {
15359 var type = tagName.toUpperCase();
15360 this.invalidHandleTypes[type] = type;
15364 * Lets you to specify an element id for a child of a drag handle
15365 * that should not initiate a drag
15366 * @method addInvalidHandleId
15367 * @param {string} id the element id of the element you wish to ignore
15369 addInvalidHandleId: function(id) {
15370 if (typeof id !== "string") {
15373 this.invalidHandleIds[id] = id;
15377 * Lets you specify a css class of elements that will not initiate a drag
15378 * @method addInvalidHandleClass
15379 * @param {string} cssClass the class of the elements you wish to ignore
15381 addInvalidHandleClass: function(cssClass) {
15382 this.invalidHandleClasses.push(cssClass);
15386 * Unsets an excluded tag name set by addInvalidHandleType
15387 * @method removeInvalidHandleType
15388 * @param {string} tagName the type of element to unexclude
15390 removeInvalidHandleType: function(tagName) {
15391 var type = tagName.toUpperCase();
15392 // this.invalidHandleTypes[type] = null;
15393 delete this.invalidHandleTypes[type];
15397 * Unsets an invalid handle id
15398 * @method removeInvalidHandleId
15399 * @param {string} id the id of the element to re-enable
15401 removeInvalidHandleId: function(id) {
15402 if (typeof id !== "string") {
15405 delete this.invalidHandleIds[id];
15409 * Unsets an invalid css class
15410 * @method removeInvalidHandleClass
15411 * @param {string} cssClass the class of the element(s) you wish to
15414 removeInvalidHandleClass: function(cssClass) {
15415 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15416 if (this.invalidHandleClasses[i] == cssClass) {
15417 delete this.invalidHandleClasses[i];
15423 * Checks the tag exclusion list to see if this click should be ignored
15424 * @method isValidHandleChild
15425 * @param {HTMLElement} node the HTMLElement to evaluate
15426 * @return {boolean} true if this is a valid tag type, false if not
15428 isValidHandleChild: function(node) {
15431 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15434 nodeName = node.nodeName.toUpperCase();
15436 nodeName = node.nodeName;
15438 valid = valid && !this.invalidHandleTypes[nodeName];
15439 valid = valid && !this.invalidHandleIds[node.id];
15441 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15442 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15451 * Create the array of horizontal tick marks if an interval was specified
15452 * in setXConstraint().
15453 * @method setXTicks
15456 setXTicks: function(iStartX, iTickSize) {
15458 this.xTickSize = iTickSize;
15462 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15464 this.xTicks[this.xTicks.length] = i;
15469 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15471 this.xTicks[this.xTicks.length] = i;
15476 this.xTicks.sort(this.DDM.numericSort) ;
15480 * Create the array of vertical tick marks if an interval was specified in
15481 * setYConstraint().
15482 * @method setYTicks
15485 setYTicks: function(iStartY, iTickSize) {
15487 this.yTickSize = iTickSize;
15491 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15493 this.yTicks[this.yTicks.length] = i;
15498 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15500 this.yTicks[this.yTicks.length] = i;
15505 this.yTicks.sort(this.DDM.numericSort) ;
15509 * By default, the element can be dragged any place on the screen. Use
15510 * this method to limit the horizontal travel of the element. Pass in
15511 * 0,0 for the parameters if you want to lock the drag to the y axis.
15512 * @method setXConstraint
15513 * @param {int} iLeft the number of pixels the element can move to the left
15514 * @param {int} iRight the number of pixels the element can move to the
15516 * @param {int} iTickSize optional parameter for specifying that the
15518 * should move iTickSize pixels at a time.
15520 setXConstraint: function(iLeft, iRight, iTickSize) {
15521 this.leftConstraint = iLeft;
15522 this.rightConstraint = iRight;
15524 this.minX = this.initPageX - iLeft;
15525 this.maxX = this.initPageX + iRight;
15526 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15528 this.constrainX = true;
15532 * Clears any constraints applied to this instance. Also clears ticks
15533 * since they can't exist independent of a constraint at this time.
15534 * @method clearConstraints
15536 clearConstraints: function() {
15537 this.constrainX = false;
15538 this.constrainY = false;
15543 * Clears any tick interval defined for this instance
15544 * @method clearTicks
15546 clearTicks: function() {
15547 this.xTicks = null;
15548 this.yTicks = null;
15549 this.xTickSize = 0;
15550 this.yTickSize = 0;
15554 * By default, the element can be dragged any place on the screen. Set
15555 * this to limit the vertical travel of the element. Pass in 0,0 for the
15556 * parameters if you want to lock the drag to the x axis.
15557 * @method setYConstraint
15558 * @param {int} iUp the number of pixels the element can move up
15559 * @param {int} iDown the number of pixels the element can move down
15560 * @param {int} iTickSize optional parameter for specifying that the
15561 * element should move iTickSize pixels at a time.
15563 setYConstraint: function(iUp, iDown, iTickSize) {
15564 this.topConstraint = iUp;
15565 this.bottomConstraint = iDown;
15567 this.minY = this.initPageY - iUp;
15568 this.maxY = this.initPageY + iDown;
15569 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15571 this.constrainY = true;
15576 * resetConstraints must be called if you manually reposition a dd element.
15577 * @method resetConstraints
15578 * @param {boolean} maintainOffset
15580 resetConstraints: function() {
15583 // Maintain offsets if necessary
15584 if (this.initPageX || this.initPageX === 0) {
15585 // figure out how much this thing has moved
15586 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15587 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15589 this.setInitPosition(dx, dy);
15591 // This is the first time we have detected the element's position
15593 this.setInitPosition();
15596 if (this.constrainX) {
15597 this.setXConstraint( this.leftConstraint,
15598 this.rightConstraint,
15602 if (this.constrainY) {
15603 this.setYConstraint( this.topConstraint,
15604 this.bottomConstraint,
15610 * Normally the drag element is moved pixel by pixel, but we can specify
15611 * that it move a number of pixels at a time. This method resolves the
15612 * location when we have it set up like this.
15614 * @param {int} val where we want to place the object
15615 * @param {int[]} tickArray sorted array of valid points
15616 * @return {int} the closest tick
15619 getTick: function(val, tickArray) {
15622 // If tick interval is not defined, it is effectively 1 pixel,
15623 // so we return the value passed to us.
15625 } else if (tickArray[0] >= val) {
15626 // The value is lower than the first tick, so we return the first
15628 return tickArray[0];
15630 for (var i=0, len=tickArray.length; i<len; ++i) {
15632 if (tickArray[next] && tickArray[next] >= val) {
15633 var diff1 = val - tickArray[i];
15634 var diff2 = tickArray[next] - val;
15635 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15639 // The value is larger than the last tick, so we return the last
15641 return tickArray[tickArray.length - 1];
15648 * @return {string} string representation of the dd obj
15650 toString: function() {
15651 return ("DragDrop " + this.id);
15659 * Ext JS Library 1.1.1
15660 * Copyright(c) 2006-2007, Ext JS, LLC.
15662 * Originally Released Under LGPL - original licence link has changed is not relivant.
15665 * <script type="text/javascript">
15670 * The drag and drop utility provides a framework for building drag and drop
15671 * applications. In addition to enabling drag and drop for specific elements,
15672 * the drag and drop elements are tracked by the manager class, and the
15673 * interactions between the various elements are tracked during the drag and
15674 * the implementing code is notified about these important moments.
15677 // Only load the library once. Rewriting the manager class would orphan
15678 // existing drag and drop instances.
15679 if (!Roo.dd.DragDropMgr) {
15682 * @class Roo.dd.DragDropMgr
15683 * DragDropMgr is a singleton that tracks the element interaction for
15684 * all DragDrop items in the window. Generally, you will not call
15685 * this class directly, but it does have helper methods that could
15686 * be useful in your DragDrop implementations.
15689 Roo.dd.DragDropMgr = function() {
15691 var Event = Roo.EventManager;
15696 * Two dimensional Array of registered DragDrop objects. The first
15697 * dimension is the DragDrop item group, the second the DragDrop
15700 * @type {string: string}
15707 * Array of element ids defined as drag handles. Used to determine
15708 * if the element that generated the mousedown event is actually the
15709 * handle and not the html element itself.
15710 * @property handleIds
15711 * @type {string: string}
15718 * the DragDrop object that is currently being dragged
15719 * @property dragCurrent
15727 * the DragDrop object(s) that are being hovered over
15728 * @property dragOvers
15736 * the X distance between the cursor and the object being dragged
15745 * the Y distance between the cursor and the object being dragged
15754 * Flag to determine if we should prevent the default behavior of the
15755 * events we define. By default this is true, but this can be set to
15756 * false if you need the default behavior (not recommended)
15757 * @property preventDefault
15761 preventDefault: true,
15764 * Flag to determine if we should stop the propagation of the events
15765 * we generate. This is true by default but you may want to set it to
15766 * false if the html element contains other features that require the
15768 * @property stopPropagation
15772 stopPropagation: true,
15775 * Internal flag that is set to true when drag and drop has been
15777 * @property initialized
15784 * All drag and drop can be disabled.
15792 * Called the first time an element is registered.
15798 this.initialized = true;
15802 * In point mode, drag and drop interaction is defined by the
15803 * location of the cursor during the drag/drop
15811 * In intersect mode, drag and drop interactio nis defined by the
15812 * overlap of two or more drag and drop objects.
15813 * @property INTERSECT
15820 * The current drag and drop mode. Default: POINT
15828 * Runs method on all drag and drop objects
15829 * @method _execOnAll
15833 _execOnAll: function(sMethod, args) {
15834 for (var i in this.ids) {
15835 for (var j in this.ids[i]) {
15836 var oDD = this.ids[i][j];
15837 if (! this.isTypeOfDD(oDD)) {
15840 oDD[sMethod].apply(oDD, args);
15846 * Drag and drop initialization. Sets up the global event handlers
15851 _onLoad: function() {
15856 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15857 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15858 Event.on(window, "unload", this._onUnload, this, true);
15859 Event.on(window, "resize", this._onResize, this, true);
15860 // Event.on(window, "mouseout", this._test);
15865 * Reset constraints on all drag and drop objs
15866 * @method _onResize
15870 _onResize: function(e) {
15871 this._execOnAll("resetConstraints", []);
15875 * Lock all drag and drop functionality
15879 lock: function() { this.locked = true; },
15882 * Unlock all drag and drop functionality
15886 unlock: function() { this.locked = false; },
15889 * Is drag and drop locked?
15891 * @return {boolean} True if drag and drop is locked, false otherwise.
15894 isLocked: function() { return this.locked; },
15897 * Location cache that is set for all drag drop objects when a drag is
15898 * initiated, cleared when the drag is finished.
15899 * @property locationCache
15906 * Set useCache to false if you want to force object the lookup of each
15907 * drag and drop linked element constantly during a drag.
15908 * @property useCache
15915 * The number of pixels that the mouse needs to move after the
15916 * mousedown before the drag is initiated. Default=3;
15917 * @property clickPixelThresh
15921 clickPixelThresh: 3,
15924 * The number of milliseconds after the mousedown event to initiate the
15925 * drag if we don't get a mouseup event. Default=1000
15926 * @property clickTimeThresh
15930 clickTimeThresh: 350,
15933 * Flag that indicates that either the drag pixel threshold or the
15934 * mousdown time threshold has been met
15935 * @property dragThreshMet
15940 dragThreshMet: false,
15943 * Timeout used for the click time threshold
15944 * @property clickTimeout
15949 clickTimeout: null,
15952 * The X position of the mousedown event stored for later use when a
15953 * drag threshold is met.
15962 * The Y position of the mousedown event stored for later use when a
15963 * drag threshold is met.
15972 * Each DragDrop instance must be registered with the DragDropMgr.
15973 * This is executed in DragDrop.init()
15974 * @method regDragDrop
15975 * @param {DragDrop} oDD the DragDrop object to register
15976 * @param {String} sGroup the name of the group this element belongs to
15979 regDragDrop: function(oDD, sGroup) {
15980 if (!this.initialized) { this.init(); }
15982 if (!this.ids[sGroup]) {
15983 this.ids[sGroup] = {};
15985 this.ids[sGroup][oDD.id] = oDD;
15989 * Removes the supplied dd instance from the supplied group. Executed
15990 * by DragDrop.removeFromGroup, so don't call this function directly.
15991 * @method removeDDFromGroup
15995 removeDDFromGroup: function(oDD, sGroup) {
15996 if (!this.ids[sGroup]) {
15997 this.ids[sGroup] = {};
16000 var obj = this.ids[sGroup];
16001 if (obj && obj[oDD.id]) {
16002 delete obj[oDD.id];
16007 * Unregisters a drag and drop item. This is executed in
16008 * DragDrop.unreg, use that method instead of calling this directly.
16013 _remove: function(oDD) {
16014 for (var g in oDD.groups) {
16015 if (g && this.ids[g][oDD.id]) {
16016 delete this.ids[g][oDD.id];
16019 delete this.handleIds[oDD.id];
16023 * Each DragDrop handle element must be registered. This is done
16024 * automatically when executing DragDrop.setHandleElId()
16025 * @method regHandle
16026 * @param {String} sDDId the DragDrop id this element is a handle for
16027 * @param {String} sHandleId the id of the element that is the drag
16031 regHandle: function(sDDId, sHandleId) {
16032 if (!this.handleIds[sDDId]) {
16033 this.handleIds[sDDId] = {};
16035 this.handleIds[sDDId][sHandleId] = sHandleId;
16039 * Utility function to determine if a given element has been
16040 * registered as a drag drop item.
16041 * @method isDragDrop
16042 * @param {String} id the element id to check
16043 * @return {boolean} true if this element is a DragDrop item,
16047 isDragDrop: function(id) {
16048 return ( this.getDDById(id) ) ? true : false;
16052 * Returns the drag and drop instances that are in all groups the
16053 * passed in instance belongs to.
16054 * @method getRelated
16055 * @param {DragDrop} p_oDD the obj to get related data for
16056 * @param {boolean} bTargetsOnly if true, only return targetable objs
16057 * @return {DragDrop[]} the related instances
16060 getRelated: function(p_oDD, bTargetsOnly) {
16062 for (var i in p_oDD.groups) {
16063 for (j in this.ids[i]) {
16064 var dd = this.ids[i][j];
16065 if (! this.isTypeOfDD(dd)) {
16068 if (!bTargetsOnly || dd.isTarget) {
16069 oDDs[oDDs.length] = dd;
16078 * Returns true if the specified dd target is a legal target for
16079 * the specifice drag obj
16080 * @method isLegalTarget
16081 * @param {DragDrop} the drag obj
16082 * @param {DragDrop} the target
16083 * @return {boolean} true if the target is a legal target for the
16087 isLegalTarget: function (oDD, oTargetDD) {
16088 var targets = this.getRelated(oDD, true);
16089 for (var i=0, len=targets.length;i<len;++i) {
16090 if (targets[i].id == oTargetDD.id) {
16099 * My goal is to be able to transparently determine if an object is
16100 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16101 * returns "object", oDD.constructor.toString() always returns
16102 * "DragDrop" and not the name of the subclass. So for now it just
16103 * evaluates a well-known variable in DragDrop.
16104 * @method isTypeOfDD
16105 * @param {Object} the object to evaluate
16106 * @return {boolean} true if typeof oDD = DragDrop
16109 isTypeOfDD: function (oDD) {
16110 return (oDD && oDD.__ygDragDrop);
16114 * Utility function to determine if a given element has been
16115 * registered as a drag drop handle for the given Drag Drop object.
16117 * @param {String} id the element id to check
16118 * @return {boolean} true if this element is a DragDrop handle, false
16122 isHandle: function(sDDId, sHandleId) {
16123 return ( this.handleIds[sDDId] &&
16124 this.handleIds[sDDId][sHandleId] );
16128 * Returns the DragDrop instance for a given id
16129 * @method getDDById
16130 * @param {String} id the id of the DragDrop object
16131 * @return {DragDrop} the drag drop object, null if it is not found
16134 getDDById: function(id) {
16135 for (var i in this.ids) {
16136 if (this.ids[i][id]) {
16137 return this.ids[i][id];
16144 * Fired after a registered DragDrop object gets the mousedown event.
16145 * Sets up the events required to track the object being dragged
16146 * @method handleMouseDown
16147 * @param {Event} e the event
16148 * @param oDD the DragDrop object being dragged
16152 handleMouseDown: function(e, oDD) {
16154 Roo.QuickTips.disable();
16156 this.currentTarget = e.getTarget();
16158 this.dragCurrent = oDD;
16160 var el = oDD.getEl();
16162 // track start position
16163 this.startX = e.getPageX();
16164 this.startY = e.getPageY();
16166 this.deltaX = this.startX - el.offsetLeft;
16167 this.deltaY = this.startY - el.offsetTop;
16169 this.dragThreshMet = false;
16171 this.clickTimeout = setTimeout(
16173 var DDM = Roo.dd.DDM;
16174 DDM.startDrag(DDM.startX, DDM.startY);
16176 this.clickTimeThresh );
16180 * Fired when either the drag pixel threshol or the mousedown hold
16181 * time threshold has been met.
16182 * @method startDrag
16183 * @param x {int} the X position of the original mousedown
16184 * @param y {int} the Y position of the original mousedown
16187 startDrag: function(x, y) {
16188 clearTimeout(this.clickTimeout);
16189 if (this.dragCurrent) {
16190 this.dragCurrent.b4StartDrag(x, y);
16191 this.dragCurrent.startDrag(x, y);
16193 this.dragThreshMet = true;
16197 * Internal function to handle the mouseup event. Will be invoked
16198 * from the context of the document.
16199 * @method handleMouseUp
16200 * @param {Event} e the event
16204 handleMouseUp: function(e) {
16207 Roo.QuickTips.enable();
16209 if (! this.dragCurrent) {
16213 clearTimeout(this.clickTimeout);
16215 if (this.dragThreshMet) {
16216 this.fireEvents(e, true);
16226 * Utility to stop event propagation and event default, if these
16227 * features are turned on.
16228 * @method stopEvent
16229 * @param {Event} e the event as returned by this.getEvent()
16232 stopEvent: function(e){
16233 if(this.stopPropagation) {
16234 e.stopPropagation();
16237 if (this.preventDefault) {
16238 e.preventDefault();
16243 * Internal function to clean up event handlers after the drag
16244 * operation is complete
16246 * @param {Event} e the event
16250 stopDrag: function(e) {
16251 // Fire the drag end event for the item that was dragged
16252 if (this.dragCurrent) {
16253 if (this.dragThreshMet) {
16254 this.dragCurrent.b4EndDrag(e);
16255 this.dragCurrent.endDrag(e);
16258 this.dragCurrent.onMouseUp(e);
16261 this.dragCurrent = null;
16262 this.dragOvers = {};
16266 * Internal function to handle the mousemove event. Will be invoked
16267 * from the context of the html element.
16269 * @TODO figure out what we can do about mouse events lost when the
16270 * user drags objects beyond the window boundary. Currently we can
16271 * detect this in internet explorer by verifying that the mouse is
16272 * down during the mousemove event. Firefox doesn't give us the
16273 * button state on the mousemove event.
16274 * @method handleMouseMove
16275 * @param {Event} e the event
16279 handleMouseMove: function(e) {
16280 if (! this.dragCurrent) {
16284 // var button = e.which || e.button;
16286 // check for IE mouseup outside of page boundary
16287 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16289 return this.handleMouseUp(e);
16292 if (!this.dragThreshMet) {
16293 var diffX = Math.abs(this.startX - e.getPageX());
16294 var diffY = Math.abs(this.startY - e.getPageY());
16295 if (diffX > this.clickPixelThresh ||
16296 diffY > this.clickPixelThresh) {
16297 this.startDrag(this.startX, this.startY);
16301 if (this.dragThreshMet) {
16302 this.dragCurrent.b4Drag(e);
16303 this.dragCurrent.onDrag(e);
16304 if(!this.dragCurrent.moveOnly){
16305 this.fireEvents(e, false);
16315 * Iterates over all of the DragDrop elements to find ones we are
16316 * hovering over or dropping on
16317 * @method fireEvents
16318 * @param {Event} e the event
16319 * @param {boolean} isDrop is this a drop op or a mouseover op?
16323 fireEvents: function(e, isDrop) {
16324 var dc = this.dragCurrent;
16326 // If the user did the mouse up outside of the window, we could
16327 // get here even though we have ended the drag.
16328 if (!dc || dc.isLocked()) {
16332 var pt = e.getPoint();
16334 // cache the previous dragOver array
16340 var enterEvts = [];
16342 // Check to see if the object(s) we were hovering over is no longer
16343 // being hovered over so we can fire the onDragOut event
16344 for (var i in this.dragOvers) {
16346 var ddo = this.dragOvers[i];
16348 if (! this.isTypeOfDD(ddo)) {
16352 if (! this.isOverTarget(pt, ddo, this.mode)) {
16353 outEvts.push( ddo );
16356 oldOvers[i] = true;
16357 delete this.dragOvers[i];
16360 for (var sGroup in dc.groups) {
16362 if ("string" != typeof sGroup) {
16366 for (i in this.ids[sGroup]) {
16367 var oDD = this.ids[sGroup][i];
16368 if (! this.isTypeOfDD(oDD)) {
16372 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16373 if (this.isOverTarget(pt, oDD, this.mode)) {
16374 // look for drop interactions
16376 dropEvts.push( oDD );
16377 // look for drag enter and drag over interactions
16380 // initial drag over: dragEnter fires
16381 if (!oldOvers[oDD.id]) {
16382 enterEvts.push( oDD );
16383 // subsequent drag overs: dragOver fires
16385 overEvts.push( oDD );
16388 this.dragOvers[oDD.id] = oDD;
16396 if (outEvts.length) {
16397 dc.b4DragOut(e, outEvts);
16398 dc.onDragOut(e, outEvts);
16401 if (enterEvts.length) {
16402 dc.onDragEnter(e, enterEvts);
16405 if (overEvts.length) {
16406 dc.b4DragOver(e, overEvts);
16407 dc.onDragOver(e, overEvts);
16410 if (dropEvts.length) {
16411 dc.b4DragDrop(e, dropEvts);
16412 dc.onDragDrop(e, dropEvts);
16416 // fire dragout events
16418 for (i=0, len=outEvts.length; i<len; ++i) {
16419 dc.b4DragOut(e, outEvts[i].id);
16420 dc.onDragOut(e, outEvts[i].id);
16423 // fire enter events
16424 for (i=0,len=enterEvts.length; i<len; ++i) {
16425 // dc.b4DragEnter(e, oDD.id);
16426 dc.onDragEnter(e, enterEvts[i].id);
16429 // fire over events
16430 for (i=0,len=overEvts.length; i<len; ++i) {
16431 dc.b4DragOver(e, overEvts[i].id);
16432 dc.onDragOver(e, overEvts[i].id);
16435 // fire drop events
16436 for (i=0, len=dropEvts.length; i<len; ++i) {
16437 dc.b4DragDrop(e, dropEvts[i].id);
16438 dc.onDragDrop(e, dropEvts[i].id);
16443 // notify about a drop that did not find a target
16444 if (isDrop && !dropEvts.length) {
16445 dc.onInvalidDrop(e);
16451 * Helper function for getting the best match from the list of drag
16452 * and drop objects returned by the drag and drop events when we are
16453 * in INTERSECT mode. It returns either the first object that the
16454 * cursor is over, or the object that has the greatest overlap with
16455 * the dragged element.
16456 * @method getBestMatch
16457 * @param {DragDrop[]} dds The array of drag and drop objects
16459 * @return {DragDrop} The best single match
16462 getBestMatch: function(dds) {
16464 // Return null if the input is not what we expect
16465 //if (!dds || !dds.length || dds.length == 0) {
16467 // If there is only one item, it wins
16468 //} else if (dds.length == 1) {
16470 var len = dds.length;
16475 // Loop through the targeted items
16476 for (var i=0; i<len; ++i) {
16478 // If the cursor is over the object, it wins. If the
16479 // cursor is over multiple matches, the first one we come
16481 if (dd.cursorIsOver) {
16484 // Otherwise the object with the most overlap wins
16487 winner.overlap.getArea() < dd.overlap.getArea()) {
16498 * Refreshes the cache of the top-left and bottom-right points of the
16499 * drag and drop objects in the specified group(s). This is in the
16500 * format that is stored in the drag and drop instance, so typical
16503 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16507 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16509 * @TODO this really should be an indexed array. Alternatively this
16510 * method could accept both.
16511 * @method refreshCache
16512 * @param {Object} groups an associative array of groups to refresh
16515 refreshCache: function(groups) {
16516 for (var sGroup in groups) {
16517 if ("string" != typeof sGroup) {
16520 for (var i in this.ids[sGroup]) {
16521 var oDD = this.ids[sGroup][i];
16523 if (this.isTypeOfDD(oDD)) {
16524 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16525 var loc = this.getLocation(oDD);
16527 this.locationCache[oDD.id] = loc;
16529 delete this.locationCache[oDD.id];
16530 // this will unregister the drag and drop object if
16531 // the element is not in a usable state
16540 * This checks to make sure an element exists and is in the DOM. The
16541 * main purpose is to handle cases where innerHTML is used to remove
16542 * drag and drop objects from the DOM. IE provides an 'unspecified
16543 * error' when trying to access the offsetParent of such an element
16545 * @param {HTMLElement} el the element to check
16546 * @return {boolean} true if the element looks usable
16549 verifyEl: function(el) {
16554 parent = el.offsetParent;
16557 parent = el.offsetParent;
16568 * Returns a Region object containing the drag and drop element's position
16569 * and size, including the padding configured for it
16570 * @method getLocation
16571 * @param {DragDrop} oDD the drag and drop object to get the
16573 * @return {Roo.lib.Region} a Region object representing the total area
16574 * the element occupies, including any padding
16575 * the instance is configured for.
16578 getLocation: function(oDD) {
16579 if (! this.isTypeOfDD(oDD)) {
16583 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16586 pos= Roo.lib.Dom.getXY(el);
16594 x2 = x1 + el.offsetWidth;
16596 y2 = y1 + el.offsetHeight;
16598 t = y1 - oDD.padding[0];
16599 r = x2 + oDD.padding[1];
16600 b = y2 + oDD.padding[2];
16601 l = x1 - oDD.padding[3];
16603 return new Roo.lib.Region( t, r, b, l );
16607 * Checks the cursor location to see if it over the target
16608 * @method isOverTarget
16609 * @param {Roo.lib.Point} pt The point to evaluate
16610 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16611 * @return {boolean} true if the mouse is over the target
16615 isOverTarget: function(pt, oTarget, intersect) {
16616 // use cache if available
16617 var loc = this.locationCache[oTarget.id];
16618 if (!loc || !this.useCache) {
16619 loc = this.getLocation(oTarget);
16620 this.locationCache[oTarget.id] = loc;
16628 oTarget.cursorIsOver = loc.contains( pt );
16630 // DragDrop is using this as a sanity check for the initial mousedown
16631 // in this case we are done. In POINT mode, if the drag obj has no
16632 // contraints, we are also done. Otherwise we need to evaluate the
16633 // location of the target as related to the actual location of the
16634 // dragged element.
16635 var dc = this.dragCurrent;
16636 if (!dc || !dc.getTargetCoord ||
16637 (!intersect && !dc.constrainX && !dc.constrainY)) {
16638 return oTarget.cursorIsOver;
16641 oTarget.overlap = null;
16643 // Get the current location of the drag element, this is the
16644 // location of the mouse event less the delta that represents
16645 // where the original mousedown happened on the element. We
16646 // need to consider constraints and ticks as well.
16647 var pos = dc.getTargetCoord(pt.x, pt.y);
16649 var el = dc.getDragEl();
16650 var curRegion = new Roo.lib.Region( pos.y,
16651 pos.x + el.offsetWidth,
16652 pos.y + el.offsetHeight,
16655 var overlap = curRegion.intersect(loc);
16658 oTarget.overlap = overlap;
16659 return (intersect) ? true : oTarget.cursorIsOver;
16666 * unload event handler
16667 * @method _onUnload
16671 _onUnload: function(e, me) {
16672 Roo.dd.DragDropMgr.unregAll();
16676 * Cleans up the drag and drop events and objects.
16681 unregAll: function() {
16683 if (this.dragCurrent) {
16685 this.dragCurrent = null;
16688 this._execOnAll("unreg", []);
16690 for (i in this.elementCache) {
16691 delete this.elementCache[i];
16694 this.elementCache = {};
16699 * A cache of DOM elements
16700 * @property elementCache
16707 * Get the wrapper for the DOM element specified
16708 * @method getElWrapper
16709 * @param {String} id the id of the element to get
16710 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16712 * @deprecated This wrapper isn't that useful
16715 getElWrapper: function(id) {
16716 var oWrapper = this.elementCache[id];
16717 if (!oWrapper || !oWrapper.el) {
16718 oWrapper = this.elementCache[id] =
16719 new this.ElementWrapper(Roo.getDom(id));
16725 * Returns the actual DOM element
16726 * @method getElement
16727 * @param {String} id the id of the elment to get
16728 * @return {Object} The element
16729 * @deprecated use Roo.getDom instead
16732 getElement: function(id) {
16733 return Roo.getDom(id);
16737 * Returns the style property for the DOM element (i.e.,
16738 * document.getElById(id).style)
16740 * @param {String} id the id of the elment to get
16741 * @return {Object} The style property of the element
16742 * @deprecated use Roo.getDom instead
16745 getCss: function(id) {
16746 var el = Roo.getDom(id);
16747 return (el) ? el.style : null;
16751 * Inner class for cached elements
16752 * @class DragDropMgr.ElementWrapper
16757 ElementWrapper: function(el) {
16762 this.el = el || null;
16767 this.id = this.el && el.id;
16769 * A reference to the style property
16772 this.css = this.el && el.style;
16776 * Returns the X position of an html element
16778 * @param el the element for which to get the position
16779 * @return {int} the X coordinate
16781 * @deprecated use Roo.lib.Dom.getX instead
16784 getPosX: function(el) {
16785 return Roo.lib.Dom.getX(el);
16789 * Returns the Y position of an html element
16791 * @param el the element for which to get the position
16792 * @return {int} the Y coordinate
16793 * @deprecated use Roo.lib.Dom.getY instead
16796 getPosY: function(el) {
16797 return Roo.lib.Dom.getY(el);
16801 * Swap two nodes. In IE, we use the native method, for others we
16802 * emulate the IE behavior
16804 * @param n1 the first node to swap
16805 * @param n2 the other node to swap
16808 swapNode: function(n1, n2) {
16812 var p = n2.parentNode;
16813 var s = n2.nextSibling;
16816 p.insertBefore(n1, n2);
16817 } else if (n2 == n1.nextSibling) {
16818 p.insertBefore(n2, n1);
16820 n1.parentNode.replaceChild(n2, n1);
16821 p.insertBefore(n1, s);
16827 * Returns the current scroll position
16828 * @method getScroll
16832 getScroll: function () {
16833 var t, l, dde=document.documentElement, db=document.body;
16834 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16836 l = dde.scrollLeft;
16843 return { top: t, left: l };
16847 * Returns the specified element style property
16849 * @param {HTMLElement} el the element
16850 * @param {string} styleProp the style property
16851 * @return {string} The value of the style property
16852 * @deprecated use Roo.lib.Dom.getStyle
16855 getStyle: function(el, styleProp) {
16856 return Roo.fly(el).getStyle(styleProp);
16860 * Gets the scrollTop
16861 * @method getScrollTop
16862 * @return {int} the document's scrollTop
16865 getScrollTop: function () { return this.getScroll().top; },
16868 * Gets the scrollLeft
16869 * @method getScrollLeft
16870 * @return {int} the document's scrollTop
16873 getScrollLeft: function () { return this.getScroll().left; },
16876 * Sets the x/y position of an element to the location of the
16879 * @param {HTMLElement} moveEl The element to move
16880 * @param {HTMLElement} targetEl The position reference element
16883 moveToEl: function (moveEl, targetEl) {
16884 var aCoord = Roo.lib.Dom.getXY(targetEl);
16885 Roo.lib.Dom.setXY(moveEl, aCoord);
16889 * Numeric array sort function
16890 * @method numericSort
16893 numericSort: function(a, b) { return (a - b); },
16897 * @property _timeoutCount
16904 * Trying to make the load order less important. Without this we get
16905 * an error if this file is loaded before the Event Utility.
16906 * @method _addListeners
16910 _addListeners: function() {
16911 var DDM = Roo.dd.DDM;
16912 if ( Roo.lib.Event && document ) {
16915 if (DDM._timeoutCount > 2000) {
16917 setTimeout(DDM._addListeners, 10);
16918 if (document && document.body) {
16919 DDM._timeoutCount += 1;
16926 * Recursively searches the immediate parent and all child nodes for
16927 * the handle element in order to determine wheter or not it was
16929 * @method handleWasClicked
16930 * @param node the html element to inspect
16933 handleWasClicked: function(node, id) {
16934 if (this.isHandle(id, node.id)) {
16937 // check to see if this is a text node child of the one we want
16938 var p = node.parentNode;
16941 if (this.isHandle(id, p.id)) {
16956 // shorter alias, save a few bytes
16957 Roo.dd.DDM = Roo.dd.DragDropMgr;
16958 Roo.dd.DDM._addListeners();
16962 * Ext JS Library 1.1.1
16963 * Copyright(c) 2006-2007, Ext JS, LLC.
16965 * Originally Released Under LGPL - original licence link has changed is not relivant.
16968 * <script type="text/javascript">
16973 * A DragDrop implementation where the linked element follows the
16974 * mouse cursor during a drag.
16975 * @extends Roo.dd.DragDrop
16977 * @param {String} id the id of the linked element
16978 * @param {String} sGroup the group of related DragDrop items
16979 * @param {object} config an object containing configurable attributes
16980 * Valid properties for DD:
16983 Roo.dd.DD = function(id, sGroup, config) {
16985 this.init(id, sGroup, config);
16989 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16992 * When set to true, the utility automatically tries to scroll the browser
16993 * window wehn a drag and drop element is dragged near the viewport boundary.
16994 * Defaults to true.
17001 * Sets the pointer offset to the distance between the linked element's top
17002 * left corner and the location the element was clicked
17003 * @method autoOffset
17004 * @param {int} iPageX the X coordinate of the click
17005 * @param {int} iPageY the Y coordinate of the click
17007 autoOffset: function(iPageX, iPageY) {
17008 var x = iPageX - this.startPageX;
17009 var y = iPageY - this.startPageY;
17010 this.setDelta(x, y);
17014 * Sets the pointer offset. You can call this directly to force the
17015 * offset to be in a particular location (e.g., pass in 0,0 to set it
17016 * to the center of the object)
17018 * @param {int} iDeltaX the distance from the left
17019 * @param {int} iDeltaY the distance from the top
17021 setDelta: function(iDeltaX, iDeltaY) {
17022 this.deltaX = iDeltaX;
17023 this.deltaY = iDeltaY;
17027 * Sets the drag element to the location of the mousedown or click event,
17028 * maintaining the cursor location relative to the location on the element
17029 * that was clicked. Override this if you want to place the element in a
17030 * location other than where the cursor is.
17031 * @method setDragElPos
17032 * @param {int} iPageX the X coordinate of the mousedown or drag event
17033 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17035 setDragElPos: function(iPageX, iPageY) {
17036 // the first time we do this, we are going to check to make sure
17037 // the element has css positioning
17039 var el = this.getDragEl();
17040 this.alignElWithMouse(el, iPageX, iPageY);
17044 * Sets the element to the location of the mousedown or click event,
17045 * maintaining the cursor location relative to the location on the element
17046 * that was clicked. Override this if you want to place the element in a
17047 * location other than where the cursor is.
17048 * @method alignElWithMouse
17049 * @param {HTMLElement} el the element to move
17050 * @param {int} iPageX the X coordinate of the mousedown or drag event
17051 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17053 alignElWithMouse: function(el, iPageX, iPageY) {
17054 var oCoord = this.getTargetCoord(iPageX, iPageY);
17055 var fly = el.dom ? el : Roo.fly(el);
17056 if (!this.deltaSetXY) {
17057 var aCoord = [oCoord.x, oCoord.y];
17059 var newLeft = fly.getLeft(true);
17060 var newTop = fly.getTop(true);
17061 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
17063 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
17066 this.cachePosition(oCoord.x, oCoord.y);
17067 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
17072 * Saves the most recent position so that we can reset the constraints and
17073 * tick marks on-demand. We need to know this so that we can calculate the
17074 * number of pixels the element is offset from its original position.
17075 * @method cachePosition
17076 * @param iPageX the current x position (optional, this just makes it so we
17077 * don't have to look it up again)
17078 * @param iPageY the current y position (optional, this just makes it so we
17079 * don't have to look it up again)
17081 cachePosition: function(iPageX, iPageY) {
17083 this.lastPageX = iPageX;
17084 this.lastPageY = iPageY;
17086 var aCoord = Roo.lib.Dom.getXY(this.getEl());
17087 this.lastPageX = aCoord[0];
17088 this.lastPageY = aCoord[1];
17093 * Auto-scroll the window if the dragged object has been moved beyond the
17094 * visible window boundary.
17095 * @method autoScroll
17096 * @param {int} x the drag element's x position
17097 * @param {int} y the drag element's y position
17098 * @param {int} h the height of the drag element
17099 * @param {int} w the width of the drag element
17102 autoScroll: function(x, y, h, w) {
17105 // The client height
17106 var clientH = Roo.lib.Dom.getViewWidth();
17108 // The client width
17109 var clientW = Roo.lib.Dom.getViewHeight();
17111 // The amt scrolled down
17112 var st = this.DDM.getScrollTop();
17114 // The amt scrolled right
17115 var sl = this.DDM.getScrollLeft();
17117 // Location of the bottom of the element
17120 // Location of the right of the element
17123 // The distance from the cursor to the bottom of the visible area,
17124 // adjusted so that we don't scroll if the cursor is beyond the
17125 // element drag constraints
17126 var toBot = (clientH + st - y - this.deltaY);
17128 // The distance from the cursor to the right of the visible area
17129 var toRight = (clientW + sl - x - this.deltaX);
17132 // How close to the edge the cursor must be before we scroll
17133 // var thresh = (document.all) ? 100 : 40;
17136 // How many pixels to scroll per autoscroll op. This helps to reduce
17137 // clunky scrolling. IE is more sensitive about this ... it needs this
17138 // value to be higher.
17139 var scrAmt = (document.all) ? 80 : 30;
17141 // Scroll down if we are near the bottom of the visible page and the
17142 // obj extends below the crease
17143 if ( bot > clientH && toBot < thresh ) {
17144 window.scrollTo(sl, st + scrAmt);
17147 // Scroll up if the window is scrolled down and the top of the object
17148 // goes above the top border
17149 if ( y < st && st > 0 && y - st < thresh ) {
17150 window.scrollTo(sl, st - scrAmt);
17153 // Scroll right if the obj is beyond the right border and the cursor is
17154 // near the border.
17155 if ( right > clientW && toRight < thresh ) {
17156 window.scrollTo(sl + scrAmt, st);
17159 // Scroll left if the window has been scrolled to the right and the obj
17160 // extends past the left border
17161 if ( x < sl && sl > 0 && x - sl < thresh ) {
17162 window.scrollTo(sl - scrAmt, st);
17168 * Finds the location the element should be placed if we want to move
17169 * it to where the mouse location less the click offset would place us.
17170 * @method getTargetCoord
17171 * @param {int} iPageX the X coordinate of the click
17172 * @param {int} iPageY the Y coordinate of the click
17173 * @return an object that contains the coordinates (Object.x and Object.y)
17176 getTargetCoord: function(iPageX, iPageY) {
17179 var x = iPageX - this.deltaX;
17180 var y = iPageY - this.deltaY;
17182 if (this.constrainX) {
17183 if (x < this.minX) { x = this.minX; }
17184 if (x > this.maxX) { x = this.maxX; }
17187 if (this.constrainY) {
17188 if (y < this.minY) { y = this.minY; }
17189 if (y > this.maxY) { y = this.maxY; }
17192 x = this.getTick(x, this.xTicks);
17193 y = this.getTick(y, this.yTicks);
17200 * Sets up config options specific to this class. Overrides
17201 * Roo.dd.DragDrop, but all versions of this method through the
17202 * inheritance chain are called
17204 applyConfig: function() {
17205 Roo.dd.DD.superclass.applyConfig.call(this);
17206 this.scroll = (this.config.scroll !== false);
17210 * Event that fires prior to the onMouseDown event. Overrides
17213 b4MouseDown: function(e) {
17214 // this.resetConstraints();
17215 this.autoOffset(e.getPageX(),
17220 * Event that fires prior to the onDrag event. Overrides
17223 b4Drag: function(e) {
17224 this.setDragElPos(e.getPageX(),
17228 toString: function() {
17229 return ("DD " + this.id);
17232 //////////////////////////////////////////////////////////////////////////
17233 // Debugging ygDragDrop events that can be overridden
17234 //////////////////////////////////////////////////////////////////////////
17236 startDrag: function(x, y) {
17239 onDrag: function(e) {
17242 onDragEnter: function(e, id) {
17245 onDragOver: function(e, id) {
17248 onDragOut: function(e, id) {
17251 onDragDrop: function(e, id) {
17254 endDrag: function(e) {
17261 * Ext JS Library 1.1.1
17262 * Copyright(c) 2006-2007, Ext JS, LLC.
17264 * Originally Released Under LGPL - original licence link has changed is not relivant.
17267 * <script type="text/javascript">
17271 * @class Roo.dd.DDProxy
17272 * A DragDrop implementation that inserts an empty, bordered div into
17273 * the document that follows the cursor during drag operations. At the time of
17274 * the click, the frame div is resized to the dimensions of the linked html
17275 * element, and moved to the exact location of the linked element.
17277 * References to the "frame" element refer to the single proxy element that
17278 * was created to be dragged in place of all DDProxy elements on the
17281 * @extends Roo.dd.DD
17283 * @param {String} id the id of the linked html element
17284 * @param {String} sGroup the group of related DragDrop objects
17285 * @param {object} config an object containing configurable attributes
17286 * Valid properties for DDProxy in addition to those in DragDrop:
17287 * resizeFrame, centerFrame, dragElId
17289 Roo.dd.DDProxy = function(id, sGroup, config) {
17291 this.init(id, sGroup, config);
17297 * The default drag frame div id
17298 * @property Roo.dd.DDProxy.dragElId
17302 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17304 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17307 * By default we resize the drag frame to be the same size as the element
17308 * we want to drag (this is to get the frame effect). We can turn it off
17309 * if we want a different behavior.
17310 * @property resizeFrame
17316 * By default the frame is positioned exactly where the drag element is, so
17317 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17318 * you do not have constraints on the obj is to have the drag frame centered
17319 * around the cursor. Set centerFrame to true for this effect.
17320 * @property centerFrame
17323 centerFrame: false,
17326 * Creates the proxy element if it does not yet exist
17327 * @method createFrame
17329 createFrame: function() {
17331 var body = document.body;
17333 if (!body || !body.firstChild) {
17334 setTimeout( function() { self.createFrame(); }, 50 );
17338 var div = this.getDragEl();
17341 div = document.createElement("div");
17342 div.id = this.dragElId;
17345 s.position = "absolute";
17346 s.visibility = "hidden";
17348 s.border = "2px solid #aaa";
17351 // appendChild can blow up IE if invoked prior to the window load event
17352 // while rendering a table. It is possible there are other scenarios
17353 // that would cause this to happen as well.
17354 body.insertBefore(div, body.firstChild);
17359 * Initialization for the drag frame element. Must be called in the
17360 * constructor of all subclasses
17361 * @method initFrame
17363 initFrame: function() {
17364 this.createFrame();
17367 applyConfig: function() {
17368 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17370 this.resizeFrame = (this.config.resizeFrame !== false);
17371 this.centerFrame = (this.config.centerFrame);
17372 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17376 * Resizes the drag frame to the dimensions of the clicked object, positions
17377 * it over the object, and finally displays it
17378 * @method showFrame
17379 * @param {int} iPageX X click position
17380 * @param {int} iPageY Y click position
17383 showFrame: function(iPageX, iPageY) {
17384 var el = this.getEl();
17385 var dragEl = this.getDragEl();
17386 var s = dragEl.style;
17388 this._resizeProxy();
17390 if (this.centerFrame) {
17391 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17392 Math.round(parseInt(s.height, 10)/2) );
17395 this.setDragElPos(iPageX, iPageY);
17397 Roo.fly(dragEl).show();
17401 * The proxy is automatically resized to the dimensions of the linked
17402 * element when a drag is initiated, unless resizeFrame is set to false
17403 * @method _resizeProxy
17406 _resizeProxy: function() {
17407 if (this.resizeFrame) {
17408 var el = this.getEl();
17409 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17413 // overrides Roo.dd.DragDrop
17414 b4MouseDown: function(e) {
17415 var x = e.getPageX();
17416 var y = e.getPageY();
17417 this.autoOffset(x, y);
17418 this.setDragElPos(x, y);
17421 // overrides Roo.dd.DragDrop
17422 b4StartDrag: function(x, y) {
17423 // show the drag frame
17424 this.showFrame(x, y);
17427 // overrides Roo.dd.DragDrop
17428 b4EndDrag: function(e) {
17429 Roo.fly(this.getDragEl()).hide();
17432 // overrides Roo.dd.DragDrop
17433 // By default we try to move the element to the last location of the frame.
17434 // This is so that the default behavior mirrors that of Roo.dd.DD.
17435 endDrag: function(e) {
17437 var lel = this.getEl();
17438 var del = this.getDragEl();
17440 // Show the drag frame briefly so we can get its position
17441 del.style.visibility = "";
17444 // Hide the linked element before the move to get around a Safari
17446 lel.style.visibility = "hidden";
17447 Roo.dd.DDM.moveToEl(lel, del);
17448 del.style.visibility = "hidden";
17449 lel.style.visibility = "";
17454 beforeMove : function(){
17458 afterDrag : function(){
17462 toString: function() {
17463 return ("DDProxy " + this.id);
17469 * Ext JS Library 1.1.1
17470 * Copyright(c) 2006-2007, Ext JS, LLC.
17472 * Originally Released Under LGPL - original licence link has changed is not relivant.
17475 * <script type="text/javascript">
17479 * @class Roo.dd.DDTarget
17480 * A DragDrop implementation that does not move, but can be a drop
17481 * target. You would get the same result by simply omitting implementation
17482 * for the event callbacks, but this way we reduce the processing cost of the
17483 * event listener and the callbacks.
17484 * @extends Roo.dd.DragDrop
17486 * @param {String} id the id of the element that is a drop target
17487 * @param {String} sGroup the group of related DragDrop objects
17488 * @param {object} config an object containing configurable attributes
17489 * Valid properties for DDTarget in addition to those in
17493 Roo.dd.DDTarget = function(id, sGroup, config) {
17495 this.initTarget(id, sGroup, config);
17497 if (config.listeners || config.events) {
17498 Roo.dd.DragDrop.superclass.constructor.call(this, {
17499 listeners : config.listeners || {},
17500 events : config.events || {}
17505 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17506 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17507 toString: function() {
17508 return ("DDTarget " + this.id);
17513 * Ext JS Library 1.1.1
17514 * Copyright(c) 2006-2007, Ext JS, LLC.
17516 * Originally Released Under LGPL - original licence link has changed is not relivant.
17519 * <script type="text/javascript">
17524 * @class Roo.dd.ScrollManager
17525 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17526 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17529 Roo.dd.ScrollManager = function(){
17530 var ddm = Roo.dd.DragDropMgr;
17535 var onStop = function(e){
17540 var triggerRefresh = function(){
17541 if(ddm.dragCurrent){
17542 ddm.refreshCache(ddm.dragCurrent.groups);
17546 var doScroll = function(){
17547 if(ddm.dragCurrent){
17548 var dds = Roo.dd.ScrollManager;
17550 if(proc.el.scroll(proc.dir, dds.increment)){
17554 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17559 var clearProc = function(){
17561 clearInterval(proc.id);
17568 var startProc = function(el, dir){
17572 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17575 var onFire = function(e, isDrop){
17576 if(isDrop || !ddm.dragCurrent){ return; }
17577 var dds = Roo.dd.ScrollManager;
17578 if(!dragEl || dragEl != ddm.dragCurrent){
17579 dragEl = ddm.dragCurrent;
17580 // refresh regions on drag start
17581 dds.refreshCache();
17584 var xy = Roo.lib.Event.getXY(e);
17585 var pt = new Roo.lib.Point(xy[0], xy[1]);
17586 for(var id in els){
17587 var el = els[id], r = el._region;
17588 if(r && r.contains(pt) && el.isScrollable()){
17589 if(r.bottom - pt.y <= dds.thresh){
17591 startProc(el, "down");
17594 }else if(r.right - pt.x <= dds.thresh){
17596 startProc(el, "left");
17599 }else if(pt.y - r.top <= dds.thresh){
17601 startProc(el, "up");
17604 }else if(pt.x - r.left <= dds.thresh){
17606 startProc(el, "right");
17615 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17616 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17620 * Registers new overflow element(s) to auto scroll
17621 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17623 register : function(el){
17624 if(el instanceof Array){
17625 for(var i = 0, len = el.length; i < len; i++) {
17626 this.register(el[i]);
17635 * Unregisters overflow element(s) so they are no longer scrolled
17636 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17638 unregister : function(el){
17639 if(el instanceof Array){
17640 for(var i = 0, len = el.length; i < len; i++) {
17641 this.unregister(el[i]);
17650 * The number of pixels from the edge of a container the pointer needs to be to
17651 * trigger scrolling (defaults to 25)
17657 * The number of pixels to scroll in each scroll increment (defaults to 50)
17663 * The frequency of scrolls in milliseconds (defaults to 500)
17669 * True to animate the scroll (defaults to true)
17675 * The animation duration in seconds -
17676 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17682 * Manually trigger a cache refresh.
17684 refreshCache : function(){
17685 for(var id in els){
17686 if(typeof els[id] == 'object'){ // for people extending the object prototype
17687 els[id]._region = els[id].getRegion();
17694 * Ext JS Library 1.1.1
17695 * Copyright(c) 2006-2007, Ext JS, LLC.
17697 * Originally Released Under LGPL - original licence link has changed is not relivant.
17700 * <script type="text/javascript">
17705 * @class Roo.dd.Registry
17706 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17707 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17710 Roo.dd.Registry = function(){
17713 var autoIdSeed = 0;
17715 var getId = function(el, autogen){
17716 if(typeof el == "string"){
17720 if(!id && autogen !== false){
17721 id = "roodd-" + (++autoIdSeed);
17729 * Register a drag drop element
17730 * @param {String|HTMLElement} element The id or DOM node to register
17731 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17732 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17733 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17734 * populated in the data object (if applicable):
17736 Value Description<br />
17737 --------- ------------------------------------------<br />
17738 handles Array of DOM nodes that trigger dragging<br />
17739 for the element being registered<br />
17740 isHandle True if the element passed in triggers<br />
17741 dragging itself, else false
17744 register : function(el, data){
17746 if(typeof el == "string"){
17747 el = document.getElementById(el);
17750 elements[getId(el)] = data;
17751 if(data.isHandle !== false){
17752 handles[data.ddel.id] = data;
17755 var hs = data.handles;
17756 for(var i = 0, len = hs.length; i < len; i++){
17757 handles[getId(hs[i])] = data;
17763 * Unregister a drag drop element
17764 * @param {String|HTMLElement} element The id or DOM node to unregister
17766 unregister : function(el){
17767 var id = getId(el, false);
17768 var data = elements[id];
17770 delete elements[id];
17772 var hs = data.handles;
17773 for(var i = 0, len = hs.length; i < len; i++){
17774 delete handles[getId(hs[i], false)];
17781 * Returns the handle registered for a DOM Node by id
17782 * @param {String|HTMLElement} id The DOM node or id to look up
17783 * @return {Object} handle The custom handle data
17785 getHandle : function(id){
17786 if(typeof id != "string"){ // must be element?
17789 return handles[id];
17793 * Returns the handle that is registered for the DOM node that is the target of the event
17794 * @param {Event} e The event
17795 * @return {Object} handle The custom handle data
17797 getHandleFromEvent : function(e){
17798 var t = Roo.lib.Event.getTarget(e);
17799 return t ? handles[t.id] : null;
17803 * Returns a custom data object that is registered for a DOM node by id
17804 * @param {String|HTMLElement} id The DOM node or id to look up
17805 * @return {Object} data The custom data
17807 getTarget : function(id){
17808 if(typeof id != "string"){ // must be element?
17811 return elements[id];
17815 * Returns a custom data object that is registered for the DOM node that is the target of the event
17816 * @param {Event} e The event
17817 * @return {Object} data The custom data
17819 getTargetFromEvent : function(e){
17820 var t = Roo.lib.Event.getTarget(e);
17821 return t ? elements[t.id] || handles[t.id] : null;
17826 * Ext JS Library 1.1.1
17827 * Copyright(c) 2006-2007, Ext JS, LLC.
17829 * Originally Released Under LGPL - original licence link has changed is not relivant.
17832 * <script type="text/javascript">
17837 * @class Roo.dd.StatusProxy
17838 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17839 * default drag proxy used by all Roo.dd components.
17841 * @param {Object} config
17843 Roo.dd.StatusProxy = function(config){
17844 Roo.apply(this, config);
17845 this.id = this.id || Roo.id();
17846 this.el = new Roo.Layer({
17848 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17849 {tag: "div", cls: "x-dd-drop-icon"},
17850 {tag: "div", cls: "x-dd-drag-ghost"}
17853 shadow: !config || config.shadow !== false
17855 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17856 this.dropStatus = this.dropNotAllowed;
17859 Roo.dd.StatusProxy.prototype = {
17861 * @cfg {String} dropAllowed
17862 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17864 dropAllowed : "x-dd-drop-ok",
17866 * @cfg {String} dropNotAllowed
17867 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17869 dropNotAllowed : "x-dd-drop-nodrop",
17872 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17873 * over the current target element.
17874 * @param {String} cssClass The css class for the new drop status indicator image
17876 setStatus : function(cssClass){
17877 cssClass = cssClass || this.dropNotAllowed;
17878 if(this.dropStatus != cssClass){
17879 this.el.replaceClass(this.dropStatus, cssClass);
17880 this.dropStatus = cssClass;
17885 * Resets the status indicator to the default dropNotAllowed value
17886 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17888 reset : function(clearGhost){
17889 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17890 this.dropStatus = this.dropNotAllowed;
17892 this.ghost.update("");
17897 * Updates the contents of the ghost element
17898 * @param {String} html The html that will replace the current innerHTML of the ghost element
17900 update : function(html){
17901 if(typeof html == "string"){
17902 this.ghost.update(html);
17904 this.ghost.update("");
17905 html.style.margin = "0";
17906 this.ghost.dom.appendChild(html);
17908 // ensure float = none set?? cant remember why though.
17909 var el = this.ghost.dom.firstChild;
17911 Roo.fly(el).setStyle('float', 'none');
17916 * Returns the underlying proxy {@link Roo.Layer}
17917 * @return {Roo.Layer} el
17919 getEl : function(){
17924 * Returns the ghost element
17925 * @return {Roo.Element} el
17927 getGhost : function(){
17933 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17935 hide : function(clear){
17943 * Stops the repair animation if it's currently running
17946 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17952 * Displays this proxy
17959 * Force the Layer to sync its shadow and shim positions to the element
17966 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17967 * invalid drop operation by the item being dragged.
17968 * @param {Array} xy The XY position of the element ([x, y])
17969 * @param {Function} callback The function to call after the repair is complete
17970 * @param {Object} scope The scope in which to execute the callback
17972 repair : function(xy, callback, scope){
17973 this.callback = callback;
17974 this.scope = scope;
17975 if(xy && this.animRepair !== false){
17976 this.el.addClass("x-dd-drag-repair");
17977 this.el.hideUnders(true);
17978 this.anim = this.el.shift({
17979 duration: this.repairDuration || .5,
17983 callback: this.afterRepair,
17987 this.afterRepair();
17992 afterRepair : function(){
17994 if(typeof this.callback == "function"){
17995 this.callback.call(this.scope || this);
17997 this.callback = null;
18002 * Ext JS Library 1.1.1
18003 * Copyright(c) 2006-2007, Ext JS, LLC.
18005 * Originally Released Under LGPL - original licence link has changed is not relivant.
18008 * <script type="text/javascript">
18012 * @class Roo.dd.DragSource
18013 * @extends Roo.dd.DDProxy
18014 * A simple class that provides the basic implementation needed to make any element draggable.
18016 * @param {String/HTMLElement/Element} el The container element
18017 * @param {Object} config
18019 Roo.dd.DragSource = function(el, config){
18020 this.el = Roo.get(el);
18021 this.dragData = {};
18023 Roo.apply(this, config);
18026 this.proxy = new Roo.dd.StatusProxy();
18029 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18030 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
18032 this.dragging = false;
18035 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
18037 * @cfg {String} dropAllowed
18038 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18040 dropAllowed : "x-dd-drop-ok",
18042 * @cfg {String} dropNotAllowed
18043 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18045 dropNotAllowed : "x-dd-drop-nodrop",
18048 * Returns the data object associated with this drag source
18049 * @return {Object} data An object containing arbitrary data
18051 getDragData : function(e){
18052 return this.dragData;
18056 onDragEnter : function(e, id){
18057 var target = Roo.dd.DragDropMgr.getDDById(id);
18058 this.cachedTarget = target;
18059 if(this.beforeDragEnter(target, e, id) !== false){
18060 if(target.isNotifyTarget){
18061 var status = target.notifyEnter(this, e, this.dragData);
18062 this.proxy.setStatus(status);
18064 this.proxy.setStatus(this.dropAllowed);
18067 if(this.afterDragEnter){
18069 * An empty function by default, but provided so that you can perform a custom action
18070 * when the dragged item enters the drop target by providing an implementation.
18071 * @param {Roo.dd.DragDrop} target The drop target
18072 * @param {Event} e The event object
18073 * @param {String} id The id of the dragged element
18074 * @method afterDragEnter
18076 this.afterDragEnter(target, e, id);
18082 * An empty function by default, but provided so that you can perform a custom action
18083 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
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 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18089 beforeDragEnter : function(target, e, id){
18094 alignElWithMouse: function() {
18095 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18100 onDragOver : function(e, id){
18101 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18102 if(this.beforeDragOver(target, e, id) !== false){
18103 if(target.isNotifyTarget){
18104 var status = target.notifyOver(this, e, this.dragData);
18105 this.proxy.setStatus(status);
18108 if(this.afterDragOver){
18110 * An empty function by default, but provided so that you can perform a custom action
18111 * while the dragged item is over the drop target by providing an implementation.
18112 * @param {Roo.dd.DragDrop} target The drop target
18113 * @param {Event} e The event object
18114 * @param {String} id The id of the dragged element
18115 * @method afterDragOver
18117 this.afterDragOver(target, e, id);
18123 * An empty function by default, but provided so that you can perform a custom action
18124 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18125 * @param {Roo.dd.DragDrop} target The drop target
18126 * @param {Event} e The event object
18127 * @param {String} id The id of the dragged element
18128 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18130 beforeDragOver : function(target, e, id){
18135 onDragOut : function(e, id){
18136 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18137 if(this.beforeDragOut(target, e, id) !== false){
18138 if(target.isNotifyTarget){
18139 target.notifyOut(this, e, this.dragData);
18141 this.proxy.reset();
18142 if(this.afterDragOut){
18144 * An empty function by default, but provided so that you can perform a custom action
18145 * after the dragged item is dragged out of the target without dropping.
18146 * @param {Roo.dd.DragDrop} target The drop target
18147 * @param {Event} e The event object
18148 * @param {String} id The id of the dragged element
18149 * @method afterDragOut
18151 this.afterDragOut(target, e, id);
18154 this.cachedTarget = null;
18158 * An empty function by default, but provided so that you can perform a custom action before the dragged
18159 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18160 * @param {Roo.dd.DragDrop} target The drop target
18161 * @param {Event} e The event object
18162 * @param {String} id The id of the dragged element
18163 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18165 beforeDragOut : function(target, e, id){
18170 onDragDrop : function(e, id){
18171 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18172 if(this.beforeDragDrop(target, e, id) !== false){
18173 if(target.isNotifyTarget){
18174 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18175 this.onValidDrop(target, e, id);
18177 this.onInvalidDrop(target, e, id);
18180 this.onValidDrop(target, e, id);
18183 if(this.afterDragDrop){
18185 * An empty function by default, but provided so that you can perform a custom action
18186 * after a valid drag drop has occurred by providing an implementation.
18187 * @param {Roo.dd.DragDrop} target The drop target
18188 * @param {Event} e The event object
18189 * @param {String} id The id of the dropped element
18190 * @method afterDragDrop
18192 this.afterDragDrop(target, e, id);
18195 delete this.cachedTarget;
18199 * An empty function by default, but provided so that you can perform a custom action before the dragged
18200 * item is dropped onto the target and optionally cancel the onDragDrop.
18201 * @param {Roo.dd.DragDrop} target The drop target
18202 * @param {Event} e The event object
18203 * @param {String} id The id of the dragged element
18204 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18206 beforeDragDrop : function(target, e, id){
18211 onValidDrop : function(target, e, id){
18213 if(this.afterValidDrop){
18215 * An empty function by default, but provided so that you can perform a custom action
18216 * after a valid drop has occurred by providing an implementation.
18217 * @param {Object} target The target DD
18218 * @param {Event} e The event object
18219 * @param {String} id The id of the dropped element
18220 * @method afterInvalidDrop
18222 this.afterValidDrop(target, e, id);
18227 getRepairXY : function(e, data){
18228 return this.el.getXY();
18232 onInvalidDrop : function(target, e, id){
18233 this.beforeInvalidDrop(target, e, id);
18234 if(this.cachedTarget){
18235 if(this.cachedTarget.isNotifyTarget){
18236 this.cachedTarget.notifyOut(this, e, this.dragData);
18238 this.cacheTarget = null;
18240 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18242 if(this.afterInvalidDrop){
18244 * An empty function by default, but provided so that you can perform a custom action
18245 * after an invalid drop has occurred by providing an implementation.
18246 * @param {Event} e The event object
18247 * @param {String} id The id of the dropped element
18248 * @method afterInvalidDrop
18250 this.afterInvalidDrop(e, id);
18255 afterRepair : function(){
18257 this.el.highlight(this.hlColor || "c3daf9");
18259 this.dragging = false;
18263 * An empty function by default, but provided so that you can perform a custom action after an invalid
18264 * drop has occurred.
18265 * @param {Roo.dd.DragDrop} target The drop target
18266 * @param {Event} e The event object
18267 * @param {String} id The id of the dragged element
18268 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18270 beforeInvalidDrop : function(target, e, id){
18275 handleMouseDown : function(e){
18276 if(this.dragging) {
18279 var data = this.getDragData(e);
18280 if(data && this.onBeforeDrag(data, e) !== false){
18281 this.dragData = data;
18283 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18288 * An empty function by default, but provided so that you can perform a custom action before the initial
18289 * drag event begins and optionally cancel it.
18290 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18291 * @param {Event} e The event object
18292 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18294 onBeforeDrag : function(data, e){
18299 * An empty function by default, but provided so that you can perform a custom action once the initial
18300 * drag event has begun. The drag cannot be canceled from this function.
18301 * @param {Number} x The x position of the click on the dragged object
18302 * @param {Number} y The y position of the click on the dragged object
18304 onStartDrag : Roo.emptyFn,
18306 // private - YUI override
18307 startDrag : function(x, y){
18308 this.proxy.reset();
18309 this.dragging = true;
18310 this.proxy.update("");
18311 this.onInitDrag(x, y);
18316 onInitDrag : function(x, y){
18317 var clone = this.el.dom.cloneNode(true);
18318 clone.id = Roo.id(); // prevent duplicate ids
18319 this.proxy.update(clone);
18320 this.onStartDrag(x, y);
18325 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18326 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18328 getProxy : function(){
18333 * Hides the drag source's {@link Roo.dd.StatusProxy}
18335 hideProxy : function(){
18337 this.proxy.reset(true);
18338 this.dragging = false;
18342 triggerCacheRefresh : function(){
18343 Roo.dd.DDM.refreshCache(this.groups);
18346 // private - override to prevent hiding
18347 b4EndDrag: function(e) {
18350 // private - override to prevent moving
18351 endDrag : function(e){
18352 this.onEndDrag(this.dragData, e);
18356 onEndDrag : function(data, e){
18359 // private - pin to cursor
18360 autoOffset : function(x, y) {
18361 this.setDelta(-12, -20);
18365 * Ext JS Library 1.1.1
18366 * Copyright(c) 2006-2007, Ext JS, LLC.
18368 * Originally Released Under LGPL - original licence link has changed is not relivant.
18371 * <script type="text/javascript">
18376 * @class Roo.dd.DropTarget
18377 * @extends Roo.dd.DDTarget
18378 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18379 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18381 * @param {String/HTMLElement/Element} el The container element
18382 * @param {Object} config
18384 Roo.dd.DropTarget = function(el, config){
18385 this.el = Roo.get(el);
18387 var listeners = false; ;
18388 if (config && config.listeners) {
18389 listeners= config.listeners;
18390 delete config.listeners;
18392 Roo.apply(this, config);
18394 if(this.containerScroll){
18395 Roo.dd.ScrollManager.register(this.el);
18399 * @scope Roo.dd.DropTarget
18404 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18405 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18406 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18408 * IMPORTANT : it should set this.overClass and this.dropAllowed
18410 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18411 * @param {Event} e The event
18412 * @param {Object} data An object containing arbitrary data supplied by the drag source
18418 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18419 * This method will be called on every mouse movement while the drag source is over the drop target.
18420 * This default implementation simply returns the dropAllowed config value.
18422 * IMPORTANT : it should set this.dropAllowed
18424 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18425 * @param {Event} e The event
18426 * @param {Object} data An object containing arbitrary data supplied by the drag source
18432 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18433 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18434 * overClass (if any) from the drop element.
18435 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18436 * @param {Event} e The event
18437 * @param {Object} data An object containing arbitrary data supplied by the drag source
18443 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18444 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18445 * implementation that does something to process the drop event and returns true so that the drag source's
18446 * repair action does not run.
18448 * IMPORTANT : it should set this.success
18450 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18451 * @param {Event} e The event
18452 * @param {Object} data An object containing arbitrary data supplied by the drag source
18458 Roo.dd.DropTarget.superclass.constructor.call( this,
18460 this.ddGroup || this.group,
18463 listeners : listeners || {}
18471 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18473 * @cfg {String} overClass
18474 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18477 * @cfg {String} ddGroup
18478 * The drag drop group to handle drop events for
18482 * @cfg {String} dropAllowed
18483 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18485 dropAllowed : "x-dd-drop-ok",
18487 * @cfg {String} dropNotAllowed
18488 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18490 dropNotAllowed : "x-dd-drop-nodrop",
18492 * @cfg {boolean} success
18493 * set this after drop listener..
18497 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
18498 * if the drop point is valid for over/enter..
18505 isNotifyTarget : true,
18510 notifyEnter : function(dd, e, data)
18513 this.fireEvent('enter', dd, e, data);
18514 if(this.overClass){
18515 this.el.addClass(this.overClass);
18517 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18518 this.valid ? this.dropAllowed : this.dropNotAllowed
18525 notifyOver : function(dd, e, data)
18528 this.fireEvent('over', dd, e, data);
18529 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18530 this.valid ? this.dropAllowed : this.dropNotAllowed
18537 notifyOut : function(dd, e, data)
18539 this.fireEvent('out', dd, e, data);
18540 if(this.overClass){
18541 this.el.removeClass(this.overClass);
18548 notifyDrop : function(dd, e, data)
18550 this.success = false;
18551 this.fireEvent('drop', dd, e, data);
18552 return this.success;
18556 * Ext JS Library 1.1.1
18557 * Copyright(c) 2006-2007, Ext JS, LLC.
18559 * Originally Released Under LGPL - original licence link has changed is not relivant.
18562 * <script type="text/javascript">
18567 * @class Roo.dd.DragZone
18568 * @extends Roo.dd.DragSource
18569 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18570 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18572 * @param {String/HTMLElement/Element} el The container element
18573 * @param {Object} config
18575 Roo.dd.DragZone = function(el, config){
18576 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18577 if(this.containerScroll){
18578 Roo.dd.ScrollManager.register(this.el);
18582 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18584 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18585 * for auto scrolling during drag operations.
18588 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18589 * method after a failed drop (defaults to "c3daf9" - light blue)
18593 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18594 * for a valid target to drag based on the mouse down. Override this method
18595 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18596 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18597 * @param {EventObject} e The mouse down event
18598 * @return {Object} The dragData
18600 getDragData : function(e){
18601 return Roo.dd.Registry.getHandleFromEvent(e);
18605 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18606 * this.dragData.ddel
18607 * @param {Number} x The x position of the click on the dragged object
18608 * @param {Number} y The y position of the click on the dragged object
18609 * @return {Boolean} true to continue the drag, false to cancel
18611 onInitDrag : function(x, y){
18612 this.proxy.update(this.dragData.ddel.cloneNode(true));
18613 this.onStartDrag(x, y);
18618 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18620 afterRepair : function(){
18622 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18624 this.dragging = false;
18628 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18629 * the XY of this.dragData.ddel
18630 * @param {EventObject} e The mouse up event
18631 * @return {Array} The xy location (e.g. [100, 200])
18633 getRepairXY : function(e){
18634 return Roo.Element.fly(this.dragData.ddel).getXY();
18638 * Ext JS Library 1.1.1
18639 * Copyright(c) 2006-2007, Ext JS, LLC.
18641 * Originally Released Under LGPL - original licence link has changed is not relivant.
18644 * <script type="text/javascript">
18647 * @class Roo.dd.DropZone
18648 * @extends Roo.dd.DropTarget
18649 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18650 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18652 * @param {String/HTMLElement/Element} el The container element
18653 * @param {Object} config
18655 Roo.dd.DropZone = function(el, config){
18656 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18659 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18661 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18662 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18663 * provide your own custom lookup.
18664 * @param {Event} e The event
18665 * @return {Object} data The custom data
18667 getTargetFromEvent : function(e){
18668 return Roo.dd.Registry.getTargetFromEvent(e);
18672 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18673 * that it has registered. This method has no default implementation and should be overridden to provide
18674 * node-specific processing if necessary.
18675 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18676 * {@link #getTargetFromEvent} for this node)
18677 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18678 * @param {Event} e The event
18679 * @param {Object} data An object containing arbitrary data supplied by the drag source
18681 onNodeEnter : function(n, dd, e, data){
18686 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18687 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18688 * overridden to provide the proper feedback.
18689 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18690 * {@link #getTargetFromEvent} for this node)
18691 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18692 * @param {Event} e The event
18693 * @param {Object} data An object containing arbitrary data supplied by the drag source
18694 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18695 * underlying {@link Roo.dd.StatusProxy} can be updated
18697 onNodeOver : function(n, dd, e, data){
18698 return this.dropAllowed;
18702 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18703 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18704 * node-specific processing if necessary.
18705 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18706 * {@link #getTargetFromEvent} for this node)
18707 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18708 * @param {Event} e The event
18709 * @param {Object} data An object containing arbitrary data supplied by the drag source
18711 onNodeOut : function(n, dd, e, data){
18716 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18717 * the drop node. The default implementation returns false, so it should be overridden to provide the
18718 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18719 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18720 * {@link #getTargetFromEvent} for this node)
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 onNodeDrop : function(n, dd, e, data){
18731 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18732 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18733 * it should be overridden to provide the proper feedback if necessary.
18734 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18735 * @param {Event} e The event
18736 * @param {Object} data An object containing arbitrary data supplied by the drag source
18737 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18738 * underlying {@link Roo.dd.StatusProxy} can be updated
18740 onContainerOver : function(dd, e, data){
18741 return this.dropNotAllowed;
18745 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18746 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18747 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18748 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18749 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18750 * @param {Event} e The event
18751 * @param {Object} data An object containing arbitrary data supplied by the drag source
18752 * @return {Boolean} True if the drop was valid, else false
18754 onContainerDrop : function(dd, e, data){
18759 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18760 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18761 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18762 * you should override this method and provide a custom implementation.
18763 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18764 * @param {Event} e The event
18765 * @param {Object} data An object containing arbitrary data supplied by the drag source
18766 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18767 * underlying {@link Roo.dd.StatusProxy} can be updated
18769 notifyEnter : function(dd, e, data){
18770 return this.dropNotAllowed;
18774 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18775 * This method will be called on every mouse movement while the drag source is over the drop zone.
18776 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18777 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18778 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18779 * registered node, it will call {@link #onContainerOver}.
18780 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18781 * @param {Event} e The event
18782 * @param {Object} data An object containing arbitrary data supplied by the drag source
18783 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18784 * underlying {@link Roo.dd.StatusProxy} can be updated
18786 notifyOver : function(dd, e, data){
18787 var n = this.getTargetFromEvent(e);
18788 if(!n){ // not over valid drop target
18789 if(this.lastOverNode){
18790 this.onNodeOut(this.lastOverNode, dd, e, data);
18791 this.lastOverNode = null;
18793 return this.onContainerOver(dd, e, data);
18795 if(this.lastOverNode != n){
18796 if(this.lastOverNode){
18797 this.onNodeOut(this.lastOverNode, dd, e, data);
18799 this.onNodeEnter(n, dd, e, data);
18800 this.lastOverNode = n;
18802 return this.onNodeOver(n, dd, e, data);
18806 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18807 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18808 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18809 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18810 * @param {Event} e The event
18811 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18813 notifyOut : function(dd, e, data){
18814 if(this.lastOverNode){
18815 this.onNodeOut(this.lastOverNode, dd, e, data);
18816 this.lastOverNode = null;
18821 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18822 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18823 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18824 * otherwise it will call {@link #onContainerDrop}.
18825 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18826 * @param {Event} e The event
18827 * @param {Object} data An object containing arbitrary data supplied by the drag source
18828 * @return {Boolean} True if the drop was valid, else false
18830 notifyDrop : function(dd, e, data){
18831 if(this.lastOverNode){
18832 this.onNodeOut(this.lastOverNode, dd, e, data);
18833 this.lastOverNode = null;
18835 var n = this.getTargetFromEvent(e);
18837 this.onNodeDrop(n, dd, e, data) :
18838 this.onContainerDrop(dd, e, data);
18842 triggerCacheRefresh : function(){
18843 Roo.dd.DDM.refreshCache(this.groups);
18847 * Ext JS Library 1.1.1
18848 * Copyright(c) 2006-2007, Ext JS, LLC.
18850 * Originally Released Under LGPL - original licence link has changed is not relivant.
18853 * <script type="text/javascript">
18858 * @class Roo.data.SortTypes
18860 * Defines the default sorting (casting?) comparison functions used when sorting data.
18862 Roo.data.SortTypes = {
18864 * Default sort that does nothing
18865 * @param {Mixed} s The value being converted
18866 * @return {Mixed} The comparison value
18868 none : function(s){
18873 * The regular expression used to strip tags
18877 stripTagsRE : /<\/?[^>]+>/gi,
18880 * Strips all HTML tags to sort on text only
18881 * @param {Mixed} s The value being converted
18882 * @return {String} The comparison value
18884 asText : function(s){
18885 return String(s).replace(this.stripTagsRE, "");
18889 * Strips all HTML tags to sort on text only - Case insensitive
18890 * @param {Mixed} s The value being converted
18891 * @return {String} The comparison value
18893 asUCText : function(s){
18894 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18898 * Case insensitive string
18899 * @param {Mixed} s The value being converted
18900 * @return {String} The comparison value
18902 asUCString : function(s) {
18903 return String(s).toUpperCase();
18908 * @param {Mixed} s The value being converted
18909 * @return {Number} The comparison value
18911 asDate : function(s) {
18915 if(s instanceof Date){
18916 return s.getTime();
18918 return Date.parse(String(s));
18923 * @param {Mixed} s The value being converted
18924 * @return {Float} The comparison value
18926 asFloat : function(s) {
18927 var val = parseFloat(String(s).replace(/,/g, ""));
18928 if(isNaN(val)) val = 0;
18934 * @param {Mixed} s The value being converted
18935 * @return {Number} The comparison value
18937 asInt : function(s) {
18938 var val = parseInt(String(s).replace(/,/g, ""));
18939 if(isNaN(val)) val = 0;
18944 * Ext JS Library 1.1.1
18945 * Copyright(c) 2006-2007, Ext JS, LLC.
18947 * Originally Released Under LGPL - original licence link has changed is not relivant.
18950 * <script type="text/javascript">
18954 * @class Roo.data.Record
18955 * Instances of this class encapsulate both record <em>definition</em> information, and record
18956 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18957 * to access Records cached in an {@link Roo.data.Store} object.<br>
18959 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18960 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18963 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18965 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18966 * {@link #create}. The parameters are the same.
18967 * @param {Array} data An associative Array of data values keyed by the field name.
18968 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18969 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18970 * not specified an integer id is generated.
18972 Roo.data.Record = function(data, id){
18973 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18978 * Generate a constructor for a specific record layout.
18979 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18980 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18981 * Each field definition object may contain the following properties: <ul>
18982 * <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,
18983 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18984 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18985 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18986 * is being used, then this is a string containing the javascript expression to reference the data relative to
18987 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18988 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18989 * this may be omitted.</p></li>
18990 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18991 * <ul><li>auto (Default, implies no conversion)</li>
18996 * <li>date</li></ul></p></li>
18997 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18998 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18999 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
19000 * by the Reader into an object that will be stored in the Record. It is passed the
19001 * following parameters:<ul>
19002 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
19004 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
19006 * <br>usage:<br><pre><code>
19007 var TopicRecord = Roo.data.Record.create(
19008 {name: 'title', mapping: 'topic_title'},
19009 {name: 'author', mapping: 'username'},
19010 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
19011 {name: 'lastPost', mapping: 'post_time', type: 'date'},
19012 {name: 'lastPoster', mapping: 'user2'},
19013 {name: 'excerpt', mapping: 'post_text'}
19016 var myNewRecord = new TopicRecord({
19017 title: 'Do my job please',
19020 lastPost: new Date(),
19021 lastPoster: 'Animal',
19022 excerpt: 'No way dude!'
19024 myStore.add(myNewRecord);
19029 Roo.data.Record.create = function(o){
19030 var f = function(){
19031 f.superclass.constructor.apply(this, arguments);
19033 Roo.extend(f, Roo.data.Record);
19034 var p = f.prototype;
19035 p.fields = new Roo.util.MixedCollection(false, function(field){
19038 for(var i = 0, len = o.length; i < len; i++){
19039 p.fields.add(new Roo.data.Field(o[i]));
19041 f.getField = function(name){
19042 return p.fields.get(name);
19047 Roo.data.Record.AUTO_ID = 1000;
19048 Roo.data.Record.EDIT = 'edit';
19049 Roo.data.Record.REJECT = 'reject';
19050 Roo.data.Record.COMMIT = 'commit';
19052 Roo.data.Record.prototype = {
19054 * Readonly flag - true if this record has been modified.
19063 join : function(store){
19064 this.store = store;
19068 * Set the named field to the specified value.
19069 * @param {String} name The name of the field to set.
19070 * @param {Object} value The value to set the field to.
19072 set : function(name, value){
19073 if(this.data[name] == value){
19077 if(!this.modified){
19078 this.modified = {};
19080 if(typeof this.modified[name] == 'undefined'){
19081 this.modified[name] = this.data[name];
19083 this.data[name] = value;
19084 if(!this.editing && this.store){
19085 this.store.afterEdit(this);
19090 * Get the value of the named field.
19091 * @param {String} name The name of the field to get the value of.
19092 * @return {Object} The value of the field.
19094 get : function(name){
19095 return this.data[name];
19099 beginEdit : function(){
19100 this.editing = true;
19101 this.modified = {};
19105 cancelEdit : function(){
19106 this.editing = false;
19107 delete this.modified;
19111 endEdit : function(){
19112 this.editing = false;
19113 if(this.dirty && this.store){
19114 this.store.afterEdit(this);
19119 * Usually called by the {@link Roo.data.Store} which owns the Record.
19120 * Rejects all changes made to the Record since either creation, or the last commit operation.
19121 * Modified fields are reverted to their original values.
19123 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19124 * of reject operations.
19126 reject : function(){
19127 var m = this.modified;
19129 if(typeof m[n] != "function"){
19130 this.data[n] = m[n];
19133 this.dirty = false;
19134 delete this.modified;
19135 this.editing = false;
19137 this.store.afterReject(this);
19142 * Usually called by the {@link Roo.data.Store} which owns the Record.
19143 * Commits all changes made to the Record since either creation, or the last commit operation.
19145 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19146 * of commit operations.
19148 commit : function(){
19149 this.dirty = false;
19150 delete this.modified;
19151 this.editing = false;
19153 this.store.afterCommit(this);
19158 hasError : function(){
19159 return this.error != null;
19163 clearError : function(){
19168 * Creates a copy of this record.
19169 * @param {String} id (optional) A new record id if you don't want to use this record's id
19172 copy : function(newId) {
19173 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19177 * Ext JS Library 1.1.1
19178 * Copyright(c) 2006-2007, Ext JS, LLC.
19180 * Originally Released Under LGPL - original licence link has changed is not relivant.
19183 * <script type="text/javascript">
19189 * @class Roo.data.Store
19190 * @extends Roo.util.Observable
19191 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19192 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19194 * 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
19195 * has no knowledge of the format of the data returned by the Proxy.<br>
19197 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19198 * instances from the data object. These records are cached and made available through accessor functions.
19200 * Creates a new Store.
19201 * @param {Object} config A config object containing the objects needed for the Store to access data,
19202 * and read the data into Records.
19204 Roo.data.Store = function(config){
19205 this.data = new Roo.util.MixedCollection(false);
19206 this.data.getKey = function(o){
19209 this.baseParams = {};
19211 this.paramNames = {
19216 "multisort" : "_multisort"
19219 if(config && config.data){
19220 this.inlineData = config.data;
19221 delete config.data;
19224 Roo.apply(this, config);
19226 if(this.reader){ // reader passed
19227 this.reader = Roo.factory(this.reader, Roo.data);
19228 this.reader.xmodule = this.xmodule || false;
19229 if(!this.recordType){
19230 this.recordType = this.reader.recordType;
19232 if(this.reader.onMetaChange){
19233 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19237 if(this.recordType){
19238 this.fields = this.recordType.prototype.fields;
19240 this.modified = [];
19244 * @event datachanged
19245 * Fires when the data cache has changed, and a widget which is using this Store
19246 * as a Record cache should refresh its view.
19247 * @param {Store} this
19249 datachanged : true,
19251 * @event metachange
19252 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19253 * @param {Store} this
19254 * @param {Object} meta The JSON metadata
19259 * Fires when Records have been added to the Store
19260 * @param {Store} this
19261 * @param {Roo.data.Record[]} records The array of Records added
19262 * @param {Number} index The index at which the record(s) were added
19267 * Fires when a Record has been removed from the Store
19268 * @param {Store} this
19269 * @param {Roo.data.Record} record The Record that was removed
19270 * @param {Number} index The index at which the record was removed
19275 * Fires when a Record has been updated
19276 * @param {Store} this
19277 * @param {Roo.data.Record} record The Record that was updated
19278 * @param {String} operation The update operation being performed. Value may be one of:
19280 Roo.data.Record.EDIT
19281 Roo.data.Record.REJECT
19282 Roo.data.Record.COMMIT
19288 * Fires when the data cache has been cleared.
19289 * @param {Store} this
19293 * @event beforeload
19294 * Fires before a request is made for a new data object. If the beforeload handler returns false
19295 * the load action will be canceled.
19296 * @param {Store} this
19297 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19302 * Fires after a new set of Records has been loaded.
19303 * @param {Store} this
19304 * @param {Roo.data.Record[]} records The Records that were loaded
19305 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19309 * @event loadexception
19310 * Fires if an exception occurs in the Proxy during loading.
19311 * Called with the signature of the Proxy's "loadexception" event.
19312 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19315 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19316 * @param {Object} load options
19317 * @param {Object} jsonData from your request (normally this contains the Exception)
19319 loadexception : true
19323 this.proxy = Roo.factory(this.proxy, Roo.data);
19324 this.proxy.xmodule = this.xmodule || false;
19325 this.relayEvents(this.proxy, ["loadexception"]);
19327 this.sortToggle = {};
19328 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
19330 Roo.data.Store.superclass.constructor.call(this);
19332 if(this.inlineData){
19333 this.loadData(this.inlineData);
19334 delete this.inlineData;
19337 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19339 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19340 * without a remote query - used by combo/forms at present.
19344 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19347 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19350 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19351 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19354 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19355 * on any HTTP request
19358 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19361 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
19365 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19366 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19368 remoteSort : false,
19371 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19372 * loaded or when a record is removed. (defaults to false).
19374 pruneModifiedRecords : false,
19377 lastOptions : null,
19380 * Add Records to the Store and fires the add event.
19381 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19383 add : function(records){
19384 records = [].concat(records);
19385 for(var i = 0, len = records.length; i < len; i++){
19386 records[i].join(this);
19388 var index = this.data.length;
19389 this.data.addAll(records);
19390 this.fireEvent("add", this, records, index);
19394 * Remove a Record from the Store and fires the remove event.
19395 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19397 remove : function(record){
19398 var index = this.data.indexOf(record);
19399 this.data.removeAt(index);
19400 if(this.pruneModifiedRecords){
19401 this.modified.remove(record);
19403 this.fireEvent("remove", this, record, index);
19407 * Remove all Records from the Store and fires the clear event.
19409 removeAll : function(){
19411 if(this.pruneModifiedRecords){
19412 this.modified = [];
19414 this.fireEvent("clear", this);
19418 * Inserts Records to the Store at the given index and fires the add event.
19419 * @param {Number} index The start index at which to insert the passed Records.
19420 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19422 insert : function(index, records){
19423 records = [].concat(records);
19424 for(var i = 0, len = records.length; i < len; i++){
19425 this.data.insert(index, records[i]);
19426 records[i].join(this);
19428 this.fireEvent("add", this, records, index);
19432 * Get the index within the cache of the passed Record.
19433 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19434 * @return {Number} The index of the passed Record. Returns -1 if not found.
19436 indexOf : function(record){
19437 return this.data.indexOf(record);
19441 * Get the index within the cache of the Record with the passed id.
19442 * @param {String} id The id of the Record to find.
19443 * @return {Number} The index of the Record. Returns -1 if not found.
19445 indexOfId : function(id){
19446 return this.data.indexOfKey(id);
19450 * Get the Record with the specified id.
19451 * @param {String} id The id of the Record to find.
19452 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19454 getById : function(id){
19455 return this.data.key(id);
19459 * Get the Record at the specified index.
19460 * @param {Number} index The index of the Record to find.
19461 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19463 getAt : function(index){
19464 return this.data.itemAt(index);
19468 * Returns a range of Records between specified indices.
19469 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19470 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19471 * @return {Roo.data.Record[]} An array of Records
19473 getRange : function(start, end){
19474 return this.data.getRange(start, end);
19478 storeOptions : function(o){
19479 o = Roo.apply({}, o);
19482 this.lastOptions = o;
19486 * Loads the Record cache from the configured Proxy using the configured Reader.
19488 * If using remote paging, then the first load call must specify the <em>start</em>
19489 * and <em>limit</em> properties in the options.params property to establish the initial
19490 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19492 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19493 * and this call will return before the new data has been loaded. Perform any post-processing
19494 * in a callback function, or in a "load" event handler.</strong>
19496 * @param {Object} options An object containing properties which control loading options:<ul>
19497 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19498 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19499 * passed the following arguments:<ul>
19500 * <li>r : Roo.data.Record[]</li>
19501 * <li>options: Options object from the load call</li>
19502 * <li>success: Boolean success indicator</li></ul></li>
19503 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19504 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19507 load : function(options){
19508 options = options || {};
19509 if(this.fireEvent("beforeload", this, options) !== false){
19510 this.storeOptions(options);
19511 var p = Roo.apply(options.params || {}, this.baseParams);
19512 // if meta was not loaded from remote source.. try requesting it.
19513 if (!this.reader.metaFromRemote) {
19514 p._requestMeta = 1;
19516 if(this.sortInfo && this.remoteSort){
19517 var pn = this.paramNames;
19518 p[pn["sort"]] = this.sortInfo.field;
19519 p[pn["dir"]] = this.sortInfo.direction;
19521 if (this.multiSort) {
19522 var pn = this.paramNames;
19523 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
19526 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19531 * Reloads the Record cache from the configured Proxy using the configured Reader and
19532 * the options from the last load operation performed.
19533 * @param {Object} options (optional) An object containing properties which may override the options
19534 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19535 * the most recently used options are reused).
19537 reload : function(options){
19538 this.load(Roo.applyIf(options||{}, this.lastOptions));
19542 // Called as a callback by the Reader during a load operation.
19543 loadRecords : function(o, options, success){
19544 if(!o || success === false){
19545 if(success !== false){
19546 this.fireEvent("load", this, [], options);
19548 if(options.callback){
19549 options.callback.call(options.scope || this, [], options, false);
19553 // if data returned failure - throw an exception.
19554 if (o.success === false) {
19555 // show a message if no listener is registered.
19556 if (!this.hasListener('loadexception') && typeof(this.reader.jsonData.errorMsg) != 'undefined') {
19557 Roo.MessageBox.alert("Error loading",this.reader.jsonData.errorMsg);
19559 // loadmask wil be hooked into this..
19560 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19563 var r = o.records, t = o.totalRecords || r.length;
19564 if(!options || options.add !== true){
19565 if(this.pruneModifiedRecords){
19566 this.modified = [];
19568 for(var i = 0, len = r.length; i < len; i++){
19572 this.data = this.snapshot;
19573 delete this.snapshot;
19576 this.data.addAll(r);
19577 this.totalLength = t;
19579 this.fireEvent("datachanged", this);
19581 this.totalLength = Math.max(t, this.data.length+r.length);
19584 this.fireEvent("load", this, r, options);
19585 if(options.callback){
19586 options.callback.call(options.scope || this, r, options, true);
19592 * Loads data from a passed data block. A Reader which understands the format of the data
19593 * must have been configured in the constructor.
19594 * @param {Object} data The data block from which to read the Records. The format of the data expected
19595 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19596 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19598 loadData : function(o, append){
19599 var r = this.reader.readRecords(o);
19600 this.loadRecords(r, {add: append}, true);
19604 * Gets the number of cached records.
19606 * <em>If using paging, this may not be the total size of the dataset. If the data object
19607 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19608 * the data set size</em>
19610 getCount : function(){
19611 return this.data.length || 0;
19615 * Gets the total number of records in the dataset as returned by the server.
19617 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19618 * the dataset size</em>
19620 getTotalCount : function(){
19621 return this.totalLength || 0;
19625 * Returns the sort state of the Store as an object with two properties:
19627 field {String} The name of the field by which the Records are sorted
19628 direction {String} The sort order, "ASC" or "DESC"
19631 getSortState : function(){
19632 return this.sortInfo;
19636 applySort : function(){
19637 if(this.sortInfo && !this.remoteSort){
19638 var s = this.sortInfo, f = s.field;
19639 var st = this.fields.get(f).sortType;
19640 var fn = function(r1, r2){
19641 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19642 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19644 this.data.sort(s.direction, fn);
19645 if(this.snapshot && this.snapshot != this.data){
19646 this.snapshot.sort(s.direction, fn);
19652 * Sets the default sort column and order to be used by the next load operation.
19653 * @param {String} fieldName The name of the field to sort by.
19654 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19656 setDefaultSort : function(field, dir){
19657 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19661 * Sort the Records.
19662 * If remote sorting is used, the sort is performed on the server, and the cache is
19663 * reloaded. If local sorting is used, the cache is sorted internally.
19664 * @param {String} fieldName The name of the field to sort by.
19665 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19667 sort : function(fieldName, dir){
19668 var f = this.fields.get(fieldName);
19670 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
19672 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
19673 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19678 this.sortToggle[f.name] = dir;
19679 this.sortInfo = {field: f.name, direction: dir};
19680 if(!this.remoteSort){
19682 this.fireEvent("datachanged", this);
19684 this.load(this.lastOptions);
19689 * Calls the specified function for each of the Records in the cache.
19690 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19691 * Returning <em>false</em> aborts and exits the iteration.
19692 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19694 each : function(fn, scope){
19695 this.data.each(fn, scope);
19699 * Gets all records modified since the last commit. Modified records are persisted across load operations
19700 * (e.g., during paging).
19701 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19703 getModifiedRecords : function(){
19704 return this.modified;
19708 createFilterFn : function(property, value, anyMatch){
19709 if(!value.exec){ // not a regex
19710 value = String(value);
19711 if(value.length == 0){
19714 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19716 return function(r){
19717 return value.test(r.data[property]);
19722 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19723 * @param {String} property A field on your records
19724 * @param {Number} start The record index to start at (defaults to 0)
19725 * @param {Number} end The last record index to include (defaults to length - 1)
19726 * @return {Number} The sum
19728 sum : function(property, start, end){
19729 var rs = this.data.items, v = 0;
19730 start = start || 0;
19731 end = (end || end === 0) ? end : rs.length-1;
19733 for(var i = start; i <= end; i++){
19734 v += (rs[i].data[property] || 0);
19740 * Filter the records by a specified property.
19741 * @param {String} field A field on your records
19742 * @param {String/RegExp} value Either a string that the field
19743 * should start with or a RegExp to test against the field
19744 * @param {Boolean} anyMatch True to match any part not just the beginning
19746 filter : function(property, value, anyMatch){
19747 var fn = this.createFilterFn(property, value, anyMatch);
19748 return fn ? this.filterBy(fn) : this.clearFilter();
19752 * Filter by a function. The specified function will be called with each
19753 * record in this data source. If the function returns true the record is included,
19754 * otherwise it is filtered.
19755 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19756 * @param {Object} scope (optional) The scope of the function (defaults to this)
19758 filterBy : function(fn, scope){
19759 this.snapshot = this.snapshot || this.data;
19760 this.data = this.queryBy(fn, scope||this);
19761 this.fireEvent("datachanged", this);
19765 * Query the records by a specified property.
19766 * @param {String} field A field on your records
19767 * @param {String/RegExp} value Either a string that the field
19768 * should start with or a RegExp to test against the field
19769 * @param {Boolean} anyMatch True to match any part not just the beginning
19770 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19772 query : function(property, value, anyMatch){
19773 var fn = this.createFilterFn(property, value, anyMatch);
19774 return fn ? this.queryBy(fn) : this.data.clone();
19778 * Query by a function. The specified function will be called with each
19779 * record in this data source. If the function returns true the record is included
19781 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19782 * @param {Object} scope (optional) The scope of the function (defaults to this)
19783 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19785 queryBy : function(fn, scope){
19786 var data = this.snapshot || this.data;
19787 return data.filterBy(fn, scope||this);
19791 * Collects unique values for a particular dataIndex from this store.
19792 * @param {String} dataIndex The property to collect
19793 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19794 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19795 * @return {Array} An array of the unique values
19797 collect : function(dataIndex, allowNull, bypassFilter){
19798 var d = (bypassFilter === true && this.snapshot) ?
19799 this.snapshot.items : this.data.items;
19800 var v, sv, r = [], l = {};
19801 for(var i = 0, len = d.length; i < len; i++){
19802 v = d[i].data[dataIndex];
19804 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19813 * Revert to a view of the Record cache with no filtering applied.
19814 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19816 clearFilter : function(suppressEvent){
19817 if(this.snapshot && this.snapshot != this.data){
19818 this.data = this.snapshot;
19819 delete this.snapshot;
19820 if(suppressEvent !== true){
19821 this.fireEvent("datachanged", this);
19827 afterEdit : function(record){
19828 if(this.modified.indexOf(record) == -1){
19829 this.modified.push(record);
19831 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19835 afterReject : function(record){
19836 this.modified.remove(record);
19837 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19841 afterCommit : function(record){
19842 this.modified.remove(record);
19843 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19847 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19848 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19850 commitChanges : function(){
19851 var m = this.modified.slice(0);
19852 this.modified = [];
19853 for(var i = 0, len = m.length; i < len; i++){
19859 * Cancel outstanding changes on all changed records.
19861 rejectChanges : function(){
19862 var m = this.modified.slice(0);
19863 this.modified = [];
19864 for(var i = 0, len = m.length; i < len; i++){
19869 onMetaChange : function(meta, rtype, o){
19870 this.recordType = rtype;
19871 this.fields = rtype.prototype.fields;
19872 delete this.snapshot;
19873 this.sortInfo = meta.sortInfo || this.sortInfo;
19874 this.modified = [];
19875 this.fireEvent('metachange', this, this.reader.meta);
19879 * Ext JS Library 1.1.1
19880 * Copyright(c) 2006-2007, Ext JS, LLC.
19882 * Originally Released Under LGPL - original licence link has changed is not relivant.
19885 * <script type="text/javascript">
19889 * @class Roo.data.SimpleStore
19890 * @extends Roo.data.Store
19891 * Small helper class to make creating Stores from Array data easier.
19892 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19893 * @cfg {Array} fields An array of field definition objects, or field name strings.
19894 * @cfg {Array} data The multi-dimensional array of data
19896 * @param {Object} config
19898 Roo.data.SimpleStore = function(config){
19899 Roo.data.SimpleStore.superclass.constructor.call(this, {
19901 reader: new Roo.data.ArrayReader({
19904 Roo.data.Record.create(config.fields)
19906 proxy : new Roo.data.MemoryProxy(config.data)
19910 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19912 * Ext JS Library 1.1.1
19913 * Copyright(c) 2006-2007, Ext JS, LLC.
19915 * Originally Released Under LGPL - original licence link has changed is not relivant.
19918 * <script type="text/javascript">
19923 * @extends Roo.data.Store
19924 * @class Roo.data.JsonStore
19925 * Small helper class to make creating Stores for JSON data easier. <br/>
19927 var store = new Roo.data.JsonStore({
19928 url: 'get-images.php',
19930 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19933 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19934 * JsonReader and HttpProxy (unless inline data is provided).</b>
19935 * @cfg {Array} fields An array of field definition objects, or field name strings.
19937 * @param {Object} config
19939 Roo.data.JsonStore = function(c){
19940 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19941 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19942 reader: new Roo.data.JsonReader(c, c.fields)
19945 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19947 * Ext JS Library 1.1.1
19948 * Copyright(c) 2006-2007, Ext JS, LLC.
19950 * Originally Released Under LGPL - original licence link has changed is not relivant.
19953 * <script type="text/javascript">
19957 Roo.data.Field = function(config){
19958 if(typeof config == "string"){
19959 config = {name: config};
19961 Roo.apply(this, config);
19964 this.type = "auto";
19967 var st = Roo.data.SortTypes;
19968 // named sortTypes are supported, here we look them up
19969 if(typeof this.sortType == "string"){
19970 this.sortType = st[this.sortType];
19973 // set default sortType for strings and dates
19974 if(!this.sortType){
19977 this.sortType = st.asUCString;
19980 this.sortType = st.asDate;
19983 this.sortType = st.none;
19988 var stripRe = /[\$,%]/g;
19990 // prebuilt conversion function for this field, instead of
19991 // switching every time we're reading a value
19993 var cv, dateFormat = this.dateFormat;
19998 cv = function(v){ return v; };
20001 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
20005 return v !== undefined && v !== null && v !== '' ?
20006 parseInt(String(v).replace(stripRe, ""), 10) : '';
20011 return v !== undefined && v !== null && v !== '' ?
20012 parseFloat(String(v).replace(stripRe, ""), 10) : '';
20017 cv = function(v){ return v === true || v === "true" || v == 1; };
20024 if(v instanceof Date){
20028 if(dateFormat == "timestamp"){
20029 return new Date(v*1000);
20031 return Date.parseDate(v, dateFormat);
20033 var parsed = Date.parse(v);
20034 return parsed ? new Date(parsed) : null;
20043 Roo.data.Field.prototype = {
20051 * Ext JS Library 1.1.1
20052 * Copyright(c) 2006-2007, Ext JS, LLC.
20054 * Originally Released Under LGPL - original licence link has changed is not relivant.
20057 * <script type="text/javascript">
20060 // Base class for reading structured data from a data source. This class is intended to be
20061 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20064 * @class Roo.data.DataReader
20065 * Base class for reading structured data from a data source. This class is intended to be
20066 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20069 Roo.data.DataReader = function(meta, recordType){
20073 this.recordType = recordType instanceof Array ?
20074 Roo.data.Record.create(recordType) : recordType;
20077 Roo.data.DataReader.prototype = {
20079 * Create an empty record
20080 * @param {Object} data (optional) - overlay some values
20081 * @return {Roo.data.Record} record created.
20083 newRow : function(d) {
20085 this.recordType.prototype.fields.each(function(c) {
20087 case 'int' : da[c.name] = 0; break;
20088 case 'date' : da[c.name] = new Date(); break;
20089 case 'float' : da[c.name] = 0.0; break;
20090 case 'boolean' : da[c.name] = false; break;
20091 default : da[c.name] = ""; break;
20095 return new this.recordType(Roo.apply(da, d));
20100 * Ext JS Library 1.1.1
20101 * Copyright(c) 2006-2007, Ext JS, LLC.
20103 * Originally Released Under LGPL - original licence link has changed is not relivant.
20106 * <script type="text/javascript">
20110 * @class Roo.data.DataProxy
20111 * @extends Roo.data.Observable
20112 * This class is an abstract base class for implementations which provide retrieval of
20113 * unformatted data objects.<br>
20115 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20116 * (of the appropriate type which knows how to parse the data object) to provide a block of
20117 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20119 * Custom implementations must implement the load method as described in
20120 * {@link Roo.data.HttpProxy#load}.
20122 Roo.data.DataProxy = function(){
20125 * @event beforeload
20126 * Fires before a network request is made to retrieve a data object.
20127 * @param {Object} This DataProxy object.
20128 * @param {Object} params The params parameter to the load function.
20133 * Fires before the load method's callback is called.
20134 * @param {Object} This DataProxy object.
20135 * @param {Object} o The data object.
20136 * @param {Object} arg The callback argument object passed to the load function.
20140 * @event loadexception
20141 * Fires if an Exception occurs during data retrieval.
20142 * @param {Object} This DataProxy object.
20143 * @param {Object} o The data object.
20144 * @param {Object} arg The callback argument object passed to the load function.
20145 * @param {Object} e The Exception.
20147 loadexception : true
20149 Roo.data.DataProxy.superclass.constructor.call(this);
20152 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20155 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20159 * Ext JS Library 1.1.1
20160 * Copyright(c) 2006-2007, Ext JS, LLC.
20162 * Originally Released Under LGPL - original licence link has changed is not relivant.
20165 * <script type="text/javascript">
20168 * @class Roo.data.MemoryProxy
20169 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20170 * to the Reader when its load method is called.
20172 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20174 Roo.data.MemoryProxy = function(data){
20178 Roo.data.MemoryProxy.superclass.constructor.call(this);
20182 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20184 * Load data from the requested source (in this case an in-memory
20185 * data object passed to the constructor), read the data object into
20186 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20187 * process that block using the passed callback.
20188 * @param {Object} params This parameter is not used by the MemoryProxy class.
20189 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20190 * object into a block of Roo.data.Records.
20191 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20192 * The function must be passed <ul>
20193 * <li>The Record block object</li>
20194 * <li>The "arg" argument from the load function</li>
20195 * <li>A boolean success indicator</li>
20197 * @param {Object} scope The scope in which to call the callback
20198 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20200 load : function(params, reader, callback, scope, arg){
20201 params = params || {};
20204 result = reader.readRecords(this.data);
20206 this.fireEvent("loadexception", this, arg, null, e);
20207 callback.call(scope, null, arg, false);
20210 callback.call(scope, result, arg, true);
20214 update : function(params, records){
20219 * Ext JS Library 1.1.1
20220 * Copyright(c) 2006-2007, Ext JS, LLC.
20222 * Originally Released Under LGPL - original licence link has changed is not relivant.
20225 * <script type="text/javascript">
20228 * @class Roo.data.HttpProxy
20229 * @extends Roo.data.DataProxy
20230 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20231 * configured to reference a certain URL.<br><br>
20233 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20234 * from which the running page was served.<br><br>
20236 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20238 * Be aware that to enable the browser to parse an XML document, the server must set
20239 * the Content-Type header in the HTTP response to "text/xml".
20241 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20242 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20243 * will be used to make the request.
20245 Roo.data.HttpProxy = function(conn){
20246 Roo.data.HttpProxy.superclass.constructor.call(this);
20247 // is conn a conn config or a real conn?
20249 this.useAjax = !conn || !conn.events;
20253 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20254 // thse are take from connection...
20257 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20260 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20261 * extra parameters to each request made by this object. (defaults to undefined)
20264 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20265 * to each request made by this object. (defaults to undefined)
20268 * @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)
20271 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20274 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20280 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20284 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20285 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20286 * a finer-grained basis than the DataProxy events.
20288 getConnection : function(){
20289 return this.useAjax ? Roo.Ajax : this.conn;
20293 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20294 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20295 * process that block using the passed callback.
20296 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20297 * for the request to the remote server.
20298 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20299 * object into a block of Roo.data.Records.
20300 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20301 * The function must be passed <ul>
20302 * <li>The Record block object</li>
20303 * <li>The "arg" argument from the load function</li>
20304 * <li>A boolean success indicator</li>
20306 * @param {Object} scope The scope in which to call the callback
20307 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20309 load : function(params, reader, callback, scope, arg){
20310 if(this.fireEvent("beforeload", this, params) !== false){
20312 params : params || {},
20314 callback : callback,
20319 callback : this.loadResponse,
20323 Roo.applyIf(o, this.conn);
20324 if(this.activeRequest){
20325 Roo.Ajax.abort(this.activeRequest);
20327 this.activeRequest = Roo.Ajax.request(o);
20329 this.conn.request(o);
20332 callback.call(scope||this, null, arg, false);
20337 loadResponse : function(o, success, response){
20338 delete this.activeRequest;
20340 this.fireEvent("loadexception", this, o, response);
20341 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20346 result = o.reader.read(response);
20348 this.fireEvent("loadexception", this, o, response, e);
20349 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20353 this.fireEvent("load", this, o, o.request.arg);
20354 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20358 update : function(dataSet){
20363 updateResponse : function(dataSet){
20368 * Ext JS Library 1.1.1
20369 * Copyright(c) 2006-2007, Ext JS, LLC.
20371 * Originally Released Under LGPL - original licence link has changed is not relivant.
20374 * <script type="text/javascript">
20378 * @class Roo.data.ScriptTagProxy
20379 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20380 * other than the originating domain of the running page.<br><br>
20382 * <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
20383 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20385 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20386 * source code that is used as the source inside a <script> tag.<br><br>
20388 * In order for the browser to process the returned data, the server must wrap the data object
20389 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20390 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20391 * depending on whether the callback name was passed:
20394 boolean scriptTag = false;
20395 String cb = request.getParameter("callback");
20398 response.setContentType("text/javascript");
20400 response.setContentType("application/x-json");
20402 Writer out = response.getWriter();
20404 out.write(cb + "(");
20406 out.print(dataBlock.toJsonString());
20413 * @param {Object} config A configuration object.
20415 Roo.data.ScriptTagProxy = function(config){
20416 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20417 Roo.apply(this, config);
20418 this.head = document.getElementsByTagName("head")[0];
20421 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20423 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20425 * @cfg {String} url The URL from which to request the data object.
20428 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20432 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20433 * the server the name of the callback function set up by the load call to process the returned data object.
20434 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20435 * javascript output which calls this named function passing the data object as its only parameter.
20437 callbackParam : "callback",
20439 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20440 * name to the request.
20445 * Load data from the configured URL, read the data object into
20446 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20447 * process that block using the passed callback.
20448 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20449 * for the request to the remote server.
20450 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20451 * object into a block of Roo.data.Records.
20452 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20453 * The function must be passed <ul>
20454 * <li>The Record block object</li>
20455 * <li>The "arg" argument from the load function</li>
20456 * <li>A boolean success indicator</li>
20458 * @param {Object} scope The scope in which to call the callback
20459 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20461 load : function(params, reader, callback, scope, arg){
20462 if(this.fireEvent("beforeload", this, params) !== false){
20464 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20466 var url = this.url;
20467 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20469 url += "&_dc=" + (new Date().getTime());
20471 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20474 cb : "stcCallback"+transId,
20475 scriptId : "stcScript"+transId,
20479 callback : callback,
20485 window[trans.cb] = function(o){
20486 conn.handleResponse(o, trans);
20489 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20491 if(this.autoAbort !== false){
20495 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20497 var script = document.createElement("script");
20498 script.setAttribute("src", url);
20499 script.setAttribute("type", "text/javascript");
20500 script.setAttribute("id", trans.scriptId);
20501 this.head.appendChild(script);
20503 this.trans = trans;
20505 callback.call(scope||this, null, arg, false);
20510 isLoading : function(){
20511 return this.trans ? true : false;
20515 * Abort the current server request.
20517 abort : function(){
20518 if(this.isLoading()){
20519 this.destroyTrans(this.trans);
20524 destroyTrans : function(trans, isLoaded){
20525 this.head.removeChild(document.getElementById(trans.scriptId));
20526 clearTimeout(trans.timeoutId);
20528 window[trans.cb] = undefined;
20530 delete window[trans.cb];
20533 // if hasn't been loaded, wait for load to remove it to prevent script error
20534 window[trans.cb] = function(){
20535 window[trans.cb] = undefined;
20537 delete window[trans.cb];
20544 handleResponse : function(o, trans){
20545 this.trans = false;
20546 this.destroyTrans(trans, true);
20549 result = trans.reader.readRecords(o);
20551 this.fireEvent("loadexception", this, o, trans.arg, e);
20552 trans.callback.call(trans.scope||window, null, trans.arg, false);
20555 this.fireEvent("load", this, o, trans.arg);
20556 trans.callback.call(trans.scope||window, result, trans.arg, true);
20560 handleFailure : function(trans){
20561 this.trans = false;
20562 this.destroyTrans(trans, false);
20563 this.fireEvent("loadexception", this, null, trans.arg);
20564 trans.callback.call(trans.scope||window, null, trans.arg, false);
20568 * Ext JS Library 1.1.1
20569 * Copyright(c) 2006-2007, Ext JS, LLC.
20571 * Originally Released Under LGPL - original licence link has changed is not relivant.
20574 * <script type="text/javascript">
20578 * @class Roo.data.JsonReader
20579 * @extends Roo.data.DataReader
20580 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20581 * based on mappings in a provided Roo.data.Record constructor.
20583 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
20584 * in the reply previously.
20589 var RecordDef = Roo.data.Record.create([
20590 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20591 {name: 'occupation'} // This field will use "occupation" as the mapping.
20593 var myReader = new Roo.data.JsonReader({
20594 totalProperty: "results", // The property which contains the total dataset size (optional)
20595 root: "rows", // The property which contains an Array of row objects
20596 id: "id" // The property within each row object that provides an ID for the record (optional)
20600 * This would consume a JSON file like this:
20602 { 'results': 2, 'rows': [
20603 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20604 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20607 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20608 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20609 * paged from the remote server.
20610 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20611 * @cfg {String} root name of the property which contains the Array of row objects.
20612 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20614 * Create a new JsonReader
20615 * @param {Object} meta Metadata configuration options
20616 * @param {Object} recordType Either an Array of field definition objects,
20617 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20619 Roo.data.JsonReader = function(meta, recordType){
20622 // set some defaults:
20623 Roo.applyIf(meta, {
20624 totalProperty: 'total',
20625 successProperty : 'success',
20630 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20632 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20635 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
20636 * Used by Store query builder to append _requestMeta to params.
20639 metaFromRemote : false,
20641 * This method is only used by a DataProxy which has retrieved data from a remote server.
20642 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20643 * @return {Object} data A data block which is used by an Roo.data.Store object as
20644 * a cache of Roo.data.Records.
20646 read : function(response){
20647 var json = response.responseText;
20649 var o = /* eval:var:o */ eval("("+json+")");
20651 throw {message: "JsonReader.read: Json object not found"};
20657 this.metaFromRemote = true;
20658 this.meta = o.metaData;
20659 this.recordType = Roo.data.Record.create(o.metaData.fields);
20660 this.onMetaChange(this.meta, this.recordType, o);
20662 return this.readRecords(o);
20665 // private function a store will implement
20666 onMetaChange : function(meta, recordType, o){
20673 simpleAccess: function(obj, subsc) {
20680 getJsonAccessor: function(){
20682 return function(expr) {
20684 return(re.test(expr))
20685 ? new Function("obj", "return obj." + expr)
20690 return Roo.emptyFn;
20695 * Create a data block containing Roo.data.Records from an XML document.
20696 * @param {Object} o An object which contains an Array of row objects in the property specified
20697 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20698 * which contains the total size of the dataset.
20699 * @return {Object} data A data block which is used by an Roo.data.Store object as
20700 * a cache of Roo.data.Records.
20702 readRecords : function(o){
20704 * After any data loads, the raw JSON data is available for further custom processing.
20708 var s = this.meta, Record = this.recordType,
20709 f = Record.prototype.fields, fi = f.items, fl = f.length;
20711 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20713 if(s.totalProperty) {
20714 this.getTotal = this.getJsonAccessor(s.totalProperty);
20716 if(s.successProperty) {
20717 this.getSuccess = this.getJsonAccessor(s.successProperty);
20719 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20721 var g = this.getJsonAccessor(s.id);
20722 this.getId = function(rec) {
20724 return (r === undefined || r === "") ? null : r;
20727 this.getId = function(){return null;};
20730 for(var jj = 0; jj < fl; jj++){
20732 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20733 this.ef[jj] = this.getJsonAccessor(map);
20737 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20738 if(s.totalProperty){
20739 var vt = parseInt(this.getTotal(o), 10);
20744 if(s.successProperty){
20745 var vs = this.getSuccess(o);
20746 if(vs === false || vs === 'false'){
20751 for(var i = 0; i < c; i++){
20754 var id = this.getId(n);
20755 for(var j = 0; j < fl; j++){
20757 var v = this.ef[j](n);
20759 Roo.log('missing convert for ' + f.name);
20763 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20765 var record = new Record(values, id);
20767 records[i] = record;
20772 totalRecords : totalRecords
20777 * Ext JS Library 1.1.1
20778 * Copyright(c) 2006-2007, Ext JS, LLC.
20780 * Originally Released Under LGPL - original licence link has changed is not relivant.
20783 * <script type="text/javascript">
20787 * @class Roo.data.XmlReader
20788 * @extends Roo.data.DataReader
20789 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20790 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20792 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20793 * header in the HTTP response must be set to "text/xml".</em>
20797 var RecordDef = Roo.data.Record.create([
20798 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20799 {name: 'occupation'} // This field will use "occupation" as the mapping.
20801 var myReader = new Roo.data.XmlReader({
20802 totalRecords: "results", // The element which contains the total dataset size (optional)
20803 record: "row", // The repeated element which contains row information
20804 id: "id" // The element within the row that provides an ID for the record (optional)
20808 * This would consume an XML file like this:
20812 <results>2</results>
20815 <name>Bill</name>
20816 <occupation>Gardener</occupation>
20820 <name>Ben</name>
20821 <occupation>Horticulturalist</occupation>
20825 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20826 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20827 * paged from the remote server.
20828 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20829 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20830 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20831 * a record identifier value.
20833 * Create a new XmlReader
20834 * @param {Object} meta Metadata configuration options
20835 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20836 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20837 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20839 Roo.data.XmlReader = function(meta, recordType){
20841 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20843 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20845 * This method is only used by a DataProxy which has retrieved data from a remote server.
20846 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20847 * to contain a method called 'responseXML' that returns an XML document object.
20848 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20849 * a cache of Roo.data.Records.
20851 read : function(response){
20852 var doc = response.responseXML;
20854 throw {message: "XmlReader.read: XML Document not available"};
20856 return this.readRecords(doc);
20860 * Create a data block containing Roo.data.Records from an XML document.
20861 * @param {Object} doc A parsed XML document.
20862 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20863 * a cache of Roo.data.Records.
20865 readRecords : function(doc){
20867 * After any data loads/reads, the raw XML Document is available for further custom processing.
20868 * @type XMLDocument
20870 this.xmlData = doc;
20871 var root = doc.documentElement || doc;
20872 var q = Roo.DomQuery;
20873 var recordType = this.recordType, fields = recordType.prototype.fields;
20874 var sid = this.meta.id;
20875 var totalRecords = 0, success = true;
20876 if(this.meta.totalRecords){
20877 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20880 if(this.meta.success){
20881 var sv = q.selectValue(this.meta.success, root, true);
20882 success = sv !== false && sv !== 'false';
20885 var ns = q.select(this.meta.record, root);
20886 for(var i = 0, len = ns.length; i < len; i++) {
20889 var id = sid ? q.selectValue(sid, n) : undefined;
20890 for(var j = 0, jlen = fields.length; j < jlen; j++){
20891 var f = fields.items[j];
20892 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20894 values[f.name] = v;
20896 var record = new recordType(values, id);
20898 records[records.length] = record;
20904 totalRecords : totalRecords || records.length
20909 * Ext JS Library 1.1.1
20910 * Copyright(c) 2006-2007, Ext JS, LLC.
20912 * Originally Released Under LGPL - original licence link has changed is not relivant.
20915 * <script type="text/javascript">
20919 * @class Roo.data.ArrayReader
20920 * @extends Roo.data.DataReader
20921 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20922 * Each element of that Array represents a row of data fields. The
20923 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20924 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20928 var RecordDef = Roo.data.Record.create([
20929 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20930 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20932 var myReader = new Roo.data.ArrayReader({
20933 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20937 * This would consume an Array like this:
20939 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20941 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20943 * Create a new JsonReader
20944 * @param {Object} meta Metadata configuration options.
20945 * @param {Object} recordType Either an Array of field definition objects
20946 * as specified to {@link Roo.data.Record#create},
20947 * or an {@link Roo.data.Record} object
20948 * created using {@link Roo.data.Record#create}.
20950 Roo.data.ArrayReader = function(meta, recordType){
20951 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20954 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20956 * Create a data block containing Roo.data.Records from an XML document.
20957 * @param {Object} o An Array of row objects which represents the dataset.
20958 * @return {Object} data A data block which is used by an Roo.data.Store object as
20959 * a cache of Roo.data.Records.
20961 readRecords : function(o){
20962 var sid = this.meta ? this.meta.id : null;
20963 var recordType = this.recordType, fields = recordType.prototype.fields;
20966 for(var i = 0; i < root.length; i++){
20969 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20970 for(var j = 0, jlen = fields.length; j < jlen; j++){
20971 var f = fields.items[j];
20972 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20973 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20975 values[f.name] = v;
20977 var record = new recordType(values, id);
20979 records[records.length] = record;
20983 totalRecords : records.length
20988 * Ext JS Library 1.1.1
20989 * Copyright(c) 2006-2007, Ext JS, LLC.
20991 * Originally Released Under LGPL - original licence link has changed is not relivant.
20994 * <script type="text/javascript">
20999 * @class Roo.data.Tree
21000 * @extends Roo.util.Observable
21001 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
21002 * in the tree have most standard DOM functionality.
21004 * @param {Node} root (optional) The root node
21006 Roo.data.Tree = function(root){
21007 this.nodeHash = {};
21009 * The root node for this tree
21014 this.setRootNode(root);
21019 * Fires when a new child node is appended to a node in this tree.
21020 * @param {Tree} tree The owner tree
21021 * @param {Node} parent The parent node
21022 * @param {Node} node The newly appended node
21023 * @param {Number} index The index of the newly appended node
21028 * Fires when a child node is removed from a node in this tree.
21029 * @param {Tree} tree The owner tree
21030 * @param {Node} parent The parent node
21031 * @param {Node} node The child node removed
21036 * Fires when a node is moved to a new location in the tree
21037 * @param {Tree} tree The owner tree
21038 * @param {Node} node The node moved
21039 * @param {Node} oldParent The old parent of this node
21040 * @param {Node} newParent The new parent of this node
21041 * @param {Number} index The index it was moved to
21046 * Fires when a new child node is inserted in a node in this tree.
21047 * @param {Tree} tree The owner tree
21048 * @param {Node} parent The parent node
21049 * @param {Node} node The child node inserted
21050 * @param {Node} refNode The child node the node was inserted before
21054 * @event beforeappend
21055 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21056 * @param {Tree} tree The owner tree
21057 * @param {Node} parent The parent node
21058 * @param {Node} node The child node to be appended
21060 "beforeappend" : true,
21062 * @event beforeremove
21063 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21064 * @param {Tree} tree The owner tree
21065 * @param {Node} parent The parent node
21066 * @param {Node} node The child node to be removed
21068 "beforeremove" : true,
21070 * @event beforemove
21071 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21072 * @param {Tree} tree The owner tree
21073 * @param {Node} node The node being moved
21074 * @param {Node} oldParent The parent of the node
21075 * @param {Node} newParent The new parent the node is moving to
21076 * @param {Number} index The index it is being moved to
21078 "beforemove" : true,
21080 * @event beforeinsert
21081 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21082 * @param {Tree} tree The owner tree
21083 * @param {Node} parent The parent node
21084 * @param {Node} node The child node to be inserted
21085 * @param {Node} refNode The child node the node is being inserted before
21087 "beforeinsert" : true
21090 Roo.data.Tree.superclass.constructor.call(this);
21093 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21094 pathSeparator: "/",
21096 proxyNodeEvent : function(){
21097 return this.fireEvent.apply(this, arguments);
21101 * Returns the root node for this tree.
21104 getRootNode : function(){
21109 * Sets the root node for this tree.
21110 * @param {Node} node
21113 setRootNode : function(node){
21115 node.ownerTree = this;
21116 node.isRoot = true;
21117 this.registerNode(node);
21122 * Gets a node in this tree by its id.
21123 * @param {String} id
21126 getNodeById : function(id){
21127 return this.nodeHash[id];
21130 registerNode : function(node){
21131 this.nodeHash[node.id] = node;
21134 unregisterNode : function(node){
21135 delete this.nodeHash[node.id];
21138 toString : function(){
21139 return "[Tree"+(this.id?" "+this.id:"")+"]";
21144 * @class Roo.data.Node
21145 * @extends Roo.util.Observable
21146 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21147 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21149 * @param {Object} attributes The attributes/config for the node
21151 Roo.data.Node = function(attributes){
21153 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21156 this.attributes = attributes || {};
21157 this.leaf = this.attributes.leaf;
21159 * The node id. @type String
21161 this.id = this.attributes.id;
21163 this.id = Roo.id(null, "ynode-");
21164 this.attributes.id = this.id;
21167 * All child nodes of this node. @type Array
21169 this.childNodes = [];
21170 if(!this.childNodes.indexOf){ // indexOf is a must
21171 this.childNodes.indexOf = function(o){
21172 for(var i = 0, len = this.length; i < len; i++){
21181 * The parent node for this node. @type Node
21183 this.parentNode = null;
21185 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21187 this.firstChild = null;
21189 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21191 this.lastChild = null;
21193 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21195 this.previousSibling = null;
21197 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21199 this.nextSibling = null;
21204 * Fires when a new child node is appended
21205 * @param {Tree} tree The owner tree
21206 * @param {Node} this This node
21207 * @param {Node} node The newly appended node
21208 * @param {Number} index The index of the newly appended node
21213 * Fires when a child node is removed
21214 * @param {Tree} tree The owner tree
21215 * @param {Node} this This node
21216 * @param {Node} node The removed node
21221 * Fires when this node is moved to a new location in the tree
21222 * @param {Tree} tree The owner tree
21223 * @param {Node} this This node
21224 * @param {Node} oldParent The old parent of this node
21225 * @param {Node} newParent The new parent of this node
21226 * @param {Number} index The index it was moved to
21231 * Fires when a new child node is inserted.
21232 * @param {Tree} tree The owner tree
21233 * @param {Node} this This node
21234 * @param {Node} node The child node inserted
21235 * @param {Node} refNode The child node the node was inserted before
21239 * @event beforeappend
21240 * Fires before a new child is appended, return false to cancel the append.
21241 * @param {Tree} tree The owner tree
21242 * @param {Node} this This node
21243 * @param {Node} node The child node to be appended
21245 "beforeappend" : true,
21247 * @event beforeremove
21248 * Fires before a child is removed, return false to cancel the remove.
21249 * @param {Tree} tree The owner tree
21250 * @param {Node} this This node
21251 * @param {Node} node The child node to be removed
21253 "beforeremove" : true,
21255 * @event beforemove
21256 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21257 * @param {Tree} tree The owner tree
21258 * @param {Node} this This node
21259 * @param {Node} oldParent The parent of this node
21260 * @param {Node} newParent The new parent this node is moving to
21261 * @param {Number} index The index it is being moved to
21263 "beforemove" : true,
21265 * @event beforeinsert
21266 * Fires before a new child is inserted, return false to cancel the insert.
21267 * @param {Tree} tree The owner tree
21268 * @param {Node} this This node
21269 * @param {Node} node The child node to be inserted
21270 * @param {Node} refNode The child node the node is being inserted before
21272 "beforeinsert" : true
21274 this.listeners = this.attributes.listeners;
21275 Roo.data.Node.superclass.constructor.call(this);
21278 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21279 fireEvent : function(evtName){
21280 // first do standard event for this node
21281 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21284 // then bubble it up to the tree if the event wasn't cancelled
21285 var ot = this.getOwnerTree();
21287 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21295 * Returns true if this node is a leaf
21296 * @return {Boolean}
21298 isLeaf : function(){
21299 return this.leaf === true;
21303 setFirstChild : function(node){
21304 this.firstChild = node;
21308 setLastChild : function(node){
21309 this.lastChild = node;
21314 * Returns true if this node is the last child of its parent
21315 * @return {Boolean}
21317 isLast : function(){
21318 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21322 * Returns true if this node is the first child of its parent
21323 * @return {Boolean}
21325 isFirst : function(){
21326 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21329 hasChildNodes : function(){
21330 return !this.isLeaf() && this.childNodes.length > 0;
21334 * Insert node(s) as the last child node of this node.
21335 * @param {Node/Array} node The node or Array of nodes to append
21336 * @return {Node} The appended node if single append, or null if an array was passed
21338 appendChild : function(node){
21340 if(node instanceof Array){
21342 }else if(arguments.length > 1){
21345 // if passed an array or multiple args do them one by one
21347 for(var i = 0, len = multi.length; i < len; i++) {
21348 this.appendChild(multi[i]);
21351 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21354 var index = this.childNodes.length;
21355 var oldParent = node.parentNode;
21356 // it's a move, make sure we move it cleanly
21358 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21361 oldParent.removeChild(node);
21363 index = this.childNodes.length;
21365 this.setFirstChild(node);
21367 this.childNodes.push(node);
21368 node.parentNode = this;
21369 var ps = this.childNodes[index-1];
21371 node.previousSibling = ps;
21372 ps.nextSibling = node;
21374 node.previousSibling = null;
21376 node.nextSibling = null;
21377 this.setLastChild(node);
21378 node.setOwnerTree(this.getOwnerTree());
21379 this.fireEvent("append", this.ownerTree, this, node, index);
21381 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21388 * Removes a child node from this node.
21389 * @param {Node} node The node to remove
21390 * @return {Node} The removed node
21392 removeChild : function(node){
21393 var index = this.childNodes.indexOf(node);
21397 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21401 // remove it from childNodes collection
21402 this.childNodes.splice(index, 1);
21405 if(node.previousSibling){
21406 node.previousSibling.nextSibling = node.nextSibling;
21408 if(node.nextSibling){
21409 node.nextSibling.previousSibling = node.previousSibling;
21412 // update child refs
21413 if(this.firstChild == node){
21414 this.setFirstChild(node.nextSibling);
21416 if(this.lastChild == node){
21417 this.setLastChild(node.previousSibling);
21420 node.setOwnerTree(null);
21421 // clear any references from the node
21422 node.parentNode = null;
21423 node.previousSibling = null;
21424 node.nextSibling = null;
21425 this.fireEvent("remove", this.ownerTree, this, node);
21430 * Inserts the first node before the second node in this nodes childNodes collection.
21431 * @param {Node} node The node to insert
21432 * @param {Node} refNode The node to insert before (if null the node is appended)
21433 * @return {Node} The inserted node
21435 insertBefore : function(node, refNode){
21436 if(!refNode){ // like standard Dom, refNode can be null for append
21437 return this.appendChild(node);
21440 if(node == refNode){
21444 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21447 var index = this.childNodes.indexOf(refNode);
21448 var oldParent = node.parentNode;
21449 var refIndex = index;
21451 // when moving internally, indexes will change after remove
21452 if(oldParent == this && this.childNodes.indexOf(node) < index){
21456 // it's a move, make sure we move it cleanly
21458 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21461 oldParent.removeChild(node);
21464 this.setFirstChild(node);
21466 this.childNodes.splice(refIndex, 0, node);
21467 node.parentNode = this;
21468 var ps = this.childNodes[refIndex-1];
21470 node.previousSibling = ps;
21471 ps.nextSibling = node;
21473 node.previousSibling = null;
21475 node.nextSibling = refNode;
21476 refNode.previousSibling = node;
21477 node.setOwnerTree(this.getOwnerTree());
21478 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21480 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21486 * Returns the child node at the specified index.
21487 * @param {Number} index
21490 item : function(index){
21491 return this.childNodes[index];
21495 * Replaces one child node in this node with another.
21496 * @param {Node} newChild The replacement node
21497 * @param {Node} oldChild The node to replace
21498 * @return {Node} The replaced node
21500 replaceChild : function(newChild, oldChild){
21501 this.insertBefore(newChild, oldChild);
21502 this.removeChild(oldChild);
21507 * Returns the index of a child node
21508 * @param {Node} node
21509 * @return {Number} The index of the node or -1 if it was not found
21511 indexOf : function(child){
21512 return this.childNodes.indexOf(child);
21516 * Returns the tree this node is in.
21519 getOwnerTree : function(){
21520 // if it doesn't have one, look for one
21521 if(!this.ownerTree){
21525 this.ownerTree = p.ownerTree;
21531 return this.ownerTree;
21535 * Returns depth of this node (the root node has a depth of 0)
21538 getDepth : function(){
21541 while(p.parentNode){
21549 setOwnerTree : function(tree){
21550 // if it's move, we need to update everyone
21551 if(tree != this.ownerTree){
21552 if(this.ownerTree){
21553 this.ownerTree.unregisterNode(this);
21555 this.ownerTree = tree;
21556 var cs = this.childNodes;
21557 for(var i = 0, len = cs.length; i < len; i++) {
21558 cs[i].setOwnerTree(tree);
21561 tree.registerNode(this);
21567 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21568 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21569 * @return {String} The path
21571 getPath : function(attr){
21572 attr = attr || "id";
21573 var p = this.parentNode;
21574 var b = [this.attributes[attr]];
21576 b.unshift(p.attributes[attr]);
21579 var sep = this.getOwnerTree().pathSeparator;
21580 return sep + b.join(sep);
21584 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21585 * function call will be the scope provided or the current node. The arguments to the function
21586 * will be the args provided or the current node. If the function returns false at any point,
21587 * the bubble is stopped.
21588 * @param {Function} fn The function to call
21589 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21590 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21592 bubble : function(fn, scope, args){
21595 if(fn.call(scope || p, args || p) === false){
21603 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21604 * function call will be the scope provided or the current node. The arguments to the function
21605 * will be the args provided or the current node. If the function returns false at any point,
21606 * the cascade is stopped on that branch.
21607 * @param {Function} fn The function to call
21608 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21609 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21611 cascade : function(fn, scope, args){
21612 if(fn.call(scope || this, args || this) !== false){
21613 var cs = this.childNodes;
21614 for(var i = 0, len = cs.length; i < len; i++) {
21615 cs[i].cascade(fn, scope, args);
21621 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21622 * function call will be the scope provided or the current node. The arguments to the function
21623 * will be the args provided or the current node. If the function returns false at any point,
21624 * the iteration stops.
21625 * @param {Function} fn The function to call
21626 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21627 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21629 eachChild : function(fn, scope, args){
21630 var cs = this.childNodes;
21631 for(var i = 0, len = cs.length; i < len; i++) {
21632 if(fn.call(scope || this, args || cs[i]) === false){
21639 * Finds the first child that has the attribute with the specified value.
21640 * @param {String} attribute The attribute name
21641 * @param {Mixed} value The value to search for
21642 * @return {Node} The found child or null if none was found
21644 findChild : function(attribute, value){
21645 var cs = this.childNodes;
21646 for(var i = 0, len = cs.length; i < len; i++) {
21647 if(cs[i].attributes[attribute] == value){
21655 * Finds the first child by a custom function. The child matches if the function passed
21657 * @param {Function} fn
21658 * @param {Object} scope (optional)
21659 * @return {Node} The found child or null if none was found
21661 findChildBy : function(fn, scope){
21662 var cs = this.childNodes;
21663 for(var i = 0, len = cs.length; i < len; i++) {
21664 if(fn.call(scope||cs[i], cs[i]) === true){
21672 * Sorts this nodes children using the supplied sort function
21673 * @param {Function} fn
21674 * @param {Object} scope (optional)
21676 sort : function(fn, scope){
21677 var cs = this.childNodes;
21678 var len = cs.length;
21680 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21682 for(var i = 0; i < len; i++){
21684 n.previousSibling = cs[i-1];
21685 n.nextSibling = cs[i+1];
21687 this.setFirstChild(n);
21690 this.setLastChild(n);
21697 * Returns true if this node is an ancestor (at any point) of the passed node.
21698 * @param {Node} node
21699 * @return {Boolean}
21701 contains : function(node){
21702 return node.isAncestor(this);
21706 * Returns true if the passed node is an ancestor (at any point) of this node.
21707 * @param {Node} node
21708 * @return {Boolean}
21710 isAncestor : function(node){
21711 var p = this.parentNode;
21721 toString : function(){
21722 return "[Node"+(this.id?" "+this.id:"")+"]";
21726 * Ext JS Library 1.1.1
21727 * Copyright(c) 2006-2007, Ext JS, LLC.
21729 * Originally Released Under LGPL - original licence link has changed is not relivant.
21732 * <script type="text/javascript">
21737 * @class Roo.ComponentMgr
21738 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21741 Roo.ComponentMgr = function(){
21742 var all = new Roo.util.MixedCollection();
21746 * Registers a component.
21747 * @param {Roo.Component} c The component
21749 register : function(c){
21754 * Unregisters a component.
21755 * @param {Roo.Component} c The component
21757 unregister : function(c){
21762 * Returns a component by id
21763 * @param {String} id The component id
21765 get : function(id){
21766 return all.get(id);
21770 * Registers a function that will be called when a specified component is added to ComponentMgr
21771 * @param {String} id The component id
21772 * @param {Funtction} fn The callback function
21773 * @param {Object} scope The scope of the callback
21775 onAvailable : function(id, fn, scope){
21776 all.on("add", function(index, o){
21778 fn.call(scope || o, o);
21779 all.un("add", fn, scope);
21786 * Ext JS Library 1.1.1
21787 * Copyright(c) 2006-2007, Ext JS, LLC.
21789 * Originally Released Under LGPL - original licence link has changed is not relivant.
21792 * <script type="text/javascript">
21796 * @class Roo.Component
21797 * @extends Roo.util.Observable
21798 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21799 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21800 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21801 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21802 * All visual components (widgets) that require rendering into a layout should subclass Component.
21804 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21805 * 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
21806 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21808 Roo.Component = function(config){
21809 config = config || {};
21810 if(config.tagName || config.dom || typeof config == "string"){ // element object
21811 config = {el: config, id: config.id || config};
21813 this.initialConfig = config;
21815 Roo.apply(this, config);
21819 * Fires after the component is disabled.
21820 * @param {Roo.Component} this
21825 * Fires after the component is enabled.
21826 * @param {Roo.Component} this
21830 * @event beforeshow
21831 * Fires before the component is shown. Return false to stop the show.
21832 * @param {Roo.Component} this
21837 * Fires after the component is shown.
21838 * @param {Roo.Component} this
21842 * @event beforehide
21843 * Fires before the component is hidden. Return false to stop the hide.
21844 * @param {Roo.Component} this
21849 * Fires after the component is hidden.
21850 * @param {Roo.Component} this
21854 * @event beforerender
21855 * Fires before the component is rendered. Return false to stop the render.
21856 * @param {Roo.Component} this
21858 beforerender : true,
21861 * Fires after the component is rendered.
21862 * @param {Roo.Component} this
21866 * @event beforedestroy
21867 * Fires before the component is destroyed. Return false to stop the destroy.
21868 * @param {Roo.Component} this
21870 beforedestroy : true,
21873 * Fires after the component is destroyed.
21874 * @param {Roo.Component} this
21879 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21881 Roo.ComponentMgr.register(this);
21882 Roo.Component.superclass.constructor.call(this);
21883 this.initComponent();
21884 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21885 this.render(this.renderTo);
21886 delete this.renderTo;
21891 Roo.Component.AUTO_ID = 1000;
21893 Roo.extend(Roo.Component, Roo.util.Observable, {
21895 * @scope Roo.Component.prototype
21897 * true if this component is hidden. Read-only.
21902 * true if this component is disabled. Read-only.
21907 * true if this component has been rendered. Read-only.
21911 /** @cfg {String} disableClass
21912 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21914 disabledClass : "x-item-disabled",
21915 /** @cfg {Boolean} allowDomMove
21916 * Whether the component can move the Dom node when rendering (defaults to true).
21918 allowDomMove : true,
21919 /** @cfg {String} hideMode
21920 * How this component should hidden. Supported values are
21921 * "visibility" (css visibility), "offsets" (negative offset position) and
21922 * "display" (css display) - defaults to "display".
21924 hideMode: 'display',
21927 ctype : "Roo.Component",
21930 * @cfg {String} actionMode
21931 * which property holds the element that used for hide() / show() / disable() / enable()
21937 getActionEl : function(){
21938 return this[this.actionMode];
21941 initComponent : Roo.emptyFn,
21943 * If this is a lazy rendering component, render it to its container element.
21944 * @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.
21946 render : function(container, position){
21947 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21948 if(!container && this.el){
21949 this.el = Roo.get(this.el);
21950 container = this.el.dom.parentNode;
21951 this.allowDomMove = false;
21953 this.container = Roo.get(container);
21954 this.rendered = true;
21955 if(position !== undefined){
21956 if(typeof position == 'number'){
21957 position = this.container.dom.childNodes[position];
21959 position = Roo.getDom(position);
21962 this.onRender(this.container, position || null);
21964 this.el.addClass(this.cls);
21968 this.el.applyStyles(this.style);
21971 this.fireEvent("render", this);
21972 this.afterRender(this.container);
21984 // default function is not really useful
21985 onRender : function(ct, position){
21987 this.el = Roo.get(this.el);
21988 if(this.allowDomMove !== false){
21989 ct.dom.insertBefore(this.el.dom, position);
21995 getAutoCreate : function(){
21996 var cfg = typeof this.autoCreate == "object" ?
21997 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21998 if(this.id && !cfg.id){
22005 afterRender : Roo.emptyFn,
22008 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
22009 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
22011 destroy : function(){
22012 if(this.fireEvent("beforedestroy", this) !== false){
22013 this.purgeListeners();
22014 this.beforeDestroy();
22016 this.el.removeAllListeners();
22018 if(this.actionMode == "container"){
22019 this.container.remove();
22023 Roo.ComponentMgr.unregister(this);
22024 this.fireEvent("destroy", this);
22029 beforeDestroy : function(){
22034 onDestroy : function(){
22039 * Returns the underlying {@link Roo.Element}.
22040 * @return {Roo.Element} The element
22042 getEl : function(){
22047 * Returns the id of this component.
22050 getId : function(){
22055 * Try to focus this component.
22056 * @param {Boolean} selectText True to also select the text in this component (if applicable)
22057 * @return {Roo.Component} this
22059 focus : function(selectText){
22062 if(selectText === true){
22063 this.el.dom.select();
22078 * Disable this component.
22079 * @return {Roo.Component} this
22081 disable : function(){
22085 this.disabled = true;
22086 this.fireEvent("disable", this);
22091 onDisable : function(){
22092 this.getActionEl().addClass(this.disabledClass);
22093 this.el.dom.disabled = true;
22097 * Enable this component.
22098 * @return {Roo.Component} this
22100 enable : function(){
22104 this.disabled = false;
22105 this.fireEvent("enable", this);
22110 onEnable : function(){
22111 this.getActionEl().removeClass(this.disabledClass);
22112 this.el.dom.disabled = false;
22116 * Convenience function for setting disabled/enabled by boolean.
22117 * @param {Boolean} disabled
22119 setDisabled : function(disabled){
22120 this[disabled ? "disable" : "enable"]();
22124 * Show this component.
22125 * @return {Roo.Component} this
22128 if(this.fireEvent("beforeshow", this) !== false){
22129 this.hidden = false;
22133 this.fireEvent("show", this);
22139 onShow : function(){
22140 var ae = this.getActionEl();
22141 if(this.hideMode == 'visibility'){
22142 ae.dom.style.visibility = "visible";
22143 }else if(this.hideMode == 'offsets'){
22144 ae.removeClass('x-hidden');
22146 ae.dom.style.display = "";
22151 * Hide this component.
22152 * @return {Roo.Component} this
22155 if(this.fireEvent("beforehide", this) !== false){
22156 this.hidden = true;
22160 this.fireEvent("hide", this);
22166 onHide : function(){
22167 var ae = this.getActionEl();
22168 if(this.hideMode == 'visibility'){
22169 ae.dom.style.visibility = "hidden";
22170 }else if(this.hideMode == 'offsets'){
22171 ae.addClass('x-hidden');
22173 ae.dom.style.display = "none";
22178 * Convenience function to hide or show this component by boolean.
22179 * @param {Boolean} visible True to show, false to hide
22180 * @return {Roo.Component} this
22182 setVisible: function(visible){
22192 * Returns true if this component is visible.
22194 isVisible : function(){
22195 return this.getActionEl().isVisible();
22198 cloneConfig : function(overrides){
22199 overrides = overrides || {};
22200 var id = overrides.id || Roo.id();
22201 var cfg = Roo.applyIf(overrides, this.initialConfig);
22202 cfg.id = id; // prevent dup id
22203 return new this.constructor(cfg);
22207 * Ext JS Library 1.1.1
22208 * Copyright(c) 2006-2007, Ext JS, LLC.
22210 * Originally Released Under LGPL - original licence link has changed is not relivant.
22213 * <script type="text/javascript">
22218 * @extends Roo.Element
22219 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22220 * automatic maintaining of shadow/shim positions.
22221 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22222 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22223 * you can pass a string with a CSS class name. False turns off the shadow.
22224 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22225 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22226 * @cfg {String} cls CSS class to add to the element
22227 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22228 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22230 * @param {Object} config An object with config options.
22231 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22234 Roo.Layer = function(config, existingEl){
22235 config = config || {};
22236 var dh = Roo.DomHelper;
22237 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22239 this.dom = Roo.getDom(existingEl);
22242 var o = config.dh || {tag: "div", cls: "x-layer"};
22243 this.dom = dh.append(pel, o);
22246 this.addClass(config.cls);
22248 this.constrain = config.constrain !== false;
22249 this.visibilityMode = Roo.Element.VISIBILITY;
22251 this.id = this.dom.id = config.id;
22253 this.id = Roo.id(this.dom);
22255 this.zindex = config.zindex || this.getZIndex();
22256 this.position("absolute", this.zindex);
22258 this.shadowOffset = config.shadowOffset || 4;
22259 this.shadow = new Roo.Shadow({
22260 offset : this.shadowOffset,
22261 mode : config.shadow
22264 this.shadowOffset = 0;
22266 this.useShim = config.shim !== false && Roo.useShims;
22267 this.useDisplay = config.useDisplay;
22271 var supr = Roo.Element.prototype;
22273 // shims are shared among layer to keep from having 100 iframes
22276 Roo.extend(Roo.Layer, Roo.Element, {
22278 getZIndex : function(){
22279 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22282 getShim : function(){
22289 var shim = shims.shift();
22291 shim = this.createShim();
22292 shim.enableDisplayMode('block');
22293 shim.dom.style.display = 'none';
22294 shim.dom.style.visibility = 'visible';
22296 var pn = this.dom.parentNode;
22297 if(shim.dom.parentNode != pn){
22298 pn.insertBefore(shim.dom, this.dom);
22300 shim.setStyle('z-index', this.getZIndex()-2);
22305 hideShim : function(){
22307 this.shim.setDisplayed(false);
22308 shims.push(this.shim);
22313 disableShadow : function(){
22315 this.shadowDisabled = true;
22316 this.shadow.hide();
22317 this.lastShadowOffset = this.shadowOffset;
22318 this.shadowOffset = 0;
22322 enableShadow : function(show){
22324 this.shadowDisabled = false;
22325 this.shadowOffset = this.lastShadowOffset;
22326 delete this.lastShadowOffset;
22334 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22335 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22336 sync : function(doShow){
22337 var sw = this.shadow;
22338 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22339 var sh = this.getShim();
22341 var w = this.getWidth(),
22342 h = this.getHeight();
22344 var l = this.getLeft(true),
22345 t = this.getTop(true);
22347 if(sw && !this.shadowDisabled){
22348 if(doShow && !sw.isVisible()){
22351 sw.realign(l, t, w, h);
22357 // fit the shim behind the shadow, so it is shimmed too
22358 var a = sw.adjusts, s = sh.dom.style;
22359 s.left = (Math.min(l, l+a.l))+"px";
22360 s.top = (Math.min(t, t+a.t))+"px";
22361 s.width = (w+a.w)+"px";
22362 s.height = (h+a.h)+"px";
22369 sh.setLeftTop(l, t);
22376 destroy : function(){
22379 this.shadow.hide();
22381 this.removeAllListeners();
22382 var pn = this.dom.parentNode;
22384 pn.removeChild(this.dom);
22386 Roo.Element.uncache(this.id);
22389 remove : function(){
22394 beginUpdate : function(){
22395 this.updating = true;
22399 endUpdate : function(){
22400 this.updating = false;
22405 hideUnders : function(negOffset){
22407 this.shadow.hide();
22413 constrainXY : function(){
22414 if(this.constrain){
22415 var vw = Roo.lib.Dom.getViewWidth(),
22416 vh = Roo.lib.Dom.getViewHeight();
22417 var s = Roo.get(document).getScroll();
22419 var xy = this.getXY();
22420 var x = xy[0], y = xy[1];
22421 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22422 // only move it if it needs it
22424 // first validate right/bottom
22425 if((x + w) > vw+s.left){
22426 x = vw - w - this.shadowOffset;
22429 if((y + h) > vh+s.top){
22430 y = vh - h - this.shadowOffset;
22433 // then make sure top/left isn't negative
22444 var ay = this.avoidY;
22445 if(y <= ay && (y+h) >= ay){
22451 supr.setXY.call(this, xy);
22457 isVisible : function(){
22458 return this.visible;
22462 showAction : function(){
22463 this.visible = true; // track visibility to prevent getStyle calls
22464 if(this.useDisplay === true){
22465 this.setDisplayed("");
22466 }else if(this.lastXY){
22467 supr.setXY.call(this, this.lastXY);
22468 }else if(this.lastLT){
22469 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22474 hideAction : function(){
22475 this.visible = false;
22476 if(this.useDisplay === true){
22477 this.setDisplayed(false);
22479 this.setLeftTop(-10000,-10000);
22483 // overridden Element method
22484 setVisible : function(v, a, d, c, e){
22489 var cb = function(){
22494 }.createDelegate(this);
22495 supr.setVisible.call(this, true, true, d, cb, e);
22498 this.hideUnders(true);
22507 }.createDelegate(this);
22509 supr.setVisible.call(this, v, a, d, cb, e);
22518 storeXY : function(xy){
22519 delete this.lastLT;
22523 storeLeftTop : function(left, top){
22524 delete this.lastXY;
22525 this.lastLT = [left, top];
22529 beforeFx : function(){
22530 this.beforeAction();
22531 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22535 afterFx : function(){
22536 Roo.Layer.superclass.afterFx.apply(this, arguments);
22537 this.sync(this.isVisible());
22541 beforeAction : function(){
22542 if(!this.updating && this.shadow){
22543 this.shadow.hide();
22547 // overridden Element method
22548 setLeft : function(left){
22549 this.storeLeftTop(left, this.getTop(true));
22550 supr.setLeft.apply(this, arguments);
22554 setTop : function(top){
22555 this.storeLeftTop(this.getLeft(true), top);
22556 supr.setTop.apply(this, arguments);
22560 setLeftTop : function(left, top){
22561 this.storeLeftTop(left, top);
22562 supr.setLeftTop.apply(this, arguments);
22566 setXY : function(xy, a, d, c, e){
22568 this.beforeAction();
22570 var cb = this.createCB(c);
22571 supr.setXY.call(this, xy, a, d, cb, e);
22578 createCB : function(c){
22589 // overridden Element method
22590 setX : function(x, a, d, c, e){
22591 this.setXY([x, this.getY()], a, d, c, e);
22594 // overridden Element method
22595 setY : function(y, a, d, c, e){
22596 this.setXY([this.getX(), y], a, d, c, e);
22599 // overridden Element method
22600 setSize : function(w, h, a, d, c, e){
22601 this.beforeAction();
22602 var cb = this.createCB(c);
22603 supr.setSize.call(this, w, h, a, d, cb, e);
22609 // overridden Element method
22610 setWidth : function(w, a, d, c, e){
22611 this.beforeAction();
22612 var cb = this.createCB(c);
22613 supr.setWidth.call(this, w, a, d, cb, e);
22619 // overridden Element method
22620 setHeight : function(h, a, d, c, e){
22621 this.beforeAction();
22622 var cb = this.createCB(c);
22623 supr.setHeight.call(this, h, a, d, cb, e);
22629 // overridden Element method
22630 setBounds : function(x, y, w, h, a, d, c, e){
22631 this.beforeAction();
22632 var cb = this.createCB(c);
22634 this.storeXY([x, y]);
22635 supr.setXY.call(this, [x, y]);
22636 supr.setSize.call(this, w, h, a, d, cb, e);
22639 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22645 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22646 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22647 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22648 * @param {Number} zindex The new z-index to set
22649 * @return {this} The Layer
22651 setZIndex : function(zindex){
22652 this.zindex = zindex;
22653 this.setStyle("z-index", zindex + 2);
22655 this.shadow.setZIndex(zindex + 1);
22658 this.shim.setStyle("z-index", zindex);
22664 * Ext JS Library 1.1.1
22665 * Copyright(c) 2006-2007, Ext JS, LLC.
22667 * Originally Released Under LGPL - original licence link has changed is not relivant.
22670 * <script type="text/javascript">
22675 * @class Roo.Shadow
22676 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22677 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22678 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22680 * Create a new Shadow
22681 * @param {Object} config The config object
22683 Roo.Shadow = function(config){
22684 Roo.apply(this, config);
22685 if(typeof this.mode != "string"){
22686 this.mode = this.defaultMode;
22688 var o = this.offset, a = {h: 0};
22689 var rad = Math.floor(this.offset/2);
22690 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22696 a.l -= this.offset + rad;
22697 a.t -= this.offset + rad;
22708 a.l -= (this.offset - rad);
22709 a.t -= this.offset + rad;
22711 a.w -= (this.offset - rad)*2;
22722 a.l -= (this.offset - rad);
22723 a.t -= (this.offset - rad);
22725 a.w -= (this.offset + rad + 1);
22726 a.h -= (this.offset + rad);
22735 Roo.Shadow.prototype = {
22737 * @cfg {String} mode
22738 * The shadow display mode. Supports the following options:<br />
22739 * sides: Shadow displays on both sides and bottom only<br />
22740 * frame: Shadow displays equally on all four sides<br />
22741 * drop: Traditional bottom-right drop shadow (default)
22744 * @cfg {String} offset
22745 * The number of pixels to offset the shadow from the element (defaults to 4)
22750 defaultMode: "drop",
22753 * Displays the shadow under the target element
22754 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22756 show : function(target){
22757 target = Roo.get(target);
22759 this.el = Roo.Shadow.Pool.pull();
22760 if(this.el.dom.nextSibling != target.dom){
22761 this.el.insertBefore(target);
22764 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22766 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22769 target.getLeft(true),
22770 target.getTop(true),
22774 this.el.dom.style.display = "block";
22778 * Returns true if the shadow is visible, else false
22780 isVisible : function(){
22781 return this.el ? true : false;
22785 * Direct alignment when values are already available. Show must be called at least once before
22786 * calling this method to ensure it is initialized.
22787 * @param {Number} left The target element left position
22788 * @param {Number} top The target element top position
22789 * @param {Number} width The target element width
22790 * @param {Number} height The target element height
22792 realign : function(l, t, w, h){
22796 var a = this.adjusts, d = this.el.dom, s = d.style;
22798 s.left = (l+a.l)+"px";
22799 s.top = (t+a.t)+"px";
22800 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22802 if(s.width != sws || s.height != shs){
22806 var cn = d.childNodes;
22807 var sww = Math.max(0, (sw-12))+"px";
22808 cn[0].childNodes[1].style.width = sww;
22809 cn[1].childNodes[1].style.width = sww;
22810 cn[2].childNodes[1].style.width = sww;
22811 cn[1].style.height = Math.max(0, (sh-12))+"px";
22817 * Hides this shadow
22821 this.el.dom.style.display = "none";
22822 Roo.Shadow.Pool.push(this.el);
22828 * Adjust the z-index of this shadow
22829 * @param {Number} zindex The new z-index
22831 setZIndex : function(z){
22834 this.el.setStyle("z-index", z);
22839 // Private utility class that manages the internal Shadow cache
22840 Roo.Shadow.Pool = function(){
22842 var markup = Roo.isIE ?
22843 '<div class="x-ie-shadow"></div>' :
22844 '<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>';
22847 var sh = p.shift();
22849 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22850 sh.autoBoxAdjust = false;
22855 push : function(sh){
22861 * Ext JS Library 1.1.1
22862 * Copyright(c) 2006-2007, Ext JS, LLC.
22864 * Originally Released Under LGPL - original licence link has changed is not relivant.
22867 * <script type="text/javascript">
22871 * @class Roo.BoxComponent
22872 * @extends Roo.Component
22873 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22874 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22875 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22876 * layout containers.
22878 * @param {Roo.Element/String/Object} config The configuration options.
22880 Roo.BoxComponent = function(config){
22881 Roo.Component.call(this, config);
22885 * Fires after the component is resized.
22886 * @param {Roo.Component} this
22887 * @param {Number} adjWidth The box-adjusted width that was set
22888 * @param {Number} adjHeight The box-adjusted height that was set
22889 * @param {Number} rawWidth The width that was originally specified
22890 * @param {Number} rawHeight The height that was originally specified
22895 * Fires after the component is moved.
22896 * @param {Roo.Component} this
22897 * @param {Number} x The new x position
22898 * @param {Number} y The new y position
22904 Roo.extend(Roo.BoxComponent, Roo.Component, {
22905 // private, set in afterRender to signify that the component has been rendered
22907 // private, used to defer height settings to subclasses
22908 deferHeight: false,
22909 /** @cfg {Number} width
22910 * width (optional) size of component
22912 /** @cfg {Number} height
22913 * height (optional) size of component
22917 * Sets the width and height of the component. This method fires the resize event. This method can accept
22918 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22919 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22920 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22921 * @return {Roo.BoxComponent} this
22923 setSize : function(w, h){
22924 // support for standard size objects
22925 if(typeof w == 'object'){
22930 if(!this.boxReady){
22936 // prevent recalcs when not needed
22937 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22940 this.lastSize = {width: w, height: h};
22942 var adj = this.adjustSize(w, h);
22943 var aw = adj.width, ah = adj.height;
22944 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22945 var rz = this.getResizeEl();
22946 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22947 rz.setSize(aw, ah);
22948 }else if(!this.deferHeight && ah !== undefined){
22950 }else if(aw !== undefined){
22953 this.onResize(aw, ah, w, h);
22954 this.fireEvent('resize', this, aw, ah, w, h);
22960 * Gets the current size of the component's underlying element.
22961 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22963 getSize : function(){
22964 return this.el.getSize();
22968 * Gets the current XY position of the component's underlying element.
22969 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22970 * @return {Array} The XY position of the element (e.g., [100, 200])
22972 getPosition : function(local){
22973 if(local === true){
22974 return [this.el.getLeft(true), this.el.getTop(true)];
22976 return this.xy || this.el.getXY();
22980 * Gets the current box measurements of the component's underlying element.
22981 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22982 * @returns {Object} box An object in the format {x, y, width, height}
22984 getBox : function(local){
22985 var s = this.el.getSize();
22987 s.x = this.el.getLeft(true);
22988 s.y = this.el.getTop(true);
22990 var xy = this.xy || this.el.getXY();
22998 * Sets the current box measurements of the component's underlying element.
22999 * @param {Object} box An object in the format {x, y, width, height}
23000 * @returns {Roo.BoxComponent} this
23002 updateBox : function(box){
23003 this.setSize(box.width, box.height);
23004 this.setPagePosition(box.x, box.y);
23009 getResizeEl : function(){
23010 return this.resizeEl || this.el;
23014 getPositionEl : function(){
23015 return this.positionEl || this.el;
23019 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
23020 * This method fires the move event.
23021 * @param {Number} left The new left
23022 * @param {Number} top The new top
23023 * @returns {Roo.BoxComponent} this
23025 setPosition : function(x, y){
23028 if(!this.boxReady){
23031 var adj = this.adjustPosition(x, y);
23032 var ax = adj.x, ay = adj.y;
23034 var el = this.getPositionEl();
23035 if(ax !== undefined || ay !== undefined){
23036 if(ax !== undefined && ay !== undefined){
23037 el.setLeftTop(ax, ay);
23038 }else if(ax !== undefined){
23040 }else if(ay !== undefined){
23043 this.onPosition(ax, ay);
23044 this.fireEvent('move', this, ax, ay);
23050 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
23051 * This method fires the move event.
23052 * @param {Number} x The new x position
23053 * @param {Number} y The new y position
23054 * @returns {Roo.BoxComponent} this
23056 setPagePosition : function(x, y){
23059 if(!this.boxReady){
23062 if(x === undefined || y === undefined){ // cannot translate undefined points
23065 var p = this.el.translatePoints(x, y);
23066 this.setPosition(p.left, p.top);
23071 onRender : function(ct, position){
23072 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23074 this.resizeEl = Roo.get(this.resizeEl);
23076 if(this.positionEl){
23077 this.positionEl = Roo.get(this.positionEl);
23082 afterRender : function(){
23083 Roo.BoxComponent.superclass.afterRender.call(this);
23084 this.boxReady = true;
23085 this.setSize(this.width, this.height);
23086 if(this.x || this.y){
23087 this.setPosition(this.x, this.y);
23089 if(this.pageX || this.pageY){
23090 this.setPagePosition(this.pageX, this.pageY);
23095 * Force the component's size to recalculate based on the underlying element's current height and width.
23096 * @returns {Roo.BoxComponent} this
23098 syncSize : function(){
23099 delete this.lastSize;
23100 this.setSize(this.el.getWidth(), this.el.getHeight());
23105 * Called after the component is resized, this method is empty by default but can be implemented by any
23106 * subclass that needs to perform custom logic after a resize occurs.
23107 * @param {Number} adjWidth The box-adjusted width that was set
23108 * @param {Number} adjHeight The box-adjusted height that was set
23109 * @param {Number} rawWidth The width that was originally specified
23110 * @param {Number} rawHeight The height that was originally specified
23112 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23117 * Called after the component is moved, this method is empty by default but can be implemented by any
23118 * subclass that needs to perform custom logic after a move occurs.
23119 * @param {Number} x The new x position
23120 * @param {Number} y The new y position
23122 onPosition : function(x, y){
23127 adjustSize : function(w, h){
23128 if(this.autoWidth){
23131 if(this.autoHeight){
23134 return {width : w, height: h};
23138 adjustPosition : function(x, y){
23139 return {x : x, y: y};
23143 * Ext JS Library 1.1.1
23144 * Copyright(c) 2006-2007, Ext JS, LLC.
23146 * Originally Released Under LGPL - original licence link has changed is not relivant.
23149 * <script type="text/javascript">
23154 * @class Roo.SplitBar
23155 * @extends Roo.util.Observable
23156 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23160 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23161 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23162 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23163 split.minSize = 100;
23164 split.maxSize = 600;
23165 split.animate = true;
23166 split.on('moved', splitterMoved);
23169 * Create a new SplitBar
23170 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23171 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23172 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23173 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23174 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23175 position of the SplitBar).
23177 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23180 this.el = Roo.get(dragElement, true);
23181 this.el.dom.unselectable = "on";
23183 this.resizingEl = Roo.get(resizingElement, true);
23187 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23188 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23191 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23194 * The minimum size of the resizing element. (Defaults to 0)
23200 * The maximum size of the resizing element. (Defaults to 2000)
23203 this.maxSize = 2000;
23206 * Whether to animate the transition to the new size
23209 this.animate = false;
23212 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23215 this.useShim = false;
23220 if(!existingProxy){
23222 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23224 this.proxy = Roo.get(existingProxy).dom;
23227 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23230 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23233 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23236 this.dragSpecs = {};
23239 * @private The adapter to use to positon and resize elements
23241 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23242 this.adapter.init(this);
23244 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23246 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23247 this.el.addClass("x-splitbar-h");
23250 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23251 this.el.addClass("x-splitbar-v");
23257 * Fires when the splitter is moved (alias for {@link #event-moved})
23258 * @param {Roo.SplitBar} this
23259 * @param {Number} newSize the new width or height
23264 * Fires when the splitter is moved
23265 * @param {Roo.SplitBar} this
23266 * @param {Number} newSize the new width or height
23270 * @event beforeresize
23271 * Fires before the splitter is dragged
23272 * @param {Roo.SplitBar} this
23274 "beforeresize" : true,
23276 "beforeapply" : true
23279 Roo.util.Observable.call(this);
23282 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23283 onStartProxyDrag : function(x, y){
23284 this.fireEvent("beforeresize", this);
23286 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23288 o.enableDisplayMode("block");
23289 // all splitbars share the same overlay
23290 Roo.SplitBar.prototype.overlay = o;
23292 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23293 this.overlay.show();
23294 Roo.get(this.proxy).setDisplayed("block");
23295 var size = this.adapter.getElementSize(this);
23296 this.activeMinSize = this.getMinimumSize();;
23297 this.activeMaxSize = this.getMaximumSize();;
23298 var c1 = size - this.activeMinSize;
23299 var c2 = Math.max(this.activeMaxSize - size, 0);
23300 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23301 this.dd.resetConstraints();
23302 this.dd.setXConstraint(
23303 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23304 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23306 this.dd.setYConstraint(0, 0);
23308 this.dd.resetConstraints();
23309 this.dd.setXConstraint(0, 0);
23310 this.dd.setYConstraint(
23311 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23312 this.placement == Roo.SplitBar.TOP ? c2 : c1
23315 this.dragSpecs.startSize = size;
23316 this.dragSpecs.startPoint = [x, y];
23317 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23321 * @private Called after the drag operation by the DDProxy
23323 onEndProxyDrag : function(e){
23324 Roo.get(this.proxy).setDisplayed(false);
23325 var endPoint = Roo.lib.Event.getXY(e);
23327 this.overlay.hide();
23330 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23331 newSize = this.dragSpecs.startSize +
23332 (this.placement == Roo.SplitBar.LEFT ?
23333 endPoint[0] - this.dragSpecs.startPoint[0] :
23334 this.dragSpecs.startPoint[0] - endPoint[0]
23337 newSize = this.dragSpecs.startSize +
23338 (this.placement == Roo.SplitBar.TOP ?
23339 endPoint[1] - this.dragSpecs.startPoint[1] :
23340 this.dragSpecs.startPoint[1] - endPoint[1]
23343 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23344 if(newSize != this.dragSpecs.startSize){
23345 if(this.fireEvent('beforeapply', this, newSize) !== false){
23346 this.adapter.setElementSize(this, newSize);
23347 this.fireEvent("moved", this, newSize);
23348 this.fireEvent("resize", this, newSize);
23354 * Get the adapter this SplitBar uses
23355 * @return The adapter object
23357 getAdapter : function(){
23358 return this.adapter;
23362 * Set the adapter this SplitBar uses
23363 * @param {Object} adapter A SplitBar adapter object
23365 setAdapter : function(adapter){
23366 this.adapter = adapter;
23367 this.adapter.init(this);
23371 * Gets the minimum size for the resizing element
23372 * @return {Number} The minimum size
23374 getMinimumSize : function(){
23375 return this.minSize;
23379 * Sets the minimum size for the resizing element
23380 * @param {Number} minSize The minimum size
23382 setMinimumSize : function(minSize){
23383 this.minSize = minSize;
23387 * Gets the maximum size for the resizing element
23388 * @return {Number} The maximum size
23390 getMaximumSize : function(){
23391 return this.maxSize;
23395 * Sets the maximum size for the resizing element
23396 * @param {Number} maxSize The maximum size
23398 setMaximumSize : function(maxSize){
23399 this.maxSize = maxSize;
23403 * Sets the initialize size for the resizing element
23404 * @param {Number} size The initial size
23406 setCurrentSize : function(size){
23407 var oldAnimate = this.animate;
23408 this.animate = false;
23409 this.adapter.setElementSize(this, size);
23410 this.animate = oldAnimate;
23414 * Destroy this splitbar.
23415 * @param {Boolean} removeEl True to remove the element
23417 destroy : function(removeEl){
23419 this.shim.remove();
23422 this.proxy.parentNode.removeChild(this.proxy);
23430 * @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.
23432 Roo.SplitBar.createProxy = function(dir){
23433 var proxy = new Roo.Element(document.createElement("div"));
23434 proxy.unselectable();
23435 var cls = 'x-splitbar-proxy';
23436 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23437 document.body.appendChild(proxy.dom);
23442 * @class Roo.SplitBar.BasicLayoutAdapter
23443 * Default Adapter. It assumes the splitter and resizing element are not positioned
23444 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23446 Roo.SplitBar.BasicLayoutAdapter = function(){
23449 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23450 // do nothing for now
23451 init : function(s){
23455 * Called before drag operations to get the current size of the resizing element.
23456 * @param {Roo.SplitBar} s The SplitBar using this adapter
23458 getElementSize : function(s){
23459 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23460 return s.resizingEl.getWidth();
23462 return s.resizingEl.getHeight();
23467 * Called after drag operations to set the size of the resizing element.
23468 * @param {Roo.SplitBar} s The SplitBar using this adapter
23469 * @param {Number} newSize The new size to set
23470 * @param {Function} onComplete A function to be invoked when resizing is complete
23472 setElementSize : function(s, newSize, onComplete){
23473 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23475 s.resizingEl.setWidth(newSize);
23477 onComplete(s, newSize);
23480 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23485 s.resizingEl.setHeight(newSize);
23487 onComplete(s, newSize);
23490 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23497 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23498 * @extends Roo.SplitBar.BasicLayoutAdapter
23499 * Adapter that moves the splitter element to align with the resized sizing element.
23500 * Used with an absolute positioned SplitBar.
23501 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23502 * document.body, make sure you assign an id to the body element.
23504 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23505 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23506 this.container = Roo.get(container);
23509 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23510 init : function(s){
23511 this.basic.init(s);
23514 getElementSize : function(s){
23515 return this.basic.getElementSize(s);
23518 setElementSize : function(s, newSize, onComplete){
23519 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23522 moveSplitter : function(s){
23523 var yes = Roo.SplitBar;
23524 switch(s.placement){
23526 s.el.setX(s.resizingEl.getRight());
23529 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23532 s.el.setY(s.resizingEl.getBottom());
23535 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23542 * Orientation constant - Create a vertical SplitBar
23546 Roo.SplitBar.VERTICAL = 1;
23549 * Orientation constant - Create a horizontal SplitBar
23553 Roo.SplitBar.HORIZONTAL = 2;
23556 * Placement constant - The resizing element is to the left of the splitter element
23560 Roo.SplitBar.LEFT = 1;
23563 * Placement constant - The resizing element is to the right of the splitter element
23567 Roo.SplitBar.RIGHT = 2;
23570 * Placement constant - The resizing element is positioned above the splitter element
23574 Roo.SplitBar.TOP = 3;
23577 * Placement constant - The resizing element is positioned under splitter element
23581 Roo.SplitBar.BOTTOM = 4;
23584 * Ext JS Library 1.1.1
23585 * Copyright(c) 2006-2007, Ext JS, LLC.
23587 * Originally Released Under LGPL - original licence link has changed is not relivant.
23590 * <script type="text/javascript">
23595 * @extends Roo.util.Observable
23596 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23597 * This class also supports single and multi selection modes. <br>
23598 * Create a data model bound view:
23600 var store = new Roo.data.Store(...);
23602 var view = new Roo.View({
23604 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
23606 singleSelect: true,
23607 selectedClass: "ydataview-selected",
23611 // listen for node click?
23612 view.on("click", function(vw, index, node, e){
23613 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23617 dataModel.load("foobar.xml");
23619 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23621 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23622 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23624 * Note: old style constructor is still suported (container, template, config)
23627 * Create a new View
23628 * @param {Object} config The config object
23631 Roo.View = function(config, depreciated_tpl, depreciated_config){
23633 if (typeof(depreciated_tpl) == 'undefined') {
23634 // new way.. - universal constructor.
23635 Roo.apply(this, config);
23636 this.el = Roo.get(this.el);
23639 this.el = Roo.get(config);
23640 this.tpl = depreciated_tpl;
23641 Roo.apply(this, depreciated_config);
23645 if(typeof(this.tpl) == "string"){
23646 this.tpl = new Roo.Template(this.tpl);
23648 // support xtype ctors..
23649 this.tpl = new Roo.factory(this.tpl, Roo);
23653 this.tpl.compile();
23660 * @event beforeclick
23661 * Fires before a click is processed. Returns false to cancel the default action.
23662 * @param {Roo.View} this
23663 * @param {Number} index The index of the target node
23664 * @param {HTMLElement} node The target node
23665 * @param {Roo.EventObject} e The raw event object
23667 "beforeclick" : true,
23670 * Fires when a template node is clicked.
23671 * @param {Roo.View} this
23672 * @param {Number} index The index of the target node
23673 * @param {HTMLElement} node The target node
23674 * @param {Roo.EventObject} e The raw event object
23679 * Fires when a template node is double clicked.
23680 * @param {Roo.View} this
23681 * @param {Number} index The index of the target node
23682 * @param {HTMLElement} node The target node
23683 * @param {Roo.EventObject} e The raw event object
23687 * @event contextmenu
23688 * Fires when a template node is right clicked.
23689 * @param {Roo.View} this
23690 * @param {Number} index The index of the target node
23691 * @param {HTMLElement} node The target node
23692 * @param {Roo.EventObject} e The raw event object
23694 "contextmenu" : true,
23696 * @event selectionchange
23697 * Fires when the selected nodes change.
23698 * @param {Roo.View} this
23699 * @param {Array} selections Array of the selected nodes
23701 "selectionchange" : true,
23704 * @event beforeselect
23705 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23706 * @param {Roo.View} this
23707 * @param {HTMLElement} node The node to be selected
23708 * @param {Array} selections Array of currently selected nodes
23710 "beforeselect" : true,
23712 * @event preparedata
23713 * Fires on every row to render, to allow you to change the data.
23714 * @param {Roo.View} this
23715 * @param {Object} data to be rendered (change this)
23717 "preparedata" : true
23721 "click": this.onClick,
23722 "dblclick": this.onDblClick,
23723 "contextmenu": this.onContextMenu,
23727 this.selections = [];
23729 this.cmp = new Roo.CompositeElementLite([]);
23731 this.store = Roo.factory(this.store, Roo.data);
23732 this.setStore(this.store, true);
23734 Roo.View.superclass.constructor.call(this);
23737 Roo.extend(Roo.View, Roo.util.Observable, {
23740 * @cfg {Roo.data.Store} store Data store to load data from.
23745 * @cfg {String|Roo.Element} el The container element.
23750 * @cfg {String|Roo.Template} tpl The template used by this View
23755 * @cfg {String} selectedClass The css class to add to selected nodes
23757 selectedClass : "x-view-selected",
23759 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23763 * @cfg {Boolean} multiSelect Allow multiple selection
23765 multiSelect : false,
23767 * @cfg {Boolean} singleSelect Allow single selection
23769 singleSelect: false,
23772 * @cfg {Boolean} toggleSelect - selecting
23774 toggleSelect : false,
23777 * Returns the element this view is bound to.
23778 * @return {Roo.Element}
23780 getEl : function(){
23785 * Refreshes the view.
23787 refresh : function(){
23789 this.clearSelections();
23790 this.el.update("");
23792 var records = this.store.getRange();
23793 if(records.length < 1){
23794 this.el.update(this.emptyText);
23797 for(var i = 0, len = records.length; i < len; i++){
23798 var data = this.prepareData(records[i].data, i, records[i]);
23799 this.fireEvent("preparedata", this, data, i, records[i]);
23800 html[html.length] = t.apply(data);
23802 this.el.update(html.join(""));
23803 this.nodes = this.el.dom.childNodes;
23804 this.updateIndexes(0);
23808 * Function to override to reformat the data that is sent to
23809 * the template for each node.
23810 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23811 * a JSON object for an UpdateManager bound view).
23813 prepareData : function(data){
23817 onUpdate : function(ds, record){
23818 this.clearSelections();
23819 var index = this.store.indexOf(record);
23820 var n = this.nodes[index];
23821 this.tpl.insertBefore(n, this.prepareData(record.data));
23822 n.parentNode.removeChild(n);
23823 this.updateIndexes(index, index);
23826 onAdd : function(ds, records, index){
23827 this.clearSelections();
23828 if(this.nodes.length == 0){
23832 var n = this.nodes[index];
23833 for(var i = 0, len = records.length; i < len; i++){
23834 var d = this.prepareData(records[i].data);
23836 this.tpl.insertBefore(n, d);
23838 this.tpl.append(this.el, d);
23841 this.updateIndexes(index);
23844 onRemove : function(ds, record, index){
23845 this.clearSelections();
23846 this.el.dom.removeChild(this.nodes[index]);
23847 this.updateIndexes(index);
23851 * Refresh an individual node.
23852 * @param {Number} index
23854 refreshNode : function(index){
23855 this.onUpdate(this.store, this.store.getAt(index));
23858 updateIndexes : function(startIndex, endIndex){
23859 var ns = this.nodes;
23860 startIndex = startIndex || 0;
23861 endIndex = endIndex || ns.length - 1;
23862 for(var i = startIndex; i <= endIndex; i++){
23863 ns[i].nodeIndex = i;
23868 * Changes the data store this view uses and refresh the view.
23869 * @param {Store} store
23871 setStore : function(store, initial){
23872 if(!initial && this.store){
23873 this.store.un("datachanged", this.refresh);
23874 this.store.un("add", this.onAdd);
23875 this.store.un("remove", this.onRemove);
23876 this.store.un("update", this.onUpdate);
23877 this.store.un("clear", this.refresh);
23881 store.on("datachanged", this.refresh, this);
23882 store.on("add", this.onAdd, this);
23883 store.on("remove", this.onRemove, this);
23884 store.on("update", this.onUpdate, this);
23885 store.on("clear", this.refresh, this);
23894 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23895 * @param {HTMLElement} node
23896 * @return {HTMLElement} The template node
23898 findItemFromChild : function(node){
23899 var el = this.el.dom;
23900 if(!node || node.parentNode == el){
23903 var p = node.parentNode;
23904 while(p && p != el){
23905 if(p.parentNode == el){
23914 onClick : function(e){
23915 var item = this.findItemFromChild(e.getTarget());
23917 var index = this.indexOf(item);
23918 if(this.onItemClick(item, index, e) !== false){
23919 this.fireEvent("click", this, index, item, e);
23922 this.clearSelections();
23927 onContextMenu : function(e){
23928 var item = this.findItemFromChild(e.getTarget());
23930 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23935 onDblClick : function(e){
23936 var item = this.findItemFromChild(e.getTarget());
23938 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23942 onItemClick : function(item, index, e)
23944 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23947 if (this.toggleSelect) {
23948 var m = this.isSelected(item) ? 'unselect' : 'select';
23951 _t[m](item, true, false);
23954 if(this.multiSelect || this.singleSelect){
23955 if(this.multiSelect && e.shiftKey && this.lastSelection){
23956 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23958 this.select(item, this.multiSelect && e.ctrlKey);
23959 this.lastSelection = item;
23961 e.preventDefault();
23967 * Get the number of selected nodes.
23970 getSelectionCount : function(){
23971 return this.selections.length;
23975 * Get the currently selected nodes.
23976 * @return {Array} An array of HTMLElements
23978 getSelectedNodes : function(){
23979 return this.selections;
23983 * Get the indexes of the selected nodes.
23986 getSelectedIndexes : function(){
23987 var indexes = [], s = this.selections;
23988 for(var i = 0, len = s.length; i < len; i++){
23989 indexes.push(s[i].nodeIndex);
23995 * Clear all selections
23996 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23998 clearSelections : function(suppressEvent){
23999 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
24000 this.cmp.elements = this.selections;
24001 this.cmp.removeClass(this.selectedClass);
24002 this.selections = [];
24003 if(!suppressEvent){
24004 this.fireEvent("selectionchange", this, this.selections);
24010 * Returns true if the passed node is selected
24011 * @param {HTMLElement/Number} node The node or node index
24012 * @return {Boolean}
24014 isSelected : function(node){
24015 var s = this.selections;
24019 node = this.getNode(node);
24020 return s.indexOf(node) !== -1;
24025 * @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
24026 * @param {Boolean} keepExisting (optional) true to keep existing selections
24027 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24029 select : function(nodeInfo, keepExisting, suppressEvent){
24030 if(nodeInfo instanceof Array){
24032 this.clearSelections(true);
24034 for(var i = 0, len = nodeInfo.length; i < len; i++){
24035 this.select(nodeInfo[i], true, true);
24039 var node = this.getNode(nodeInfo);
24040 if(!node || this.isSelected(node)){
24041 return; // already selected.
24044 this.clearSelections(true);
24046 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
24047 Roo.fly(node).addClass(this.selectedClass);
24048 this.selections.push(node);
24049 if(!suppressEvent){
24050 this.fireEvent("selectionchange", this, this.selections);
24058 * @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
24059 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
24060 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24062 unselect : function(nodeInfo, keepExisting, suppressEvent)
24064 if(nodeInfo instanceof Array){
24065 Roo.each(this.selections, function(s) {
24066 this.unselect(s, nodeInfo);
24070 var node = this.getNode(nodeInfo);
24071 if(!node || !this.isSelected(node)){
24072 Roo.log("not selected");
24073 return; // not selected.
24077 Roo.each(this.selections, function(s) {
24079 Roo.fly(node).removeClass(this.selectedClass);
24086 this.selections= ns;
24087 this.fireEvent("selectionchange", this, this.selections);
24091 * Gets a template node.
24092 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24093 * @return {HTMLElement} The node or null if it wasn't found
24095 getNode : function(nodeInfo){
24096 if(typeof nodeInfo == "string"){
24097 return document.getElementById(nodeInfo);
24098 }else if(typeof nodeInfo == "number"){
24099 return this.nodes[nodeInfo];
24105 * Gets a range template nodes.
24106 * @param {Number} startIndex
24107 * @param {Number} endIndex
24108 * @return {Array} An array of nodes
24110 getNodes : function(start, end){
24111 var ns = this.nodes;
24112 start = start || 0;
24113 end = typeof end == "undefined" ? ns.length - 1 : end;
24116 for(var i = start; i <= end; i++){
24120 for(var i = start; i >= end; i--){
24128 * Finds the index of the passed node
24129 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24130 * @return {Number} The index of the node or -1
24132 indexOf : function(node){
24133 node = this.getNode(node);
24134 if(typeof node.nodeIndex == "number"){
24135 return node.nodeIndex;
24137 var ns = this.nodes;
24138 for(var i = 0, len = ns.length; i < len; i++){
24148 * Ext JS Library 1.1.1
24149 * Copyright(c) 2006-2007, Ext JS, LLC.
24151 * Originally Released Under LGPL - original licence link has changed is not relivant.
24154 * <script type="text/javascript">
24158 * @class Roo.JsonView
24159 * @extends Roo.View
24160 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24162 var view = new Roo.JsonView({
24163 container: "my-element",
24164 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24169 // listen for node click?
24170 view.on("click", function(vw, index, node, e){
24171 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24174 // direct load of JSON data
24175 view.load("foobar.php");
24177 // Example from my blog list
24178 var tpl = new Roo.Template(
24179 '<div class="entry">' +
24180 '<a class="entry-title" href="{link}">{title}</a>' +
24181 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24182 "</div><hr />"
24185 var moreView = new Roo.JsonView({
24186 container : "entry-list",
24190 moreView.on("beforerender", this.sortEntries, this);
24192 url: "/blog/get-posts.php",
24193 params: "allposts=true",
24194 text: "Loading Blog Entries..."
24198 * Note: old code is supported with arguments : (container, template, config)
24202 * Create a new JsonView
24204 * @param {Object} config The config object
24207 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24210 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24212 var um = this.el.getUpdateManager();
24213 um.setRenderer(this);
24214 um.on("update", this.onLoad, this);
24215 um.on("failure", this.onLoadException, this);
24218 * @event beforerender
24219 * Fires before rendering of the downloaded JSON data.
24220 * @param {Roo.JsonView} this
24221 * @param {Object} data The JSON data loaded
24225 * Fires when data is loaded.
24226 * @param {Roo.JsonView} this
24227 * @param {Object} data The JSON data loaded
24228 * @param {Object} response The raw Connect response object
24231 * @event loadexception
24232 * Fires when loading fails.
24233 * @param {Roo.JsonView} this
24234 * @param {Object} response The raw Connect response object
24237 'beforerender' : true,
24239 'loadexception' : true
24242 Roo.extend(Roo.JsonView, Roo.View, {
24244 * @type {String} The root property in the loaded JSON object that contains the data
24249 * Refreshes the view.
24251 refresh : function(){
24252 this.clearSelections();
24253 this.el.update("");
24255 var o = this.jsonData;
24256 if(o && o.length > 0){
24257 for(var i = 0, len = o.length; i < len; i++){
24258 var data = this.prepareData(o[i], i, o);
24259 html[html.length] = this.tpl.apply(data);
24262 html.push(this.emptyText);
24264 this.el.update(html.join(""));
24265 this.nodes = this.el.dom.childNodes;
24266 this.updateIndexes(0);
24270 * 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.
24271 * @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:
24274 url: "your-url.php",
24275 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24276 callback: yourFunction,
24277 scope: yourObject, //(optional scope)
24280 text: "Loading...",
24285 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24286 * 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.
24287 * @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}
24288 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24289 * @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.
24292 var um = this.el.getUpdateManager();
24293 um.update.apply(um, arguments);
24296 render : function(el, response){
24297 this.clearSelections();
24298 this.el.update("");
24301 o = Roo.util.JSON.decode(response.responseText);
24304 o = o[this.jsonRoot];
24309 * The current JSON data or null
24312 this.beforeRender();
24317 * Get the number of records in the current JSON dataset
24320 getCount : function(){
24321 return this.jsonData ? this.jsonData.length : 0;
24325 * Returns the JSON object for the specified node(s)
24326 * @param {HTMLElement/Array} node The node or an array of nodes
24327 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24328 * you get the JSON object for the node
24330 getNodeData : function(node){
24331 if(node instanceof Array){
24333 for(var i = 0, len = node.length; i < len; i++){
24334 data.push(this.getNodeData(node[i]));
24338 return this.jsonData[this.indexOf(node)] || null;
24341 beforeRender : function(){
24342 this.snapshot = this.jsonData;
24344 this.sort.apply(this, this.sortInfo);
24346 this.fireEvent("beforerender", this, this.jsonData);
24349 onLoad : function(el, o){
24350 this.fireEvent("load", this, this.jsonData, o);
24353 onLoadException : function(el, o){
24354 this.fireEvent("loadexception", this, o);
24358 * Filter the data by a specific property.
24359 * @param {String} property A property on your JSON objects
24360 * @param {String/RegExp} value Either string that the property values
24361 * should start with, or a RegExp to test against the property
24363 filter : function(property, value){
24366 var ss = this.snapshot;
24367 if(typeof value == "string"){
24368 var vlen = value.length;
24370 this.clearFilter();
24373 value = value.toLowerCase();
24374 for(var i = 0, len = ss.length; i < len; i++){
24376 if(o[property].substr(0, vlen).toLowerCase() == value){
24380 } else if(value.exec){ // regex?
24381 for(var i = 0, len = ss.length; i < len; i++){
24383 if(value.test(o[property])){
24390 this.jsonData = data;
24396 * Filter by a function. The passed function will be called with each
24397 * object in the current dataset. If the function returns true the value is kept,
24398 * otherwise it is filtered.
24399 * @param {Function} fn
24400 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24402 filterBy : function(fn, scope){
24405 var ss = this.snapshot;
24406 for(var i = 0, len = ss.length; i < len; i++){
24408 if(fn.call(scope || this, o)){
24412 this.jsonData = data;
24418 * Clears the current filter.
24420 clearFilter : function(){
24421 if(this.snapshot && this.jsonData != this.snapshot){
24422 this.jsonData = this.snapshot;
24429 * Sorts the data for this view and refreshes it.
24430 * @param {String} property A property on your JSON objects to sort on
24431 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24432 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24434 sort : function(property, dir, sortType){
24435 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24438 var dsc = dir && dir.toLowerCase() == "desc";
24439 var f = function(o1, o2){
24440 var v1 = sortType ? sortType(o1[p]) : o1[p];
24441 var v2 = sortType ? sortType(o2[p]) : o2[p];
24444 return dsc ? +1 : -1;
24445 } else if(v1 > v2){
24446 return dsc ? -1 : +1;
24451 this.jsonData.sort(f);
24453 if(this.jsonData != this.snapshot){
24454 this.snapshot.sort(f);
24460 * Ext JS Library 1.1.1
24461 * Copyright(c) 2006-2007, Ext JS, LLC.
24463 * Originally Released Under LGPL - original licence link has changed is not relivant.
24466 * <script type="text/javascript">
24471 * @class Roo.ColorPalette
24472 * @extends Roo.Component
24473 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24474 * Here's an example of typical usage:
24476 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24477 cp.render('my-div');
24479 cp.on('select', function(palette, selColor){
24480 // do something with selColor
24484 * Create a new ColorPalette
24485 * @param {Object} config The config object
24487 Roo.ColorPalette = function(config){
24488 Roo.ColorPalette.superclass.constructor.call(this, config);
24492 * Fires when a color is selected
24493 * @param {ColorPalette} this
24494 * @param {String} color The 6-digit color hex code (without the # symbol)
24500 this.on("select", this.handler, this.scope, true);
24503 Roo.extend(Roo.ColorPalette, Roo.Component, {
24505 * @cfg {String} itemCls
24506 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24508 itemCls : "x-color-palette",
24510 * @cfg {String} value
24511 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24512 * the hex codes are case-sensitive.
24515 clickEvent:'click',
24517 ctype: "Roo.ColorPalette",
24520 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24522 allowReselect : false,
24525 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24526 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24527 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24528 * of colors with the width setting until the box is symmetrical.</p>
24529 * <p>You can override individual colors if needed:</p>
24531 var cp = new Roo.ColorPalette();
24532 cp.colors[0] = "FF0000"; // change the first box to red
24535 Or you can provide a custom array of your own for complete control:
24537 var cp = new Roo.ColorPalette();
24538 cp.colors = ["000000", "993300", "333300"];
24543 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24544 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24545 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24546 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24547 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24551 onRender : function(container, position){
24552 var t = new Roo.MasterTemplate(
24553 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24555 var c = this.colors;
24556 for(var i = 0, len = c.length; i < len; i++){
24559 var el = document.createElement("div");
24560 el.className = this.itemCls;
24562 container.dom.insertBefore(el, position);
24563 this.el = Roo.get(el);
24564 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24565 if(this.clickEvent != 'click'){
24566 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24571 afterRender : function(){
24572 Roo.ColorPalette.superclass.afterRender.call(this);
24574 var s = this.value;
24581 handleClick : function(e, t){
24582 e.preventDefault();
24583 if(!this.disabled){
24584 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24585 this.select(c.toUpperCase());
24590 * Selects the specified color in the palette (fires the select event)
24591 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24593 select : function(color){
24594 color = color.replace("#", "");
24595 if(color != this.value || this.allowReselect){
24598 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24600 el.child("a.color-"+color).addClass("x-color-palette-sel");
24601 this.value = color;
24602 this.fireEvent("select", this, color);
24607 * Ext JS Library 1.1.1
24608 * Copyright(c) 2006-2007, Ext JS, LLC.
24610 * Originally Released Under LGPL - original licence link has changed is not relivant.
24613 * <script type="text/javascript">
24617 * @class Roo.DatePicker
24618 * @extends Roo.Component
24619 * Simple date picker class.
24621 * Create a new DatePicker
24622 * @param {Object} config The config object
24624 Roo.DatePicker = function(config){
24625 Roo.DatePicker.superclass.constructor.call(this, config);
24627 this.value = config && config.value ?
24628 config.value.clearTime() : new Date().clearTime();
24633 * Fires when a date is selected
24634 * @param {DatePicker} this
24635 * @param {Date} date The selected date
24639 * @event monthchange
24640 * Fires when the displayed month changes
24641 * @param {DatePicker} this
24642 * @param {Date} date The selected month
24644 'monthchange': true
24648 this.on("select", this.handler, this.scope || this);
24650 // build the disabledDatesRE
24651 if(!this.disabledDatesRE && this.disabledDates){
24652 var dd = this.disabledDates;
24654 for(var i = 0; i < dd.length; i++){
24656 if(i != dd.length-1) re += "|";
24658 this.disabledDatesRE = new RegExp(re + ")");
24662 Roo.extend(Roo.DatePicker, Roo.Component, {
24664 * @cfg {String} todayText
24665 * The text to display on the button that selects the current date (defaults to "Today")
24667 todayText : "Today",
24669 * @cfg {String} okText
24670 * The text to display on the ok button
24672 okText : " OK ", //   to give the user extra clicking room
24674 * @cfg {String} cancelText
24675 * The text to display on the cancel button
24677 cancelText : "Cancel",
24679 * @cfg {String} todayTip
24680 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24682 todayTip : "{0} (Spacebar)",
24684 * @cfg {Date} minDate
24685 * Minimum allowable date (JavaScript date object, defaults to null)
24689 * @cfg {Date} maxDate
24690 * Maximum allowable date (JavaScript date object, defaults to null)
24694 * @cfg {String} minText
24695 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24697 minText : "This date is before the minimum date",
24699 * @cfg {String} maxText
24700 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24702 maxText : "This date is after the maximum date",
24704 * @cfg {String} format
24705 * The default date format string which can be overriden for localization support. The format must be
24706 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24710 * @cfg {Array} disabledDays
24711 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24713 disabledDays : null,
24715 * @cfg {String} disabledDaysText
24716 * The tooltip to display when the date falls on a disabled day (defaults to "")
24718 disabledDaysText : "",
24720 * @cfg {RegExp} disabledDatesRE
24721 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24723 disabledDatesRE : null,
24725 * @cfg {String} disabledDatesText
24726 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24728 disabledDatesText : "",
24730 * @cfg {Boolean} constrainToViewport
24731 * True to constrain the date picker to the viewport (defaults to true)
24733 constrainToViewport : true,
24735 * @cfg {Array} monthNames
24736 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24738 monthNames : Date.monthNames,
24740 * @cfg {Array} dayNames
24741 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24743 dayNames : Date.dayNames,
24745 * @cfg {String} nextText
24746 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24748 nextText: 'Next Month (Control+Right)',
24750 * @cfg {String} prevText
24751 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24753 prevText: 'Previous Month (Control+Left)',
24755 * @cfg {String} monthYearText
24756 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24758 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24760 * @cfg {Number} startDay
24761 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24765 * @cfg {Bool} showClear
24766 * Show a clear button (usefull for date form elements that can be blank.)
24772 * Sets the value of the date field
24773 * @param {Date} value The date to set
24775 setValue : function(value){
24776 var old = this.value;
24777 this.value = value.clearTime(true);
24779 this.update(this.value);
24784 * Gets the current selected value of the date field
24785 * @return {Date} The selected date
24787 getValue : function(){
24792 focus : function(){
24794 this.update(this.activeDate);
24799 onRender : function(container, position){
24801 '<table cellspacing="0">',
24802 '<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>',
24803 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24804 var dn = this.dayNames;
24805 for(var i = 0; i < 7; i++){
24806 var d = this.startDay+i;
24810 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24812 m[m.length] = "</tr></thead><tbody><tr>";
24813 for(var i = 0; i < 42; i++) {
24814 if(i % 7 == 0 && i != 0){
24815 m[m.length] = "</tr><tr>";
24817 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24819 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24820 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24822 var el = document.createElement("div");
24823 el.className = "x-date-picker";
24824 el.innerHTML = m.join("");
24826 container.dom.insertBefore(el, position);
24828 this.el = Roo.get(el);
24829 this.eventEl = Roo.get(el.firstChild);
24831 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24832 handler: this.showPrevMonth,
24834 preventDefault:true,
24838 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24839 handler: this.showNextMonth,
24841 preventDefault:true,
24845 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24847 this.monthPicker = this.el.down('div.x-date-mp');
24848 this.monthPicker.enableDisplayMode('block');
24850 var kn = new Roo.KeyNav(this.eventEl, {
24851 "left" : function(e){
24853 this.showPrevMonth() :
24854 this.update(this.activeDate.add("d", -1));
24857 "right" : function(e){
24859 this.showNextMonth() :
24860 this.update(this.activeDate.add("d", 1));
24863 "up" : function(e){
24865 this.showNextYear() :
24866 this.update(this.activeDate.add("d", -7));
24869 "down" : function(e){
24871 this.showPrevYear() :
24872 this.update(this.activeDate.add("d", 7));
24875 "pageUp" : function(e){
24876 this.showNextMonth();
24879 "pageDown" : function(e){
24880 this.showPrevMonth();
24883 "enter" : function(e){
24884 e.stopPropagation();
24891 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24893 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24895 this.el.unselectable();
24897 this.cells = this.el.select("table.x-date-inner tbody td");
24898 this.textNodes = this.el.query("table.x-date-inner tbody span");
24900 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24902 tooltip: this.monthYearText
24905 this.mbtn.on('click', this.showMonthPicker, this);
24906 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24909 var today = (new Date()).dateFormat(this.format);
24911 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24912 if (this.showClear) {
24913 baseTb.add( new Roo.Toolbar.Fill());
24916 text: String.format(this.todayText, today),
24917 tooltip: String.format(this.todayTip, today),
24918 handler: this.selectToday,
24922 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24925 if (this.showClear) {
24927 baseTb.add( new Roo.Toolbar.Fill());
24930 cls: 'x-btn-icon x-btn-clear',
24931 handler: function() {
24933 this.fireEvent("select", this, '');
24943 this.update(this.value);
24946 createMonthPicker : function(){
24947 if(!this.monthPicker.dom.firstChild){
24948 var buf = ['<table border="0" cellspacing="0">'];
24949 for(var i = 0; i < 6; i++){
24951 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24952 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24954 '<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>' :
24955 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24959 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24961 '</button><button type="button" class="x-date-mp-cancel">',
24963 '</button></td></tr>',
24966 this.monthPicker.update(buf.join(''));
24967 this.monthPicker.on('click', this.onMonthClick, this);
24968 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24970 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24971 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24973 this.mpMonths.each(function(m, a, i){
24976 m.dom.xmonth = 5 + Math.round(i * .5);
24978 m.dom.xmonth = Math.round((i-1) * .5);
24984 showMonthPicker : function(){
24985 this.createMonthPicker();
24986 var size = this.el.getSize();
24987 this.monthPicker.setSize(size);
24988 this.monthPicker.child('table').setSize(size);
24990 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24991 this.updateMPMonth(this.mpSelMonth);
24992 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24993 this.updateMPYear(this.mpSelYear);
24995 this.monthPicker.slideIn('t', {duration:.2});
24998 updateMPYear : function(y){
25000 var ys = this.mpYears.elements;
25001 for(var i = 1; i <= 10; i++){
25002 var td = ys[i-1], y2;
25004 y2 = y + Math.round(i * .5);
25005 td.firstChild.innerHTML = y2;
25008 y2 = y - (5-Math.round(i * .5));
25009 td.firstChild.innerHTML = y2;
25012 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
25016 updateMPMonth : function(sm){
25017 this.mpMonths.each(function(m, a, i){
25018 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
25022 selectMPMonth: function(m){
25026 onMonthClick : function(e, t){
25028 var el = new Roo.Element(t), pn;
25029 if(el.is('button.x-date-mp-cancel')){
25030 this.hideMonthPicker();
25032 else if(el.is('button.x-date-mp-ok')){
25033 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25034 this.hideMonthPicker();
25036 else if(pn = el.up('td.x-date-mp-month', 2)){
25037 this.mpMonths.removeClass('x-date-mp-sel');
25038 pn.addClass('x-date-mp-sel');
25039 this.mpSelMonth = pn.dom.xmonth;
25041 else if(pn = el.up('td.x-date-mp-year', 2)){
25042 this.mpYears.removeClass('x-date-mp-sel');
25043 pn.addClass('x-date-mp-sel');
25044 this.mpSelYear = pn.dom.xyear;
25046 else if(el.is('a.x-date-mp-prev')){
25047 this.updateMPYear(this.mpyear-10);
25049 else if(el.is('a.x-date-mp-next')){
25050 this.updateMPYear(this.mpyear+10);
25054 onMonthDblClick : function(e, t){
25056 var el = new Roo.Element(t), pn;
25057 if(pn = el.up('td.x-date-mp-month', 2)){
25058 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
25059 this.hideMonthPicker();
25061 else if(pn = el.up('td.x-date-mp-year', 2)){
25062 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25063 this.hideMonthPicker();
25067 hideMonthPicker : function(disableAnim){
25068 if(this.monthPicker){
25069 if(disableAnim === true){
25070 this.monthPicker.hide();
25072 this.monthPicker.slideOut('t', {duration:.2});
25078 showPrevMonth : function(e){
25079 this.update(this.activeDate.add("mo", -1));
25083 showNextMonth : function(e){
25084 this.update(this.activeDate.add("mo", 1));
25088 showPrevYear : function(){
25089 this.update(this.activeDate.add("y", -1));
25093 showNextYear : function(){
25094 this.update(this.activeDate.add("y", 1));
25098 handleMouseWheel : function(e){
25099 var delta = e.getWheelDelta();
25101 this.showPrevMonth();
25103 } else if(delta < 0){
25104 this.showNextMonth();
25110 handleDateClick : function(e, t){
25112 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25113 this.setValue(new Date(t.dateValue));
25114 this.fireEvent("select", this, this.value);
25119 selectToday : function(){
25120 this.setValue(new Date().clearTime());
25121 this.fireEvent("select", this, this.value);
25125 update : function(date)
25127 var vd = this.activeDate;
25128 this.activeDate = date;
25130 var t = date.getTime();
25131 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25132 this.cells.removeClass("x-date-selected");
25133 this.cells.each(function(c){
25134 if(c.dom.firstChild.dateValue == t){
25135 c.addClass("x-date-selected");
25136 setTimeout(function(){
25137 try{c.dom.firstChild.focus();}catch(e){}
25146 var days = date.getDaysInMonth();
25147 var firstOfMonth = date.getFirstDateOfMonth();
25148 var startingPos = firstOfMonth.getDay()-this.startDay;
25150 if(startingPos <= this.startDay){
25154 var pm = date.add("mo", -1);
25155 var prevStart = pm.getDaysInMonth()-startingPos;
25157 var cells = this.cells.elements;
25158 var textEls = this.textNodes;
25159 days += startingPos;
25161 // convert everything to numbers so it's fast
25162 var day = 86400000;
25163 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25164 var today = new Date().clearTime().getTime();
25165 var sel = date.clearTime().getTime();
25166 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25167 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25168 var ddMatch = this.disabledDatesRE;
25169 var ddText = this.disabledDatesText;
25170 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25171 var ddaysText = this.disabledDaysText;
25172 var format = this.format;
25174 var setCellClass = function(cal, cell){
25176 var t = d.getTime();
25177 cell.firstChild.dateValue = t;
25179 cell.className += " x-date-today";
25180 cell.title = cal.todayText;
25183 cell.className += " x-date-selected";
25184 setTimeout(function(){
25185 try{cell.firstChild.focus();}catch(e){}
25190 cell.className = " x-date-disabled";
25191 cell.title = cal.minText;
25195 cell.className = " x-date-disabled";
25196 cell.title = cal.maxText;
25200 if(ddays.indexOf(d.getDay()) != -1){
25201 cell.title = ddaysText;
25202 cell.className = " x-date-disabled";
25205 if(ddMatch && format){
25206 var fvalue = d.dateFormat(format);
25207 if(ddMatch.test(fvalue)){
25208 cell.title = ddText.replace("%0", fvalue);
25209 cell.className = " x-date-disabled";
25215 for(; i < startingPos; i++) {
25216 textEls[i].innerHTML = (++prevStart);
25217 d.setDate(d.getDate()+1);
25218 cells[i].className = "x-date-prevday";
25219 setCellClass(this, cells[i]);
25221 for(; i < days; i++){
25222 intDay = i - startingPos + 1;
25223 textEls[i].innerHTML = (intDay);
25224 d.setDate(d.getDate()+1);
25225 cells[i].className = "x-date-active";
25226 setCellClass(this, cells[i]);
25229 for(; i < 42; i++) {
25230 textEls[i].innerHTML = (++extraDays);
25231 d.setDate(d.getDate()+1);
25232 cells[i].className = "x-date-nextday";
25233 setCellClass(this, cells[i]);
25236 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25237 this.fireEvent('monthchange', this, date);
25239 if(!this.internalRender){
25240 var main = this.el.dom.firstChild;
25241 var w = main.offsetWidth;
25242 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25243 Roo.fly(main).setWidth(w);
25244 this.internalRender = true;
25245 // opera does not respect the auto grow header center column
25246 // then, after it gets a width opera refuses to recalculate
25247 // without a second pass
25248 if(Roo.isOpera && !this.secondPass){
25249 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25250 this.secondPass = true;
25251 this.update.defer(10, this, [date]);
25259 * Ext JS Library 1.1.1
25260 * Copyright(c) 2006-2007, Ext JS, LLC.
25262 * Originally Released Under LGPL - original licence link has changed is not relivant.
25265 * <script type="text/javascript">
25268 * @class Roo.TabPanel
25269 * @extends Roo.util.Observable
25270 * A lightweight tab container.
25274 // basic tabs 1, built from existing content
25275 var tabs = new Roo.TabPanel("tabs1");
25276 tabs.addTab("script", "View Script");
25277 tabs.addTab("markup", "View Markup");
25278 tabs.activate("script");
25280 // more advanced tabs, built from javascript
25281 var jtabs = new Roo.TabPanel("jtabs");
25282 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25284 // set up the UpdateManager
25285 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25286 var updater = tab2.getUpdateManager();
25287 updater.setDefaultUrl("ajax1.htm");
25288 tab2.on('activate', updater.refresh, updater, true);
25290 // Use setUrl for Ajax loading
25291 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25292 tab3.setUrl("ajax2.htm", null, true);
25295 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25298 jtabs.activate("jtabs-1");
25301 * Create a new TabPanel.
25302 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25303 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25305 Roo.TabPanel = function(container, config){
25307 * The container element for this TabPanel.
25308 * @type Roo.Element
25310 this.el = Roo.get(container, true);
25312 if(typeof config == "boolean"){
25313 this.tabPosition = config ? "bottom" : "top";
25315 Roo.apply(this, config);
25318 if(this.tabPosition == "bottom"){
25319 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25320 this.el.addClass("x-tabs-bottom");
25322 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25323 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25324 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25326 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25328 if(this.tabPosition != "bottom"){
25329 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
25330 * @type Roo.Element
25332 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25333 this.el.addClass("x-tabs-top");
25337 this.bodyEl.setStyle("position", "relative");
25339 this.active = null;
25340 this.activateDelegate = this.activate.createDelegate(this);
25345 * Fires when the active tab changes
25346 * @param {Roo.TabPanel} this
25347 * @param {Roo.TabPanelItem} activePanel The new active tab
25351 * @event beforetabchange
25352 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25353 * @param {Roo.TabPanel} this
25354 * @param {Object} e Set cancel to true on this object to cancel the tab change
25355 * @param {Roo.TabPanelItem} tab The tab being changed to
25357 "beforetabchange" : true
25360 Roo.EventManager.onWindowResize(this.onResize, this);
25361 this.cpad = this.el.getPadding("lr");
25362 this.hiddenCount = 0;
25365 // toolbar on the tabbar support...
25366 if (this.toolbar) {
25367 var tcfg = this.toolbar;
25368 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
25369 this.toolbar = new Roo.Toolbar(tcfg);
25370 if (Roo.isSafari) {
25371 var tbl = tcfg.container.child('table', true);
25372 tbl.setAttribute('width', '100%');
25379 Roo.TabPanel.superclass.constructor.call(this);
25382 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25384 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25386 tabPosition : "top",
25388 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25390 currentTabWidth : 0,
25392 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25396 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25400 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25402 preferredTabWidth : 175,
25404 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25406 resizeTabs : false,
25408 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25410 monitorResize : true,
25412 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
25417 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25418 * @param {String} id The id of the div to use <b>or create</b>
25419 * @param {String} text The text for the tab
25420 * @param {String} content (optional) Content to put in the TabPanelItem body
25421 * @param {Boolean} closable (optional) True to create a close icon on the tab
25422 * @return {Roo.TabPanelItem} The created TabPanelItem
25424 addTab : function(id, text, content, closable){
25425 var item = new Roo.TabPanelItem(this, id, text, closable);
25426 this.addTabItem(item);
25428 item.setContent(content);
25434 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25435 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25436 * @return {Roo.TabPanelItem}
25438 getTab : function(id){
25439 return this.items[id];
25443 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25444 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25446 hideTab : function(id){
25447 var t = this.items[id];
25450 this.hiddenCount++;
25451 this.autoSizeTabs();
25456 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25457 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25459 unhideTab : function(id){
25460 var t = this.items[id];
25462 t.setHidden(false);
25463 this.hiddenCount--;
25464 this.autoSizeTabs();
25469 * Adds an existing {@link Roo.TabPanelItem}.
25470 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25472 addTabItem : function(item){
25473 this.items[item.id] = item;
25474 this.items.push(item);
25475 if(this.resizeTabs){
25476 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25477 this.autoSizeTabs();
25484 * Removes a {@link Roo.TabPanelItem}.
25485 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25487 removeTab : function(id){
25488 var items = this.items;
25489 var tab = items[id];
25490 if(!tab) { return; }
25491 var index = items.indexOf(tab);
25492 if(this.active == tab && items.length > 1){
25493 var newTab = this.getNextAvailable(index);
25498 this.stripEl.dom.removeChild(tab.pnode.dom);
25499 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25500 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25502 items.splice(index, 1);
25503 delete this.items[tab.id];
25504 tab.fireEvent("close", tab);
25505 tab.purgeListeners();
25506 this.autoSizeTabs();
25509 getNextAvailable : function(start){
25510 var items = this.items;
25512 // look for a next tab that will slide over to
25513 // replace the one being removed
25514 while(index < items.length){
25515 var item = items[++index];
25516 if(item && !item.isHidden()){
25520 // if one isn't found select the previous tab (on the left)
25523 var item = items[--index];
25524 if(item && !item.isHidden()){
25532 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25533 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25535 disableTab : function(id){
25536 var tab = this.items[id];
25537 if(tab && this.active != tab){
25543 * Enables a {@link Roo.TabPanelItem} that is disabled.
25544 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25546 enableTab : function(id){
25547 var tab = this.items[id];
25552 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25553 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25554 * @return {Roo.TabPanelItem} The TabPanelItem.
25556 activate : function(id){
25557 var tab = this.items[id];
25561 if(tab == this.active || tab.disabled){
25565 this.fireEvent("beforetabchange", this, e, tab);
25566 if(e.cancel !== true && !tab.disabled){
25568 this.active.hide();
25570 this.active = this.items[id];
25571 this.active.show();
25572 this.fireEvent("tabchange", this, this.active);
25578 * Gets the active {@link Roo.TabPanelItem}.
25579 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25581 getActiveTab : function(){
25582 return this.active;
25586 * Updates the tab body element to fit the height of the container element
25587 * for overflow scrolling
25588 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25590 syncHeight : function(targetHeight){
25591 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25592 var bm = this.bodyEl.getMargins();
25593 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25594 this.bodyEl.setHeight(newHeight);
25598 onResize : function(){
25599 if(this.monitorResize){
25600 this.autoSizeTabs();
25605 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25607 beginUpdate : function(){
25608 this.updating = true;
25612 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25614 endUpdate : function(){
25615 this.updating = false;
25616 this.autoSizeTabs();
25620 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25622 autoSizeTabs : function(){
25623 var count = this.items.length;
25624 var vcount = count - this.hiddenCount;
25625 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25626 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25627 var availWidth = Math.floor(w / vcount);
25628 var b = this.stripBody;
25629 if(b.getWidth() > w){
25630 var tabs = this.items;
25631 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25632 if(availWidth < this.minTabWidth){
25633 /*if(!this.sleft){ // incomplete scrolling code
25634 this.createScrollButtons();
25637 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25640 if(this.currentTabWidth < this.preferredTabWidth){
25641 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25647 * Returns the number of tabs in this TabPanel.
25650 getCount : function(){
25651 return this.items.length;
25655 * Resizes all the tabs to the passed width
25656 * @param {Number} The new width
25658 setTabWidth : function(width){
25659 this.currentTabWidth = width;
25660 for(var i = 0, len = this.items.length; i < len; i++) {
25661 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25666 * Destroys this TabPanel
25667 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25669 destroy : function(removeEl){
25670 Roo.EventManager.removeResizeListener(this.onResize, this);
25671 for(var i = 0, len = this.items.length; i < len; i++){
25672 this.items[i].purgeListeners();
25674 if(removeEl === true){
25675 this.el.update("");
25682 * @class Roo.TabPanelItem
25683 * @extends Roo.util.Observable
25684 * Represents an individual item (tab plus body) in a TabPanel.
25685 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25686 * @param {String} id The id of this TabPanelItem
25687 * @param {String} text The text for the tab of this TabPanelItem
25688 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25690 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25692 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25693 * @type Roo.TabPanel
25695 this.tabPanel = tabPanel;
25697 * The id for this TabPanelItem
25702 this.disabled = false;
25706 this.loaded = false;
25707 this.closable = closable;
25710 * The body element for this TabPanelItem.
25711 * @type Roo.Element
25713 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25714 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25715 this.bodyEl.setStyle("display", "block");
25716 this.bodyEl.setStyle("zoom", "1");
25719 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25721 this.el = Roo.get(els.el, true);
25722 this.inner = Roo.get(els.inner, true);
25723 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25724 this.pnode = Roo.get(els.el.parentNode, true);
25725 this.el.on("mousedown", this.onTabMouseDown, this);
25726 this.el.on("click", this.onTabClick, this);
25729 var c = Roo.get(els.close, true);
25730 c.dom.title = this.closeText;
25731 c.addClassOnOver("close-over");
25732 c.on("click", this.closeClick, this);
25738 * Fires when this tab becomes the active tab.
25739 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25740 * @param {Roo.TabPanelItem} this
25744 * @event beforeclose
25745 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25746 * @param {Roo.TabPanelItem} this
25747 * @param {Object} e Set cancel to true on this object to cancel the close.
25749 "beforeclose": true,
25752 * Fires when this tab is closed.
25753 * @param {Roo.TabPanelItem} this
25757 * @event deactivate
25758 * Fires when this tab is no longer the active tab.
25759 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25760 * @param {Roo.TabPanelItem} this
25762 "deactivate" : true
25764 this.hidden = false;
25766 Roo.TabPanelItem.superclass.constructor.call(this);
25769 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25770 purgeListeners : function(){
25771 Roo.util.Observable.prototype.purgeListeners.call(this);
25772 this.el.removeAllListeners();
25775 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25778 this.pnode.addClass("on");
25781 this.tabPanel.stripWrap.repaint();
25783 this.fireEvent("activate", this.tabPanel, this);
25787 * Returns true if this tab is the active tab.
25788 * @return {Boolean}
25790 isActive : function(){
25791 return this.tabPanel.getActiveTab() == this;
25795 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25798 this.pnode.removeClass("on");
25800 this.fireEvent("deactivate", this.tabPanel, this);
25803 hideAction : function(){
25804 this.bodyEl.hide();
25805 this.bodyEl.setStyle("position", "absolute");
25806 this.bodyEl.setLeft("-20000px");
25807 this.bodyEl.setTop("-20000px");
25810 showAction : function(){
25811 this.bodyEl.setStyle("position", "relative");
25812 this.bodyEl.setTop("");
25813 this.bodyEl.setLeft("");
25814 this.bodyEl.show();
25818 * Set the tooltip for the tab.
25819 * @param {String} tooltip The tab's tooltip
25821 setTooltip : function(text){
25822 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25823 this.textEl.dom.qtip = text;
25824 this.textEl.dom.removeAttribute('title');
25826 this.textEl.dom.title = text;
25830 onTabClick : function(e){
25831 e.preventDefault();
25832 this.tabPanel.activate(this.id);
25835 onTabMouseDown : function(e){
25836 e.preventDefault();
25837 this.tabPanel.activate(this.id);
25840 getWidth : function(){
25841 return this.inner.getWidth();
25844 setWidth : function(width){
25845 var iwidth = width - this.pnode.getPadding("lr");
25846 this.inner.setWidth(iwidth);
25847 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25848 this.pnode.setWidth(width);
25852 * Show or hide the tab
25853 * @param {Boolean} hidden True to hide or false to show.
25855 setHidden : function(hidden){
25856 this.hidden = hidden;
25857 this.pnode.setStyle("display", hidden ? "none" : "");
25861 * Returns true if this tab is "hidden"
25862 * @return {Boolean}
25864 isHidden : function(){
25865 return this.hidden;
25869 * Returns the text for this tab
25872 getText : function(){
25876 autoSize : function(){
25877 //this.el.beginMeasure();
25878 this.textEl.setWidth(1);
25879 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25880 //this.el.endMeasure();
25884 * Sets the text for the tab (Note: this also sets the tooltip text)
25885 * @param {String} text The tab's text and tooltip
25887 setText : function(text){
25889 this.textEl.update(text);
25890 this.setTooltip(text);
25891 if(!this.tabPanel.resizeTabs){
25896 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25898 activate : function(){
25899 this.tabPanel.activate(this.id);
25903 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25905 disable : function(){
25906 if(this.tabPanel.active != this){
25907 this.disabled = true;
25908 this.pnode.addClass("disabled");
25913 * Enables this TabPanelItem if it was previously disabled.
25915 enable : function(){
25916 this.disabled = false;
25917 this.pnode.removeClass("disabled");
25921 * Sets the content for this TabPanelItem.
25922 * @param {String} content The content
25923 * @param {Boolean} loadScripts true to look for and load scripts
25925 setContent : function(content, loadScripts){
25926 this.bodyEl.update(content, loadScripts);
25930 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25931 * @return {Roo.UpdateManager} The UpdateManager
25933 getUpdateManager : function(){
25934 return this.bodyEl.getUpdateManager();
25938 * Set a URL to be used to load the content for this TabPanelItem.
25939 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25940 * @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)
25941 * @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)
25942 * @return {Roo.UpdateManager} The UpdateManager
25944 setUrl : function(url, params, loadOnce){
25945 if(this.refreshDelegate){
25946 this.un('activate', this.refreshDelegate);
25948 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25949 this.on("activate", this.refreshDelegate);
25950 return this.bodyEl.getUpdateManager();
25954 _handleRefresh : function(url, params, loadOnce){
25955 if(!loadOnce || !this.loaded){
25956 var updater = this.bodyEl.getUpdateManager();
25957 updater.update(url, params, this._setLoaded.createDelegate(this));
25962 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25963 * Will fail silently if the setUrl method has not been called.
25964 * This does not activate the panel, just updates its content.
25966 refresh : function(){
25967 if(this.refreshDelegate){
25968 this.loaded = false;
25969 this.refreshDelegate();
25974 _setLoaded : function(){
25975 this.loaded = true;
25979 closeClick : function(e){
25982 this.fireEvent("beforeclose", this, o);
25983 if(o.cancel !== true){
25984 this.tabPanel.removeTab(this.id);
25988 * The text displayed in the tooltip for the close icon.
25991 closeText : "Close this tab"
25995 Roo.TabPanel.prototype.createStrip = function(container){
25996 var strip = document.createElement("div");
25997 strip.className = "x-tabs-wrap";
25998 container.appendChild(strip);
26002 Roo.TabPanel.prototype.createStripList = function(strip){
26003 // div wrapper for retard IE
26004 // returns the "tr" element.
26005 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
26006 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
26007 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
26008 return strip.firstChild.firstChild.firstChild.firstChild;
26011 Roo.TabPanel.prototype.createBody = function(container){
26012 var body = document.createElement("div");
26013 Roo.id(body, "tab-body");
26014 Roo.fly(body).addClass("x-tabs-body");
26015 container.appendChild(body);
26019 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
26020 var body = Roo.getDom(id);
26022 body = document.createElement("div");
26025 Roo.fly(body).addClass("x-tabs-item-body");
26026 bodyEl.insertBefore(body, bodyEl.firstChild);
26030 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
26031 var td = document.createElement("td");
26032 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
26033 //stripEl.appendChild(td);
26035 td.className = "x-tabs-closable";
26036 if(!this.closeTpl){
26037 this.closeTpl = new Roo.Template(
26038 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26039 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
26040 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
26043 var el = this.closeTpl.overwrite(td, {"text": text});
26044 var close = el.getElementsByTagName("div")[0];
26045 var inner = el.getElementsByTagName("em")[0];
26046 return {"el": el, "close": close, "inner": inner};
26049 this.tabTpl = new Roo.Template(
26050 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26051 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
26054 var el = this.tabTpl.overwrite(td, {"text": text});
26055 var inner = el.getElementsByTagName("em")[0];
26056 return {"el": el, "inner": inner};
26060 * Ext JS Library 1.1.1
26061 * Copyright(c) 2006-2007, Ext JS, LLC.
26063 * Originally Released Under LGPL - original licence link has changed is not relivant.
26066 * <script type="text/javascript">
26070 * @class Roo.Button
26071 * @extends Roo.util.Observable
26072 * Simple Button class
26073 * @cfg {String} text The button text
26074 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
26075 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
26076 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
26077 * @cfg {Object} scope The scope of the handler
26078 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
26079 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
26080 * @cfg {Boolean} hidden True to start hidden (defaults to false)
26081 * @cfg {Boolean} disabled True to start disabled (defaults to false)
26082 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
26083 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
26084 applies if enableToggle = true)
26085 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
26086 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
26087 an {@link Roo.util.ClickRepeater} config object (defaults to false).
26089 * Create a new button
26090 * @param {Object} config The config object
26092 Roo.Button = function(renderTo, config)
26096 renderTo = config.renderTo || false;
26099 Roo.apply(this, config);
26103 * Fires when this button is clicked
26104 * @param {Button} this
26105 * @param {EventObject} e The click event
26110 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26111 * @param {Button} this
26112 * @param {Boolean} pressed
26117 * Fires when the mouse hovers over the button
26118 * @param {Button} this
26119 * @param {Event} e The event object
26121 'mouseover' : true,
26124 * Fires when the mouse exits the button
26125 * @param {Button} this
26126 * @param {Event} e The event object
26131 * Fires when the button is rendered
26132 * @param {Button} this
26137 this.menu = Roo.menu.MenuMgr.get(this.menu);
26139 // register listeners first!! - so render can be captured..
26140 Roo.util.Observable.call(this);
26142 this.render(renderTo);
26148 Roo.extend(Roo.Button, Roo.util.Observable, {
26154 * Read-only. True if this button is hidden
26159 * Read-only. True if this button is disabled
26164 * Read-only. True if this button is pressed (only if enableToggle = true)
26170 * @cfg {Number} tabIndex
26171 * The DOM tabIndex for this button (defaults to undefined)
26173 tabIndex : undefined,
26176 * @cfg {Boolean} enableToggle
26177 * True to enable pressed/not pressed toggling (defaults to false)
26179 enableToggle: false,
26181 * @cfg {Mixed} menu
26182 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26186 * @cfg {String} menuAlign
26187 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26189 menuAlign : "tl-bl?",
26192 * @cfg {String} iconCls
26193 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26195 iconCls : undefined,
26197 * @cfg {String} type
26198 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26203 menuClassTarget: 'tr',
26206 * @cfg {String} clickEvent
26207 * The type of event to map to the button's event handler (defaults to 'click')
26209 clickEvent : 'click',
26212 * @cfg {Boolean} handleMouseEvents
26213 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26215 handleMouseEvents : true,
26218 * @cfg {String} tooltipType
26219 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26221 tooltipType : 'qtip',
26224 * @cfg {String} cls
26225 * A CSS class to apply to the button's main element.
26229 * @cfg {Roo.Template} template (Optional)
26230 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26231 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26232 * require code modifications if required elements (e.g. a button) aren't present.
26236 render : function(renderTo){
26238 if(this.hideParent){
26239 this.parentEl = Roo.get(renderTo);
26241 if(!this.dhconfig){
26242 if(!this.template){
26243 if(!Roo.Button.buttonTemplate){
26244 // hideous table template
26245 Roo.Button.buttonTemplate = new Roo.Template(
26246 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26247 '<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>',
26248 "</tr></tbody></table>");
26250 this.template = Roo.Button.buttonTemplate;
26252 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26253 var btnEl = btn.child("button:first");
26254 btnEl.on('focus', this.onFocus, this);
26255 btnEl.on('blur', this.onBlur, this);
26257 btn.addClass(this.cls);
26260 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26263 btnEl.addClass(this.iconCls);
26265 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26268 if(this.tabIndex !== undefined){
26269 btnEl.dom.tabIndex = this.tabIndex;
26272 if(typeof this.tooltip == 'object'){
26273 Roo.QuickTips.tips(Roo.apply({
26277 btnEl.dom[this.tooltipType] = this.tooltip;
26281 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26285 this.el.dom.id = this.el.id = this.id;
26288 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26289 this.menu.on("show", this.onMenuShow, this);
26290 this.menu.on("hide", this.onMenuHide, this);
26292 btn.addClass("x-btn");
26293 if(Roo.isIE && !Roo.isIE7){
26294 this.autoWidth.defer(1, this);
26298 if(this.handleMouseEvents){
26299 btn.on("mouseover", this.onMouseOver, this);
26300 btn.on("mouseout", this.onMouseOut, this);
26301 btn.on("mousedown", this.onMouseDown, this);
26303 btn.on(this.clickEvent, this.onClick, this);
26304 //btn.on("mouseup", this.onMouseUp, this);
26311 Roo.ButtonToggleMgr.register(this);
26313 this.el.addClass("x-btn-pressed");
26316 var repeater = new Roo.util.ClickRepeater(btn,
26317 typeof this.repeat == "object" ? this.repeat : {}
26319 repeater.on("click", this.onClick, this);
26322 this.fireEvent('render', this);
26326 * Returns the button's underlying element
26327 * @return {Roo.Element} The element
26329 getEl : function(){
26334 * Destroys this Button and removes any listeners.
26336 destroy : function(){
26337 Roo.ButtonToggleMgr.unregister(this);
26338 this.el.removeAllListeners();
26339 this.purgeListeners();
26344 autoWidth : function(){
26346 this.el.setWidth("auto");
26347 if(Roo.isIE7 && Roo.isStrict){
26348 var ib = this.el.child('button');
26349 if(ib && ib.getWidth() > 20){
26351 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26356 this.el.beginMeasure();
26358 if(this.el.getWidth() < this.minWidth){
26359 this.el.setWidth(this.minWidth);
26362 this.el.endMeasure();
26369 * Assigns this button's click handler
26370 * @param {Function} handler The function to call when the button is clicked
26371 * @param {Object} scope (optional) Scope for the function passed in
26373 setHandler : function(handler, scope){
26374 this.handler = handler;
26375 this.scope = scope;
26379 * Sets this button's text
26380 * @param {String} text The button text
26382 setText : function(text){
26385 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26391 * Gets the text for this button
26392 * @return {String} The button text
26394 getText : function(){
26402 this.hidden = false;
26404 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26412 this.hidden = true;
26414 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26419 * Convenience function for boolean show/hide
26420 * @param {Boolean} visible True to show, false to hide
26422 setVisible: function(visible){
26431 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26432 * @param {Boolean} state (optional) Force a particular state
26434 toggle : function(state){
26435 state = state === undefined ? !this.pressed : state;
26436 if(state != this.pressed){
26438 this.el.addClass("x-btn-pressed");
26439 this.pressed = true;
26440 this.fireEvent("toggle", this, true);
26442 this.el.removeClass("x-btn-pressed");
26443 this.pressed = false;
26444 this.fireEvent("toggle", this, false);
26446 if(this.toggleHandler){
26447 this.toggleHandler.call(this.scope || this, this, state);
26455 focus : function(){
26456 this.el.child('button:first').focus();
26460 * Disable this button
26462 disable : function(){
26464 this.el.addClass("x-btn-disabled");
26466 this.disabled = true;
26470 * Enable this button
26472 enable : function(){
26474 this.el.removeClass("x-btn-disabled");
26476 this.disabled = false;
26480 * Convenience function for boolean enable/disable
26481 * @param {Boolean} enabled True to enable, false to disable
26483 setDisabled : function(v){
26484 this[v !== true ? "enable" : "disable"]();
26488 onClick : function(e){
26490 e.preventDefault();
26495 if(!this.disabled){
26496 if(this.enableToggle){
26499 if(this.menu && !this.menu.isVisible()){
26500 this.menu.show(this.el, this.menuAlign);
26502 this.fireEvent("click", this, e);
26504 this.el.removeClass("x-btn-over");
26505 this.handler.call(this.scope || this, this, e);
26510 onMouseOver : function(e){
26511 if(!this.disabled){
26512 this.el.addClass("x-btn-over");
26513 this.fireEvent('mouseover', this, e);
26517 onMouseOut : function(e){
26518 if(!e.within(this.el, true)){
26519 this.el.removeClass("x-btn-over");
26520 this.fireEvent('mouseout', this, e);
26524 onFocus : function(e){
26525 if(!this.disabled){
26526 this.el.addClass("x-btn-focus");
26530 onBlur : function(e){
26531 this.el.removeClass("x-btn-focus");
26534 onMouseDown : function(e){
26535 if(!this.disabled && e.button == 0){
26536 this.el.addClass("x-btn-click");
26537 Roo.get(document).on('mouseup', this.onMouseUp, this);
26541 onMouseUp : function(e){
26543 this.el.removeClass("x-btn-click");
26544 Roo.get(document).un('mouseup', this.onMouseUp, this);
26548 onMenuShow : function(e){
26549 this.el.addClass("x-btn-menu-active");
26552 onMenuHide : function(e){
26553 this.el.removeClass("x-btn-menu-active");
26557 // Private utility class used by Button
26558 Roo.ButtonToggleMgr = function(){
26561 function toggleGroup(btn, state){
26563 var g = groups[btn.toggleGroup];
26564 for(var i = 0, l = g.length; i < l; i++){
26566 g[i].toggle(false);
26573 register : function(btn){
26574 if(!btn.toggleGroup){
26577 var g = groups[btn.toggleGroup];
26579 g = groups[btn.toggleGroup] = [];
26582 btn.on("toggle", toggleGroup);
26585 unregister : function(btn){
26586 if(!btn.toggleGroup){
26589 var g = groups[btn.toggleGroup];
26592 btn.un("toggle", toggleGroup);
26598 * Ext JS Library 1.1.1
26599 * Copyright(c) 2006-2007, Ext JS, LLC.
26601 * Originally Released Under LGPL - original licence link has changed is not relivant.
26604 * <script type="text/javascript">
26608 * @class Roo.SplitButton
26609 * @extends Roo.Button
26610 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26611 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26612 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26613 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26614 * @cfg {String} arrowTooltip The title attribute of the arrow
26616 * Create a new menu button
26617 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26618 * @param {Object} config The config object
26620 Roo.SplitButton = function(renderTo, config){
26621 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26623 * @event arrowclick
26624 * Fires when this button's arrow is clicked
26625 * @param {SplitButton} this
26626 * @param {EventObject} e The click event
26628 this.addEvents({"arrowclick":true});
26631 Roo.extend(Roo.SplitButton, Roo.Button, {
26632 render : function(renderTo){
26633 // this is one sweet looking template!
26634 var tpl = new Roo.Template(
26635 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26636 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26637 '<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>',
26638 "</tbody></table></td><td>",
26639 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26640 '<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>',
26641 "</tbody></table></td></tr></table>"
26643 var btn = tpl.append(renderTo, [this.text, this.type], true);
26644 var btnEl = btn.child("button");
26646 btn.addClass(this.cls);
26649 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26652 btnEl.addClass(this.iconCls);
26654 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26658 if(this.handleMouseEvents){
26659 btn.on("mouseover", this.onMouseOver, this);
26660 btn.on("mouseout", this.onMouseOut, this);
26661 btn.on("mousedown", this.onMouseDown, this);
26662 btn.on("mouseup", this.onMouseUp, this);
26664 btn.on(this.clickEvent, this.onClick, this);
26666 if(typeof this.tooltip == 'object'){
26667 Roo.QuickTips.tips(Roo.apply({
26671 btnEl.dom[this.tooltipType] = this.tooltip;
26674 if(this.arrowTooltip){
26675 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26684 this.el.addClass("x-btn-pressed");
26686 if(Roo.isIE && !Roo.isIE7){
26687 this.autoWidth.defer(1, this);
26692 this.menu.on("show", this.onMenuShow, this);
26693 this.menu.on("hide", this.onMenuHide, this);
26695 this.fireEvent('render', this);
26699 autoWidth : function(){
26701 var tbl = this.el.child("table:first");
26702 var tbl2 = this.el.child("table:last");
26703 this.el.setWidth("auto");
26704 tbl.setWidth("auto");
26705 if(Roo.isIE7 && Roo.isStrict){
26706 var ib = this.el.child('button:first');
26707 if(ib && ib.getWidth() > 20){
26709 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26714 this.el.beginMeasure();
26716 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26717 tbl.setWidth(this.minWidth-tbl2.getWidth());
26720 this.el.endMeasure();
26723 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26727 * Sets this button's click handler
26728 * @param {Function} handler The function to call when the button is clicked
26729 * @param {Object} scope (optional) Scope for the function passed above
26731 setHandler : function(handler, scope){
26732 this.handler = handler;
26733 this.scope = scope;
26737 * Sets this button's arrow click handler
26738 * @param {Function} handler The function to call when the arrow is clicked
26739 * @param {Object} scope (optional) Scope for the function passed above
26741 setArrowHandler : function(handler, scope){
26742 this.arrowHandler = handler;
26743 this.scope = scope;
26749 focus : function(){
26751 this.el.child("button:first").focus();
26756 onClick : function(e){
26757 e.preventDefault();
26758 if(!this.disabled){
26759 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26760 if(this.menu && !this.menu.isVisible()){
26761 this.menu.show(this.el, this.menuAlign);
26763 this.fireEvent("arrowclick", this, e);
26764 if(this.arrowHandler){
26765 this.arrowHandler.call(this.scope || this, this, e);
26768 this.fireEvent("click", this, e);
26770 this.handler.call(this.scope || this, this, e);
26776 onMouseDown : function(e){
26777 if(!this.disabled){
26778 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26782 onMouseUp : function(e){
26783 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26788 // backwards compat
26789 Roo.MenuButton = Roo.SplitButton;/*
26791 * Ext JS Library 1.1.1
26792 * Copyright(c) 2006-2007, Ext JS, LLC.
26794 * Originally Released Under LGPL - original licence link has changed is not relivant.
26797 * <script type="text/javascript">
26801 * @class Roo.Toolbar
26802 * Basic Toolbar class.
26804 * Creates a new Toolbar
26805 * @param {Object} container The config object
26807 Roo.Toolbar = function(container, buttons, config)
26809 /// old consturctor format still supported..
26810 if(container instanceof Array){ // omit the container for later rendering
26811 buttons = container;
26815 if (typeof(container) == 'object' && container.xtype) {
26816 config = container;
26817 container = config.container;
26818 buttons = config.buttons || []; // not really - use items!!
26821 if (config && config.items) {
26822 xitems = config.items;
26823 delete config.items;
26825 Roo.apply(this, config);
26826 this.buttons = buttons;
26829 this.render(container);
26831 this.xitems = xitems;
26832 Roo.each(xitems, function(b) {
26838 Roo.Toolbar.prototype = {
26840 * @cfg {Array} items
26841 * array of button configs or elements to add (will be converted to a MixedCollection)
26845 * @cfg {String/HTMLElement/Element} container
26846 * The id or element that will contain the toolbar
26849 render : function(ct){
26850 this.el = Roo.get(ct);
26852 this.el.addClass(this.cls);
26854 // using a table allows for vertical alignment
26855 // 100% width is needed by Safari...
26856 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26857 this.tr = this.el.child("tr", true);
26859 this.items = new Roo.util.MixedCollection(false, function(o){
26860 return o.id || ("item" + (++autoId));
26863 this.add.apply(this, this.buttons);
26864 delete this.buttons;
26869 * Adds element(s) to the toolbar -- this function takes a variable number of
26870 * arguments of mixed type and adds them to the toolbar.
26871 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26873 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26874 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26875 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26876 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26877 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26878 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26879 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26880 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26881 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26883 * @param {Mixed} arg2
26884 * @param {Mixed} etc.
26887 var a = arguments, l = a.length;
26888 for(var i = 0; i < l; i++){
26893 _add : function(el) {
26896 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26899 if (el.applyTo){ // some kind of form field
26900 return this.addField(el);
26902 if (el.render){ // some kind of Toolbar.Item
26903 return this.addItem(el);
26905 if (typeof el == "string"){ // string
26906 if(el == "separator" || el == "-"){
26907 return this.addSeparator();
26910 return this.addSpacer();
26913 return this.addFill();
26915 return this.addText(el);
26918 if(el.tagName){ // element
26919 return this.addElement(el);
26921 if(typeof el == "object"){ // must be button config?
26922 return this.addButton(el);
26924 // and now what?!?!
26930 * Add an Xtype element
26931 * @param {Object} xtype Xtype Object
26932 * @return {Object} created Object
26934 addxtype : function(e){
26935 return this.add(e);
26939 * Returns the Element for this toolbar.
26940 * @return {Roo.Element}
26942 getEl : function(){
26948 * @return {Roo.Toolbar.Item} The separator item
26950 addSeparator : function(){
26951 return this.addItem(new Roo.Toolbar.Separator());
26955 * Adds a spacer element
26956 * @return {Roo.Toolbar.Spacer} The spacer item
26958 addSpacer : function(){
26959 return this.addItem(new Roo.Toolbar.Spacer());
26963 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26964 * @return {Roo.Toolbar.Fill} The fill item
26966 addFill : function(){
26967 return this.addItem(new Roo.Toolbar.Fill());
26971 * Adds any standard HTML element to the toolbar
26972 * @param {String/HTMLElement/Element} el The element or id of the element to add
26973 * @return {Roo.Toolbar.Item} The element's item
26975 addElement : function(el){
26976 return this.addItem(new Roo.Toolbar.Item(el));
26979 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26980 * @type Roo.util.MixedCollection
26985 * Adds any Toolbar.Item or subclass
26986 * @param {Roo.Toolbar.Item} item
26987 * @return {Roo.Toolbar.Item} The item
26989 addItem : function(item){
26990 var td = this.nextBlock();
26992 this.items.add(item);
26997 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26998 * @param {Object/Array} config A button config or array of configs
26999 * @return {Roo.Toolbar.Button/Array}
27001 addButton : function(config){
27002 if(config instanceof Array){
27004 for(var i = 0, len = config.length; i < len; i++) {
27005 buttons.push(this.addButton(config[i]));
27010 if(!(config instanceof Roo.Toolbar.Button)){
27012 new Roo.Toolbar.SplitButton(config) :
27013 new Roo.Toolbar.Button(config);
27015 var td = this.nextBlock();
27022 * Adds text to the toolbar
27023 * @param {String} text The text to add
27024 * @return {Roo.Toolbar.Item} The element's item
27026 addText : function(text){
27027 return this.addItem(new Roo.Toolbar.TextItem(text));
27031 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
27032 * @param {Number} index The index where the item is to be inserted
27033 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
27034 * @return {Roo.Toolbar.Button/Item}
27036 insertButton : function(index, item){
27037 if(item instanceof Array){
27039 for(var i = 0, len = item.length; i < len; i++) {
27040 buttons.push(this.insertButton(index + i, item[i]));
27044 if (!(item instanceof Roo.Toolbar.Button)){
27045 item = new Roo.Toolbar.Button(item);
27047 var td = document.createElement("td");
27048 this.tr.insertBefore(td, this.tr.childNodes[index]);
27050 this.items.insert(index, item);
27055 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
27056 * @param {Object} config
27057 * @return {Roo.Toolbar.Item} The element's item
27059 addDom : function(config, returnEl){
27060 var td = this.nextBlock();
27061 Roo.DomHelper.overwrite(td, config);
27062 var ti = new Roo.Toolbar.Item(td.firstChild);
27064 this.items.add(ti);
27069 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
27070 * @type Roo.util.MixedCollection
27075 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
27076 * Note: the field should not have been rendered yet. For a field that has already been
27077 * rendered, use {@link #addElement}.
27078 * @param {Roo.form.Field} field
27079 * @return {Roo.ToolbarItem}
27083 addField : function(field) {
27084 if (!this.fields) {
27086 this.fields = new Roo.util.MixedCollection(false, function(o){
27087 return o.id || ("item" + (++autoId));
27092 var td = this.nextBlock();
27094 var ti = new Roo.Toolbar.Item(td.firstChild);
27096 this.items.add(ti);
27097 this.fields.add(field);
27108 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
27109 this.el.child('div').hide();
27117 this.el.child('div').show();
27121 nextBlock : function(){
27122 var td = document.createElement("td");
27123 this.tr.appendChild(td);
27128 destroy : function(){
27129 if(this.items){ // rendered?
27130 Roo.destroy.apply(Roo, this.items.items);
27132 if(this.fields){ // rendered?
27133 Roo.destroy.apply(Roo, this.fields.items);
27135 Roo.Element.uncache(this.el, this.tr);
27140 * @class Roo.Toolbar.Item
27141 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27143 * Creates a new Item
27144 * @param {HTMLElement} el
27146 Roo.Toolbar.Item = function(el){
27147 this.el = Roo.getDom(el);
27148 this.id = Roo.id(this.el);
27149 this.hidden = false;
27152 Roo.Toolbar.Item.prototype = {
27155 * Get this item's HTML Element
27156 * @return {HTMLElement}
27158 getEl : function(){
27163 render : function(td){
27165 td.appendChild(this.el);
27169 * Removes and destroys this item.
27171 destroy : function(){
27172 this.td.parentNode.removeChild(this.td);
27179 this.hidden = false;
27180 this.td.style.display = "";
27187 this.hidden = true;
27188 this.td.style.display = "none";
27192 * Convenience function for boolean show/hide.
27193 * @param {Boolean} visible true to show/false to hide
27195 setVisible: function(visible){
27204 * Try to focus this item.
27206 focus : function(){
27207 Roo.fly(this.el).focus();
27211 * Disables this item.
27213 disable : function(){
27214 Roo.fly(this.td).addClass("x-item-disabled");
27215 this.disabled = true;
27216 this.el.disabled = true;
27220 * Enables this item.
27222 enable : function(){
27223 Roo.fly(this.td).removeClass("x-item-disabled");
27224 this.disabled = false;
27225 this.el.disabled = false;
27231 * @class Roo.Toolbar.Separator
27232 * @extends Roo.Toolbar.Item
27233 * A simple toolbar separator class
27235 * Creates a new Separator
27237 Roo.Toolbar.Separator = function(){
27238 var s = document.createElement("span");
27239 s.className = "ytb-sep";
27240 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27242 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27243 enable:Roo.emptyFn,
27244 disable:Roo.emptyFn,
27249 * @class Roo.Toolbar.Spacer
27250 * @extends Roo.Toolbar.Item
27251 * A simple element that adds extra horizontal space to a toolbar.
27253 * Creates a new Spacer
27255 Roo.Toolbar.Spacer = function(){
27256 var s = document.createElement("div");
27257 s.className = "ytb-spacer";
27258 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27260 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27261 enable:Roo.emptyFn,
27262 disable:Roo.emptyFn,
27267 * @class Roo.Toolbar.Fill
27268 * @extends Roo.Toolbar.Spacer
27269 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27271 * Creates a new Spacer
27273 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27275 render : function(td){
27276 td.style.width = '100%';
27277 Roo.Toolbar.Fill.superclass.render.call(this, td);
27282 * @class Roo.Toolbar.TextItem
27283 * @extends Roo.Toolbar.Item
27284 * A simple class that renders text directly into a toolbar.
27286 * Creates a new TextItem
27287 * @param {String} text
27289 Roo.Toolbar.TextItem = function(text){
27290 if (typeof(text) == 'object') {
27293 var s = document.createElement("span");
27294 s.className = "ytb-text";
27295 s.innerHTML = text;
27296 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27298 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27299 enable:Roo.emptyFn,
27300 disable:Roo.emptyFn,
27305 * @class Roo.Toolbar.Button
27306 * @extends Roo.Button
27307 * A button that renders into a toolbar.
27309 * Creates a new Button
27310 * @param {Object} config A standard {@link Roo.Button} config object
27312 Roo.Toolbar.Button = function(config){
27313 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27315 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27316 render : function(td){
27318 Roo.Toolbar.Button.superclass.render.call(this, td);
27322 * Removes and destroys this button
27324 destroy : function(){
27325 Roo.Toolbar.Button.superclass.destroy.call(this);
27326 this.td.parentNode.removeChild(this.td);
27330 * Shows this button
27333 this.hidden = false;
27334 this.td.style.display = "";
27338 * Hides this button
27341 this.hidden = true;
27342 this.td.style.display = "none";
27346 * Disables this item
27348 disable : function(){
27349 Roo.fly(this.td).addClass("x-item-disabled");
27350 this.disabled = true;
27354 * Enables this item
27356 enable : function(){
27357 Roo.fly(this.td).removeClass("x-item-disabled");
27358 this.disabled = false;
27361 // backwards compat
27362 Roo.ToolbarButton = Roo.Toolbar.Button;
27365 * @class Roo.Toolbar.SplitButton
27366 * @extends Roo.SplitButton
27367 * A menu button that renders into a toolbar.
27369 * Creates a new SplitButton
27370 * @param {Object} config A standard {@link Roo.SplitButton} config object
27372 Roo.Toolbar.SplitButton = function(config){
27373 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27375 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27376 render : function(td){
27378 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27382 * Removes and destroys this button
27384 destroy : function(){
27385 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27386 this.td.parentNode.removeChild(this.td);
27390 * Shows this button
27393 this.hidden = false;
27394 this.td.style.display = "";
27398 * Hides this button
27401 this.hidden = true;
27402 this.td.style.display = "none";
27406 // backwards compat
27407 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27409 * Ext JS Library 1.1.1
27410 * Copyright(c) 2006-2007, Ext JS, LLC.
27412 * Originally Released Under LGPL - original licence link has changed is not relivant.
27415 * <script type="text/javascript">
27419 * @class Roo.PagingToolbar
27420 * @extends Roo.Toolbar
27421 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27423 * Create a new PagingToolbar
27424 * @param {Object} config The config object
27426 Roo.PagingToolbar = function(el, ds, config)
27428 // old args format still supported... - xtype is prefered..
27429 if (typeof(el) == 'object' && el.xtype) {
27430 // created from xtype...
27432 ds = el.dataSource;
27433 el = config.container;
27436 if (config.items) {
27437 items = config.items;
27441 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27444 this.renderButtons(this.el);
27447 // supprot items array.
27449 Roo.each(items, function(e) {
27450 this.add(Roo.factory(e));
27455 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27457 * @cfg {Roo.data.Store} dataSource
27458 * The underlying data store providing the paged data
27461 * @cfg {String/HTMLElement/Element} container
27462 * container The id or element that will contain the toolbar
27465 * @cfg {Boolean} displayInfo
27466 * True to display the displayMsg (defaults to false)
27469 * @cfg {Number} pageSize
27470 * The number of records to display per page (defaults to 20)
27474 * @cfg {String} displayMsg
27475 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27477 displayMsg : 'Displaying {0} - {1} of {2}',
27479 * @cfg {String} emptyMsg
27480 * The message to display when no records are found (defaults to "No data to display")
27482 emptyMsg : 'No data to display',
27484 * Customizable piece of the default paging text (defaults to "Page")
27487 beforePageText : "Page",
27489 * Customizable piece of the default paging text (defaults to "of %0")
27492 afterPageText : "of {0}",
27494 * Customizable piece of the default paging text (defaults to "First Page")
27497 firstText : "First Page",
27499 * Customizable piece of the default paging text (defaults to "Previous Page")
27502 prevText : "Previous Page",
27504 * Customizable piece of the default paging text (defaults to "Next Page")
27507 nextText : "Next Page",
27509 * Customizable piece of the default paging text (defaults to "Last Page")
27512 lastText : "Last Page",
27514 * Customizable piece of the default paging text (defaults to "Refresh")
27517 refreshText : "Refresh",
27520 renderButtons : function(el){
27521 Roo.PagingToolbar.superclass.render.call(this, el);
27522 this.first = this.addButton({
27523 tooltip: this.firstText,
27524 cls: "x-btn-icon x-grid-page-first",
27526 handler: this.onClick.createDelegate(this, ["first"])
27528 this.prev = this.addButton({
27529 tooltip: this.prevText,
27530 cls: "x-btn-icon x-grid-page-prev",
27532 handler: this.onClick.createDelegate(this, ["prev"])
27534 //this.addSeparator();
27535 this.add(this.beforePageText);
27536 this.field = Roo.get(this.addDom({
27541 cls: "x-grid-page-number"
27543 this.field.on("keydown", this.onPagingKeydown, this);
27544 this.field.on("focus", function(){this.dom.select();});
27545 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27546 this.field.setHeight(18);
27547 //this.addSeparator();
27548 this.next = this.addButton({
27549 tooltip: this.nextText,
27550 cls: "x-btn-icon x-grid-page-next",
27552 handler: this.onClick.createDelegate(this, ["next"])
27554 this.last = this.addButton({
27555 tooltip: this.lastText,
27556 cls: "x-btn-icon x-grid-page-last",
27558 handler: this.onClick.createDelegate(this, ["last"])
27560 //this.addSeparator();
27561 this.loading = this.addButton({
27562 tooltip: this.refreshText,
27563 cls: "x-btn-icon x-grid-loading",
27564 handler: this.onClick.createDelegate(this, ["refresh"])
27567 if(this.displayInfo){
27568 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27573 updateInfo : function(){
27574 if(this.displayEl){
27575 var count = this.ds.getCount();
27576 var msg = count == 0 ?
27580 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27582 this.displayEl.update(msg);
27587 onLoad : function(ds, r, o){
27588 this.cursor = o.params ? o.params.start : 0;
27589 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27591 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27592 this.field.dom.value = ap;
27593 this.first.setDisabled(ap == 1);
27594 this.prev.setDisabled(ap == 1);
27595 this.next.setDisabled(ap == ps);
27596 this.last.setDisabled(ap == ps);
27597 this.loading.enable();
27602 getPageData : function(){
27603 var total = this.ds.getTotalCount();
27606 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27607 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27612 onLoadError : function(){
27613 this.loading.enable();
27617 onPagingKeydown : function(e){
27618 var k = e.getKey();
27619 var d = this.getPageData();
27621 var v = this.field.dom.value, pageNum;
27622 if(!v || isNaN(pageNum = parseInt(v, 10))){
27623 this.field.dom.value = d.activePage;
27626 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27627 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27630 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))
27632 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27633 this.field.dom.value = pageNum;
27634 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27637 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27639 var v = this.field.dom.value, pageNum;
27640 var increment = (e.shiftKey) ? 10 : 1;
27641 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27643 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27644 this.field.dom.value = d.activePage;
27647 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27649 this.field.dom.value = parseInt(v, 10) + increment;
27650 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27651 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27658 beforeLoad : function(){
27660 this.loading.disable();
27665 onClick : function(which){
27669 ds.load({params:{start: 0, limit: this.pageSize}});
27672 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27675 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27678 var total = ds.getTotalCount();
27679 var extra = total % this.pageSize;
27680 var lastStart = extra ? (total - extra) : total-this.pageSize;
27681 ds.load({params:{start: lastStart, limit: this.pageSize}});
27684 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27690 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27691 * @param {Roo.data.Store} store The data store to unbind
27693 unbind : function(ds){
27694 ds.un("beforeload", this.beforeLoad, this);
27695 ds.un("load", this.onLoad, this);
27696 ds.un("loadexception", this.onLoadError, this);
27697 ds.un("remove", this.updateInfo, this);
27698 ds.un("add", this.updateInfo, this);
27699 this.ds = undefined;
27703 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27704 * @param {Roo.data.Store} store The data store to bind
27706 bind : function(ds){
27707 ds.on("beforeload", this.beforeLoad, this);
27708 ds.on("load", this.onLoad, this);
27709 ds.on("loadexception", this.onLoadError, this);
27710 ds.on("remove", this.updateInfo, this);
27711 ds.on("add", this.updateInfo, this);
27716 * Ext JS Library 1.1.1
27717 * Copyright(c) 2006-2007, Ext JS, LLC.
27719 * Originally Released Under LGPL - original licence link has changed is not relivant.
27722 * <script type="text/javascript">
27726 * @class Roo.Resizable
27727 * @extends Roo.util.Observable
27728 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27729 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27730 * 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
27731 * the element will be wrapped for you automatically.</p>
27732 * <p>Here is the list of valid resize handles:</p>
27735 ------ -------------------
27744 'hd' horizontal drag
27747 * <p>Here's an example showing the creation of a typical Resizable:</p>
27749 var resizer = new Roo.Resizable("element-id", {
27757 resizer.on("resize", myHandler);
27759 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27760 * resizer.east.setDisplayed(false);</p>
27761 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27762 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27763 * resize operation's new size (defaults to [0, 0])
27764 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27765 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27766 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27767 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27768 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27769 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27770 * @cfg {Number} width The width of the element in pixels (defaults to null)
27771 * @cfg {Number} height The height of the element in pixels (defaults to null)
27772 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27773 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27774 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27775 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27776 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27777 * in favor of the handles config option (defaults to false)
27778 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27779 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27780 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27781 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27782 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27783 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27784 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27785 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27786 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27787 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27788 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27790 * Create a new resizable component
27791 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27792 * @param {Object} config configuration options
27794 Roo.Resizable = function(el, config)
27796 this.el = Roo.get(el);
27798 if(config && config.wrap){
27799 config.resizeChild = this.el;
27800 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27801 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27802 this.el.setStyle("overflow", "hidden");
27803 this.el.setPositioning(config.resizeChild.getPositioning());
27804 config.resizeChild.clearPositioning();
27805 if(!config.width || !config.height){
27806 var csize = config.resizeChild.getSize();
27807 this.el.setSize(csize.width, csize.height);
27809 if(config.pinned && !config.adjustments){
27810 config.adjustments = "auto";
27814 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27815 this.proxy.unselectable();
27816 this.proxy.enableDisplayMode('block');
27818 Roo.apply(this, config);
27821 this.disableTrackOver = true;
27822 this.el.addClass("x-resizable-pinned");
27824 // if the element isn't positioned, make it relative
27825 var position = this.el.getStyle("position");
27826 if(position != "absolute" && position != "fixed"){
27827 this.el.setStyle("position", "relative");
27829 if(!this.handles){ // no handles passed, must be legacy style
27830 this.handles = 's,e,se';
27831 if(this.multiDirectional){
27832 this.handles += ',n,w';
27835 if(this.handles == "all"){
27836 this.handles = "n s e w ne nw se sw";
27838 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27839 var ps = Roo.Resizable.positions;
27840 for(var i = 0, len = hs.length; i < len; i++){
27841 if(hs[i] && ps[hs[i]]){
27842 var pos = ps[hs[i]];
27843 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27847 this.corner = this.southeast;
27849 // updateBox = the box can move..
27850 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27851 this.updateBox = true;
27854 this.activeHandle = null;
27856 if(this.resizeChild){
27857 if(typeof this.resizeChild == "boolean"){
27858 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27860 this.resizeChild = Roo.get(this.resizeChild, true);
27864 if(this.adjustments == "auto"){
27865 var rc = this.resizeChild;
27866 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27867 if(rc && (hw || hn)){
27868 rc.position("relative");
27869 rc.setLeft(hw ? hw.el.getWidth() : 0);
27870 rc.setTop(hn ? hn.el.getHeight() : 0);
27872 this.adjustments = [
27873 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27874 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27878 if(this.draggable){
27879 this.dd = this.dynamic ?
27880 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27881 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27887 * @event beforeresize
27888 * Fired before resize is allowed. Set enabled to false to cancel resize.
27889 * @param {Roo.Resizable} this
27890 * @param {Roo.EventObject} e The mousedown event
27892 "beforeresize" : true,
27895 * Fired after a resize.
27896 * @param {Roo.Resizable} this
27897 * @param {Number} width The new width
27898 * @param {Number} height The new height
27899 * @param {Roo.EventObject} e The mouseup event
27904 if(this.width !== null && this.height !== null){
27905 this.resizeTo(this.width, this.height);
27907 this.updateChildSize();
27910 this.el.dom.style.zoom = 1;
27912 Roo.Resizable.superclass.constructor.call(this);
27915 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27916 resizeChild : false,
27917 adjustments : [0, 0],
27927 multiDirectional : false,
27928 disableTrackOver : false,
27929 easing : 'easeOutStrong',
27930 widthIncrement : 0,
27931 heightIncrement : 0,
27935 preserveRatio : false,
27936 transparent: false,
27942 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27944 constrainTo: undefined,
27946 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27948 resizeRegion: undefined,
27952 * Perform a manual resize
27953 * @param {Number} width
27954 * @param {Number} height
27956 resizeTo : function(width, height){
27957 this.el.setSize(width, height);
27958 this.updateChildSize();
27959 this.fireEvent("resize", this, width, height, null);
27963 startSizing : function(e, handle){
27964 this.fireEvent("beforeresize", this, e);
27965 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27968 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27969 this.overlay.unselectable();
27970 this.overlay.enableDisplayMode("block");
27971 this.overlay.on("mousemove", this.onMouseMove, this);
27972 this.overlay.on("mouseup", this.onMouseUp, this);
27974 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27976 this.resizing = true;
27977 this.startBox = this.el.getBox();
27978 this.startPoint = e.getXY();
27979 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27980 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27982 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27983 this.overlay.show();
27985 if(this.constrainTo) {
27986 var ct = Roo.get(this.constrainTo);
27987 this.resizeRegion = ct.getRegion().adjust(
27988 ct.getFrameWidth('t'),
27989 ct.getFrameWidth('l'),
27990 -ct.getFrameWidth('b'),
27991 -ct.getFrameWidth('r')
27995 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27997 this.proxy.setBox(this.startBox);
27999 this.proxy.setStyle('visibility', 'visible');
28005 onMouseDown : function(handle, e){
28008 this.activeHandle = handle;
28009 this.startSizing(e, handle);
28014 onMouseUp : function(e){
28015 var size = this.resizeElement();
28016 this.resizing = false;
28018 this.overlay.hide();
28020 this.fireEvent("resize", this, size.width, size.height, e);
28024 updateChildSize : function(){
28025 if(this.resizeChild){
28027 var child = this.resizeChild;
28028 var adj = this.adjustments;
28029 if(el.dom.offsetWidth){
28030 var b = el.getSize(true);
28031 child.setSize(b.width+adj[0], b.height+adj[1]);
28033 // Second call here for IE
28034 // The first call enables instant resizing and
28035 // the second call corrects scroll bars if they
28038 setTimeout(function(){
28039 if(el.dom.offsetWidth){
28040 var b = el.getSize(true);
28041 child.setSize(b.width+adj[0], b.height+adj[1]);
28049 snap : function(value, inc, min){
28050 if(!inc || !value) return value;
28051 var newValue = value;
28052 var m = value % inc;
28055 newValue = value + (inc-m);
28057 newValue = value - m;
28060 return Math.max(min, newValue);
28064 resizeElement : function(){
28065 var box = this.proxy.getBox();
28066 if(this.updateBox){
28067 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
28069 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
28071 this.updateChildSize();
28079 constrain : function(v, diff, m, mx){
28082 }else if(v - diff > mx){
28089 onMouseMove : function(e){
28091 try{// try catch so if something goes wrong the user doesn't get hung
28093 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
28097 //var curXY = this.startPoint;
28098 var curSize = this.curSize || this.startBox;
28099 var x = this.startBox.x, y = this.startBox.y;
28100 var ox = x, oy = y;
28101 var w = curSize.width, h = curSize.height;
28102 var ow = w, oh = h;
28103 var mw = this.minWidth, mh = this.minHeight;
28104 var mxw = this.maxWidth, mxh = this.maxHeight;
28105 var wi = this.widthIncrement;
28106 var hi = this.heightIncrement;
28108 var eventXY = e.getXY();
28109 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
28110 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28112 var pos = this.activeHandle.position;
28117 w = Math.min(Math.max(mw, w), mxw);
28122 h = Math.min(Math.max(mh, h), mxh);
28127 w = Math.min(Math.max(mw, w), mxw);
28128 h = Math.min(Math.max(mh, h), mxh);
28131 diffY = this.constrain(h, diffY, mh, mxh);
28138 var adiffX = Math.abs(diffX);
28139 var sub = (adiffX % wi); // how much
28140 if (sub > (wi/2)) { // far enough to snap
28141 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28143 // remove difference..
28144 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28148 x = Math.max(this.minX, x);
28151 diffX = this.constrain(w, diffX, mw, mxw);
28157 w = Math.min(Math.max(mw, w), mxw);
28158 diffY = this.constrain(h, diffY, mh, mxh);
28163 diffX = this.constrain(w, diffX, mw, mxw);
28164 diffY = this.constrain(h, diffY, mh, mxh);
28171 diffX = this.constrain(w, diffX, mw, mxw);
28173 h = Math.min(Math.max(mh, h), mxh);
28179 var sw = this.snap(w, wi, mw);
28180 var sh = this.snap(h, hi, mh);
28181 if(sw != w || sh != h){
28204 if(this.preserveRatio){
28209 h = Math.min(Math.max(mh, h), mxh);
28214 w = Math.min(Math.max(mw, w), mxw);
28219 w = Math.min(Math.max(mw, w), mxw);
28225 w = Math.min(Math.max(mw, w), mxw);
28231 h = Math.min(Math.max(mh, h), mxh);
28239 h = Math.min(Math.max(mh, h), mxh);
28249 h = Math.min(Math.max(mh, h), mxh);
28257 if (pos == 'hdrag') {
28260 this.proxy.setBounds(x, y, w, h);
28262 this.resizeElement();
28269 handleOver : function(){
28271 this.el.addClass("x-resizable-over");
28276 handleOut : function(){
28277 if(!this.resizing){
28278 this.el.removeClass("x-resizable-over");
28283 * Returns the element this component is bound to.
28284 * @return {Roo.Element}
28286 getEl : function(){
28291 * Returns the resizeChild element (or null).
28292 * @return {Roo.Element}
28294 getResizeChild : function(){
28295 return this.resizeChild;
28299 * Destroys this resizable. If the element was wrapped and
28300 * removeEl is not true then the element remains.
28301 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28303 destroy : function(removeEl){
28304 this.proxy.remove();
28306 this.overlay.removeAllListeners();
28307 this.overlay.remove();
28309 var ps = Roo.Resizable.positions;
28311 if(typeof ps[k] != "function" && this[ps[k]]){
28312 var h = this[ps[k]];
28313 h.el.removeAllListeners();
28318 this.el.update("");
28325 // hash to map config positions to true positions
28326 Roo.Resizable.positions = {
28327 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28332 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28334 // only initialize the template if resizable is used
28335 var tpl = Roo.DomHelper.createTemplate(
28336 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28339 Roo.Resizable.Handle.prototype.tpl = tpl;
28341 this.position = pos;
28343 // show north drag fro topdra
28344 var handlepos = pos == 'hdrag' ? 'north' : pos;
28346 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28347 if (pos == 'hdrag') {
28348 this.el.setStyle('cursor', 'pointer');
28350 this.el.unselectable();
28352 this.el.setOpacity(0);
28354 this.el.on("mousedown", this.onMouseDown, this);
28355 if(!disableTrackOver){
28356 this.el.on("mouseover", this.onMouseOver, this);
28357 this.el.on("mouseout", this.onMouseOut, this);
28362 Roo.Resizable.Handle.prototype = {
28363 afterResize : function(rz){
28367 onMouseDown : function(e){
28368 this.rz.onMouseDown(this, e);
28371 onMouseOver : function(e){
28372 this.rz.handleOver(this, e);
28375 onMouseOut : function(e){
28376 this.rz.handleOut(this, e);
28380 * Ext JS Library 1.1.1
28381 * Copyright(c) 2006-2007, Ext JS, LLC.
28383 * Originally Released Under LGPL - original licence link has changed is not relivant.
28386 * <script type="text/javascript">
28390 * @class Roo.Editor
28391 * @extends Roo.Component
28392 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28394 * Create a new Editor
28395 * @param {Roo.form.Field} field The Field object (or descendant)
28396 * @param {Object} config The config object
28398 Roo.Editor = function(field, config){
28399 Roo.Editor.superclass.constructor.call(this, config);
28400 this.field = field;
28403 * @event beforestartedit
28404 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28405 * false from the handler of this event.
28406 * @param {Editor} this
28407 * @param {Roo.Element} boundEl The underlying element bound to this editor
28408 * @param {Mixed} value The field value being set
28410 "beforestartedit" : true,
28413 * Fires when this editor is displayed
28414 * @param {Roo.Element} boundEl The underlying element bound to this editor
28415 * @param {Mixed} value The starting field value
28417 "startedit" : true,
28419 * @event beforecomplete
28420 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28421 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28422 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28423 * event will not fire since no edit actually occurred.
28424 * @param {Editor} this
28425 * @param {Mixed} value The current field value
28426 * @param {Mixed} startValue The original field value
28428 "beforecomplete" : true,
28431 * Fires after editing is complete and any changed value has been written to the underlying field.
28432 * @param {Editor} this
28433 * @param {Mixed} value The current field value
28434 * @param {Mixed} startValue The original field value
28438 * @event specialkey
28439 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28440 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28441 * @param {Roo.form.Field} this
28442 * @param {Roo.EventObject} e The event object
28444 "specialkey" : true
28448 Roo.extend(Roo.Editor, Roo.Component, {
28450 * @cfg {Boolean/String} autosize
28451 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28452 * or "height" to adopt the height only (defaults to false)
28455 * @cfg {Boolean} revertInvalid
28456 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28457 * validation fails (defaults to true)
28460 * @cfg {Boolean} ignoreNoChange
28461 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28462 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28463 * will never be ignored.
28466 * @cfg {Boolean} hideEl
28467 * False to keep the bound element visible while the editor is displayed (defaults to true)
28470 * @cfg {Mixed} value
28471 * The data value of the underlying field (defaults to "")
28475 * @cfg {String} alignment
28476 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28480 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28481 * for bottom-right shadow (defaults to "frame")
28485 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28489 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28491 completeOnEnter : false,
28493 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28495 cancelOnEsc : false,
28497 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28502 onRender : function(ct, position){
28503 this.el = new Roo.Layer({
28504 shadow: this.shadow,
28510 constrain: this.constrain
28512 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28513 if(this.field.msgTarget != 'title'){
28514 this.field.msgTarget = 'qtip';
28516 this.field.render(this.el);
28518 this.field.el.dom.setAttribute('autocomplete', 'off');
28520 this.field.on("specialkey", this.onSpecialKey, this);
28521 if(this.swallowKeys){
28522 this.field.el.swallowEvent(['keydown','keypress']);
28525 this.field.on("blur", this.onBlur, this);
28526 if(this.field.grow){
28527 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28531 onSpecialKey : function(field, e)
28533 //Roo.log('editor onSpecialKey');
28534 if(this.completeOnEnter && e.getKey() == e.ENTER){
28536 this.completeEdit();
28539 // do not fire special key otherwise it might hide close the editor...
28540 if(e.getKey() == e.ENTER){
28543 if(this.cancelOnEsc && e.getKey() == e.ESC){
28547 this.fireEvent('specialkey', field, e);
28552 * Starts the editing process and shows the editor.
28553 * @param {String/HTMLElement/Element} el The element to edit
28554 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28555 * to the innerHTML of el.
28557 startEdit : function(el, value){
28559 this.completeEdit();
28561 this.boundEl = Roo.get(el);
28562 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28563 if(!this.rendered){
28564 this.render(this.parentEl || document.body);
28566 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28569 this.startValue = v;
28570 this.field.setValue(v);
28572 var sz = this.boundEl.getSize();
28573 switch(this.autoSize){
28575 this.setSize(sz.width, "");
28578 this.setSize("", sz.height);
28581 this.setSize(sz.width, sz.height);
28584 this.el.alignTo(this.boundEl, this.alignment);
28585 this.editing = true;
28587 Roo.QuickTips.disable();
28593 * Sets the height and width of this editor.
28594 * @param {Number} width The new width
28595 * @param {Number} height The new height
28597 setSize : function(w, h){
28598 this.field.setSize(w, h);
28605 * Realigns the editor to the bound field based on the current alignment config value.
28607 realign : function(){
28608 this.el.alignTo(this.boundEl, this.alignment);
28612 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28613 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28615 completeEdit : function(remainVisible){
28619 var v = this.getValue();
28620 if(this.revertInvalid !== false && !this.field.isValid()){
28621 v = this.startValue;
28622 this.cancelEdit(true);
28624 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28625 this.editing = false;
28629 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28630 this.editing = false;
28631 if(this.updateEl && this.boundEl){
28632 this.boundEl.update(v);
28634 if(remainVisible !== true){
28637 this.fireEvent("complete", this, v, this.startValue);
28642 onShow : function(){
28644 if(this.hideEl !== false){
28645 this.boundEl.hide();
28648 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28649 this.fixIEFocus = true;
28650 this.deferredFocus.defer(50, this);
28652 this.field.focus();
28654 this.fireEvent("startedit", this.boundEl, this.startValue);
28657 deferredFocus : function(){
28659 this.field.focus();
28664 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28665 * reverted to the original starting value.
28666 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28667 * cancel (defaults to false)
28669 cancelEdit : function(remainVisible){
28671 this.setValue(this.startValue);
28672 if(remainVisible !== true){
28679 onBlur : function(){
28680 if(this.allowBlur !== true && this.editing){
28681 this.completeEdit();
28686 onHide : function(){
28688 this.completeEdit();
28692 if(this.field.collapse){
28693 this.field.collapse();
28696 if(this.hideEl !== false){
28697 this.boundEl.show();
28700 Roo.QuickTips.enable();
28705 * Sets the data value of the editor
28706 * @param {Mixed} value Any valid value supported by the underlying field
28708 setValue : function(v){
28709 this.field.setValue(v);
28713 * Gets the data value of the editor
28714 * @return {Mixed} The data value
28716 getValue : function(){
28717 return this.field.getValue();
28721 * Ext JS Library 1.1.1
28722 * Copyright(c) 2006-2007, Ext JS, LLC.
28724 * Originally Released Under LGPL - original licence link has changed is not relivant.
28727 * <script type="text/javascript">
28731 * @class Roo.BasicDialog
28732 * @extends Roo.util.Observable
28733 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28735 var dlg = new Roo.BasicDialog("my-dlg", {
28744 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28745 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28746 dlg.addButton('Cancel', dlg.hide, dlg);
28749 <b>A Dialog should always be a direct child of the body element.</b>
28750 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28751 * @cfg {String} title Default text to display in the title bar (defaults to null)
28752 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28753 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28754 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28755 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28756 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28757 * (defaults to null with no animation)
28758 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28759 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28760 * property for valid values (defaults to 'all')
28761 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28762 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28763 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28764 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28765 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28766 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28767 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28768 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28769 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28770 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28771 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28772 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28773 * draggable = true (defaults to false)
28774 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28775 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28776 * shadow (defaults to false)
28777 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28778 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28779 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28780 * @cfg {Array} buttons Array of buttons
28781 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28783 * Create a new BasicDialog.
28784 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28785 * @param {Object} config Configuration options
28787 Roo.BasicDialog = function(el, config){
28788 this.el = Roo.get(el);
28789 var dh = Roo.DomHelper;
28790 if(!this.el && config && config.autoCreate){
28791 if(typeof config.autoCreate == "object"){
28792 if(!config.autoCreate.id){
28793 config.autoCreate.id = el;
28795 this.el = dh.append(document.body,
28796 config.autoCreate, true);
28798 this.el = dh.append(document.body,
28799 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28803 el.setDisplayed(true);
28804 el.hide = this.hideAction;
28806 el.addClass("x-dlg");
28808 Roo.apply(this, config);
28810 this.proxy = el.createProxy("x-dlg-proxy");
28811 this.proxy.hide = this.hideAction;
28812 this.proxy.setOpacity(.5);
28816 el.setWidth(config.width);
28819 el.setHeight(config.height);
28821 this.size = el.getSize();
28822 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28823 this.xy = [config.x,config.y];
28825 this.xy = el.getCenterXY(true);
28827 /** The header element @type Roo.Element */
28828 this.header = el.child("> .x-dlg-hd");
28829 /** The body element @type Roo.Element */
28830 this.body = el.child("> .x-dlg-bd");
28831 /** The footer element @type Roo.Element */
28832 this.footer = el.child("> .x-dlg-ft");
28835 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28838 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28841 this.header.unselectable();
28843 this.header.update(this.title);
28845 // this element allows the dialog to be focused for keyboard event
28846 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28847 this.focusEl.swallowEvent("click", true);
28849 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28851 // wrap the body and footer for special rendering
28852 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28854 this.bwrap.dom.appendChild(this.footer.dom);
28857 this.bg = this.el.createChild({
28858 tag: "div", cls:"x-dlg-bg",
28859 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28861 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28864 if(this.autoScroll !== false && !this.autoTabs){
28865 this.body.setStyle("overflow", "auto");
28868 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28870 if(this.closable !== false){
28871 this.el.addClass("x-dlg-closable");
28872 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28873 this.close.on("click", this.closeClick, this);
28874 this.close.addClassOnOver("x-dlg-close-over");
28876 if(this.collapsible !== false){
28877 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28878 this.collapseBtn.on("click", this.collapseClick, this);
28879 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28880 this.header.on("dblclick", this.collapseClick, this);
28882 if(this.resizable !== false){
28883 this.el.addClass("x-dlg-resizable");
28884 this.resizer = new Roo.Resizable(el, {
28885 minWidth: this.minWidth || 80,
28886 minHeight:this.minHeight || 80,
28887 handles: this.resizeHandles || "all",
28890 this.resizer.on("beforeresize", this.beforeResize, this);
28891 this.resizer.on("resize", this.onResize, this);
28893 if(this.draggable !== false){
28894 el.addClass("x-dlg-draggable");
28895 if (!this.proxyDrag) {
28896 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28899 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28901 dd.setHandleElId(this.header.id);
28902 dd.endDrag = this.endMove.createDelegate(this);
28903 dd.startDrag = this.startMove.createDelegate(this);
28904 dd.onDrag = this.onDrag.createDelegate(this);
28909 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28910 this.mask.enableDisplayMode("block");
28912 this.el.addClass("x-dlg-modal");
28915 this.shadow = new Roo.Shadow({
28916 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28917 offset : this.shadowOffset
28920 this.shadowOffset = 0;
28922 if(Roo.useShims && this.shim !== false){
28923 this.shim = this.el.createShim();
28924 this.shim.hide = this.hideAction;
28932 if (this.buttons) {
28933 var bts= this.buttons;
28935 Roo.each(bts, function(b) {
28944 * Fires when a key is pressed
28945 * @param {Roo.BasicDialog} this
28946 * @param {Roo.EventObject} e
28951 * Fires when this dialog is moved by the user.
28952 * @param {Roo.BasicDialog} this
28953 * @param {Number} x The new page X
28954 * @param {Number} y The new page Y
28959 * Fires when this dialog is resized by the user.
28960 * @param {Roo.BasicDialog} this
28961 * @param {Number} width The new width
28962 * @param {Number} height The new height
28966 * @event beforehide
28967 * Fires before this dialog is hidden.
28968 * @param {Roo.BasicDialog} this
28970 "beforehide" : true,
28973 * Fires when this dialog is hidden.
28974 * @param {Roo.BasicDialog} this
28978 * @event beforeshow
28979 * Fires before this dialog is shown.
28980 * @param {Roo.BasicDialog} this
28982 "beforeshow" : true,
28985 * Fires when this dialog is shown.
28986 * @param {Roo.BasicDialog} this
28990 el.on("keydown", this.onKeyDown, this);
28991 el.on("mousedown", this.toFront, this);
28992 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28994 Roo.DialogManager.register(this);
28995 Roo.BasicDialog.superclass.constructor.call(this);
28998 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28999 shadowOffset: Roo.isIE ? 6 : 5,
29002 minButtonWidth: 75,
29003 defaultButton: null,
29004 buttonAlign: "right",
29009 * Sets the dialog title text
29010 * @param {String} text The title text to display
29011 * @return {Roo.BasicDialog} this
29013 setTitle : function(text){
29014 this.header.update(text);
29019 closeClick : function(){
29024 collapseClick : function(){
29025 this[this.collapsed ? "expand" : "collapse"]();
29029 * Collapses the dialog to its minimized state (only the title bar is visible).
29030 * Equivalent to the user clicking the collapse dialog button.
29032 collapse : function(){
29033 if(!this.collapsed){
29034 this.collapsed = true;
29035 this.el.addClass("x-dlg-collapsed");
29036 this.restoreHeight = this.el.getHeight();
29037 this.resizeTo(this.el.getWidth(), this.header.getHeight());
29042 * Expands a collapsed dialog back to its normal state. Equivalent to the user
29043 * clicking the expand dialog button.
29045 expand : function(){
29046 if(this.collapsed){
29047 this.collapsed = false;
29048 this.el.removeClass("x-dlg-collapsed");
29049 this.resizeTo(this.el.getWidth(), this.restoreHeight);
29054 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
29055 * @return {Roo.TabPanel} The tabs component
29057 initTabs : function(){
29058 var tabs = this.getTabs();
29059 while(tabs.getTab(0)){
29062 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
29064 tabs.addTab(Roo.id(dom), dom.title);
29072 beforeResize : function(){
29073 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
29077 onResize : function(){
29078 this.refreshSize();
29079 this.syncBodyHeight();
29080 this.adjustAssets();
29082 this.fireEvent("resize", this, this.size.width, this.size.height);
29086 onKeyDown : function(e){
29087 if(this.isVisible()){
29088 this.fireEvent("keydown", this, e);
29093 * Resizes the dialog.
29094 * @param {Number} width
29095 * @param {Number} height
29096 * @return {Roo.BasicDialog} this
29098 resizeTo : function(width, height){
29099 this.el.setSize(width, height);
29100 this.size = {width: width, height: height};
29101 this.syncBodyHeight();
29102 if(this.fixedcenter){
29105 if(this.isVisible()){
29106 this.constrainXY();
29107 this.adjustAssets();
29109 this.fireEvent("resize", this, width, height);
29115 * Resizes the dialog to fit the specified content size.
29116 * @param {Number} width
29117 * @param {Number} height
29118 * @return {Roo.BasicDialog} this
29120 setContentSize : function(w, h){
29121 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29122 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29123 //if(!this.el.isBorderBox()){
29124 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29125 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29128 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29129 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29131 this.resizeTo(w, h);
29136 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29137 * executed in response to a particular key being pressed while the dialog is active.
29138 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29139 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29140 * @param {Function} fn The function to call
29141 * @param {Object} scope (optional) The scope of the function
29142 * @return {Roo.BasicDialog} this
29144 addKeyListener : function(key, fn, scope){
29145 var keyCode, shift, ctrl, alt;
29146 if(typeof key == "object" && !(key instanceof Array)){
29147 keyCode = key["key"];
29148 shift = key["shift"];
29149 ctrl = key["ctrl"];
29154 var handler = function(dlg, e){
29155 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29156 var k = e.getKey();
29157 if(keyCode instanceof Array){
29158 for(var i = 0, len = keyCode.length; i < len; i++){
29159 if(keyCode[i] == k){
29160 fn.call(scope || window, dlg, k, e);
29166 fn.call(scope || window, dlg, k, e);
29171 this.on("keydown", handler);
29176 * Returns the TabPanel component (creates it if it doesn't exist).
29177 * Note: If you wish to simply check for the existence of tabs without creating them,
29178 * check for a null 'tabs' property.
29179 * @return {Roo.TabPanel} The tabs component
29181 getTabs : function(){
29183 this.el.addClass("x-dlg-auto-tabs");
29184 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29185 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29191 * Adds a button to the footer section of the dialog.
29192 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29193 * object or a valid Roo.DomHelper element config
29194 * @param {Function} handler The function called when the button is clicked
29195 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29196 * @return {Roo.Button} The new button
29198 addButton : function(config, handler, scope){
29199 var dh = Roo.DomHelper;
29201 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29203 if(!this.btnContainer){
29204 var tb = this.footer.createChild({
29206 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29207 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29209 this.btnContainer = tb.firstChild.firstChild.firstChild;
29214 minWidth: this.minButtonWidth,
29217 if(typeof config == "string"){
29218 bconfig.text = config;
29221 bconfig.dhconfig = config;
29223 Roo.apply(bconfig, config);
29227 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29228 bconfig.position = Math.max(0, bconfig.position);
29229 fc = this.btnContainer.childNodes[bconfig.position];
29232 var btn = new Roo.Button(
29234 this.btnContainer.insertBefore(document.createElement("td"),fc)
29235 : this.btnContainer.appendChild(document.createElement("td")),
29236 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29239 this.syncBodyHeight();
29242 * Array of all the buttons that have been added to this dialog via addButton
29247 this.buttons.push(btn);
29252 * Sets the default button to be focused when the dialog is displayed.
29253 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29254 * @return {Roo.BasicDialog} this
29256 setDefaultButton : function(btn){
29257 this.defaultButton = btn;
29262 getHeaderFooterHeight : function(safe){
29265 height += this.header.getHeight();
29268 var fm = this.footer.getMargins();
29269 height += (this.footer.getHeight()+fm.top+fm.bottom);
29271 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29272 height += this.centerBg.getPadding("tb");
29277 syncBodyHeight : function(){
29278 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29279 var height = this.size.height - this.getHeaderFooterHeight(false);
29280 bd.setHeight(height-bd.getMargins("tb"));
29281 var hh = this.header.getHeight();
29282 var h = this.size.height-hh;
29284 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29285 bw.setHeight(h-cb.getPadding("tb"));
29286 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29287 bd.setWidth(bw.getWidth(true));
29289 this.tabs.syncHeight();
29291 this.tabs.el.repaint();
29297 * Restores the previous state of the dialog if Roo.state is configured.
29298 * @return {Roo.BasicDialog} this
29300 restoreState : function(){
29301 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29302 if(box && box.width){
29303 this.xy = [box.x, box.y];
29304 this.resizeTo(box.width, box.height);
29310 beforeShow : function(){
29312 if(this.fixedcenter){
29313 this.xy = this.el.getCenterXY(true);
29316 Roo.get(document.body).addClass("x-body-masked");
29317 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29320 this.constrainXY();
29324 animShow : function(){
29325 var b = Roo.get(this.animateTarget).getBox();
29326 this.proxy.setSize(b.width, b.height);
29327 this.proxy.setLocation(b.x, b.y);
29329 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29330 true, .35, this.showEl.createDelegate(this));
29334 * Shows the dialog.
29335 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29336 * @return {Roo.BasicDialog} this
29338 show : function(animateTarget){
29339 if (this.fireEvent("beforeshow", this) === false){
29342 if(this.syncHeightBeforeShow){
29343 this.syncBodyHeight();
29344 }else if(this.firstShow){
29345 this.firstShow = false;
29346 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29348 this.animateTarget = animateTarget || this.animateTarget;
29349 if(!this.el.isVisible()){
29351 if(this.animateTarget && Roo.get(this.animateTarget)){
29361 showEl : function(){
29363 this.el.setXY(this.xy);
29365 this.adjustAssets(true);
29368 // IE peekaboo bug - fix found by Dave Fenwick
29372 this.fireEvent("show", this);
29376 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29377 * dialog itself will receive focus.
29379 focus : function(){
29380 if(this.defaultButton){
29381 this.defaultButton.focus();
29383 this.focusEl.focus();
29388 constrainXY : function(){
29389 if(this.constraintoviewport !== false){
29390 if(!this.viewSize){
29391 if(this.container){
29392 var s = this.container.getSize();
29393 this.viewSize = [s.width, s.height];
29395 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29398 var s = Roo.get(this.container||document).getScroll();
29400 var x = this.xy[0], y = this.xy[1];
29401 var w = this.size.width, h = this.size.height;
29402 var vw = this.viewSize[0], vh = this.viewSize[1];
29403 // only move it if it needs it
29405 // first validate right/bottom
29406 if(x + w > vw+s.left){
29410 if(y + h > vh+s.top){
29414 // then make sure top/left isn't negative
29426 if(this.isVisible()){
29427 this.el.setLocation(x, y);
29428 this.adjustAssets();
29435 onDrag : function(){
29436 if(!this.proxyDrag){
29437 this.xy = this.el.getXY();
29438 this.adjustAssets();
29443 adjustAssets : function(doShow){
29444 var x = this.xy[0], y = this.xy[1];
29445 var w = this.size.width, h = this.size.height;
29446 if(doShow === true){
29448 this.shadow.show(this.el);
29454 if(this.shadow && this.shadow.isVisible()){
29455 this.shadow.show(this.el);
29457 if(this.shim && this.shim.isVisible()){
29458 this.shim.setBounds(x, y, w, h);
29463 adjustViewport : function(w, h){
29465 w = Roo.lib.Dom.getViewWidth();
29466 h = Roo.lib.Dom.getViewHeight();
29469 this.viewSize = [w, h];
29470 if(this.modal && this.mask.isVisible()){
29471 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29472 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29474 if(this.isVisible()){
29475 this.constrainXY();
29480 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29481 * shadow, proxy, mask, etc.) Also removes all event listeners.
29482 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29484 destroy : function(removeEl){
29485 if(this.isVisible()){
29486 this.animateTarget = null;
29489 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29491 this.tabs.destroy(removeEl);
29504 for(var i = 0, len = this.buttons.length; i < len; i++){
29505 this.buttons[i].destroy();
29508 this.el.removeAllListeners();
29509 if(removeEl === true){
29510 this.el.update("");
29513 Roo.DialogManager.unregister(this);
29517 startMove : function(){
29518 if(this.proxyDrag){
29521 if(this.constraintoviewport !== false){
29522 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29527 endMove : function(){
29528 if(!this.proxyDrag){
29529 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29531 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29534 this.refreshSize();
29535 this.adjustAssets();
29537 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29541 * Brings this dialog to the front of any other visible dialogs
29542 * @return {Roo.BasicDialog} this
29544 toFront : function(){
29545 Roo.DialogManager.bringToFront(this);
29550 * Sends this dialog to the back (under) of any other visible dialogs
29551 * @return {Roo.BasicDialog} this
29553 toBack : function(){
29554 Roo.DialogManager.sendToBack(this);
29559 * Centers this dialog in the viewport
29560 * @return {Roo.BasicDialog} this
29562 center : function(){
29563 var xy = this.el.getCenterXY(true);
29564 this.moveTo(xy[0], xy[1]);
29569 * Moves the dialog's top-left corner to the specified point
29570 * @param {Number} x
29571 * @param {Number} y
29572 * @return {Roo.BasicDialog} this
29574 moveTo : function(x, y){
29576 if(this.isVisible()){
29577 this.el.setXY(this.xy);
29578 this.adjustAssets();
29584 * Aligns the dialog to the specified element
29585 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29586 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29587 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29588 * @return {Roo.BasicDialog} this
29590 alignTo : function(element, position, offsets){
29591 this.xy = this.el.getAlignToXY(element, position, offsets);
29592 if(this.isVisible()){
29593 this.el.setXY(this.xy);
29594 this.adjustAssets();
29600 * Anchors an element to another element and realigns it when the window is resized.
29601 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29602 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29603 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29604 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29605 * is a number, it is used as the buffer delay (defaults to 50ms).
29606 * @return {Roo.BasicDialog} this
29608 anchorTo : function(el, alignment, offsets, monitorScroll){
29609 var action = function(){
29610 this.alignTo(el, alignment, offsets);
29612 Roo.EventManager.onWindowResize(action, this);
29613 var tm = typeof monitorScroll;
29614 if(tm != 'undefined'){
29615 Roo.EventManager.on(window, 'scroll', action, this,
29616 {buffer: tm == 'number' ? monitorScroll : 50});
29623 * Returns true if the dialog is visible
29624 * @return {Boolean}
29626 isVisible : function(){
29627 return this.el.isVisible();
29631 animHide : function(callback){
29632 var b = Roo.get(this.animateTarget).getBox();
29634 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29636 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29637 this.hideEl.createDelegate(this, [callback]));
29641 * Hides the dialog.
29642 * @param {Function} callback (optional) Function to call when the dialog is hidden
29643 * @return {Roo.BasicDialog} this
29645 hide : function(callback){
29646 if (this.fireEvent("beforehide", this) === false){
29650 this.shadow.hide();
29655 // sometimes animateTarget seems to get set.. causing problems...
29656 // this just double checks..
29657 if(this.animateTarget && Roo.get(this.animateTarget)) {
29658 this.animHide(callback);
29661 this.hideEl(callback);
29667 hideEl : function(callback){
29671 Roo.get(document.body).removeClass("x-body-masked");
29673 this.fireEvent("hide", this);
29674 if(typeof callback == "function"){
29680 hideAction : function(){
29681 this.setLeft("-10000px");
29682 this.setTop("-10000px");
29683 this.setStyle("visibility", "hidden");
29687 refreshSize : function(){
29688 this.size = this.el.getSize();
29689 this.xy = this.el.getXY();
29690 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29694 // z-index is managed by the DialogManager and may be overwritten at any time
29695 setZIndex : function(index){
29697 this.mask.setStyle("z-index", index);
29700 this.shim.setStyle("z-index", ++index);
29703 this.shadow.setZIndex(++index);
29705 this.el.setStyle("z-index", ++index);
29707 this.proxy.setStyle("z-index", ++index);
29710 this.resizer.proxy.setStyle("z-index", ++index);
29713 this.lastZIndex = index;
29717 * Returns the element for this dialog
29718 * @return {Roo.Element} The underlying dialog Element
29720 getEl : function(){
29726 * @class Roo.DialogManager
29727 * Provides global access to BasicDialogs that have been created and
29728 * support for z-indexing (layering) multiple open dialogs.
29730 Roo.DialogManager = function(){
29732 var accessList = [];
29736 var sortDialogs = function(d1, d2){
29737 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29741 var orderDialogs = function(){
29742 accessList.sort(sortDialogs);
29743 var seed = Roo.DialogManager.zseed;
29744 for(var i = 0, len = accessList.length; i < len; i++){
29745 var dlg = accessList[i];
29747 dlg.setZIndex(seed + (i*10));
29754 * The starting z-index for BasicDialogs (defaults to 9000)
29755 * @type Number The z-index value
29760 register : function(dlg){
29761 list[dlg.id] = dlg;
29762 accessList.push(dlg);
29766 unregister : function(dlg){
29767 delete list[dlg.id];
29770 if(!accessList.indexOf){
29771 for( i = 0, len = accessList.length; i < len; i++){
29772 if(accessList[i] == dlg){
29773 accessList.splice(i, 1);
29778 i = accessList.indexOf(dlg);
29780 accessList.splice(i, 1);
29786 * Gets a registered dialog by id
29787 * @param {String/Object} id The id of the dialog or a dialog
29788 * @return {Roo.BasicDialog} this
29790 get : function(id){
29791 return typeof id == "object" ? id : list[id];
29795 * Brings the specified dialog to the front
29796 * @param {String/Object} dlg The id of the dialog or a dialog
29797 * @return {Roo.BasicDialog} this
29799 bringToFront : function(dlg){
29800 dlg = this.get(dlg);
29803 dlg._lastAccess = new Date().getTime();
29810 * Sends the specified dialog to the back
29811 * @param {String/Object} dlg The id of the dialog or a dialog
29812 * @return {Roo.BasicDialog} this
29814 sendToBack : function(dlg){
29815 dlg = this.get(dlg);
29816 dlg._lastAccess = -(new Date().getTime());
29822 * Hides all dialogs
29824 hideAll : function(){
29825 for(var id in list){
29826 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29835 * @class Roo.LayoutDialog
29836 * @extends Roo.BasicDialog
29837 * Dialog which provides adjustments for working with a layout in a Dialog.
29838 * Add your necessary layout config options to the dialog's config.<br>
29839 * Example usage (including a nested layout):
29842 dialog = new Roo.LayoutDialog("download-dlg", {
29851 // layout config merges with the dialog config
29853 tabPosition: "top",
29854 alwaysShowTabs: true
29857 dialog.addKeyListener(27, dialog.hide, dialog);
29858 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29859 dialog.addButton("Build It!", this.getDownload, this);
29861 // we can even add nested layouts
29862 var innerLayout = new Roo.BorderLayout("dl-inner", {
29872 innerLayout.beginUpdate();
29873 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29874 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29875 innerLayout.endUpdate(true);
29877 var layout = dialog.getLayout();
29878 layout.beginUpdate();
29879 layout.add("center", new Roo.ContentPanel("standard-panel",
29880 {title: "Download the Source", fitToFrame:true}));
29881 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29882 {title: "Build your own roo.js"}));
29883 layout.getRegion("center").showPanel(sp);
29884 layout.endUpdate();
29888 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29889 * @param {Object} config configuration options
29891 Roo.LayoutDialog = function(el, cfg){
29894 if (typeof(cfg) == 'undefined') {
29895 config = Roo.apply({}, el);
29896 // not sure why we use documentElement here.. - it should always be body.
29897 // IE7 borks horribly if we use documentElement.
29898 // webkit also does not like documentElement - it creates a body element...
29899 el = Roo.get( document.body || document.documentElement ).createChild();
29900 //config.autoCreate = true;
29904 config.autoTabs = false;
29905 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29906 this.body.setStyle({overflow:"hidden", position:"relative"});
29907 this.layout = new Roo.BorderLayout(this.body.dom, config);
29908 this.layout.monitorWindowResize = false;
29909 this.el.addClass("x-dlg-auto-layout");
29910 // fix case when center region overwrites center function
29911 this.center = Roo.BasicDialog.prototype.center;
29912 this.on("show", this.layout.layout, this.layout, true);
29913 if (config.items) {
29914 var xitems = config.items;
29915 delete config.items;
29916 Roo.each(xitems, this.addxtype, this);
29921 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29923 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29926 endUpdate : function(){
29927 this.layout.endUpdate();
29931 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29934 beginUpdate : function(){
29935 this.layout.beginUpdate();
29939 * Get the BorderLayout for this dialog
29940 * @return {Roo.BorderLayout}
29942 getLayout : function(){
29943 return this.layout;
29946 showEl : function(){
29947 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29949 this.layout.layout();
29954 // Use the syncHeightBeforeShow config option to control this automatically
29955 syncBodyHeight : function(){
29956 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29957 if(this.layout){this.layout.layout();}
29961 * Add an xtype element (actually adds to the layout.)
29962 * @return {Object} xdata xtype object data.
29965 addxtype : function(c) {
29966 return this.layout.addxtype(c);
29970 * Ext JS Library 1.1.1
29971 * Copyright(c) 2006-2007, Ext JS, LLC.
29973 * Originally Released Under LGPL - original licence link has changed is not relivant.
29976 * <script type="text/javascript">
29980 * @class Roo.MessageBox
29981 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29985 Roo.Msg.alert('Status', 'Changes saved successfully.');
29987 // Prompt for user data:
29988 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29990 // process text value...
29994 // Show a dialog using config options:
29996 title:'Save Changes?',
29997 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29998 buttons: Roo.Msg.YESNOCANCEL,
30005 Roo.MessageBox = function(){
30006 var dlg, opt, mask, waitTimer;
30007 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
30008 var buttons, activeTextEl, bwidth;
30011 var handleButton = function(button){
30013 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
30017 var handleHide = function(){
30018 if(opt && opt.cls){
30019 dlg.el.removeClass(opt.cls);
30022 Roo.TaskMgr.stop(waitTimer);
30028 var updateButtons = function(b){
30031 buttons["ok"].hide();
30032 buttons["cancel"].hide();
30033 buttons["yes"].hide();
30034 buttons["no"].hide();
30035 dlg.footer.dom.style.display = 'none';
30038 dlg.footer.dom.style.display = '';
30039 for(var k in buttons){
30040 if(typeof buttons[k] != "function"){
30043 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
30044 width += buttons[k].el.getWidth()+15;
30054 var handleEsc = function(d, k, e){
30055 if(opt && opt.closable !== false){
30065 * Returns a reference to the underlying {@link Roo.BasicDialog} element
30066 * @return {Roo.BasicDialog} The BasicDialog element
30068 getDialog : function(){
30070 dlg = new Roo.BasicDialog("x-msg-box", {
30075 constraintoviewport:false,
30077 collapsible : false,
30080 width:400, height:100,
30081 buttonAlign:"center",
30082 closeClick : function(){
30083 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
30084 handleButton("no");
30086 handleButton("cancel");
30090 dlg.on("hide", handleHide);
30092 dlg.addKeyListener(27, handleEsc);
30094 var bt = this.buttonText;
30095 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
30096 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
30097 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
30098 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
30099 bodyEl = dlg.body.createChild({
30101 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>'
30103 msgEl = bodyEl.dom.firstChild;
30104 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
30105 textboxEl.enableDisplayMode();
30106 textboxEl.addKeyListener([10,13], function(){
30107 if(dlg.isVisible() && opt && opt.buttons){
30108 if(opt.buttons.ok){
30109 handleButton("ok");
30110 }else if(opt.buttons.yes){
30111 handleButton("yes");
30115 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
30116 textareaEl.enableDisplayMode();
30117 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
30118 progressEl.enableDisplayMode();
30119 var pf = progressEl.dom.firstChild;
30121 pp = Roo.get(pf.firstChild);
30122 pp.setHeight(pf.offsetHeight);
30130 * Updates the message box body text
30131 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30132 * the XHTML-compliant non-breaking space character '&#160;')
30133 * @return {Roo.MessageBox} This message box
30135 updateText : function(text){
30136 if(!dlg.isVisible() && !opt.width){
30137 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30139 msgEl.innerHTML = text || ' ';
30140 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
30141 Math.max(opt.minWidth || this.minWidth, bwidth));
30143 activeTextEl.setWidth(w);
30145 if(dlg.isVisible()){
30146 dlg.fixedcenter = false;
30148 // to big, make it scoll.
30149 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
30150 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
30151 bodyEl.dom.style.overflowY = 'auto';
30153 bodyEl.dom.style.height = '';
30154 bodyEl.dom.style.overflowY = '';
30157 dlg.setContentSize(w, bodyEl.getHeight());
30158 if(dlg.isVisible()){
30159 dlg.fixedcenter = true;
30165 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30166 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30167 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30168 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30169 * @return {Roo.MessageBox} This message box
30171 updateProgress : function(value, text){
30173 this.updateText(text);
30175 if (pp) { // weird bug on my firefox - for some reason this is not defined
30176 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30182 * Returns true if the message box is currently displayed
30183 * @return {Boolean} True if the message box is visible, else false
30185 isVisible : function(){
30186 return dlg && dlg.isVisible();
30190 * Hides the message box if it is displayed
30193 if(this.isVisible()){
30199 * Displays a new message box, or reinitializes an existing message box, based on the config options
30200 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30201 * The following config object properties are supported:
30203 Property Type Description
30204 ---------- --------------- ------------------------------------------------------------------------------------
30205 animEl String/Element An id or Element from which the message box should animate as it opens and
30206 closes (defaults to undefined)
30207 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30208 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30209 closable Boolean False to hide the top-right close button (defaults to true). Note that
30210 progress and wait dialogs will ignore this property and always hide the
30211 close button as they can only be closed programmatically.
30212 cls String A custom CSS class to apply to the message box element
30213 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30214 displayed (defaults to 75)
30215 fn Function A callback function to execute after closing the dialog. The arguments to the
30216 function will be btn (the name of the button that was clicked, if applicable,
30217 e.g. "ok"), and text (the value of the active text field, if applicable).
30218 Progress and wait dialogs will ignore this option since they do not respond to
30219 user actions and can only be closed programmatically, so any required function
30220 should be called by the same code after it closes the dialog.
30221 icon String A CSS class that provides a background image to be used as an icon for
30222 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30223 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30224 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30225 modal Boolean False to allow user interaction with the page while the message box is
30226 displayed (defaults to true)
30227 msg String A string that will replace the existing message box body text (defaults
30228 to the XHTML-compliant non-breaking space character ' ')
30229 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30230 progress Boolean True to display a progress bar (defaults to false)
30231 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30232 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30233 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30234 title String The title text
30235 value String The string value to set into the active textbox element if displayed
30236 wait Boolean True to display a progress bar (defaults to false)
30237 width Number The width of the dialog in pixels
30244 msg: 'Please enter your address:',
30246 buttons: Roo.MessageBox.OKCANCEL,
30249 animEl: 'addAddressBtn'
30252 * @param {Object} config Configuration options
30253 * @return {Roo.MessageBox} This message box
30255 show : function(options)
30258 // this causes nightmares if you show one dialog after another
30259 // especially on callbacks..
30261 if(this.isVisible()){
30264 Roo.log("Old Dialog Message:" + msgEl.innerHTML )
30265 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
30266 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
30269 var d = this.getDialog();
30271 d.setTitle(opt.title || " ");
30272 d.close.setDisplayed(opt.closable !== false);
30273 activeTextEl = textboxEl;
30274 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30279 textareaEl.setHeight(typeof opt.multiline == "number" ?
30280 opt.multiline : this.defaultTextHeight);
30281 activeTextEl = textareaEl;
30290 progressEl.setDisplayed(opt.progress === true);
30291 this.updateProgress(0);
30292 activeTextEl.dom.value = opt.value || "";
30294 dlg.setDefaultButton(activeTextEl);
30296 var bs = opt.buttons;
30299 db = buttons["ok"];
30300 }else if(bs && bs.yes){
30301 db = buttons["yes"];
30303 dlg.setDefaultButton(db);
30305 bwidth = updateButtons(opt.buttons);
30306 this.updateText(opt.msg);
30308 d.el.addClass(opt.cls);
30310 d.proxyDrag = opt.proxyDrag === true;
30311 d.modal = opt.modal !== false;
30312 d.mask = opt.modal !== false ? mask : false;
30313 if(!d.isVisible()){
30314 // force it to the end of the z-index stack so it gets a cursor in FF
30315 document.body.appendChild(dlg.el.dom);
30316 d.animateTarget = null;
30317 d.show(options.animEl);
30323 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30324 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30325 * and closing the message box when the process is complete.
30326 * @param {String} title The title bar text
30327 * @param {String} msg The message box body text
30328 * @return {Roo.MessageBox} This message box
30330 progress : function(title, msg){
30337 minWidth: this.minProgressWidth,
30344 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30345 * If a callback function is passed it will be called after the user clicks the button, and the
30346 * id of the button that was clicked will be passed as the only parameter to the callback
30347 * (could also be the top-right close button).
30348 * @param {String} title The title bar text
30349 * @param {String} msg The message box body text
30350 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30351 * @param {Object} scope (optional) The scope of the callback function
30352 * @return {Roo.MessageBox} This message box
30354 alert : function(title, msg, fn, scope){
30367 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30368 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30369 * You are responsible for closing the message box when the process is complete.
30370 * @param {String} msg The message box body text
30371 * @param {String} title (optional) The title bar text
30372 * @return {Roo.MessageBox} This message box
30374 wait : function(msg, title){
30385 waitTimer = Roo.TaskMgr.start({
30387 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30395 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30396 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30397 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30398 * @param {String} title The title bar text
30399 * @param {String} msg The message box body text
30400 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30401 * @param {Object} scope (optional) The scope of the callback function
30402 * @return {Roo.MessageBox} This message box
30404 confirm : function(title, msg, fn, scope){
30408 buttons: this.YESNO,
30417 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30418 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30419 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30420 * (could also be the top-right close button) and the text that was entered will be passed as the two
30421 * parameters to the callback.
30422 * @param {String} title The title bar text
30423 * @param {String} msg The message box body text
30424 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30425 * @param {Object} scope (optional) The scope of the callback function
30426 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30427 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30428 * @return {Roo.MessageBox} This message box
30430 prompt : function(title, msg, fn, scope, multiline){
30434 buttons: this.OKCANCEL,
30439 multiline: multiline,
30446 * Button config that displays a single OK button
30451 * Button config that displays Yes and No buttons
30454 YESNO : {yes:true, no:true},
30456 * Button config that displays OK and Cancel buttons
30459 OKCANCEL : {ok:true, cancel:true},
30461 * Button config that displays Yes, No and Cancel buttons
30464 YESNOCANCEL : {yes:true, no:true, cancel:true},
30467 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30470 defaultTextHeight : 75,
30472 * The maximum width in pixels of the message box (defaults to 600)
30477 * The minimum width in pixels of the message box (defaults to 100)
30482 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30483 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30486 minProgressWidth : 250,
30488 * An object containing the default button text strings that can be overriden for localized language support.
30489 * Supported properties are: ok, cancel, yes and no.
30490 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30503 * Shorthand for {@link Roo.MessageBox}
30505 Roo.Msg = Roo.MessageBox;/*
30507 * Ext JS Library 1.1.1
30508 * Copyright(c) 2006-2007, Ext JS, LLC.
30510 * Originally Released Under LGPL - original licence link has changed is not relivant.
30513 * <script type="text/javascript">
30516 * @class Roo.QuickTips
30517 * Provides attractive and customizable tooltips for any element.
30520 Roo.QuickTips = function(){
30521 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30522 var ce, bd, xy, dd;
30523 var visible = false, disabled = true, inited = false;
30524 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30526 var onOver = function(e){
30530 var t = e.getTarget();
30531 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30534 if(ce && t == ce.el){
30535 clearTimeout(hideProc);
30538 if(t && tagEls[t.id]){
30539 tagEls[t.id].el = t;
30540 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30543 var ttp, et = Roo.fly(t);
30544 var ns = cfg.namespace;
30545 if(tm.interceptTitles && t.title){
30548 t.removeAttribute("title");
30549 e.preventDefault();
30551 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30554 showProc = show.defer(tm.showDelay, tm, [{
30557 width: et.getAttributeNS(ns, cfg.width),
30558 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30559 title: et.getAttributeNS(ns, cfg.title),
30560 cls: et.getAttributeNS(ns, cfg.cls)
30565 var onOut = function(e){
30566 clearTimeout(showProc);
30567 var t = e.getTarget();
30568 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30569 hideProc = setTimeout(hide, tm.hideDelay);
30573 var onMove = function(e){
30579 if(tm.trackMouse && ce){
30584 var onDown = function(e){
30585 clearTimeout(showProc);
30586 clearTimeout(hideProc);
30588 if(tm.hideOnClick){
30591 tm.enable.defer(100, tm);
30596 var getPad = function(){
30597 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30600 var show = function(o){
30604 clearTimeout(dismissProc);
30606 if(removeCls){ // in case manually hidden
30607 el.removeClass(removeCls);
30611 el.addClass(ce.cls);
30612 removeCls = ce.cls;
30615 tipTitle.update(ce.title);
30618 tipTitle.update('');
30621 el.dom.style.width = tm.maxWidth+'px';
30622 //tipBody.dom.style.width = '';
30623 tipBodyText.update(o.text);
30624 var p = getPad(), w = ce.width;
30626 var td = tipBodyText.dom;
30627 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30628 if(aw > tm.maxWidth){
30630 }else if(aw < tm.minWidth){
30636 //tipBody.setWidth(w);
30637 el.setWidth(parseInt(w, 10) + p);
30638 if(ce.autoHide === false){
30639 close.setDisplayed(true);
30644 close.setDisplayed(false);
30650 el.avoidY = xy[1]-18;
30655 el.setStyle("visibility", "visible");
30656 el.fadeIn({callback: afterShow});
30662 var afterShow = function(){
30666 if(tm.autoDismiss && ce.autoHide !== false){
30667 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30672 var hide = function(noanim){
30673 clearTimeout(dismissProc);
30674 clearTimeout(hideProc);
30676 if(el.isVisible()){
30678 if(noanim !== true && tm.animate){
30679 el.fadeOut({callback: afterHide});
30686 var afterHide = function(){
30689 el.removeClass(removeCls);
30696 * @cfg {Number} minWidth
30697 * The minimum width of the quick tip (defaults to 40)
30701 * @cfg {Number} maxWidth
30702 * The maximum width of the quick tip (defaults to 300)
30706 * @cfg {Boolean} interceptTitles
30707 * True to automatically use the element's DOM title value if available (defaults to false)
30709 interceptTitles : false,
30711 * @cfg {Boolean} trackMouse
30712 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30714 trackMouse : false,
30716 * @cfg {Boolean} hideOnClick
30717 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30719 hideOnClick : true,
30721 * @cfg {Number} showDelay
30722 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30726 * @cfg {Number} hideDelay
30727 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30731 * @cfg {Boolean} autoHide
30732 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30733 * Used in conjunction with hideDelay.
30738 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30739 * (defaults to true). Used in conjunction with autoDismissDelay.
30741 autoDismiss : true,
30744 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30746 autoDismissDelay : 5000,
30748 * @cfg {Boolean} animate
30749 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30754 * @cfg {String} title
30755 * Title text to display (defaults to ''). This can be any valid HTML markup.
30759 * @cfg {String} text
30760 * Body text to display (defaults to ''). This can be any valid HTML markup.
30764 * @cfg {String} cls
30765 * A CSS class to apply to the base quick tip element (defaults to '').
30769 * @cfg {Number} width
30770 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30771 * minWidth or maxWidth.
30776 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30777 * or display QuickTips in a page.
30780 tm = Roo.QuickTips;
30781 cfg = tm.tagConfig;
30783 if(!Roo.isReady){ // allow calling of init() before onReady
30784 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30787 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30788 el.fxDefaults = {stopFx: true};
30789 // maximum custom styling
30790 //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>');
30791 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>');
30792 tipTitle = el.child('h3');
30793 tipTitle.enableDisplayMode("block");
30794 tipBody = el.child('div.x-tip-bd');
30795 tipBodyText = el.child('div.x-tip-bd-inner');
30796 //bdLeft = el.child('div.x-tip-bd-left');
30797 //bdRight = el.child('div.x-tip-bd-right');
30798 close = el.child('div.x-tip-close');
30799 close.enableDisplayMode("block");
30800 close.on("click", hide);
30801 var d = Roo.get(document);
30802 d.on("mousedown", onDown);
30803 d.on("mouseover", onOver);
30804 d.on("mouseout", onOut);
30805 d.on("mousemove", onMove);
30806 esc = d.addKeyListener(27, hide);
30809 dd = el.initDD("default", null, {
30810 onDrag : function(){
30814 dd.setHandleElId(tipTitle.id);
30823 * Configures a new quick tip instance and assigns it to a target element. The following config options
30826 Property Type Description
30827 ---------- --------------------- ------------------------------------------------------------------------
30828 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30830 * @param {Object} config The config object
30832 register : function(config){
30833 var cs = config instanceof Array ? config : arguments;
30834 for(var i = 0, len = cs.length; i < len; i++) {
30836 var target = c.target;
30838 if(target instanceof Array){
30839 for(var j = 0, jlen = target.length; j < jlen; j++){
30840 tagEls[target[j]] = c;
30843 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30850 * Removes this quick tip from its element and destroys it.
30851 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30853 unregister : function(el){
30854 delete tagEls[Roo.id(el)];
30858 * Enable this quick tip.
30860 enable : function(){
30861 if(inited && disabled){
30863 if(locks.length < 1){
30870 * Disable this quick tip.
30872 disable : function(){
30874 clearTimeout(showProc);
30875 clearTimeout(hideProc);
30876 clearTimeout(dismissProc);
30884 * Returns true if the quick tip is enabled, else false.
30886 isEnabled : function(){
30893 attribute : "qtip",
30903 // backwards compat
30904 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30906 * Ext JS Library 1.1.1
30907 * Copyright(c) 2006-2007, Ext JS, LLC.
30909 * Originally Released Under LGPL - original licence link has changed is not relivant.
30912 * <script type="text/javascript">
30917 * @class Roo.tree.TreePanel
30918 * @extends Roo.data.Tree
30920 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30921 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30922 * @cfg {Boolean} enableDD true to enable drag and drop
30923 * @cfg {Boolean} enableDrag true to enable just drag
30924 * @cfg {Boolean} enableDrop true to enable just drop
30925 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30926 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30927 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30928 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30929 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30930 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30931 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30932 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30933 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30934 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30935 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30936 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30937 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
30938 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30939 * @cfg {Function} renderer DEPRECATED - use TreeLoader:create event / Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
30940 * @cfg {Function} rendererTip DEPRECATED - use TreeLoader:create event / Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
30943 * @param {String/HTMLElement/Element} el The container element
30944 * @param {Object} config
30946 Roo.tree.TreePanel = function(el, config){
30948 var loader = false;
30950 root = config.root;
30951 delete config.root;
30953 if (config.loader) {
30954 loader = config.loader;
30955 delete config.loader;
30958 Roo.apply(this, config);
30959 Roo.tree.TreePanel.superclass.constructor.call(this);
30960 this.el = Roo.get(el);
30961 this.el.addClass('x-tree');
30962 //console.log(root);
30964 this.setRootNode( Roo.factory(root, Roo.tree));
30967 this.loader = Roo.factory(loader, Roo.tree);
30970 * Read-only. The id of the container element becomes this TreePanel's id.
30972 this.id = this.el.id;
30975 * @event beforeload
30976 * Fires before a node is loaded, return false to cancel
30977 * @param {Node} node The node being loaded
30979 "beforeload" : true,
30982 * Fires when a node is loaded
30983 * @param {Node} node The node that was loaded
30987 * @event textchange
30988 * Fires when the text for a node is changed
30989 * @param {Node} node The node
30990 * @param {String} text The new text
30991 * @param {String} oldText The old text
30993 "textchange" : true,
30995 * @event beforeexpand
30996 * Fires before a node is expanded, return false to cancel.
30997 * @param {Node} node The node
30998 * @param {Boolean} deep
30999 * @param {Boolean} anim
31001 "beforeexpand" : true,
31003 * @event beforecollapse
31004 * Fires before a node is collapsed, return false to cancel.
31005 * @param {Node} node The node
31006 * @param {Boolean} deep
31007 * @param {Boolean} anim
31009 "beforecollapse" : true,
31012 * Fires when a node is expanded
31013 * @param {Node} node The node
31017 * @event disabledchange
31018 * Fires when the disabled status of a node changes
31019 * @param {Node} node The node
31020 * @param {Boolean} disabled
31022 "disabledchange" : true,
31025 * Fires when a node is collapsed
31026 * @param {Node} node The node
31030 * @event beforeclick
31031 * Fires before click processing on a node. Return false to cancel the default action.
31032 * @param {Node} node The node
31033 * @param {Roo.EventObject} e The event object
31035 "beforeclick":true,
31037 * @event checkchange
31038 * Fires when a node with a checkbox's checked property changes
31039 * @param {Node} this This node
31040 * @param {Boolean} checked
31042 "checkchange":true,
31045 * Fires when a node is clicked
31046 * @param {Node} node The node
31047 * @param {Roo.EventObject} e The event object
31052 * Fires when a node is double clicked
31053 * @param {Node} node The node
31054 * @param {Roo.EventObject} e The event object
31058 * @event contextmenu
31059 * Fires when a node is right clicked
31060 * @param {Node} node The node
31061 * @param {Roo.EventObject} e The event object
31063 "contextmenu":true,
31065 * @event beforechildrenrendered
31066 * Fires right before the child nodes for a node are rendered
31067 * @param {Node} node The node
31069 "beforechildrenrendered":true,
31072 * Fires when a node starts being dragged
31073 * @param {Roo.tree.TreePanel} this
31074 * @param {Roo.tree.TreeNode} node
31075 * @param {event} e The raw browser event
31077 "startdrag" : true,
31080 * Fires when a drag operation is complete
31081 * @param {Roo.tree.TreePanel} this
31082 * @param {Roo.tree.TreeNode} node
31083 * @param {event} e The raw browser event
31088 * Fires when a dragged node is dropped on a valid DD target
31089 * @param {Roo.tree.TreePanel} this
31090 * @param {Roo.tree.TreeNode} node
31091 * @param {DD} dd The dd it was dropped on
31092 * @param {event} e The raw browser event
31096 * @event beforenodedrop
31097 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
31098 * passed to handlers has the following properties:<br />
31099 * <ul style="padding:5px;padding-left:16px;">
31100 * <li>tree - The TreePanel</li>
31101 * <li>target - The node being targeted for the drop</li>
31102 * <li>data - The drag data from the drag source</li>
31103 * <li>point - The point of the drop - append, above or below</li>
31104 * <li>source - The drag source</li>
31105 * <li>rawEvent - Raw mouse event</li>
31106 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
31107 * to be inserted by setting them on this object.</li>
31108 * <li>cancel - Set this to true to cancel the drop.</li>
31110 * @param {Object} dropEvent
31112 "beforenodedrop" : true,
31115 * Fires after a DD object is dropped on a node in this tree. The dropEvent
31116 * passed to handlers has the following properties:<br />
31117 * <ul style="padding:5px;padding-left:16px;">
31118 * <li>tree - The TreePanel</li>
31119 * <li>target - The node being targeted for the drop</li>
31120 * <li>data - The drag data from the drag source</li>
31121 * <li>point - The point of the drop - append, above or below</li>
31122 * <li>source - The drag source</li>
31123 * <li>rawEvent - Raw mouse event</li>
31124 * <li>dropNode - Dropped node(s).</li>
31126 * @param {Object} dropEvent
31130 * @event nodedragover
31131 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31132 * passed to handlers has the following properties:<br />
31133 * <ul style="padding:5px;padding-left:16px;">
31134 * <li>tree - The TreePanel</li>
31135 * <li>target - The node being targeted for the drop</li>
31136 * <li>data - The drag data from the drag source</li>
31137 * <li>point - The point of the drop - append, above or below</li>
31138 * <li>source - The drag source</li>
31139 * <li>rawEvent - Raw mouse event</li>
31140 * <li>dropNode - Drop node(s) provided by the source.</li>
31141 * <li>cancel - Set this to true to signal drop not allowed.</li>
31143 * @param {Object} dragOverEvent
31145 "nodedragover" : true
31148 if(this.singleExpand){
31149 this.on("beforeexpand", this.restrictExpand, this);
31152 this.editor.tree = this;
31153 this.editor = Roo.factory(this.editor, Roo.tree);
31156 if (this.selModel) {
31157 this.selModel = Roo.factory(this.selModel, Roo.tree);
31161 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31162 rootVisible : true,
31163 animate: Roo.enableFx,
31166 hlDrop : Roo.enableFx,
31170 rendererTip: false,
31172 restrictExpand : function(node){
31173 var p = node.parentNode;
31175 if(p.expandedChild && p.expandedChild.parentNode == p){
31176 p.expandedChild.collapse();
31178 p.expandedChild = node;
31182 // private override
31183 setRootNode : function(node){
31184 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31185 if(!this.rootVisible){
31186 node.ui = new Roo.tree.RootTreeNodeUI(node);
31192 * Returns the container element for this TreePanel
31194 getEl : function(){
31199 * Returns the default TreeLoader for this TreePanel
31201 getLoader : function(){
31202 return this.loader;
31208 expandAll : function(){
31209 this.root.expand(true);
31213 * Collapse all nodes
31215 collapseAll : function(){
31216 this.root.collapse(true);
31220 * Returns the selection model used by this TreePanel
31222 getSelectionModel : function(){
31223 if(!this.selModel){
31224 this.selModel = new Roo.tree.DefaultSelectionModel();
31226 return this.selModel;
31230 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31231 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31232 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31235 getChecked : function(a, startNode){
31236 startNode = startNode || this.root;
31238 var f = function(){
31239 if(this.attributes.checked){
31240 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31243 startNode.cascade(f);
31248 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31249 * @param {String} path
31250 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31251 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31252 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31254 expandPath : function(path, attr, callback){
31255 attr = attr || "id";
31256 var keys = path.split(this.pathSeparator);
31257 var curNode = this.root;
31258 if(curNode.attributes[attr] != keys[1]){ // invalid root
31260 callback(false, null);
31265 var f = function(){
31266 if(++index == keys.length){
31268 callback(true, curNode);
31272 var c = curNode.findChild(attr, keys[index]);
31275 callback(false, curNode);
31280 c.expand(false, false, f);
31282 curNode.expand(false, false, f);
31286 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31287 * @param {String} path
31288 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31289 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31290 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31292 selectPath : function(path, attr, callback){
31293 attr = attr || "id";
31294 var keys = path.split(this.pathSeparator);
31295 var v = keys.pop();
31296 if(keys.length > 0){
31297 var f = function(success, node){
31298 if(success && node){
31299 var n = node.findChild(attr, v);
31305 }else if(callback){
31306 callback(false, n);
31310 callback(false, n);
31314 this.expandPath(keys.join(this.pathSeparator), attr, f);
31316 this.root.select();
31318 callback(true, this.root);
31323 getTreeEl : function(){
31328 * Trigger rendering of this TreePanel
31330 render : function(){
31331 if (this.innerCt) {
31332 return this; // stop it rendering more than once!!
31335 this.innerCt = this.el.createChild({tag:"ul",
31336 cls:"x-tree-root-ct " +
31337 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31339 if(this.containerScroll){
31340 Roo.dd.ScrollManager.register(this.el);
31342 if((this.enableDD || this.enableDrop) && !this.dropZone){
31344 * The dropZone used by this tree if drop is enabled
31345 * @type Roo.tree.TreeDropZone
31347 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31348 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31351 if((this.enableDD || this.enableDrag) && !this.dragZone){
31353 * The dragZone used by this tree if drag is enabled
31354 * @type Roo.tree.TreeDragZone
31356 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31357 ddGroup: this.ddGroup || "TreeDD",
31358 scroll: this.ddScroll
31361 this.getSelectionModel().init(this);
31363 console.log("ROOT not set in tree");
31366 this.root.render();
31367 if(!this.rootVisible){
31368 this.root.renderChildren();
31374 * Ext JS Library 1.1.1
31375 * Copyright(c) 2006-2007, Ext JS, LLC.
31377 * Originally Released Under LGPL - original licence link has changed is not relivant.
31380 * <script type="text/javascript">
31385 * @class Roo.tree.DefaultSelectionModel
31386 * @extends Roo.util.Observable
31387 * The default single selection for a TreePanel.
31388 * @param {Object} cfg Configuration
31390 Roo.tree.DefaultSelectionModel = function(cfg){
31391 this.selNode = null;
31397 * @event selectionchange
31398 * Fires when the selected node changes
31399 * @param {DefaultSelectionModel} this
31400 * @param {TreeNode} node the new selection
31402 "selectionchange" : true,
31405 * @event beforeselect
31406 * Fires before the selected node changes, return false to cancel the change
31407 * @param {DefaultSelectionModel} this
31408 * @param {TreeNode} node the new selection
31409 * @param {TreeNode} node the old selection
31411 "beforeselect" : true
31414 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
31417 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31418 init : function(tree){
31420 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31421 tree.on("click", this.onNodeClick, this);
31424 onNodeClick : function(node, e){
31425 if (e.ctrlKey && this.selNode == node) {
31426 this.unselect(node);
31434 * @param {TreeNode} node The node to select
31435 * @return {TreeNode} The selected node
31437 select : function(node){
31438 var last = this.selNode;
31439 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31441 last.ui.onSelectedChange(false);
31443 this.selNode = node;
31444 node.ui.onSelectedChange(true);
31445 this.fireEvent("selectionchange", this, node, last);
31452 * @param {TreeNode} node The node to unselect
31454 unselect : function(node){
31455 if(this.selNode == node){
31456 this.clearSelections();
31461 * Clear all selections
31463 clearSelections : function(){
31464 var n = this.selNode;
31466 n.ui.onSelectedChange(false);
31467 this.selNode = null;
31468 this.fireEvent("selectionchange", this, null);
31474 * Get the selected node
31475 * @return {TreeNode} The selected node
31477 getSelectedNode : function(){
31478 return this.selNode;
31482 * Returns true if the node is selected
31483 * @param {TreeNode} node The node to check
31484 * @return {Boolean}
31486 isSelected : function(node){
31487 return this.selNode == node;
31491 * Selects the node above the selected node in the tree, intelligently walking the nodes
31492 * @return TreeNode The new selection
31494 selectPrevious : function(){
31495 var s = this.selNode || this.lastSelNode;
31499 var ps = s.previousSibling;
31501 if(!ps.isExpanded() || ps.childNodes.length < 1){
31502 return this.select(ps);
31504 var lc = ps.lastChild;
31505 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31508 return this.select(lc);
31510 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31511 return this.select(s.parentNode);
31517 * Selects the node above the selected node in the tree, intelligently walking the nodes
31518 * @return TreeNode The new selection
31520 selectNext : function(){
31521 var s = this.selNode || this.lastSelNode;
31525 if(s.firstChild && s.isExpanded()){
31526 return this.select(s.firstChild);
31527 }else if(s.nextSibling){
31528 return this.select(s.nextSibling);
31529 }else if(s.parentNode){
31531 s.parentNode.bubble(function(){
31532 if(this.nextSibling){
31533 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31542 onKeyDown : function(e){
31543 var s = this.selNode || this.lastSelNode;
31544 // undesirable, but required
31549 var k = e.getKey();
31557 this.selectPrevious();
31560 e.preventDefault();
31561 if(s.hasChildNodes()){
31562 if(!s.isExpanded()){
31564 }else if(s.firstChild){
31565 this.select(s.firstChild, e);
31570 e.preventDefault();
31571 if(s.hasChildNodes() && s.isExpanded()){
31573 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31574 this.select(s.parentNode, e);
31582 * @class Roo.tree.MultiSelectionModel
31583 * @extends Roo.util.Observable
31584 * Multi selection for a TreePanel.
31585 * @param {Object} cfg Configuration
31587 Roo.tree.MultiSelectionModel = function(){
31588 this.selNodes = [];
31592 * @event selectionchange
31593 * Fires when the selected nodes change
31594 * @param {MultiSelectionModel} this
31595 * @param {Array} nodes Array of the selected nodes
31597 "selectionchange" : true
31599 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
31603 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31604 init : function(tree){
31606 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31607 tree.on("click", this.onNodeClick, this);
31610 onNodeClick : function(node, e){
31611 this.select(node, e, e.ctrlKey);
31616 * @param {TreeNode} node The node to select
31617 * @param {EventObject} e (optional) An event associated with the selection
31618 * @param {Boolean} keepExisting True to retain existing selections
31619 * @return {TreeNode} The selected node
31621 select : function(node, e, keepExisting){
31622 if(keepExisting !== true){
31623 this.clearSelections(true);
31625 if(this.isSelected(node)){
31626 this.lastSelNode = node;
31629 this.selNodes.push(node);
31630 this.selMap[node.id] = node;
31631 this.lastSelNode = node;
31632 node.ui.onSelectedChange(true);
31633 this.fireEvent("selectionchange", this, this.selNodes);
31639 * @param {TreeNode} node The node to unselect
31641 unselect : function(node){
31642 if(this.selMap[node.id]){
31643 node.ui.onSelectedChange(false);
31644 var sn = this.selNodes;
31647 index = sn.indexOf(node);
31649 for(var i = 0, len = sn.length; i < len; i++){
31657 this.selNodes.splice(index, 1);
31659 delete this.selMap[node.id];
31660 this.fireEvent("selectionchange", this, this.selNodes);
31665 * Clear all selections
31667 clearSelections : function(suppressEvent){
31668 var sn = this.selNodes;
31670 for(var i = 0, len = sn.length; i < len; i++){
31671 sn[i].ui.onSelectedChange(false);
31673 this.selNodes = [];
31675 if(suppressEvent !== true){
31676 this.fireEvent("selectionchange", this, this.selNodes);
31682 * Returns true if the node is selected
31683 * @param {TreeNode} node The node to check
31684 * @return {Boolean}
31686 isSelected : function(node){
31687 return this.selMap[node.id] ? true : false;
31691 * Returns an array of the selected nodes
31694 getSelectedNodes : function(){
31695 return this.selNodes;
31698 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31700 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31702 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31705 * Ext JS Library 1.1.1
31706 * Copyright(c) 2006-2007, Ext JS, LLC.
31708 * Originally Released Under LGPL - original licence link has changed is not relivant.
31711 * <script type="text/javascript">
31715 * @class Roo.tree.TreeNode
31716 * @extends Roo.data.Node
31717 * @cfg {String} text The text for this node
31718 * @cfg {Boolean} expanded true to start the node expanded
31719 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31720 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31721 * @cfg {Boolean} disabled true to start the node disabled
31722 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31723 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31724 * @cfg {String} cls A css class to be added to the node
31725 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31726 * @cfg {String} href URL of the link used for the node (defaults to #)
31727 * @cfg {String} hrefTarget target frame for the link
31728 * @cfg {String} qtip An Ext QuickTip for the node
31729 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31730 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31731 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31732 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31733 * (defaults to undefined with no checkbox rendered)
31735 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31737 Roo.tree.TreeNode = function(attributes){
31738 attributes = attributes || {};
31739 if(typeof attributes == "string"){
31740 attributes = {text: attributes};
31742 this.childrenRendered = false;
31743 this.rendered = false;
31744 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31745 this.expanded = attributes.expanded === true;
31746 this.isTarget = attributes.isTarget !== false;
31747 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31748 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31751 * Read-only. The text for this node. To change it use setText().
31754 this.text = attributes.text;
31756 * True if this node is disabled.
31759 this.disabled = attributes.disabled === true;
31763 * @event textchange
31764 * Fires when the text for this node is changed
31765 * @param {Node} this This node
31766 * @param {String} text The new text
31767 * @param {String} oldText The old text
31769 "textchange" : true,
31771 * @event beforeexpand
31772 * Fires before this node is expanded, return false to cancel.
31773 * @param {Node} this This node
31774 * @param {Boolean} deep
31775 * @param {Boolean} anim
31777 "beforeexpand" : true,
31779 * @event beforecollapse
31780 * Fires before this node is collapsed, return false to cancel.
31781 * @param {Node} this This node
31782 * @param {Boolean} deep
31783 * @param {Boolean} anim
31785 "beforecollapse" : true,
31788 * Fires when this node is expanded
31789 * @param {Node} this This node
31793 * @event disabledchange
31794 * Fires when the disabled status of this node changes
31795 * @param {Node} this This node
31796 * @param {Boolean} disabled
31798 "disabledchange" : true,
31801 * Fires when this node is collapsed
31802 * @param {Node} this This node
31806 * @event beforeclick
31807 * Fires before click processing. Return false to cancel the default action.
31808 * @param {Node} this This node
31809 * @param {Roo.EventObject} e The event object
31811 "beforeclick":true,
31813 * @event checkchange
31814 * Fires when a node with a checkbox's checked property changes
31815 * @param {Node} this This node
31816 * @param {Boolean} checked
31818 "checkchange":true,
31821 * Fires when this node is clicked
31822 * @param {Node} this This node
31823 * @param {Roo.EventObject} e The event object
31828 * Fires when this node is double clicked
31829 * @param {Node} this This node
31830 * @param {Roo.EventObject} e The event object
31834 * @event contextmenu
31835 * Fires when this node is right clicked
31836 * @param {Node} this This node
31837 * @param {Roo.EventObject} e The event object
31839 "contextmenu":true,
31841 * @event beforechildrenrendered
31842 * Fires right before the child nodes for this node are rendered
31843 * @param {Node} this This node
31845 "beforechildrenrendered":true
31848 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31851 * Read-only. The UI for this node
31854 this.ui = new uiClass(this);
31856 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31857 preventHScroll: true,
31859 * Returns true if this node is expanded
31860 * @return {Boolean}
31862 isExpanded : function(){
31863 return this.expanded;
31867 * Returns the UI object for this node
31868 * @return {TreeNodeUI}
31870 getUI : function(){
31874 // private override
31875 setFirstChild : function(node){
31876 var of = this.firstChild;
31877 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31878 if(this.childrenRendered && of && node != of){
31879 of.renderIndent(true, true);
31882 this.renderIndent(true, true);
31886 // private override
31887 setLastChild : function(node){
31888 var ol = this.lastChild;
31889 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31890 if(this.childrenRendered && ol && node != ol){
31891 ol.renderIndent(true, true);
31894 this.renderIndent(true, true);
31898 // these methods are overridden to provide lazy rendering support
31899 // private override
31900 appendChild : function(){
31901 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31902 if(node && this.childrenRendered){
31905 this.ui.updateExpandIcon();
31909 // private override
31910 removeChild : function(node){
31911 this.ownerTree.getSelectionModel().unselect(node);
31912 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31913 // if it's been rendered remove dom node
31914 if(this.childrenRendered){
31917 if(this.childNodes.length < 1){
31918 this.collapse(false, false);
31920 this.ui.updateExpandIcon();
31922 if(!this.firstChild) {
31923 this.childrenRendered = false;
31928 // private override
31929 insertBefore : function(node, refNode){
31930 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31931 if(newNode && refNode && this.childrenRendered){
31934 this.ui.updateExpandIcon();
31939 * Sets the text for this node
31940 * @param {String} text
31942 setText : function(text){
31943 var oldText = this.text;
31945 this.attributes.text = text;
31946 if(this.rendered){ // event without subscribing
31947 this.ui.onTextChange(this, text, oldText);
31949 this.fireEvent("textchange", this, text, oldText);
31953 * Triggers selection of this node
31955 select : function(){
31956 this.getOwnerTree().getSelectionModel().select(this);
31960 * Triggers deselection of this node
31962 unselect : function(){
31963 this.getOwnerTree().getSelectionModel().unselect(this);
31967 * Returns true if this node is selected
31968 * @return {Boolean}
31970 isSelected : function(){
31971 return this.getOwnerTree().getSelectionModel().isSelected(this);
31975 * Expand this node.
31976 * @param {Boolean} deep (optional) True to expand all children as well
31977 * @param {Boolean} anim (optional) false to cancel the default animation
31978 * @param {Function} callback (optional) A callback to be called when
31979 * expanding this node completes (does not wait for deep expand to complete).
31980 * Called with 1 parameter, this node.
31982 expand : function(deep, anim, callback){
31983 if(!this.expanded){
31984 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31987 if(!this.childrenRendered){
31988 this.renderChildren();
31990 this.expanded = true;
31991 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31992 this.ui.animExpand(function(){
31993 this.fireEvent("expand", this);
31994 if(typeof callback == "function"){
31998 this.expandChildNodes(true);
32000 }.createDelegate(this));
32004 this.fireEvent("expand", this);
32005 if(typeof callback == "function"){
32010 if(typeof callback == "function"){
32015 this.expandChildNodes(true);
32019 isHiddenRoot : function(){
32020 return this.isRoot && !this.getOwnerTree().rootVisible;
32024 * Collapse this node.
32025 * @param {Boolean} deep (optional) True to collapse all children as well
32026 * @param {Boolean} anim (optional) false to cancel the default animation
32028 collapse : function(deep, anim){
32029 if(this.expanded && !this.isHiddenRoot()){
32030 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
32033 this.expanded = false;
32034 if((this.getOwnerTree().animate && anim !== false) || anim){
32035 this.ui.animCollapse(function(){
32036 this.fireEvent("collapse", this);
32038 this.collapseChildNodes(true);
32040 }.createDelegate(this));
32043 this.ui.collapse();
32044 this.fireEvent("collapse", this);
32048 var cs = this.childNodes;
32049 for(var i = 0, len = cs.length; i < len; i++) {
32050 cs[i].collapse(true, false);
32056 delayedExpand : function(delay){
32057 if(!this.expandProcId){
32058 this.expandProcId = this.expand.defer(delay, this);
32063 cancelExpand : function(){
32064 if(this.expandProcId){
32065 clearTimeout(this.expandProcId);
32067 this.expandProcId = false;
32071 * Toggles expanded/collapsed state of the node
32073 toggle : function(){
32082 * Ensures all parent nodes are expanded
32084 ensureVisible : function(callback){
32085 var tree = this.getOwnerTree();
32086 tree.expandPath(this.parentNode.getPath(), false, function(){
32087 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
32088 Roo.callback(callback);
32089 }.createDelegate(this));
32093 * Expand all child nodes
32094 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
32096 expandChildNodes : function(deep){
32097 var cs = this.childNodes;
32098 for(var i = 0, len = cs.length; i < len; i++) {
32099 cs[i].expand(deep);
32104 * Collapse all child nodes
32105 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
32107 collapseChildNodes : function(deep){
32108 var cs = this.childNodes;
32109 for(var i = 0, len = cs.length; i < len; i++) {
32110 cs[i].collapse(deep);
32115 * Disables this node
32117 disable : function(){
32118 this.disabled = true;
32120 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32121 this.ui.onDisableChange(this, true);
32123 this.fireEvent("disabledchange", this, true);
32127 * Enables this node
32129 enable : function(){
32130 this.disabled = false;
32131 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32132 this.ui.onDisableChange(this, false);
32134 this.fireEvent("disabledchange", this, false);
32138 renderChildren : function(suppressEvent){
32139 if(suppressEvent !== false){
32140 this.fireEvent("beforechildrenrendered", this);
32142 var cs = this.childNodes;
32143 for(var i = 0, len = cs.length; i < len; i++){
32144 cs[i].render(true);
32146 this.childrenRendered = true;
32150 sort : function(fn, scope){
32151 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32152 if(this.childrenRendered){
32153 var cs = this.childNodes;
32154 for(var i = 0, len = cs.length; i < len; i++){
32155 cs[i].render(true);
32161 render : function(bulkRender){
32162 this.ui.render(bulkRender);
32163 if(!this.rendered){
32164 this.rendered = true;
32166 this.expanded = false;
32167 this.expand(false, false);
32173 renderIndent : function(deep, refresh){
32175 this.ui.childIndent = null;
32177 this.ui.renderIndent();
32178 if(deep === true && this.childrenRendered){
32179 var cs = this.childNodes;
32180 for(var i = 0, len = cs.length; i < len; i++){
32181 cs[i].renderIndent(true, refresh);
32187 * Ext JS Library 1.1.1
32188 * Copyright(c) 2006-2007, Ext JS, LLC.
32190 * Originally Released Under LGPL - original licence link has changed is not relivant.
32193 * <script type="text/javascript">
32197 * @class Roo.tree.AsyncTreeNode
32198 * @extends Roo.tree.TreeNode
32199 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32201 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32203 Roo.tree.AsyncTreeNode = function(config){
32204 this.loaded = false;
32205 this.loading = false;
32206 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32208 * @event beforeload
32209 * Fires before this node is loaded, return false to cancel
32210 * @param {Node} this This node
32212 this.addEvents({'beforeload':true, 'load': true});
32215 * Fires when this node is loaded
32216 * @param {Node} this This node
32219 * The loader used by this node (defaults to using the tree's defined loader)
32224 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32225 expand : function(deep, anim, callback){
32226 if(this.loading){ // if an async load is already running, waiting til it's done
32228 var f = function(){
32229 if(!this.loading){ // done loading
32230 clearInterval(timer);
32231 this.expand(deep, anim, callback);
32233 }.createDelegate(this);
32234 timer = setInterval(f, 200);
32238 if(this.fireEvent("beforeload", this) === false){
32241 this.loading = true;
32242 this.ui.beforeLoad(this);
32243 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32245 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32249 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32253 * Returns true if this node is currently loading
32254 * @return {Boolean}
32256 isLoading : function(){
32257 return this.loading;
32260 loadComplete : function(deep, anim, callback){
32261 this.loading = false;
32262 this.loaded = true;
32263 this.ui.afterLoad(this);
32264 this.fireEvent("load", this);
32265 this.expand(deep, anim, callback);
32269 * Returns true if this node has been loaded
32270 * @return {Boolean}
32272 isLoaded : function(){
32273 return this.loaded;
32276 hasChildNodes : function(){
32277 if(!this.isLeaf() && !this.loaded){
32280 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32285 * Trigger a reload for this node
32286 * @param {Function} callback
32288 reload : function(callback){
32289 this.collapse(false, false);
32290 while(this.firstChild){
32291 this.removeChild(this.firstChild);
32293 this.childrenRendered = false;
32294 this.loaded = false;
32295 if(this.isHiddenRoot()){
32296 this.expanded = false;
32298 this.expand(false, false, callback);
32302 * Ext JS Library 1.1.1
32303 * Copyright(c) 2006-2007, Ext JS, LLC.
32305 * Originally Released Under LGPL - original licence link has changed is not relivant.
32308 * <script type="text/javascript">
32312 * @class Roo.tree.TreeNodeUI
32314 * @param {Object} node The node to render
32315 * The TreeNode UI implementation is separate from the
32316 * tree implementation. Unless you are customizing the tree UI,
32317 * you should never have to use this directly.
32319 Roo.tree.TreeNodeUI = function(node){
32321 this.rendered = false;
32322 this.animating = false;
32323 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32326 Roo.tree.TreeNodeUI.prototype = {
32327 removeChild : function(node){
32329 this.ctNode.removeChild(node.ui.getEl());
32333 beforeLoad : function(){
32334 this.addClass("x-tree-node-loading");
32337 afterLoad : function(){
32338 this.removeClass("x-tree-node-loading");
32341 onTextChange : function(node, text, oldText){
32343 this.textNode.innerHTML = text;
32347 onDisableChange : function(node, state){
32348 this.disabled = state;
32350 this.addClass("x-tree-node-disabled");
32352 this.removeClass("x-tree-node-disabled");
32356 onSelectedChange : function(state){
32359 this.addClass("x-tree-selected");
32362 this.removeClass("x-tree-selected");
32366 onMove : function(tree, node, oldParent, newParent, index, refNode){
32367 this.childIndent = null;
32369 var targetNode = newParent.ui.getContainer();
32370 if(!targetNode){//target not rendered
32371 this.holder = document.createElement("div");
32372 this.holder.appendChild(this.wrap);
32375 var insertBefore = refNode ? refNode.ui.getEl() : null;
32377 targetNode.insertBefore(this.wrap, insertBefore);
32379 targetNode.appendChild(this.wrap);
32381 this.node.renderIndent(true);
32385 addClass : function(cls){
32387 Roo.fly(this.elNode).addClass(cls);
32391 removeClass : function(cls){
32393 Roo.fly(this.elNode).removeClass(cls);
32397 remove : function(){
32399 this.holder = document.createElement("div");
32400 this.holder.appendChild(this.wrap);
32404 fireEvent : function(){
32405 return this.node.fireEvent.apply(this.node, arguments);
32408 initEvents : function(){
32409 this.node.on("move", this.onMove, this);
32410 var E = Roo.EventManager;
32411 var a = this.anchor;
32413 var el = Roo.fly(a, '_treeui');
32415 if(Roo.isOpera){ // opera render bug ignores the CSS
32416 el.setStyle("text-decoration", "none");
32419 el.on("click", this.onClick, this);
32420 el.on("dblclick", this.onDblClick, this);
32423 Roo.EventManager.on(this.checkbox,
32424 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32427 el.on("contextmenu", this.onContextMenu, this);
32429 var icon = Roo.fly(this.iconNode);
32430 icon.on("click", this.onClick, this);
32431 icon.on("dblclick", this.onDblClick, this);
32432 icon.on("contextmenu", this.onContextMenu, this);
32433 E.on(this.ecNode, "click", this.ecClick, this, true);
32435 if(this.node.disabled){
32436 this.addClass("x-tree-node-disabled");
32438 if(this.node.hidden){
32439 this.addClass("x-tree-node-disabled");
32441 var ot = this.node.getOwnerTree();
32442 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32443 if(dd && (!this.node.isRoot || ot.rootVisible)){
32444 Roo.dd.Registry.register(this.elNode, {
32446 handles: this.getDDHandles(),
32452 getDDHandles : function(){
32453 return [this.iconNode, this.textNode];
32458 this.wrap.style.display = "none";
32464 this.wrap.style.display = "";
32468 onContextMenu : function(e){
32469 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32470 e.preventDefault();
32472 this.fireEvent("contextmenu", this.node, e);
32476 onClick : function(e){
32481 if(this.fireEvent("beforeclick", this.node, e) !== false){
32482 if(!this.disabled && this.node.attributes.href){
32483 this.fireEvent("click", this.node, e);
32486 e.preventDefault();
32491 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32492 this.node.toggle();
32495 this.fireEvent("click", this.node, e);
32501 onDblClick : function(e){
32502 e.preventDefault();
32507 this.toggleCheck();
32509 if(!this.animating && this.node.hasChildNodes()){
32510 this.node.toggle();
32512 this.fireEvent("dblclick", this.node, e);
32515 onCheckChange : function(){
32516 var checked = this.checkbox.checked;
32517 this.node.attributes.checked = checked;
32518 this.fireEvent('checkchange', this.node, checked);
32521 ecClick : function(e){
32522 if(!this.animating && this.node.hasChildNodes()){
32523 this.node.toggle();
32527 startDrop : function(){
32528 this.dropping = true;
32531 // delayed drop so the click event doesn't get fired on a drop
32532 endDrop : function(){
32533 setTimeout(function(){
32534 this.dropping = false;
32535 }.createDelegate(this), 50);
32538 expand : function(){
32539 this.updateExpandIcon();
32540 this.ctNode.style.display = "";
32543 focus : function(){
32544 if(!this.node.preventHScroll){
32545 try{this.anchor.focus();
32547 }else if(!Roo.isIE){
32549 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32550 var l = noscroll.scrollLeft;
32551 this.anchor.focus();
32552 noscroll.scrollLeft = l;
32557 toggleCheck : function(value){
32558 var cb = this.checkbox;
32560 cb.checked = (value === undefined ? !cb.checked : value);
32566 this.anchor.blur();
32570 animExpand : function(callback){
32571 var ct = Roo.get(this.ctNode);
32573 if(!this.node.hasChildNodes()){
32574 this.updateExpandIcon();
32575 this.ctNode.style.display = "";
32576 Roo.callback(callback);
32579 this.animating = true;
32580 this.updateExpandIcon();
32583 callback : function(){
32584 this.animating = false;
32585 Roo.callback(callback);
32588 duration: this.node.ownerTree.duration || .25
32592 highlight : function(){
32593 var tree = this.node.getOwnerTree();
32594 Roo.fly(this.wrap).highlight(
32595 tree.hlColor || "C3DAF9",
32596 {endColor: tree.hlBaseColor}
32600 collapse : function(){
32601 this.updateExpandIcon();
32602 this.ctNode.style.display = "none";
32605 animCollapse : function(callback){
32606 var ct = Roo.get(this.ctNode);
32607 ct.enableDisplayMode('block');
32610 this.animating = true;
32611 this.updateExpandIcon();
32614 callback : function(){
32615 this.animating = false;
32616 Roo.callback(callback);
32619 duration: this.node.ownerTree.duration || .25
32623 getContainer : function(){
32624 return this.ctNode;
32627 getEl : function(){
32631 appendDDGhost : function(ghostNode){
32632 ghostNode.appendChild(this.elNode.cloneNode(true));
32635 getDDRepairXY : function(){
32636 return Roo.lib.Dom.getXY(this.iconNode);
32639 onRender : function(){
32643 render : function(bulkRender){
32644 var n = this.node, a = n.attributes;
32645 var targetNode = n.parentNode ?
32646 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32648 if(!this.rendered){
32649 this.rendered = true;
32651 this.renderElements(n, a, targetNode, bulkRender);
32654 if(this.textNode.setAttributeNS){
32655 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32657 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32660 this.textNode.setAttribute("ext:qtip", a.qtip);
32662 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32665 }else if(a.qtipCfg){
32666 a.qtipCfg.target = Roo.id(this.textNode);
32667 Roo.QuickTips.register(a.qtipCfg);
32670 if(!this.node.expanded){
32671 this.updateExpandIcon();
32674 if(bulkRender === true) {
32675 targetNode.appendChild(this.wrap);
32680 renderElements : function(n, a, targetNode, bulkRender)
32682 // add some indent caching, this helps performance when rendering a large tree
32683 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32684 var t = n.getOwnerTree();
32685 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32686 if (typeof(n.attributes.html) != 'undefined') {
32687 txt = n.attributes.html;
32689 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32690 var cb = typeof a.checked == 'boolean';
32691 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32692 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32693 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32694 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32695 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32696 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32697 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32698 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32699 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32700 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32703 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32704 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32705 n.nextSibling.ui.getEl(), buf.join(""));
32707 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32710 this.elNode = this.wrap.childNodes[0];
32711 this.ctNode = this.wrap.childNodes[1];
32712 var cs = this.elNode.childNodes;
32713 this.indentNode = cs[0];
32714 this.ecNode = cs[1];
32715 this.iconNode = cs[2];
32718 this.checkbox = cs[3];
32721 this.anchor = cs[index];
32722 this.textNode = cs[index].firstChild;
32725 getAnchor : function(){
32726 return this.anchor;
32729 getTextEl : function(){
32730 return this.textNode;
32733 getIconEl : function(){
32734 return this.iconNode;
32737 isChecked : function(){
32738 return this.checkbox ? this.checkbox.checked : false;
32741 updateExpandIcon : function(){
32743 var n = this.node, c1, c2;
32744 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32745 var hasChild = n.hasChildNodes();
32749 c1 = "x-tree-node-collapsed";
32750 c2 = "x-tree-node-expanded";
32753 c1 = "x-tree-node-expanded";
32754 c2 = "x-tree-node-collapsed";
32757 this.removeClass("x-tree-node-leaf");
32758 this.wasLeaf = false;
32760 if(this.c1 != c1 || this.c2 != c2){
32761 Roo.fly(this.elNode).replaceClass(c1, c2);
32762 this.c1 = c1; this.c2 = c2;
32765 // this changes non-leafs into leafs if they have no children.
32766 // it's not very rational behaviour..
32768 if(!this.wasLeaf && this.node.leaf){
32769 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32772 this.wasLeaf = true;
32775 var ecc = "x-tree-ec-icon "+cls;
32776 if(this.ecc != ecc){
32777 this.ecNode.className = ecc;
32783 getChildIndent : function(){
32784 if(!this.childIndent){
32788 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32790 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32792 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32797 this.childIndent = buf.join("");
32799 return this.childIndent;
32802 renderIndent : function(){
32805 var p = this.node.parentNode;
32807 indent = p.ui.getChildIndent();
32809 if(this.indentMarkup != indent){ // don't rerender if not required
32810 this.indentNode.innerHTML = indent;
32811 this.indentMarkup = indent;
32813 this.updateExpandIcon();
32818 Roo.tree.RootTreeNodeUI = function(){
32819 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32821 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32822 render : function(){
32823 if(!this.rendered){
32824 var targetNode = this.node.ownerTree.innerCt.dom;
32825 this.node.expanded = true;
32826 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32827 this.wrap = this.ctNode = targetNode.firstChild;
32830 collapse : function(){
32832 expand : function(){
32836 * Ext JS Library 1.1.1
32837 * Copyright(c) 2006-2007, Ext JS, LLC.
32839 * Originally Released Under LGPL - original licence link has changed is not relivant.
32842 * <script type="text/javascript">
32845 * @class Roo.tree.TreeLoader
32846 * @extends Roo.util.Observable
32847 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32848 * nodes from a specified URL. The response must be a javascript Array definition
32849 * who's elements are node definition objects. eg:
32851 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32852 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32855 * A server request is sent, and child nodes are loaded only when a node is expanded.
32856 * The loading node's id is passed to the server under the parameter name "node" to
32857 * enable the server to produce the correct child nodes.
32859 * To pass extra parameters, an event handler may be attached to the "beforeload"
32860 * event, and the parameters specified in the TreeLoader's baseParams property:
32862 myTreeLoader.on("beforeload", function(treeLoader, node) {
32863 this.baseParams.category = node.attributes.category;
32866 * This would pass an HTTP parameter called "category" to the server containing
32867 * the value of the Node's "category" attribute.
32869 * Creates a new Treeloader.
32870 * @param {Object} config A config object containing config properties.
32872 Roo.tree.TreeLoader = function(config){
32873 this.baseParams = {};
32874 this.requestMethod = "POST";
32875 Roo.apply(this, config);
32880 * @event beforeload
32881 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32882 * @param {Object} This TreeLoader object.
32883 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32884 * @param {Object} callback The callback function specified in the {@link #load} call.
32889 * Fires when the node has been successfuly loaded.
32890 * @param {Object} This TreeLoader object.
32891 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32892 * @param {Object} response The response object containing the data from the server.
32896 * @event loadexception
32897 * Fires if the network request failed.
32898 * @param {Object} This TreeLoader object.
32899 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32900 * @param {Object} response The response object containing the data from the server.
32902 loadexception : true,
32905 * Fires before a node is created, enabling you to return custom Node types
32906 * @param {Object} This TreeLoader object.
32907 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32912 Roo.tree.TreeLoader.superclass.constructor.call(this);
32915 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32917 * @cfg {String} dataUrl The URL from which to request a Json string which
32918 * specifies an array of node definition object representing the child nodes
32922 * @cfg {Object} baseParams (optional) An object containing properties which
32923 * specify HTTP parameters to be passed to each request for child nodes.
32926 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32927 * created by this loader. If the attributes sent by the server have an attribute in this object,
32928 * they take priority.
32931 * @cfg {Object} uiProviders (optional) An object containing properties which
32933 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
32934 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32935 * <i>uiProvider</i> attribute of a returned child node is a string rather
32936 * than a reference to a TreeNodeUI implementation, this that string value
32937 * is used as a property name in the uiProviders object. You can define the provider named
32938 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32943 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32944 * child nodes before loading.
32946 clearOnLoad : true,
32949 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32950 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32951 * Grid query { data : [ .....] }
32956 * @cfg {String} queryParam (optional)
32957 * Name of the query as it will be passed on the querystring (defaults to 'node')
32958 * eg. the request will be ?node=[id]
32965 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32966 * This is called automatically when a node is expanded, but may be used to reload
32967 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32968 * @param {Roo.tree.TreeNode} node
32969 * @param {Function} callback
32971 load : function(node, callback){
32972 if(this.clearOnLoad){
32973 while(node.firstChild){
32974 node.removeChild(node.firstChild);
32977 if(node.attributes.children){ // preloaded json children
32978 var cs = node.attributes.children;
32979 for(var i = 0, len = cs.length; i < len; i++){
32980 node.appendChild(this.createNode(cs[i]));
32982 if(typeof callback == "function"){
32985 }else if(this.dataUrl){
32986 this.requestData(node, callback);
32990 getParams: function(node){
32991 var buf = [], bp = this.baseParams;
32992 for(var key in bp){
32993 if(typeof bp[key] != "function"){
32994 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32997 var n = this.queryParam === false ? 'node' : this.queryParam;
32998 buf.push(n + "=", encodeURIComponent(node.id));
32999 return buf.join("");
33002 requestData : function(node, callback){
33003 if(this.fireEvent("beforeload", this, node, callback) !== false){
33004 this.transId = Roo.Ajax.request({
33005 method:this.requestMethod,
33006 url: this.dataUrl||this.url,
33007 success: this.handleResponse,
33008 failure: this.handleFailure,
33010 argument: {callback: callback, node: node},
33011 params: this.getParams(node)
33014 // if the load is cancelled, make sure we notify
33015 // the node that we are done
33016 if(typeof callback == "function"){
33022 isLoading : function(){
33023 return this.transId ? true : false;
33026 abort : function(){
33027 if(this.isLoading()){
33028 Roo.Ajax.abort(this.transId);
33033 createNode : function(attr)
33035 // apply baseAttrs, nice idea Corey!
33036 if(this.baseAttrs){
33037 Roo.applyIf(attr, this.baseAttrs);
33039 if(this.applyLoader !== false){
33040 attr.loader = this;
33042 // uiProvider = depreciated..
33044 if(typeof(attr.uiProvider) == 'string'){
33045 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
33046 /** eval:var:attr */ eval(attr.uiProvider);
33048 if(typeof(this.uiProviders['default']) != 'undefined') {
33049 attr.uiProvider = this.uiProviders['default'];
33052 this.fireEvent('create', this, attr);
33054 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
33056 new Roo.tree.TreeNode(attr) :
33057 new Roo.tree.AsyncTreeNode(attr));
33060 processResponse : function(response, node, callback)
33062 var json = response.responseText;
33065 var o = Roo.decode(json);
33068 // it's a failure condition.
33069 var a = response.argument;
33070 this.fireEvent("loadexception", this, a.node, response);
33071 Roo.log("Load failed - should have a handler really");
33075 if (this.root !== false) {
33079 for(var i = 0, len = o.length; i < len; i++){
33080 var n = this.createNode(o[i]);
33082 node.appendChild(n);
33085 if(typeof callback == "function"){
33086 callback(this, node);
33089 this.handleFailure(response);
33093 handleResponse : function(response){
33094 this.transId = false;
33095 var a = response.argument;
33096 this.processResponse(response, a.node, a.callback);
33097 this.fireEvent("load", this, a.node, response);
33100 handleFailure : function(response)
33102 // should handle failure better..
33103 this.transId = false;
33104 var a = response.argument;
33105 this.fireEvent("loadexception", this, a.node, response);
33106 if(typeof a.callback == "function"){
33107 a.callback(this, a.node);
33112 * Ext JS Library 1.1.1
33113 * Copyright(c) 2006-2007, Ext JS, LLC.
33115 * Originally Released Under LGPL - original licence link has changed is not relivant.
33118 * <script type="text/javascript">
33122 * @class Roo.tree.TreeFilter
33123 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
33124 * @param {TreePanel} tree
33125 * @param {Object} config (optional)
33127 Roo.tree.TreeFilter = function(tree, config){
33129 this.filtered = {};
33130 Roo.apply(this, config);
33133 Roo.tree.TreeFilter.prototype = {
33140 * Filter the data by a specific attribute.
33141 * @param {String/RegExp} value Either string that the attribute value
33142 * should start with or a RegExp to test against the attribute
33143 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
33144 * @param {TreeNode} startNode (optional) The node to start the filter at.
33146 filter : function(value, attr, startNode){
33147 attr = attr || "text";
33149 if(typeof value == "string"){
33150 var vlen = value.length;
33151 // auto clear empty filter
33152 if(vlen == 0 && this.clearBlank){
33156 value = value.toLowerCase();
33158 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
33160 }else if(value.exec){ // regex?
33162 return value.test(n.attributes[attr]);
33165 throw 'Illegal filter type, must be string or regex';
33167 this.filterBy(f, null, startNode);
33171 * Filter by a function. The passed function will be called with each
33172 * node in the tree (or from the startNode). If the function returns true, the node is kept
33173 * otherwise it is filtered. If a node is filtered, its children are also filtered.
33174 * @param {Function} fn The filter function
33175 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33177 filterBy : function(fn, scope, startNode){
33178 startNode = startNode || this.tree.root;
33179 if(this.autoClear){
33182 var af = this.filtered, rv = this.reverse;
33183 var f = function(n){
33184 if(n == startNode){
33190 var m = fn.call(scope || n, n);
33198 startNode.cascade(f);
33201 if(typeof id != "function"){
33203 if(n && n.parentNode){
33204 n.parentNode.removeChild(n);
33212 * Clears the current filter. Note: with the "remove" option
33213 * set a filter cannot be cleared.
33215 clear : function(){
33217 var af = this.filtered;
33219 if(typeof id != "function"){
33226 this.filtered = {};
33231 * Ext JS Library 1.1.1
33232 * Copyright(c) 2006-2007, Ext JS, LLC.
33234 * Originally Released Under LGPL - original licence link has changed is not relivant.
33237 * <script type="text/javascript">
33242 * @class Roo.tree.TreeSorter
33243 * Provides sorting of nodes in a TreePanel
33245 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33246 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33247 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33248 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33249 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33250 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33252 * @param {TreePanel} tree
33253 * @param {Object} config
33255 Roo.tree.TreeSorter = function(tree, config){
33256 Roo.apply(this, config);
33257 tree.on("beforechildrenrendered", this.doSort, this);
33258 tree.on("append", this.updateSort, this);
33259 tree.on("insert", this.updateSort, this);
33261 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33262 var p = this.property || "text";
33263 var sortType = this.sortType;
33264 var fs = this.folderSort;
33265 var cs = this.caseSensitive === true;
33266 var leafAttr = this.leafAttr || 'leaf';
33268 this.sortFn = function(n1, n2){
33270 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33273 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33277 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33278 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33280 return dsc ? +1 : -1;
33282 return dsc ? -1 : +1;
33289 Roo.tree.TreeSorter.prototype = {
33290 doSort : function(node){
33291 node.sort(this.sortFn);
33294 compareNodes : function(n1, n2){
33295 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33298 updateSort : function(tree, node){
33299 if(node.childrenRendered){
33300 this.doSort.defer(1, this, [node]);
33305 * Ext JS Library 1.1.1
33306 * Copyright(c) 2006-2007, Ext JS, LLC.
33308 * Originally Released Under LGPL - original licence link has changed is not relivant.
33311 * <script type="text/javascript">
33314 if(Roo.dd.DropZone){
33316 Roo.tree.TreeDropZone = function(tree, config){
33317 this.allowParentInsert = false;
33318 this.allowContainerDrop = false;
33319 this.appendOnly = false;
33320 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33322 this.lastInsertClass = "x-tree-no-status";
33323 this.dragOverData = {};
33326 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33327 ddGroup : "TreeDD",
33329 expandDelay : 1000,
33331 expandNode : function(node){
33332 if(node.hasChildNodes() && !node.isExpanded()){
33333 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33337 queueExpand : function(node){
33338 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33341 cancelExpand : function(){
33342 if(this.expandProcId){
33343 clearTimeout(this.expandProcId);
33344 this.expandProcId = false;
33348 isValidDropPoint : function(n, pt, dd, e, data){
33349 if(!n || !data){ return false; }
33350 var targetNode = n.node;
33351 var dropNode = data.node;
33352 // default drop rules
33353 if(!(targetNode && targetNode.isTarget && pt)){
33356 if(pt == "append" && targetNode.allowChildren === false){
33359 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33362 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33365 // reuse the object
33366 var overEvent = this.dragOverData;
33367 overEvent.tree = this.tree;
33368 overEvent.target = targetNode;
33369 overEvent.data = data;
33370 overEvent.point = pt;
33371 overEvent.source = dd;
33372 overEvent.rawEvent = e;
33373 overEvent.dropNode = dropNode;
33374 overEvent.cancel = false;
33375 var result = this.tree.fireEvent("nodedragover", overEvent);
33376 return overEvent.cancel === false && result !== false;
33379 getDropPoint : function(e, n, dd){
33382 return tn.allowChildren !== false ? "append" : false; // always append for root
33384 var dragEl = n.ddel;
33385 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33386 var y = Roo.lib.Event.getPageY(e);
33387 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33389 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33390 var noAppend = tn.allowChildren === false;
33391 if(this.appendOnly || tn.parentNode.allowChildren === false){
33392 return noAppend ? false : "append";
33394 var noBelow = false;
33395 if(!this.allowParentInsert){
33396 noBelow = tn.hasChildNodes() && tn.isExpanded();
33398 var q = (b - t) / (noAppend ? 2 : 3);
33399 if(y >= t && y < (t + q)){
33401 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33408 onNodeEnter : function(n, dd, e, data){
33409 this.cancelExpand();
33412 onNodeOver : function(n, dd, e, data){
33413 var pt = this.getDropPoint(e, n, dd);
33416 // auto node expand check
33417 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33418 this.queueExpand(node);
33419 }else if(pt != "append"){
33420 this.cancelExpand();
33423 // set the insert point style on the target node
33424 var returnCls = this.dropNotAllowed;
33425 if(this.isValidDropPoint(n, pt, dd, e, data)){
33430 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33431 cls = "x-tree-drag-insert-above";
33432 }else if(pt == "below"){
33433 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33434 cls = "x-tree-drag-insert-below";
33436 returnCls = "x-tree-drop-ok-append";
33437 cls = "x-tree-drag-append";
33439 if(this.lastInsertClass != cls){
33440 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33441 this.lastInsertClass = cls;
33448 onNodeOut : function(n, dd, e, data){
33449 this.cancelExpand();
33450 this.removeDropIndicators(n);
33453 onNodeDrop : function(n, dd, e, data){
33454 var point = this.getDropPoint(e, n, dd);
33455 var targetNode = n.node;
33456 targetNode.ui.startDrop();
33457 if(!this.isValidDropPoint(n, point, dd, e, data)){
33458 targetNode.ui.endDrop();
33461 // first try to find the drop node
33462 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33465 target: targetNode,
33470 dropNode: dropNode,
33473 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33474 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33475 targetNode.ui.endDrop();
33478 // allow target changing
33479 targetNode = dropEvent.target;
33480 if(point == "append" && !targetNode.isExpanded()){
33481 targetNode.expand(false, null, function(){
33482 this.completeDrop(dropEvent);
33483 }.createDelegate(this));
33485 this.completeDrop(dropEvent);
33490 completeDrop : function(de){
33491 var ns = de.dropNode, p = de.point, t = de.target;
33492 if(!(ns instanceof Array)){
33496 for(var i = 0, len = ns.length; i < len; i++){
33499 t.parentNode.insertBefore(n, t);
33500 }else if(p == "below"){
33501 t.parentNode.insertBefore(n, t.nextSibling);
33507 if(this.tree.hlDrop){
33511 this.tree.fireEvent("nodedrop", de);
33514 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33515 if(this.tree.hlDrop){
33516 dropNode.ui.focus();
33517 dropNode.ui.highlight();
33519 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33522 getTree : function(){
33526 removeDropIndicators : function(n){
33529 Roo.fly(el).removeClass([
33530 "x-tree-drag-insert-above",
33531 "x-tree-drag-insert-below",
33532 "x-tree-drag-append"]);
33533 this.lastInsertClass = "_noclass";
33537 beforeDragDrop : function(target, e, id){
33538 this.cancelExpand();
33542 afterRepair : function(data){
33543 if(data && Roo.enableFx){
33544 data.node.ui.highlight();
33553 * Ext JS Library 1.1.1
33554 * Copyright(c) 2006-2007, Ext JS, LLC.
33556 * Originally Released Under LGPL - original licence link has changed is not relivant.
33559 * <script type="text/javascript">
33563 if(Roo.dd.DragZone){
33564 Roo.tree.TreeDragZone = function(tree, config){
33565 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33569 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33570 ddGroup : "TreeDD",
33572 onBeforeDrag : function(data, e){
33574 return n && n.draggable && !n.disabled;
33577 onInitDrag : function(e){
33578 var data = this.dragData;
33579 this.tree.getSelectionModel().select(data.node);
33580 this.proxy.update("");
33581 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33582 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33585 getRepairXY : function(e, data){
33586 return data.node.ui.getDDRepairXY();
33589 onEndDrag : function(data, e){
33590 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33593 onValidDrop : function(dd, e, id){
33594 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33598 beforeInvalidDrop : function(e, id){
33599 // this scrolls the original position back into view
33600 var sm = this.tree.getSelectionModel();
33601 sm.clearSelections();
33602 sm.select(this.dragData.node);
33607 * Ext JS Library 1.1.1
33608 * Copyright(c) 2006-2007, Ext JS, LLC.
33610 * Originally Released Under LGPL - original licence link has changed is not relivant.
33613 * <script type="text/javascript">
33616 * @class Roo.tree.TreeEditor
33617 * @extends Roo.Editor
33618 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33619 * as the editor field.
33621 * @param {Object} config (used to be the tree panel.)
33622 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33624 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
33625 * @cfg {Roo.form.TextField|Object} field The field configuration
33629 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
33632 if (oldconfig) { // old style..
33633 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
33636 tree = config.tree;
33637 config.field = config.field || {};
33638 config.field.xtype = 'TextField';
33639 field = Roo.factory(config.field, Roo.form);
33641 config = config || {};
33646 * @event beforenodeedit
33647 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
33648 * false from the handler of this event.
33649 * @param {Editor} this
33650 * @param {Roo.tree.Node} node
33652 "beforenodeedit" : true
33656 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
33660 tree.on('beforeclick', this.beforeNodeClick, this);
33661 tree.getTreeEl().on('mousedown', this.hide, this);
33662 this.on('complete', this.updateNode, this);
33663 this.on('beforestartedit', this.fitToTree, this);
33664 this.on('startedit', this.bindScroll, this, {delay:10});
33665 this.on('specialkey', this.onSpecialKey, this);
33668 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33670 * @cfg {String} alignment
33671 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33677 * @cfg {Boolean} hideEl
33678 * True to hide the bound element while the editor is displayed (defaults to false)
33682 * @cfg {String} cls
33683 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33685 cls: "x-small-editor x-tree-editor",
33687 * @cfg {Boolean} shim
33688 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33694 * @cfg {Number} maxWidth
33695 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33696 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33697 * scroll and client offsets into account prior to each edit.
33704 fitToTree : function(ed, el){
33705 var td = this.tree.getTreeEl().dom, nd = el.dom;
33706 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33707 td.scrollLeft = nd.offsetLeft;
33711 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33712 this.setSize(w, '');
33714 return this.fireEvent('beforenodeedit', this, this.editNode);
33719 triggerEdit : function(node){
33720 this.completeEdit();
33721 this.editNode = node;
33722 this.startEdit(node.ui.textNode, node.text);
33726 bindScroll : function(){
33727 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33731 beforeNodeClick : function(node, e){
33732 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33733 this.lastClick = new Date();
33734 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33736 this.triggerEdit(node);
33743 updateNode : function(ed, value){
33744 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33745 this.editNode.setText(value);
33749 onHide : function(){
33750 Roo.tree.TreeEditor.superclass.onHide.call(this);
33752 this.editNode.ui.focus();
33757 onSpecialKey : function(field, e){
33758 var k = e.getKey();
33762 }else if(k == e.ENTER && !e.hasModifier()){
33764 this.completeEdit();
33767 });//<Script type="text/javascript">
33770 * Ext JS Library 1.1.1
33771 * Copyright(c) 2006-2007, Ext JS, LLC.
33773 * Originally Released Under LGPL - original licence link has changed is not relivant.
33776 * <script type="text/javascript">
33780 * Not documented??? - probably should be...
33783 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33784 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33786 renderElements : function(n, a, targetNode, bulkRender){
33787 //consel.log("renderElements?");
33788 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33790 var t = n.getOwnerTree();
33791 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33793 var cols = t.columns;
33794 var bw = t.borderWidth;
33796 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33797 var cb = typeof a.checked == "boolean";
33798 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33799 var colcls = 'x-t-' + tid + '-c0';
33801 '<li class="x-tree-node">',
33804 '<div class="x-tree-node-el ', a.cls,'">',
33806 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33809 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33810 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33811 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33812 (a.icon ? ' x-tree-node-inline-icon' : ''),
33813 (a.iconCls ? ' '+a.iconCls : ''),
33814 '" unselectable="on" />',
33815 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33816 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33818 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33819 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33820 '<span unselectable="on" qtip="' + tx + '">',
33824 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33825 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33827 for(var i = 1, len = cols.length; i < len; i++){
33829 colcls = 'x-t-' + tid + '-c' +i;
33830 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33831 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33832 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33838 '<div class="x-clear"></div></div>',
33839 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33842 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33843 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33844 n.nextSibling.ui.getEl(), buf.join(""));
33846 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33848 var el = this.wrap.firstChild;
33850 this.elNode = el.firstChild;
33851 this.ranchor = el.childNodes[1];
33852 this.ctNode = this.wrap.childNodes[1];
33853 var cs = el.firstChild.childNodes;
33854 this.indentNode = cs[0];
33855 this.ecNode = cs[1];
33856 this.iconNode = cs[2];
33859 this.checkbox = cs[3];
33862 this.anchor = cs[index];
33864 this.textNode = cs[index].firstChild;
33866 //el.on("click", this.onClick, this);
33867 //el.on("dblclick", this.onDblClick, this);
33870 // console.log(this);
33872 initEvents : function(){
33873 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33876 var a = this.ranchor;
33878 var el = Roo.get(a);
33880 if(Roo.isOpera){ // opera render bug ignores the CSS
33881 el.setStyle("text-decoration", "none");
33884 el.on("click", this.onClick, this);
33885 el.on("dblclick", this.onDblClick, this);
33886 el.on("contextmenu", this.onContextMenu, this);
33890 /*onSelectedChange : function(state){
33893 this.addClass("x-tree-selected");
33896 this.removeClass("x-tree-selected");
33899 addClass : function(cls){
33901 Roo.fly(this.elRow).addClass(cls);
33907 removeClass : function(cls){
33909 Roo.fly(this.elRow).removeClass(cls);
33915 });//<Script type="text/javascript">
33919 * Ext JS Library 1.1.1
33920 * Copyright(c) 2006-2007, Ext JS, LLC.
33922 * Originally Released Under LGPL - original licence link has changed is not relivant.
33925 * <script type="text/javascript">
33930 * @class Roo.tree.ColumnTree
33931 * @extends Roo.data.TreePanel
33932 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33933 * @cfg {int} borderWidth compined right/left border allowance
33935 * @param {String/HTMLElement/Element} el The container element
33936 * @param {Object} config
33938 Roo.tree.ColumnTree = function(el, config)
33940 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33944 * Fire this event on a container when it resizes
33945 * @param {int} w Width
33946 * @param {int} h Height
33950 this.on('resize', this.onResize, this);
33953 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33957 borderWidth: Roo.isBorderBox ? 0 : 2,
33960 render : function(){
33961 // add the header.....
33963 Roo.tree.ColumnTree.superclass.render.apply(this);
33965 this.el.addClass('x-column-tree');
33967 this.headers = this.el.createChild(
33968 {cls:'x-tree-headers'},this.innerCt.dom);
33970 var cols = this.columns, c;
33971 var totalWidth = 0;
33973 var len = cols.length;
33974 for(var i = 0; i < len; i++){
33976 totalWidth += c.width;
33977 this.headEls.push(this.headers.createChild({
33978 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33980 cls:'x-tree-hd-text',
33983 style:'width:'+(c.width-this.borderWidth)+'px;'
33986 this.headers.createChild({cls:'x-clear'});
33987 // prevent floats from wrapping when clipped
33988 this.headers.setWidth(totalWidth);
33989 //this.innerCt.setWidth(totalWidth);
33990 this.innerCt.setStyle({ overflow: 'auto' });
33991 this.onResize(this.width, this.height);
33995 onResize : function(w,h)
34000 this.innerCt.setWidth(this.width);
34001 this.innerCt.setHeight(this.height-20);
34004 var cols = this.columns, c;
34005 var totalWidth = 0;
34007 var len = cols.length;
34008 for(var i = 0; i < len; i++){
34010 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
34011 // it's the expander..
34012 expEl = this.headEls[i];
34015 totalWidth += c.width;
34019 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
34021 this.headers.setWidth(w-20);
34030 * Ext JS Library 1.1.1
34031 * Copyright(c) 2006-2007, Ext JS, LLC.
34033 * Originally Released Under LGPL - original licence link has changed is not relivant.
34036 * <script type="text/javascript">
34040 * @class Roo.menu.Menu
34041 * @extends Roo.util.Observable
34042 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
34043 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
34045 * Creates a new Menu
34046 * @param {Object} config Configuration options
34048 Roo.menu.Menu = function(config){
34049 Roo.apply(this, config);
34050 this.id = this.id || Roo.id();
34053 * @event beforeshow
34054 * Fires before this menu is displayed
34055 * @param {Roo.menu.Menu} this
34059 * @event beforehide
34060 * Fires before this menu is hidden
34061 * @param {Roo.menu.Menu} this
34066 * Fires after this menu is displayed
34067 * @param {Roo.menu.Menu} this
34072 * Fires after this menu is hidden
34073 * @param {Roo.menu.Menu} this
34078 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
34079 * @param {Roo.menu.Menu} this
34080 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34081 * @param {Roo.EventObject} e
34086 * Fires when the mouse is hovering over this menu
34087 * @param {Roo.menu.Menu} this
34088 * @param {Roo.EventObject} e
34089 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34094 * Fires when the mouse exits this menu
34095 * @param {Roo.menu.Menu} this
34096 * @param {Roo.EventObject} e
34097 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34102 * Fires when a menu item contained in this menu is clicked
34103 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
34104 * @param {Roo.EventObject} e
34108 if (this.registerMenu) {
34109 Roo.menu.MenuMgr.register(this);
34112 var mis = this.items;
34113 this.items = new Roo.util.MixedCollection();
34115 this.add.apply(this, mis);
34119 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
34121 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
34125 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
34126 * for bottom-right shadow (defaults to "sides")
34130 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
34131 * this menu (defaults to "tl-tr?")
34133 subMenuAlign : "tl-tr?",
34135 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
34136 * relative to its element of origin (defaults to "tl-bl?")
34138 defaultAlign : "tl-bl?",
34140 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
34142 allowOtherMenus : false,
34144 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
34146 registerMenu : true,
34151 render : function(){
34155 var el = this.el = new Roo.Layer({
34157 shadow:this.shadow,
34159 parentEl: this.parentEl || document.body,
34163 this.keyNav = new Roo.menu.MenuNav(this);
34166 el.addClass("x-menu-plain");
34169 el.addClass(this.cls);
34171 // generic focus element
34172 this.focusEl = el.createChild({
34173 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
34175 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
34176 ul.on("click", this.onClick, this);
34177 ul.on("mouseover", this.onMouseOver, this);
34178 ul.on("mouseout", this.onMouseOut, this);
34179 this.items.each(function(item){
34180 var li = document.createElement("li");
34181 li.className = "x-menu-list-item";
34182 ul.dom.appendChild(li);
34183 item.render(li, this);
34190 autoWidth : function(){
34191 var el = this.el, ul = this.ul;
34195 var w = this.width;
34198 }else if(Roo.isIE){
34199 el.setWidth(this.minWidth);
34200 var t = el.dom.offsetWidth; // force recalc
34201 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34206 delayAutoWidth : function(){
34209 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
34211 this.awTask.delay(20);
34216 findTargetItem : function(e){
34217 var t = e.getTarget(".x-menu-list-item", this.ul, true);
34218 if(t && t.menuItemId){
34219 return this.items.get(t.menuItemId);
34224 onClick : function(e){
34226 if(t = this.findTargetItem(e)){
34228 this.fireEvent("click", this, t, e);
34233 setActiveItem : function(item, autoExpand){
34234 if(item != this.activeItem){
34235 if(this.activeItem){
34236 this.activeItem.deactivate();
34238 this.activeItem = item;
34239 item.activate(autoExpand);
34240 }else if(autoExpand){
34246 tryActivate : function(start, step){
34247 var items = this.items;
34248 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34249 var item = items.get(i);
34250 if(!item.disabled && item.canActivate){
34251 this.setActiveItem(item, false);
34259 onMouseOver : function(e){
34261 if(t = this.findTargetItem(e)){
34262 if(t.canActivate && !t.disabled){
34263 this.setActiveItem(t, true);
34266 this.fireEvent("mouseover", this, e, t);
34270 onMouseOut : function(e){
34272 if(t = this.findTargetItem(e)){
34273 if(t == this.activeItem && t.shouldDeactivate(e)){
34274 this.activeItem.deactivate();
34275 delete this.activeItem;
34278 this.fireEvent("mouseout", this, e, t);
34282 * Read-only. Returns true if the menu is currently displayed, else false.
34285 isVisible : function(){
34286 return this.el && !this.hidden;
34290 * Displays this menu relative to another element
34291 * @param {String/HTMLElement/Roo.Element} element The element to align to
34292 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34293 * the element (defaults to this.defaultAlign)
34294 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34296 show : function(el, pos, parentMenu){
34297 this.parentMenu = parentMenu;
34301 this.fireEvent("beforeshow", this);
34302 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34306 * Displays this menu at a specific xy position
34307 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34308 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34310 showAt : function(xy, parentMenu, /* private: */_e){
34311 this.parentMenu = parentMenu;
34316 this.fireEvent("beforeshow", this);
34317 xy = this.el.adjustForConstraints(xy);
34321 this.hidden = false;
34323 this.fireEvent("show", this);
34326 focus : function(){
34328 this.doFocus.defer(50, this);
34332 doFocus : function(){
34334 this.focusEl.focus();
34339 * Hides this menu and optionally all parent menus
34340 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34342 hide : function(deep){
34343 if(this.el && this.isVisible()){
34344 this.fireEvent("beforehide", this);
34345 if(this.activeItem){
34346 this.activeItem.deactivate();
34347 this.activeItem = null;
34350 this.hidden = true;
34351 this.fireEvent("hide", this);
34353 if(deep === true && this.parentMenu){
34354 this.parentMenu.hide(true);
34359 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34360 * Any of the following are valid:
34362 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34363 * <li>An HTMLElement object which will be converted to a menu item</li>
34364 * <li>A menu item config object that will be created as a new menu item</li>
34365 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34366 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34371 var menu = new Roo.menu.Menu();
34373 // Create a menu item to add by reference
34374 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34376 // Add a bunch of items at once using different methods.
34377 // Only the last item added will be returned.
34378 var item = menu.add(
34379 menuItem, // add existing item by ref
34380 'Dynamic Item', // new TextItem
34381 '-', // new separator
34382 { text: 'Config Item' } // new item by config
34385 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34386 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34389 var a = arguments, l = a.length, item;
34390 for(var i = 0; i < l; i++){
34392 if ((typeof(el) == "object") && el.xtype && el.xns) {
34393 el = Roo.factory(el, Roo.menu);
34396 if(el.render){ // some kind of Item
34397 item = this.addItem(el);
34398 }else if(typeof el == "string"){ // string
34399 if(el == "separator" || el == "-"){
34400 item = this.addSeparator();
34402 item = this.addText(el);
34404 }else if(el.tagName || el.el){ // element
34405 item = this.addElement(el);
34406 }else if(typeof el == "object"){ // must be menu item config?
34407 item = this.addMenuItem(el);
34414 * Returns this menu's underlying {@link Roo.Element} object
34415 * @return {Roo.Element} The element
34417 getEl : function(){
34425 * Adds a separator bar to the menu
34426 * @return {Roo.menu.Item} The menu item that was added
34428 addSeparator : function(){
34429 return this.addItem(new Roo.menu.Separator());
34433 * Adds an {@link Roo.Element} object to the menu
34434 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34435 * @return {Roo.menu.Item} The menu item that was added
34437 addElement : function(el){
34438 return this.addItem(new Roo.menu.BaseItem(el));
34442 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34443 * @param {Roo.menu.Item} item The menu item to add
34444 * @return {Roo.menu.Item} The menu item that was added
34446 addItem : function(item){
34447 this.items.add(item);
34449 var li = document.createElement("li");
34450 li.className = "x-menu-list-item";
34451 this.ul.dom.appendChild(li);
34452 item.render(li, this);
34453 this.delayAutoWidth();
34459 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34460 * @param {Object} config A MenuItem config object
34461 * @return {Roo.menu.Item} The menu item that was added
34463 addMenuItem : function(config){
34464 if(!(config instanceof Roo.menu.Item)){
34465 if(typeof config.checked == "boolean"){ // must be check menu item config?
34466 config = new Roo.menu.CheckItem(config);
34468 config = new Roo.menu.Item(config);
34471 return this.addItem(config);
34475 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34476 * @param {String} text The text to display in the menu item
34477 * @return {Roo.menu.Item} The menu item that was added
34479 addText : function(text){
34480 return this.addItem(new Roo.menu.TextItem({ text : text }));
34484 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34485 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34486 * @param {Roo.menu.Item} item The menu item to add
34487 * @return {Roo.menu.Item} The menu item that was added
34489 insert : function(index, item){
34490 this.items.insert(index, item);
34492 var li = document.createElement("li");
34493 li.className = "x-menu-list-item";
34494 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34495 item.render(li, this);
34496 this.delayAutoWidth();
34502 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34503 * @param {Roo.menu.Item} item The menu item to remove
34505 remove : function(item){
34506 this.items.removeKey(item.id);
34511 * Removes and destroys all items in the menu
34513 removeAll : function(){
34515 while(f = this.items.first()){
34521 // MenuNav is a private utility class used internally by the Menu
34522 Roo.menu.MenuNav = function(menu){
34523 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34524 this.scope = this.menu = menu;
34527 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34528 doRelay : function(e, h){
34529 var k = e.getKey();
34530 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34531 this.menu.tryActivate(0, 1);
34534 return h.call(this.scope || this, e, this.menu);
34537 up : function(e, m){
34538 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34539 m.tryActivate(m.items.length-1, -1);
34543 down : function(e, m){
34544 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34545 m.tryActivate(0, 1);
34549 right : function(e, m){
34551 m.activeItem.expandMenu(true);
34555 left : function(e, m){
34557 if(m.parentMenu && m.parentMenu.activeItem){
34558 m.parentMenu.activeItem.activate();
34562 enter : function(e, m){
34564 e.stopPropagation();
34565 m.activeItem.onClick(e);
34566 m.fireEvent("click", this, m.activeItem);
34572 * Ext JS Library 1.1.1
34573 * Copyright(c) 2006-2007, Ext JS, LLC.
34575 * Originally Released Under LGPL - original licence link has changed is not relivant.
34578 * <script type="text/javascript">
34582 * @class Roo.menu.MenuMgr
34583 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34586 Roo.menu.MenuMgr = function(){
34587 var menus, active, groups = {}, attached = false, lastShow = new Date();
34589 // private - called when first menu is created
34592 active = new Roo.util.MixedCollection();
34593 Roo.get(document).addKeyListener(27, function(){
34594 if(active.length > 0){
34601 function hideAll(){
34602 if(active && active.length > 0){
34603 var c = active.clone();
34604 c.each(function(m){
34611 function onHide(m){
34613 if(active.length < 1){
34614 Roo.get(document).un("mousedown", onMouseDown);
34620 function onShow(m){
34621 var last = active.last();
34622 lastShow = new Date();
34625 Roo.get(document).on("mousedown", onMouseDown);
34629 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34630 m.parentMenu.activeChild = m;
34631 }else if(last && last.isVisible()){
34632 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34637 function onBeforeHide(m){
34639 m.activeChild.hide();
34641 if(m.autoHideTimer){
34642 clearTimeout(m.autoHideTimer);
34643 delete m.autoHideTimer;
34648 function onBeforeShow(m){
34649 var pm = m.parentMenu;
34650 if(!pm && !m.allowOtherMenus){
34652 }else if(pm && pm.activeChild && active != m){
34653 pm.activeChild.hide();
34658 function onMouseDown(e){
34659 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34665 function onBeforeCheck(mi, state){
34667 var g = groups[mi.group];
34668 for(var i = 0, l = g.length; i < l; i++){
34670 g[i].setChecked(false);
34679 * Hides all menus that are currently visible
34681 hideAll : function(){
34686 register : function(menu){
34690 menus[menu.id] = menu;
34691 menu.on("beforehide", onBeforeHide);
34692 menu.on("hide", onHide);
34693 menu.on("beforeshow", onBeforeShow);
34694 menu.on("show", onShow);
34695 var g = menu.group;
34696 if(g && menu.events["checkchange"]){
34700 groups[g].push(menu);
34701 menu.on("checkchange", onCheck);
34706 * Returns a {@link Roo.menu.Menu} object
34707 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34708 * be used to generate and return a new Menu instance.
34710 get : function(menu){
34711 if(typeof menu == "string"){ // menu id
34712 return menus[menu];
34713 }else if(menu.events){ // menu instance
34715 }else if(typeof menu.length == 'number'){ // array of menu items?
34716 return new Roo.menu.Menu({items:menu});
34717 }else{ // otherwise, must be a config
34718 return new Roo.menu.Menu(menu);
34723 unregister : function(menu){
34724 delete menus[menu.id];
34725 menu.un("beforehide", onBeforeHide);
34726 menu.un("hide", onHide);
34727 menu.un("beforeshow", onBeforeShow);
34728 menu.un("show", onShow);
34729 var g = menu.group;
34730 if(g && menu.events["checkchange"]){
34731 groups[g].remove(menu);
34732 menu.un("checkchange", onCheck);
34737 registerCheckable : function(menuItem){
34738 var g = menuItem.group;
34743 groups[g].push(menuItem);
34744 menuItem.on("beforecheckchange", onBeforeCheck);
34749 unregisterCheckable : function(menuItem){
34750 var g = menuItem.group;
34752 groups[g].remove(menuItem);
34753 menuItem.un("beforecheckchange", onBeforeCheck);
34759 * Ext JS Library 1.1.1
34760 * Copyright(c) 2006-2007, Ext JS, LLC.
34762 * Originally Released Under LGPL - original licence link has changed is not relivant.
34765 * <script type="text/javascript">
34770 * @class Roo.menu.BaseItem
34771 * @extends Roo.Component
34772 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34773 * management and base configuration options shared by all menu components.
34775 * Creates a new BaseItem
34776 * @param {Object} config Configuration options
34778 Roo.menu.BaseItem = function(config){
34779 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34784 * Fires when this item is clicked
34785 * @param {Roo.menu.BaseItem} this
34786 * @param {Roo.EventObject} e
34791 * Fires when this item is activated
34792 * @param {Roo.menu.BaseItem} this
34796 * @event deactivate
34797 * Fires when this item is deactivated
34798 * @param {Roo.menu.BaseItem} this
34804 this.on("click", this.handler, this.scope, true);
34808 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34810 * @cfg {Function} handler
34811 * A function that will handle the click event of this menu item (defaults to undefined)
34814 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34816 canActivate : false,
34818 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34820 activeClass : "x-menu-item-active",
34822 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34824 hideOnClick : true,
34826 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34831 ctype: "Roo.menu.BaseItem",
34834 actionMode : "container",
34837 render : function(container, parentMenu){
34838 this.parentMenu = parentMenu;
34839 Roo.menu.BaseItem.superclass.render.call(this, container);
34840 this.container.menuItemId = this.id;
34844 onRender : function(container, position){
34845 this.el = Roo.get(this.el);
34846 container.dom.appendChild(this.el.dom);
34850 onClick : function(e){
34851 if(!this.disabled && this.fireEvent("click", this, e) !== false
34852 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34853 this.handleClick(e);
34860 activate : function(){
34864 var li = this.container;
34865 li.addClass(this.activeClass);
34866 this.region = li.getRegion().adjust(2, 2, -2, -2);
34867 this.fireEvent("activate", this);
34872 deactivate : function(){
34873 this.container.removeClass(this.activeClass);
34874 this.fireEvent("deactivate", this);
34878 shouldDeactivate : function(e){
34879 return !this.region || !this.region.contains(e.getPoint());
34883 handleClick : function(e){
34884 if(this.hideOnClick){
34885 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34890 expandMenu : function(autoActivate){
34895 hideMenu : function(){
34900 * Ext JS Library 1.1.1
34901 * Copyright(c) 2006-2007, Ext JS, LLC.
34903 * Originally Released Under LGPL - original licence link has changed is not relivant.
34906 * <script type="text/javascript">
34910 * @class Roo.menu.Adapter
34911 * @extends Roo.menu.BaseItem
34912 * 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.
34913 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34915 * Creates a new Adapter
34916 * @param {Object} config Configuration options
34918 Roo.menu.Adapter = function(component, config){
34919 Roo.menu.Adapter.superclass.constructor.call(this, config);
34920 this.component = component;
34922 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34924 canActivate : true,
34927 onRender : function(container, position){
34928 this.component.render(container);
34929 this.el = this.component.getEl();
34933 activate : function(){
34937 this.component.focus();
34938 this.fireEvent("activate", this);
34943 deactivate : function(){
34944 this.fireEvent("deactivate", this);
34948 disable : function(){
34949 this.component.disable();
34950 Roo.menu.Adapter.superclass.disable.call(this);
34954 enable : function(){
34955 this.component.enable();
34956 Roo.menu.Adapter.superclass.enable.call(this);
34960 * Ext JS Library 1.1.1
34961 * Copyright(c) 2006-2007, Ext JS, LLC.
34963 * Originally Released Under LGPL - original licence link has changed is not relivant.
34966 * <script type="text/javascript">
34970 * @class Roo.menu.TextItem
34971 * @extends Roo.menu.BaseItem
34972 * Adds a static text string to a menu, usually used as either a heading or group separator.
34973 * Note: old style constructor with text is still supported.
34976 * Creates a new TextItem
34977 * @param {Object} cfg Configuration
34979 Roo.menu.TextItem = function(cfg){
34980 if (typeof(cfg) == 'string') {
34983 Roo.apply(this,cfg);
34986 Roo.menu.TextItem.superclass.constructor.call(this);
34989 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34991 * @cfg {Boolean} text Text to show on item.
34996 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34998 hideOnClick : false,
35000 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
35002 itemCls : "x-menu-text",
35005 onRender : function(){
35006 var s = document.createElement("span");
35007 s.className = this.itemCls;
35008 s.innerHTML = this.text;
35010 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
35014 * Ext JS Library 1.1.1
35015 * Copyright(c) 2006-2007, Ext JS, LLC.
35017 * Originally Released Under LGPL - original licence link has changed is not relivant.
35020 * <script type="text/javascript">
35024 * @class Roo.menu.Separator
35025 * @extends Roo.menu.BaseItem
35026 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
35027 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
35029 * @param {Object} config Configuration options
35031 Roo.menu.Separator = function(config){
35032 Roo.menu.Separator.superclass.constructor.call(this, config);
35035 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
35037 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
35039 itemCls : "x-menu-sep",
35041 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35043 hideOnClick : false,
35046 onRender : function(li){
35047 var s = document.createElement("span");
35048 s.className = this.itemCls;
35049 s.innerHTML = " ";
35051 li.addClass("x-menu-sep-li");
35052 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
35056 * Ext JS Library 1.1.1
35057 * Copyright(c) 2006-2007, Ext JS, LLC.
35059 * Originally Released Under LGPL - original licence link has changed is not relivant.
35062 * <script type="text/javascript">
35065 * @class Roo.menu.Item
35066 * @extends Roo.menu.BaseItem
35067 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
35068 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
35069 * activation and click handling.
35071 * Creates a new Item
35072 * @param {Object} config Configuration options
35074 Roo.menu.Item = function(config){
35075 Roo.menu.Item.superclass.constructor.call(this, config);
35077 this.menu = Roo.menu.MenuMgr.get(this.menu);
35080 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
35083 * @cfg {String} text
35084 * The text to show on the menu item.
35088 * @cfg {String} HTML to render in menu
35089 * The text to show on the menu item (HTML version).
35093 * @cfg {String} icon
35094 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
35098 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
35100 itemCls : "x-menu-item",
35102 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
35104 canActivate : true,
35106 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
35109 // doc'd in BaseItem
35113 ctype: "Roo.menu.Item",
35116 onRender : function(container, position){
35117 var el = document.createElement("a");
35118 el.hideFocus = true;
35119 el.unselectable = "on";
35120 el.href = this.href || "#";
35121 if(this.hrefTarget){
35122 el.target = this.hrefTarget;
35124 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
35126 var html = this.html.length ? this.html : String.format('{0}',this.text);
35128 el.innerHTML = String.format(
35129 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
35130 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
35132 Roo.menu.Item.superclass.onRender.call(this, container, position);
35136 * Sets the text to display in this menu item
35137 * @param {String} text The text to display
35138 * @param {Boolean} isHTML true to indicate text is pure html.
35140 setText : function(text, isHTML){
35148 var html = this.html.length ? this.html : String.format('{0}',this.text);
35150 this.el.update(String.format(
35151 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
35152 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
35153 this.parentMenu.autoWidth();
35158 handleClick : function(e){
35159 if(!this.href){ // if no link defined, stop the event automatically
35162 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
35166 activate : function(autoExpand){
35167 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
35177 shouldDeactivate : function(e){
35178 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
35179 if(this.menu && this.menu.isVisible()){
35180 return !this.menu.getEl().getRegion().contains(e.getPoint());
35188 deactivate : function(){
35189 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
35194 expandMenu : function(autoActivate){
35195 if(!this.disabled && this.menu){
35196 clearTimeout(this.hideTimer);
35197 delete this.hideTimer;
35198 if(!this.menu.isVisible() && !this.showTimer){
35199 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
35200 }else if (this.menu.isVisible() && autoActivate){
35201 this.menu.tryActivate(0, 1);
35207 deferExpand : function(autoActivate){
35208 delete this.showTimer;
35209 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35211 this.menu.tryActivate(0, 1);
35216 hideMenu : function(){
35217 clearTimeout(this.showTimer);
35218 delete this.showTimer;
35219 if(!this.hideTimer && this.menu && this.menu.isVisible()){
35220 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35225 deferHide : function(){
35226 delete this.hideTimer;
35231 * Ext JS Library 1.1.1
35232 * Copyright(c) 2006-2007, Ext JS, LLC.
35234 * Originally Released Under LGPL - original licence link has changed is not relivant.
35237 * <script type="text/javascript">
35241 * @class Roo.menu.CheckItem
35242 * @extends Roo.menu.Item
35243 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35245 * Creates a new CheckItem
35246 * @param {Object} config Configuration options
35248 Roo.menu.CheckItem = function(config){
35249 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35252 * @event beforecheckchange
35253 * Fires before the checked value is set, providing an opportunity to cancel if needed
35254 * @param {Roo.menu.CheckItem} this
35255 * @param {Boolean} checked The new checked value that will be set
35257 "beforecheckchange" : true,
35259 * @event checkchange
35260 * Fires after the checked value has been set
35261 * @param {Roo.menu.CheckItem} this
35262 * @param {Boolean} checked The checked value that was set
35264 "checkchange" : true
35266 if(this.checkHandler){
35267 this.on('checkchange', this.checkHandler, this.scope);
35270 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35272 * @cfg {String} group
35273 * All check items with the same group name will automatically be grouped into a single-select
35274 * radio button group (defaults to '')
35277 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35279 itemCls : "x-menu-item x-menu-check-item",
35281 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35283 groupClass : "x-menu-group-item",
35286 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35287 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35288 * initialized with checked = true will be rendered as checked.
35293 ctype: "Roo.menu.CheckItem",
35296 onRender : function(c){
35297 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35299 this.el.addClass(this.groupClass);
35301 Roo.menu.MenuMgr.registerCheckable(this);
35303 this.checked = false;
35304 this.setChecked(true, true);
35309 destroy : function(){
35311 Roo.menu.MenuMgr.unregisterCheckable(this);
35313 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35317 * Set the checked state of this item
35318 * @param {Boolean} checked The new checked value
35319 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35321 setChecked : function(state, suppressEvent){
35322 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35323 if(this.container){
35324 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35326 this.checked = state;
35327 if(suppressEvent !== true){
35328 this.fireEvent("checkchange", this, state);
35334 handleClick : function(e){
35335 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35336 this.setChecked(!this.checked);
35338 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35342 * Ext JS Library 1.1.1
35343 * Copyright(c) 2006-2007, Ext JS, LLC.
35345 * Originally Released Under LGPL - original licence link has changed is not relivant.
35348 * <script type="text/javascript">
35352 * @class Roo.menu.DateItem
35353 * @extends Roo.menu.Adapter
35354 * A menu item that wraps the {@link Roo.DatPicker} component.
35356 * Creates a new DateItem
35357 * @param {Object} config Configuration options
35359 Roo.menu.DateItem = function(config){
35360 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35361 /** The Roo.DatePicker object @type Roo.DatePicker */
35362 this.picker = this.component;
35363 this.addEvents({select: true});
35365 this.picker.on("render", function(picker){
35366 picker.getEl().swallowEvent("click");
35367 picker.container.addClass("x-menu-date-item");
35370 this.picker.on("select", this.onSelect, this);
35373 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35375 onSelect : function(picker, date){
35376 this.fireEvent("select", this, date, picker);
35377 Roo.menu.DateItem.superclass.handleClick.call(this);
35381 * Ext JS Library 1.1.1
35382 * Copyright(c) 2006-2007, Ext JS, LLC.
35384 * Originally Released Under LGPL - original licence link has changed is not relivant.
35387 * <script type="text/javascript">
35391 * @class Roo.menu.ColorItem
35392 * @extends Roo.menu.Adapter
35393 * A menu item that wraps the {@link Roo.ColorPalette} component.
35395 * Creates a new ColorItem
35396 * @param {Object} config Configuration options
35398 Roo.menu.ColorItem = function(config){
35399 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35400 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35401 this.palette = this.component;
35402 this.relayEvents(this.palette, ["select"]);
35403 if(this.selectHandler){
35404 this.on('select', this.selectHandler, this.scope);
35407 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35409 * Ext JS Library 1.1.1
35410 * Copyright(c) 2006-2007, Ext JS, LLC.
35412 * Originally Released Under LGPL - original licence link has changed is not relivant.
35415 * <script type="text/javascript">
35420 * @class Roo.menu.DateMenu
35421 * @extends Roo.menu.Menu
35422 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35424 * Creates a new DateMenu
35425 * @param {Object} config Configuration options
35427 Roo.menu.DateMenu = function(config){
35428 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35430 var di = new Roo.menu.DateItem(config);
35433 * The {@link Roo.DatePicker} instance for this DateMenu
35436 this.picker = di.picker;
35439 * @param {DatePicker} picker
35440 * @param {Date} date
35442 this.relayEvents(di, ["select"]);
35444 this.on('beforeshow', function(){
35446 this.picker.hideMonthPicker(true);
35450 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35454 * Ext JS Library 1.1.1
35455 * Copyright(c) 2006-2007, Ext JS, LLC.
35457 * Originally Released Under LGPL - original licence link has changed is not relivant.
35460 * <script type="text/javascript">
35465 * @class Roo.menu.ColorMenu
35466 * @extends Roo.menu.Menu
35467 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35469 * Creates a new ColorMenu
35470 * @param {Object} config Configuration options
35472 Roo.menu.ColorMenu = function(config){
35473 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35475 var ci = new Roo.menu.ColorItem(config);
35478 * The {@link Roo.ColorPalette} instance for this ColorMenu
35479 * @type ColorPalette
35481 this.palette = ci.palette;
35484 * @param {ColorPalette} palette
35485 * @param {String} color
35487 this.relayEvents(ci, ["select"]);
35489 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35491 * Ext JS Library 1.1.1
35492 * Copyright(c) 2006-2007, Ext JS, LLC.
35494 * Originally Released Under LGPL - original licence link has changed is not relivant.
35497 * <script type="text/javascript">
35501 * @class Roo.form.Field
35502 * @extends Roo.BoxComponent
35503 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35505 * Creates a new Field
35506 * @param {Object} config Configuration options
35508 Roo.form.Field = function(config){
35509 Roo.form.Field.superclass.constructor.call(this, config);
35512 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35514 * @cfg {String} fieldLabel Label to use when rendering a form.
35517 * @cfg {String} qtip Mouse over tip
35521 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35523 invalidClass : "x-form-invalid",
35525 * @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")
35527 invalidText : "The value in this field is invalid",
35529 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35531 focusClass : "x-form-focus",
35533 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35534 automatic validation (defaults to "keyup").
35536 validationEvent : "keyup",
35538 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35540 validateOnBlur : true,
35542 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35544 validationDelay : 250,
35546 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35547 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35549 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35551 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35553 fieldClass : "x-form-field",
35555 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35558 ----------- ----------------------------------------------------------------------
35559 qtip Display a quick tip when the user hovers over the field
35560 title Display a default browser title attribute popup
35561 under Add a block div beneath the field containing the error text
35562 side Add an error icon to the right of the field with a popup on hover
35563 [element id] Add the error text directly to the innerHTML of the specified element
35566 msgTarget : 'qtip',
35568 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35573 * @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.
35578 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35583 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35585 inputType : undefined,
35588 * @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).
35590 tabIndex : undefined,
35593 isFormField : true,
35598 * @property {Roo.Element} fieldEl
35599 * Element Containing the rendered Field (with label etc.)
35602 * @cfg {Mixed} value A value to initialize this field with.
35607 * @cfg {String} name The field's HTML name attribute.
35610 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35614 initComponent : function(){
35615 Roo.form.Field.superclass.initComponent.call(this);
35619 * Fires when this field receives input focus.
35620 * @param {Roo.form.Field} this
35625 * Fires when this field loses input focus.
35626 * @param {Roo.form.Field} this
35630 * @event specialkey
35631 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35632 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35633 * @param {Roo.form.Field} this
35634 * @param {Roo.EventObject} e The event object
35639 * Fires just before the field blurs if the field value has changed.
35640 * @param {Roo.form.Field} this
35641 * @param {Mixed} newValue The new value
35642 * @param {Mixed} oldValue The original value
35647 * Fires after the field has been marked as invalid.
35648 * @param {Roo.form.Field} this
35649 * @param {String} msg The validation message
35654 * Fires after the field has been validated with no errors.
35655 * @param {Roo.form.Field} this
35660 * Fires after the key up
35661 * @param {Roo.form.Field} this
35662 * @param {Roo.EventObject} e The event Object
35669 * Returns the name attribute of the field if available
35670 * @return {String} name The field name
35672 getName: function(){
35673 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35677 onRender : function(ct, position){
35678 Roo.form.Field.superclass.onRender.call(this, ct, position);
35680 var cfg = this.getAutoCreate();
35682 cfg.name = this.name || this.id;
35684 if(this.inputType){
35685 cfg.type = this.inputType;
35687 this.el = ct.createChild(cfg, position);
35689 var type = this.el.dom.type;
35691 if(type == 'password'){
35694 this.el.addClass('x-form-'+type);
35697 this.el.dom.readOnly = true;
35699 if(this.tabIndex !== undefined){
35700 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35703 this.el.addClass([this.fieldClass, this.cls]);
35708 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35709 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35710 * @return {Roo.form.Field} this
35712 applyTo : function(target){
35713 this.allowDomMove = false;
35714 this.el = Roo.get(target);
35715 this.render(this.el.dom.parentNode);
35720 initValue : function(){
35721 if(this.value !== undefined){
35722 this.setValue(this.value);
35723 }else if(this.el.dom.value.length > 0){
35724 this.setValue(this.el.dom.value);
35729 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35731 isDirty : function() {
35732 if(this.disabled) {
35735 return String(this.getValue()) !== String(this.originalValue);
35739 afterRender : function(){
35740 Roo.form.Field.superclass.afterRender.call(this);
35745 fireKey : function(e){
35746 //Roo.log('field ' + e.getKey());
35747 if(e.isNavKeyPress()){
35748 this.fireEvent("specialkey", this, e);
35753 * Resets the current field value to the originally loaded value and clears any validation messages
35755 reset : function(){
35756 this.setValue(this.originalValue);
35757 this.clearInvalid();
35761 initEvents : function(){
35762 // safari killled keypress - so keydown is now used..
35763 this.el.on("keydown" , this.fireKey, this);
35764 this.el.on("focus", this.onFocus, this);
35765 this.el.on("blur", this.onBlur, this);
35766 this.el.relayEvent('keyup', this);
35768 // reference to original value for reset
35769 this.originalValue = this.getValue();
35773 onFocus : function(){
35774 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35775 this.el.addClass(this.focusClass);
35777 if(!this.hasFocus){
35778 this.hasFocus = true;
35779 this.startValue = this.getValue();
35780 this.fireEvent("focus", this);
35784 beforeBlur : Roo.emptyFn,
35787 onBlur : function(){
35789 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35790 this.el.removeClass(this.focusClass);
35792 this.hasFocus = false;
35793 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35796 var v = this.getValue();
35797 if(String(v) !== String(this.startValue)){
35798 this.fireEvent('change', this, v, this.startValue);
35800 this.fireEvent("blur", this);
35804 * Returns whether or not the field value is currently valid
35805 * @param {Boolean} preventMark True to disable marking the field invalid
35806 * @return {Boolean} True if the value is valid, else false
35808 isValid : function(preventMark){
35812 var restore = this.preventMark;
35813 this.preventMark = preventMark === true;
35814 var v = this.validateValue(this.processValue(this.getRawValue()));
35815 this.preventMark = restore;
35820 * Validates the field value
35821 * @return {Boolean} True if the value is valid, else false
35823 validate : function(){
35824 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35825 this.clearInvalid();
35831 processValue : function(value){
35836 // Subclasses should provide the validation implementation by overriding this
35837 validateValue : function(value){
35842 * Mark this field as invalid
35843 * @param {String} msg The validation message
35845 markInvalid : function(msg){
35846 if(!this.rendered || this.preventMark){ // not rendered
35849 this.el.addClass(this.invalidClass);
35850 msg = msg || this.invalidText;
35851 switch(this.msgTarget){
35853 this.el.dom.qtip = msg;
35854 this.el.dom.qclass = 'x-form-invalid-tip';
35855 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35856 Roo.QuickTips.enable();
35860 this.el.dom.title = msg;
35864 var elp = this.el.findParent('.x-form-element', 5, true);
35865 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35866 this.errorEl.setWidth(elp.getWidth(true)-20);
35868 this.errorEl.update(msg);
35869 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35872 if(!this.errorIcon){
35873 var elp = this.el.findParent('.x-form-element', 5, true);
35874 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35876 this.alignErrorIcon();
35877 this.errorIcon.dom.qtip = msg;
35878 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35879 this.errorIcon.show();
35880 this.on('resize', this.alignErrorIcon, this);
35883 var t = Roo.getDom(this.msgTarget);
35885 t.style.display = this.msgDisplay;
35888 this.fireEvent('invalid', this, msg);
35892 alignErrorIcon : function(){
35893 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35897 * Clear any invalid styles/messages for this field
35899 clearInvalid : function(){
35900 if(!this.rendered || this.preventMark){ // not rendered
35903 this.el.removeClass(this.invalidClass);
35904 switch(this.msgTarget){
35906 this.el.dom.qtip = '';
35909 this.el.dom.title = '';
35913 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35917 if(this.errorIcon){
35918 this.errorIcon.dom.qtip = '';
35919 this.errorIcon.hide();
35920 this.un('resize', this.alignErrorIcon, this);
35924 var t = Roo.getDom(this.msgTarget);
35926 t.style.display = 'none';
35929 this.fireEvent('valid', this);
35933 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35934 * @return {Mixed} value The field value
35936 getRawValue : function(){
35937 var v = this.el.getValue();
35938 if(v === this.emptyText){
35945 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35946 * @return {Mixed} value The field value
35948 getValue : function(){
35949 var v = this.el.getValue();
35950 if(v === this.emptyText || v === undefined){
35957 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35958 * @param {Mixed} value The value to set
35960 setRawValue : function(v){
35961 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35965 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35966 * @param {Mixed} value The value to set
35968 setValue : function(v){
35971 this.el.dom.value = (v === null || v === undefined ? '' : v);
35976 adjustSize : function(w, h){
35977 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35978 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35982 adjustWidth : function(tag, w){
35983 tag = tag.toLowerCase();
35984 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35985 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35986 if(tag == 'input'){
35989 if(tag = 'textarea'){
35992 }else if(Roo.isOpera){
35993 if(tag == 'input'){
35996 if(tag = 'textarea'){
36006 // anything other than normal should be considered experimental
36007 Roo.form.Field.msgFx = {
36009 show: function(msgEl, f){
36010 msgEl.setDisplayed('block');
36013 hide : function(msgEl, f){
36014 msgEl.setDisplayed(false).update('');
36019 show: function(msgEl, f){
36020 msgEl.slideIn('t', {stopFx:true});
36023 hide : function(msgEl, f){
36024 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
36029 show: function(msgEl, f){
36030 msgEl.fixDisplay();
36031 msgEl.alignTo(f.el, 'tl-tr');
36032 msgEl.slideIn('l', {stopFx:true});
36035 hide : function(msgEl, f){
36036 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
36041 * Ext JS Library 1.1.1
36042 * Copyright(c) 2006-2007, Ext JS, LLC.
36044 * Originally Released Under LGPL - original licence link has changed is not relivant.
36047 * <script type="text/javascript">
36052 * @class Roo.form.TextField
36053 * @extends Roo.form.Field
36054 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
36055 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
36057 * Creates a new TextField
36058 * @param {Object} config Configuration options
36060 Roo.form.TextField = function(config){
36061 Roo.form.TextField.superclass.constructor.call(this, config);
36065 * Fires when the autosize function is triggered. The field may or may not have actually changed size
36066 * according to the default logic, but this event provides a hook for the developer to apply additional
36067 * logic at runtime to resize the field if needed.
36068 * @param {Roo.form.Field} this This text field
36069 * @param {Number} width The new field width
36075 Roo.extend(Roo.form.TextField, Roo.form.Field, {
36077 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
36081 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
36085 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
36089 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
36093 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
36097 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
36099 disableKeyFilter : false,
36101 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
36105 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
36109 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
36111 maxLength : Number.MAX_VALUE,
36113 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
36115 minLengthText : "The minimum length for this field is {0}",
36117 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
36119 maxLengthText : "The maximum length for this field is {0}",
36121 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
36123 selectOnFocus : false,
36125 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
36127 blankText : "This field is required",
36129 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
36130 * If available, this function will be called only after the basic validators all return true, and will be passed the
36131 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
36135 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
36136 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
36137 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
36141 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
36145 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
36149 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
36150 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
36152 emptyClass : 'x-form-empty-field',
36155 initEvents : function(){
36156 Roo.form.TextField.superclass.initEvents.call(this);
36157 if(this.validationEvent == 'keyup'){
36158 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
36159 this.el.on('keyup', this.filterValidation, this);
36161 else if(this.validationEvent !== false){
36162 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
36164 if(this.selectOnFocus || this.emptyText){
36165 this.on("focus", this.preFocus, this);
36166 if(this.emptyText){
36167 this.on('blur', this.postBlur, this);
36168 this.applyEmptyText();
36171 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
36172 this.el.on("keypress", this.filterKeys, this);
36175 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
36176 this.el.on("click", this.autoSize, this);
36180 processValue : function(value){
36181 if(this.stripCharsRe){
36182 var newValue = value.replace(this.stripCharsRe, '');
36183 if(newValue !== value){
36184 this.setRawValue(newValue);
36191 filterValidation : function(e){
36192 if(!e.isNavKeyPress()){
36193 this.validationTask.delay(this.validationDelay);
36198 onKeyUp : function(e){
36199 if(!e.isNavKeyPress()){
36205 * Resets the current field value to the originally-loaded value and clears any validation messages.
36206 * Also adds emptyText and emptyClass if the original value was blank.
36208 reset : function(){
36209 Roo.form.TextField.superclass.reset.call(this);
36210 this.applyEmptyText();
36213 applyEmptyText : function(){
36214 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
36215 this.setRawValue(this.emptyText);
36216 this.el.addClass(this.emptyClass);
36221 preFocus : function(){
36222 if(this.emptyText){
36223 if(this.el.dom.value == this.emptyText){
36224 this.setRawValue('');
36226 this.el.removeClass(this.emptyClass);
36228 if(this.selectOnFocus){
36229 this.el.dom.select();
36234 postBlur : function(){
36235 this.applyEmptyText();
36239 filterKeys : function(e){
36240 var k = e.getKey();
36241 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36244 var c = e.getCharCode(), cc = String.fromCharCode(c);
36245 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36248 if(!this.maskRe.test(cc)){
36253 setValue : function(v){
36254 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
36255 this.el.removeClass(this.emptyClass);
36257 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36258 this.applyEmptyText();
36263 * Validates a value according to the field's validation rules and marks the field as invalid
36264 * if the validation fails
36265 * @param {Mixed} value The value to validate
36266 * @return {Boolean} True if the value is valid, else false
36268 validateValue : function(value){
36269 if(value.length < 1 || value === this.emptyText){ // if it's blank
36270 if(this.allowBlank){
36271 this.clearInvalid();
36274 this.markInvalid(this.blankText);
36278 if(value.length < this.minLength){
36279 this.markInvalid(String.format(this.minLengthText, this.minLength));
36282 if(value.length > this.maxLength){
36283 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36287 var vt = Roo.form.VTypes;
36288 if(!vt[this.vtype](value, this)){
36289 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36293 if(typeof this.validator == "function"){
36294 var msg = this.validator(value);
36296 this.markInvalid(msg);
36300 if(this.regex && !this.regex.test(value)){
36301 this.markInvalid(this.regexText);
36308 * Selects text in this field
36309 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36310 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36312 selectText : function(start, end){
36313 var v = this.getRawValue();
36315 start = start === undefined ? 0 : start;
36316 end = end === undefined ? v.length : end;
36317 var d = this.el.dom;
36318 if(d.setSelectionRange){
36319 d.setSelectionRange(start, end);
36320 }else if(d.createTextRange){
36321 var range = d.createTextRange();
36322 range.moveStart("character", start);
36323 range.moveEnd("character", v.length-end);
36330 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36331 * This only takes effect if grow = true, and fires the autosize event.
36333 autoSize : function(){
36334 if(!this.grow || !this.rendered){
36338 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36341 var v = el.dom.value;
36342 var d = document.createElement('div');
36343 d.appendChild(document.createTextNode(v));
36347 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36348 this.el.setWidth(w);
36349 this.fireEvent("autosize", this, w);
36353 * Ext JS Library 1.1.1
36354 * Copyright(c) 2006-2007, Ext JS, LLC.
36356 * Originally Released Under LGPL - original licence link has changed is not relivant.
36359 * <script type="text/javascript">
36363 * @class Roo.form.Hidden
36364 * @extends Roo.form.TextField
36365 * Simple Hidden element used on forms
36367 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36370 * Creates a new Hidden form element.
36371 * @param {Object} config Configuration options
36376 // easy hidden field...
36377 Roo.form.Hidden = function(config){
36378 Roo.form.Hidden.superclass.constructor.call(this, config);
36381 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36383 inputType: 'hidden',
36386 labelSeparator: '',
36388 itemCls : 'x-form-item-display-none'
36396 * Ext JS Library 1.1.1
36397 * Copyright(c) 2006-2007, Ext JS, LLC.
36399 * Originally Released Under LGPL - original licence link has changed is not relivant.
36402 * <script type="text/javascript">
36406 * @class Roo.form.TriggerField
36407 * @extends Roo.form.TextField
36408 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36409 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36410 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36411 * for which you can provide a custom implementation. For example:
36413 var trigger = new Roo.form.TriggerField();
36414 trigger.onTriggerClick = myTriggerFn;
36415 trigger.applyTo('my-field');
36418 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36419 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36420 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36421 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36423 * Create a new TriggerField.
36424 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36425 * to the base TextField)
36427 Roo.form.TriggerField = function(config){
36428 this.mimicing = false;
36429 Roo.form.TriggerField.superclass.constructor.call(this, config);
36432 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36434 * @cfg {String} triggerClass A CSS class to apply to the trigger
36437 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36438 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36440 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36442 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36446 /** @cfg {Boolean} grow @hide */
36447 /** @cfg {Number} growMin @hide */
36448 /** @cfg {Number} growMax @hide */
36454 autoSize: Roo.emptyFn,
36458 deferHeight : true,
36461 actionMode : 'wrap',
36463 onResize : function(w, h){
36464 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36465 if(typeof w == 'number'){
36466 var x = w - this.trigger.getWidth();
36467 this.el.setWidth(this.adjustWidth('input', x));
36468 this.trigger.setStyle('left', x+'px');
36473 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36476 getResizeEl : function(){
36481 getPositionEl : function(){
36486 alignErrorIcon : function(){
36487 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36491 onRender : function(ct, position){
36492 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36493 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36494 this.trigger = this.wrap.createChild(this.triggerConfig ||
36495 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36496 if(this.hideTrigger){
36497 this.trigger.setDisplayed(false);
36499 this.initTrigger();
36501 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36506 initTrigger : function(){
36507 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36508 this.trigger.addClassOnOver('x-form-trigger-over');
36509 this.trigger.addClassOnClick('x-form-trigger-click');
36513 onDestroy : function(){
36515 this.trigger.removeAllListeners();
36516 this.trigger.remove();
36519 this.wrap.remove();
36521 Roo.form.TriggerField.superclass.onDestroy.call(this);
36525 onFocus : function(){
36526 Roo.form.TriggerField.superclass.onFocus.call(this);
36527 if(!this.mimicing){
36528 this.wrap.addClass('x-trigger-wrap-focus');
36529 this.mimicing = true;
36530 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36531 if(this.monitorTab){
36532 this.el.on("keydown", this.checkTab, this);
36538 checkTab : function(e){
36539 if(e.getKey() == e.TAB){
36540 this.triggerBlur();
36545 onBlur : function(){
36550 mimicBlur : function(e, t){
36551 if(!this.wrap.contains(t) && this.validateBlur()){
36552 this.triggerBlur();
36557 triggerBlur : function(){
36558 this.mimicing = false;
36559 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36560 if(this.monitorTab){
36561 this.el.un("keydown", this.checkTab, this);
36563 this.wrap.removeClass('x-trigger-wrap-focus');
36564 Roo.form.TriggerField.superclass.onBlur.call(this);
36568 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36569 validateBlur : function(e, t){
36574 onDisable : function(){
36575 Roo.form.TriggerField.superclass.onDisable.call(this);
36577 this.wrap.addClass('x-item-disabled');
36582 onEnable : function(){
36583 Roo.form.TriggerField.superclass.onEnable.call(this);
36585 this.wrap.removeClass('x-item-disabled');
36590 onShow : function(){
36591 var ae = this.getActionEl();
36594 ae.dom.style.display = '';
36595 ae.dom.style.visibility = 'visible';
36601 onHide : function(){
36602 var ae = this.getActionEl();
36603 ae.dom.style.display = 'none';
36607 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36608 * by an implementing function.
36610 * @param {EventObject} e
36612 onTriggerClick : Roo.emptyFn
36615 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36616 // to be extended by an implementing class. For an example of implementing this class, see the custom
36617 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36618 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36619 initComponent : function(){
36620 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36622 this.triggerConfig = {
36623 tag:'span', cls:'x-form-twin-triggers', cn:[
36624 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36625 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36629 getTrigger : function(index){
36630 return this.triggers[index];
36633 initTrigger : function(){
36634 var ts = this.trigger.select('.x-form-trigger', true);
36635 this.wrap.setStyle('overflow', 'hidden');
36636 var triggerField = this;
36637 ts.each(function(t, all, index){
36638 t.hide = function(){
36639 var w = triggerField.wrap.getWidth();
36640 this.dom.style.display = 'none';
36641 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36643 t.show = function(){
36644 var w = triggerField.wrap.getWidth();
36645 this.dom.style.display = '';
36646 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36648 var triggerIndex = 'Trigger'+(index+1);
36650 if(this['hide'+triggerIndex]){
36651 t.dom.style.display = 'none';
36653 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36654 t.addClassOnOver('x-form-trigger-over');
36655 t.addClassOnClick('x-form-trigger-click');
36657 this.triggers = ts.elements;
36660 onTrigger1Click : Roo.emptyFn,
36661 onTrigger2Click : Roo.emptyFn
36664 * Ext JS Library 1.1.1
36665 * Copyright(c) 2006-2007, Ext JS, LLC.
36667 * Originally Released Under LGPL - original licence link has changed is not relivant.
36670 * <script type="text/javascript">
36674 * @class Roo.form.TextArea
36675 * @extends Roo.form.TextField
36676 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36677 * support for auto-sizing.
36679 * Creates a new TextArea
36680 * @param {Object} config Configuration options
36682 Roo.form.TextArea = function(config){
36683 Roo.form.TextArea.superclass.constructor.call(this, config);
36684 // these are provided exchanges for backwards compat
36685 // minHeight/maxHeight were replaced by growMin/growMax to be
36686 // compatible with TextField growing config values
36687 if(this.minHeight !== undefined){
36688 this.growMin = this.minHeight;
36690 if(this.maxHeight !== undefined){
36691 this.growMax = this.maxHeight;
36695 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36697 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36701 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36705 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36706 * in the field (equivalent to setting overflow: hidden, defaults to false)
36708 preventScrollbars: false,
36710 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36711 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36715 onRender : function(ct, position){
36717 this.defaultAutoCreate = {
36719 style:"width:300px;height:60px;",
36720 autocomplete: "off"
36723 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36725 this.textSizeEl = Roo.DomHelper.append(document.body, {
36726 tag: "pre", cls: "x-form-grow-sizer"
36728 if(this.preventScrollbars){
36729 this.el.setStyle("overflow", "hidden");
36731 this.el.setHeight(this.growMin);
36735 onDestroy : function(){
36736 if(this.textSizeEl){
36737 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36739 Roo.form.TextArea.superclass.onDestroy.call(this);
36743 onKeyUp : function(e){
36744 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36750 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36751 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36753 autoSize : function(){
36754 if(!this.grow || !this.textSizeEl){
36758 var v = el.dom.value;
36759 var ts = this.textSizeEl;
36762 ts.appendChild(document.createTextNode(v));
36765 Roo.fly(ts).setWidth(this.el.getWidth());
36767 v = "  ";
36770 v = v.replace(/\n/g, '<p> </p>');
36772 v += " \n ";
36775 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36776 if(h != this.lastHeight){
36777 this.lastHeight = h;
36778 this.el.setHeight(h);
36779 this.fireEvent("autosize", this, h);
36784 * Ext JS Library 1.1.1
36785 * Copyright(c) 2006-2007, Ext JS, LLC.
36787 * Originally Released Under LGPL - original licence link has changed is not relivant.
36790 * <script type="text/javascript">
36795 * @class Roo.form.NumberField
36796 * @extends Roo.form.TextField
36797 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36799 * Creates a new NumberField
36800 * @param {Object} config Configuration options
36802 Roo.form.NumberField = function(config){
36803 Roo.form.NumberField.superclass.constructor.call(this, config);
36806 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36808 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36810 fieldClass: "x-form-field x-form-num-field",
36812 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36814 allowDecimals : true,
36816 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36818 decimalSeparator : ".",
36820 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36822 decimalPrecision : 2,
36824 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36826 allowNegative : true,
36828 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36830 minValue : Number.NEGATIVE_INFINITY,
36832 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36834 maxValue : Number.MAX_VALUE,
36836 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36838 minText : "The minimum value for this field is {0}",
36840 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36842 maxText : "The maximum value for this field is {0}",
36844 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36845 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36847 nanText : "{0} is not a valid number",
36850 initEvents : function(){
36851 Roo.form.NumberField.superclass.initEvents.call(this);
36852 var allowed = "0123456789";
36853 if(this.allowDecimals){
36854 allowed += this.decimalSeparator;
36856 if(this.allowNegative){
36859 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36860 var keyPress = function(e){
36861 var k = e.getKey();
36862 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36865 var c = e.getCharCode();
36866 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36870 this.el.on("keypress", keyPress, this);
36874 validateValue : function(value){
36875 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36878 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36881 var num = this.parseValue(value);
36883 this.markInvalid(String.format(this.nanText, value));
36886 if(num < this.minValue){
36887 this.markInvalid(String.format(this.minText, this.minValue));
36890 if(num > this.maxValue){
36891 this.markInvalid(String.format(this.maxText, this.maxValue));
36897 getValue : function(){
36898 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36902 parseValue : function(value){
36903 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36904 return isNaN(value) ? '' : value;
36908 fixPrecision : function(value){
36909 var nan = isNaN(value);
36910 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36911 return nan ? '' : value;
36913 return parseFloat(value).toFixed(this.decimalPrecision);
36916 setValue : function(v){
36917 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36921 decimalPrecisionFcn : function(v){
36922 return Math.floor(v);
36925 beforeBlur : function(){
36926 var v = this.parseValue(this.getRawValue());
36928 this.setValue(this.fixPrecision(v));
36933 * Ext JS Library 1.1.1
36934 * Copyright(c) 2006-2007, Ext JS, LLC.
36936 * Originally Released Under LGPL - original licence link has changed is not relivant.
36939 * <script type="text/javascript">
36943 * @class Roo.form.DateField
36944 * @extends Roo.form.TriggerField
36945 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36947 * Create a new DateField
36948 * @param {Object} config
36950 Roo.form.DateField = function(config){
36951 Roo.form.DateField.superclass.constructor.call(this, config);
36957 * Fires when a date is selected
36958 * @param {Roo.form.DateField} combo This combo box
36959 * @param {Date} date The date selected
36966 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36967 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36968 this.ddMatch = null;
36969 if(this.disabledDates){
36970 var dd = this.disabledDates;
36972 for(var i = 0; i < dd.length; i++){
36974 if(i != dd.length-1) re += "|";
36976 this.ddMatch = new RegExp(re + ")");
36980 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36982 * @cfg {String} format
36983 * The default date format string which can be overriden for localization support. The format must be
36984 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36988 * @cfg {String} altFormats
36989 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36990 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36992 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36994 * @cfg {Array} disabledDays
36995 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36997 disabledDays : null,
36999 * @cfg {String} disabledDaysText
37000 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
37002 disabledDaysText : "Disabled",
37004 * @cfg {Array} disabledDates
37005 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
37006 * expression so they are very powerful. Some examples:
37008 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
37009 * <li>["03/08", "09/16"] would disable those days for every year</li>
37010 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
37011 * <li>["03/../2006"] would disable every day in March 2006</li>
37012 * <li>["^03"] would disable every day in every March</li>
37014 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
37015 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
37017 disabledDates : null,
37019 * @cfg {String} disabledDatesText
37020 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
37022 disabledDatesText : "Disabled",
37024 * @cfg {Date/String} minValue
37025 * The minimum allowed date. Can be either a Javascript date object or a string date in a
37026 * valid format (defaults to null).
37030 * @cfg {Date/String} maxValue
37031 * The maximum allowed date. Can be either a Javascript date object or a string date in a
37032 * valid format (defaults to null).
37036 * @cfg {String} minText
37037 * The error text to display when the date in the cell is before minValue (defaults to
37038 * 'The date in this field must be after {minValue}').
37040 minText : "The date in this field must be equal to or after {0}",
37042 * @cfg {String} maxText
37043 * The error text to display when the date in the cell is after maxValue (defaults to
37044 * 'The date in this field must be before {maxValue}').
37046 maxText : "The date in this field must be equal to or before {0}",
37048 * @cfg {String} invalidText
37049 * The error text to display when the date in the field is invalid (defaults to
37050 * '{value} is not a valid date - it must be in the format {format}').
37052 invalidText : "{0} is not a valid date - it must be in the format {1}",
37054 * @cfg {String} triggerClass
37055 * An additional CSS class used to style the trigger button. The trigger will always get the
37056 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
37057 * which displays a calendar icon).
37059 triggerClass : 'x-form-date-trigger',
37063 * @cfg {bool} useIso
37064 * if enabled, then the date field will use a hidden field to store the
37065 * real value as iso formated date. default (false)
37069 * @cfg {String/Object} autoCreate
37070 * A DomHelper element spec, or true for a default element spec (defaults to
37071 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
37074 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
37077 hiddenField: false,
37079 onRender : function(ct, position)
37081 Roo.form.DateField.superclass.onRender.call(this, ct, position);
37083 this.el.dom.removeAttribute('name');
37084 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
37086 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
37087 // prevent input submission
37088 this.hiddenName = this.name;
37095 validateValue : function(value)
37097 value = this.formatDate(value);
37098 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
37101 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37104 var svalue = value;
37105 value = this.parseDate(value);
37107 this.markInvalid(String.format(this.invalidText, svalue, this.format));
37110 var time = value.getTime();
37111 if(this.minValue && time < this.minValue.getTime()){
37112 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
37115 if(this.maxValue && time > this.maxValue.getTime()){
37116 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
37119 if(this.disabledDays){
37120 var day = value.getDay();
37121 for(var i = 0; i < this.disabledDays.length; i++) {
37122 if(day === this.disabledDays[i]){
37123 this.markInvalid(this.disabledDaysText);
37128 var fvalue = this.formatDate(value);
37129 if(this.ddMatch && this.ddMatch.test(fvalue)){
37130 this.markInvalid(String.format(this.disabledDatesText, fvalue));
37137 // Provides logic to override the default TriggerField.validateBlur which just returns true
37138 validateBlur : function(){
37139 return !this.menu || !this.menu.isVisible();
37143 * Returns the current date value of the date field.
37144 * @return {Date} The date value
37146 getValue : function(){
37148 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
37152 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
37153 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
37154 * (the default format used is "m/d/y").
37157 //All of these calls set the same date value (May 4, 2006)
37159 //Pass a date object:
37160 var dt = new Date('5/4/06');
37161 dateField.setValue(dt);
37163 //Pass a date string (default format):
37164 dateField.setValue('5/4/06');
37166 //Pass a date string (custom format):
37167 dateField.format = 'Y-m-d';
37168 dateField.setValue('2006-5-4');
37170 * @param {String/Date} date The date or valid date string
37172 setValue : function(date){
37173 if (this.hiddenField) {
37174 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
37176 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
37180 parseDate : function(value){
37181 if(!value || value instanceof Date){
37184 var v = Date.parseDate(value, this.format);
37185 if(!v && this.altFormats){
37186 if(!this.altFormatsArray){
37187 this.altFormatsArray = this.altFormats.split("|");
37189 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
37190 v = Date.parseDate(value, this.altFormatsArray[i]);
37197 formatDate : function(date, fmt){
37198 return (!date || !(date instanceof Date)) ?
37199 date : date.dateFormat(fmt || this.format);
37204 select: function(m, d){
37206 this.fireEvent('select', this, d);
37208 show : function(){ // retain focus styling
37212 this.focus.defer(10, this);
37213 var ml = this.menuListeners;
37214 this.menu.un("select", ml.select, this);
37215 this.menu.un("show", ml.show, this);
37216 this.menu.un("hide", ml.hide, this);
37221 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37222 onTriggerClick : function(){
37226 if(this.menu == null){
37227 this.menu = new Roo.menu.DateMenu();
37229 Roo.apply(this.menu.picker, {
37230 showClear: this.allowBlank,
37231 minDate : this.minValue,
37232 maxDate : this.maxValue,
37233 disabledDatesRE : this.ddMatch,
37234 disabledDatesText : this.disabledDatesText,
37235 disabledDays : this.disabledDays,
37236 disabledDaysText : this.disabledDaysText,
37237 format : this.format,
37238 minText : String.format(this.minText, this.formatDate(this.minValue)),
37239 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37241 this.menu.on(Roo.apply({}, this.menuListeners, {
37244 this.menu.picker.setValue(this.getValue() || new Date());
37245 this.menu.show(this.el, "tl-bl?");
37248 beforeBlur : function(){
37249 var v = this.parseDate(this.getRawValue());
37255 /** @cfg {Boolean} grow @hide */
37256 /** @cfg {Number} growMin @hide */
37257 /** @cfg {Number} growMax @hide */
37264 * Ext JS Library 1.1.1
37265 * Copyright(c) 2006-2007, Ext JS, LLC.
37267 * Originally Released Under LGPL - original licence link has changed is not relivant.
37270 * <script type="text/javascript">
37275 * @class Roo.form.ComboBox
37276 * @extends Roo.form.TriggerField
37277 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
37279 * Create a new ComboBox.
37280 * @param {Object} config Configuration options
37282 Roo.form.ComboBox = function(config){
37283 Roo.form.ComboBox.superclass.constructor.call(this, config);
37287 * Fires when the dropdown list is expanded
37288 * @param {Roo.form.ComboBox} combo This combo box
37293 * Fires when the dropdown list is collapsed
37294 * @param {Roo.form.ComboBox} combo This combo box
37298 * @event beforeselect
37299 * Fires before a list item is selected. Return false to cancel the selection.
37300 * @param {Roo.form.ComboBox} combo This combo box
37301 * @param {Roo.data.Record} record The data record returned from the underlying store
37302 * @param {Number} index The index of the selected item in the dropdown list
37304 'beforeselect' : true,
37307 * Fires when a list item is selected
37308 * @param {Roo.form.ComboBox} combo This combo box
37309 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37310 * @param {Number} index The index of the selected item in the dropdown list
37314 * @event beforequery
37315 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37316 * The event object passed has these properties:
37317 * @param {Roo.form.ComboBox} combo This combo box
37318 * @param {String} query The query
37319 * @param {Boolean} forceAll true to force "all" query
37320 * @param {Boolean} cancel true to cancel the query
37321 * @param {Object} e The query event object
37323 'beforequery': true,
37326 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37327 * @param {Roo.form.ComboBox} combo This combo box
37332 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37333 * @param {Roo.form.ComboBox} combo This combo box
37334 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37340 if(this.transform){
37341 this.allowDomMove = false;
37342 var s = Roo.getDom(this.transform);
37343 if(!this.hiddenName){
37344 this.hiddenName = s.name;
37347 this.mode = 'local';
37348 var d = [], opts = s.options;
37349 for(var i = 0, len = opts.length;i < len; i++){
37351 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37353 this.value = value;
37355 d.push([value, o.text]);
37357 this.store = new Roo.data.SimpleStore({
37359 fields: ['value', 'text'],
37362 this.valueField = 'value';
37363 this.displayField = 'text';
37365 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37366 if(!this.lazyRender){
37367 this.target = true;
37368 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37369 s.parentNode.removeChild(s); // remove it
37370 this.render(this.el.parentNode);
37372 s.parentNode.removeChild(s); // remove it
37377 this.store = Roo.factory(this.store, Roo.data);
37380 this.selectedIndex = -1;
37381 if(this.mode == 'local'){
37382 if(config.queryDelay === undefined){
37383 this.queryDelay = 10;
37385 if(config.minChars === undefined){
37391 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37393 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37396 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37397 * rendering into an Roo.Editor, defaults to false)
37400 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37401 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37404 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37407 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37408 * the dropdown list (defaults to undefined, with no header element)
37412 * @cfg {String/Roo.Template} tpl The template to use to render the output
37416 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37418 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37420 listWidth: undefined,
37422 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37423 * mode = 'remote' or 'text' if mode = 'local')
37425 displayField: undefined,
37427 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37428 * mode = 'remote' or 'value' if mode = 'local').
37429 * Note: use of a valueField requires the user make a selection
37430 * in order for a value to be mapped.
37432 valueField: undefined,
37436 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37437 * field's data value (defaults to the underlying DOM element's name)
37439 hiddenName: undefined,
37441 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37445 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37447 selectedClass: 'x-combo-selected',
37449 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37450 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37451 * which displays a downward arrow icon).
37453 triggerClass : 'x-form-arrow-trigger',
37455 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37459 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37460 * anchor positions (defaults to 'tl-bl')
37462 listAlign: 'tl-bl?',
37464 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37468 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37469 * query specified by the allQuery config option (defaults to 'query')
37471 triggerAction: 'query',
37473 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37474 * (defaults to 4, does not apply if editable = false)
37478 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37479 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37483 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37484 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37488 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37489 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37493 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37494 * when editable = true (defaults to false)
37496 selectOnFocus:false,
37498 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37500 queryParam: 'query',
37502 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37503 * when mode = 'remote' (defaults to 'Loading...')
37505 loadingText: 'Loading...',
37507 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37511 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37515 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37516 * traditional select (defaults to true)
37520 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37524 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37528 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37529 * listWidth has a higher value)
37533 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37534 * allow the user to set arbitrary text into the field (defaults to false)
37536 forceSelection:false,
37538 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37539 * if typeAhead = true (defaults to 250)
37541 typeAheadDelay : 250,
37543 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37544 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37546 valueNotFoundText : undefined,
37548 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37550 blockFocus : false,
37553 * @cfg {Boolean} disableClear Disable showing of clear button.
37555 disableClear : false,
37557 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37559 alwaysQuery : false,
37565 // element that contains real text value.. (when hidden is used..)
37568 onRender : function(ct, position){
37569 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37570 if(this.hiddenName){
37571 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37573 this.hiddenField.value =
37574 this.hiddenValue !== undefined ? this.hiddenValue :
37575 this.value !== undefined ? this.value : '';
37577 // prevent input submission
37578 this.el.dom.removeAttribute('name');
37583 this.el.dom.setAttribute('autocomplete', 'off');
37586 var cls = 'x-combo-list';
37588 this.list = new Roo.Layer({
37589 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37592 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37593 this.list.setWidth(lw);
37594 this.list.swallowEvent('mousewheel');
37595 this.assetHeight = 0;
37598 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37599 this.assetHeight += this.header.getHeight();
37602 this.innerList = this.list.createChild({cls:cls+'-inner'});
37603 this.innerList.on('mouseover', this.onViewOver, this);
37604 this.innerList.on('mousemove', this.onViewMove, this);
37605 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37607 if(this.allowBlank && !this.pageSize && !this.disableClear){
37608 this.footer = this.list.createChild({cls:cls+'-ft'});
37609 this.pageTb = new Roo.Toolbar(this.footer);
37613 this.footer = this.list.createChild({cls:cls+'-ft'});
37614 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37615 {pageSize: this.pageSize});
37619 if (this.pageTb && this.allowBlank && !this.disableClear) {
37621 this.pageTb.add(new Roo.Toolbar.Fill(), {
37622 cls: 'x-btn-icon x-btn-clear',
37624 handler: function()
37627 _this.clearValue();
37628 _this.onSelect(false, -1);
37633 this.assetHeight += this.footer.getHeight();
37638 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37641 this.view = new Roo.View(this.innerList, this.tpl, {
37642 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37645 this.view.on('click', this.onViewClick, this);
37647 this.store.on('beforeload', this.onBeforeLoad, this);
37648 this.store.on('load', this.onLoad, this);
37649 this.store.on('loadexception', this.onLoadException, this);
37651 if(this.resizable){
37652 this.resizer = new Roo.Resizable(this.list, {
37653 pinned:true, handles:'se'
37655 this.resizer.on('resize', function(r, w, h){
37656 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37657 this.listWidth = w;
37658 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37659 this.restrictHeight();
37661 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37663 if(!this.editable){
37664 this.editable = true;
37665 this.setEditable(false);
37669 if (typeof(this.events.add.listeners) != 'undefined') {
37671 this.addicon = this.wrap.createChild(
37672 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37674 this.addicon.on('click', function(e) {
37675 this.fireEvent('add', this);
37678 if (typeof(this.events.edit.listeners) != 'undefined') {
37680 this.editicon = this.wrap.createChild(
37681 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37682 if (this.addicon) {
37683 this.editicon.setStyle('margin-left', '40px');
37685 this.editicon.on('click', function(e) {
37687 // we fire even if inothing is selected..
37688 this.fireEvent('edit', this, this.lastData );
37698 initEvents : function(){
37699 Roo.form.ComboBox.superclass.initEvents.call(this);
37701 this.keyNav = new Roo.KeyNav(this.el, {
37702 "up" : function(e){
37703 this.inKeyMode = true;
37707 "down" : function(e){
37708 if(!this.isExpanded()){
37709 this.onTriggerClick();
37711 this.inKeyMode = true;
37716 "enter" : function(e){
37717 this.onViewClick();
37721 "esc" : function(e){
37725 "tab" : function(e){
37726 this.onViewClick(false);
37727 this.fireEvent("specialkey", this, e);
37733 doRelay : function(foo, bar, hname){
37734 if(hname == 'down' || this.scope.isExpanded()){
37735 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37742 this.queryDelay = Math.max(this.queryDelay || 10,
37743 this.mode == 'local' ? 10 : 250);
37744 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37745 if(this.typeAhead){
37746 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37748 if(this.editable !== false){
37749 this.el.on("keyup", this.onKeyUp, this);
37751 if(this.forceSelection){
37752 this.on('blur', this.doForce, this);
37756 onDestroy : function(){
37758 this.view.setStore(null);
37759 this.view.el.removeAllListeners();
37760 this.view.el.remove();
37761 this.view.purgeListeners();
37764 this.list.destroy();
37767 this.store.un('beforeload', this.onBeforeLoad, this);
37768 this.store.un('load', this.onLoad, this);
37769 this.store.un('loadexception', this.onLoadException, this);
37771 Roo.form.ComboBox.superclass.onDestroy.call(this);
37775 fireKey : function(e){
37776 if(e.isNavKeyPress() && !this.list.isVisible()){
37777 this.fireEvent("specialkey", this, e);
37782 onResize: function(w, h){
37783 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37785 if(typeof w != 'number'){
37786 // we do not handle it!?!?
37789 var tw = this.trigger.getWidth();
37790 tw += this.addicon ? this.addicon.getWidth() : 0;
37791 tw += this.editicon ? this.editicon.getWidth() : 0;
37793 this.el.setWidth( this.adjustWidth('input', x));
37795 this.trigger.setStyle('left', x+'px');
37797 if(this.list && this.listWidth === undefined){
37798 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37799 this.list.setWidth(lw);
37800 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37808 * Allow or prevent the user from directly editing the field text. If false is passed,
37809 * the user will only be able to select from the items defined in the dropdown list. This method
37810 * is the runtime equivalent of setting the 'editable' config option at config time.
37811 * @param {Boolean} value True to allow the user to directly edit the field text
37813 setEditable : function(value){
37814 if(value == this.editable){
37817 this.editable = value;
37819 this.el.dom.setAttribute('readOnly', true);
37820 this.el.on('mousedown', this.onTriggerClick, this);
37821 this.el.addClass('x-combo-noedit');
37823 this.el.dom.setAttribute('readOnly', false);
37824 this.el.un('mousedown', this.onTriggerClick, this);
37825 this.el.removeClass('x-combo-noedit');
37830 onBeforeLoad : function(){
37831 if(!this.hasFocus){
37834 this.innerList.update(this.loadingText ?
37835 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37836 this.restrictHeight();
37837 this.selectedIndex = -1;
37841 onLoad : function(){
37842 if(!this.hasFocus){
37845 if(this.store.getCount() > 0){
37847 this.restrictHeight();
37848 if(this.lastQuery == this.allQuery){
37850 this.el.dom.select();
37852 if(!this.selectByValue(this.value, true)){
37853 this.select(0, true);
37857 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37858 this.taTask.delay(this.typeAheadDelay);
37862 this.onEmptyResults();
37867 onLoadException : function()
37870 Roo.log(this.store.reader.jsonData);
37871 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
37872 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
37878 onTypeAhead : function(){
37879 if(this.store.getCount() > 0){
37880 var r = this.store.getAt(0);
37881 var newValue = r.data[this.displayField];
37882 var len = newValue.length;
37883 var selStart = this.getRawValue().length;
37884 if(selStart != len){
37885 this.setRawValue(newValue);
37886 this.selectText(selStart, newValue.length);
37892 onSelect : function(record, index){
37893 if(this.fireEvent('beforeselect', this, record, index) !== false){
37894 this.setFromData(index > -1 ? record.data : false);
37896 this.fireEvent('select', this, record, index);
37901 * Returns the currently selected field value or empty string if no value is set.
37902 * @return {String} value The selected value
37904 getValue : function(){
37905 if(this.valueField){
37906 return typeof this.value != 'undefined' ? this.value : '';
37908 return Roo.form.ComboBox.superclass.getValue.call(this);
37913 * Clears any text/value currently set in the field
37915 clearValue : function(){
37916 if(this.hiddenField){
37917 this.hiddenField.value = '';
37920 this.setRawValue('');
37921 this.lastSelectionText = '';
37922 this.applyEmptyText();
37926 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37927 * will be displayed in the field. If the value does not match the data value of an existing item,
37928 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37929 * Otherwise the field will be blank (although the value will still be set).
37930 * @param {String} value The value to match
37932 setValue : function(v){
37934 if(this.valueField){
37935 var r = this.findRecord(this.valueField, v);
37937 text = r.data[this.displayField];
37938 }else if(this.valueNotFoundText !== undefined){
37939 text = this.valueNotFoundText;
37942 this.lastSelectionText = text;
37943 if(this.hiddenField){
37944 this.hiddenField.value = v;
37946 Roo.form.ComboBox.superclass.setValue.call(this, text);
37950 * @property {Object} the last set data for the element
37955 * Sets the value of the field based on a object which is related to the record format for the store.
37956 * @param {Object} value the value to set as. or false on reset?
37958 setFromData : function(o){
37959 var dv = ''; // display value
37960 var vv = ''; // value value..
37962 if (this.displayField) {
37963 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37965 // this is an error condition!!!
37966 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
37969 if(this.valueField){
37970 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37972 if(this.hiddenField){
37973 this.hiddenField.value = vv;
37975 this.lastSelectionText = dv;
37976 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37980 // no hidden field.. - we store the value in 'value', but still display
37981 // display field!!!!
37982 this.lastSelectionText = dv;
37983 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37989 reset : function(){
37990 // overridden so that last data is reset..
37991 this.setValue(this.originalValue);
37992 this.clearInvalid();
37993 this.lastData = false;
37996 findRecord : function(prop, value){
37998 if(this.store.getCount() > 0){
37999 this.store.each(function(r){
38000 if(r.data[prop] == value){
38010 getName: function()
38012 // returns hidden if it's set..
38013 if (!this.rendered) {return ''};
38014 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38018 onViewMove : function(e, t){
38019 this.inKeyMode = false;
38023 onViewOver : function(e, t){
38024 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
38027 var item = this.view.findItemFromChild(t);
38029 var index = this.view.indexOf(item);
38030 this.select(index, false);
38035 onViewClick : function(doFocus)
38037 var index = this.view.getSelectedIndexes()[0];
38038 var r = this.store.getAt(index);
38040 this.onSelect(r, index);
38042 if(doFocus !== false && !this.blockFocus){
38048 restrictHeight : function(){
38049 this.innerList.dom.style.height = '';
38050 var inner = this.innerList.dom;
38051 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
38052 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
38053 this.list.beginUpdate();
38054 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
38055 this.list.alignTo(this.el, this.listAlign);
38056 this.list.endUpdate();
38060 onEmptyResults : function(){
38065 * Returns true if the dropdown list is expanded, else false.
38067 isExpanded : function(){
38068 return this.list.isVisible();
38072 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
38073 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
38074 * @param {String} value The data value of the item to select
38075 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
38076 * selected item if it is not currently in view (defaults to true)
38077 * @return {Boolean} True if the value matched an item in the list, else false
38079 selectByValue : function(v, scrollIntoView){
38080 if(v !== undefined && v !== null){
38081 var r = this.findRecord(this.valueField || this.displayField, v);
38083 this.select(this.store.indexOf(r), scrollIntoView);
38091 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
38092 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
38093 * @param {Number} index The zero-based index of the list item to select
38094 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
38095 * selected item if it is not currently in view (defaults to true)
38097 select : function(index, scrollIntoView){
38098 this.selectedIndex = index;
38099 this.view.select(index);
38100 if(scrollIntoView !== false){
38101 var el = this.view.getNode(index);
38103 this.innerList.scrollChildIntoView(el, false);
38109 selectNext : function(){
38110 var ct = this.store.getCount();
38112 if(this.selectedIndex == -1){
38114 }else if(this.selectedIndex < ct-1){
38115 this.select(this.selectedIndex+1);
38121 selectPrev : function(){
38122 var ct = this.store.getCount();
38124 if(this.selectedIndex == -1){
38126 }else if(this.selectedIndex != 0){
38127 this.select(this.selectedIndex-1);
38133 onKeyUp : function(e){
38134 if(this.editable !== false && !e.isSpecialKey()){
38135 this.lastKey = e.getKey();
38136 this.dqTask.delay(this.queryDelay);
38141 validateBlur : function(){
38142 return !this.list || !this.list.isVisible();
38146 initQuery : function(){
38147 this.doQuery(this.getRawValue());
38151 doForce : function(){
38152 if(this.el.dom.value.length > 0){
38153 this.el.dom.value =
38154 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
38155 this.applyEmptyText();
38160 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
38161 * query allowing the query action to be canceled if needed.
38162 * @param {String} query The SQL query to execute
38163 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
38164 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
38165 * saved in the current store (defaults to false)
38167 doQuery : function(q, forceAll){
38168 if(q === undefined || q === null){
38173 forceAll: forceAll,
38177 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
38181 forceAll = qe.forceAll;
38182 if(forceAll === true || (q.length >= this.minChars)){
38183 if(this.lastQuery != q || this.alwaysQuery){
38184 this.lastQuery = q;
38185 if(this.mode == 'local'){
38186 this.selectedIndex = -1;
38188 this.store.clearFilter();
38190 this.store.filter(this.displayField, q);
38194 this.store.baseParams[this.queryParam] = q;
38196 params: this.getParams(q)
38201 this.selectedIndex = -1;
38208 getParams : function(q){
38210 //p[this.queryParam] = q;
38213 p.limit = this.pageSize;
38219 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
38221 collapse : function(){
38222 if(!this.isExpanded()){
38226 Roo.get(document).un('mousedown', this.collapseIf, this);
38227 Roo.get(document).un('mousewheel', this.collapseIf, this);
38228 if (!this.editable) {
38229 Roo.get(document).un('keydown', this.listKeyPress, this);
38231 this.fireEvent('collapse', this);
38235 collapseIf : function(e){
38236 if(!e.within(this.wrap) && !e.within(this.list)){
38242 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
38244 expand : function(){
38245 if(this.isExpanded() || !this.hasFocus){
38248 this.list.alignTo(this.el, this.listAlign);
38250 Roo.get(document).on('mousedown', this.collapseIf, this);
38251 Roo.get(document).on('mousewheel', this.collapseIf, this);
38252 if (!this.editable) {
38253 Roo.get(document).on('keydown', this.listKeyPress, this);
38256 this.fireEvent('expand', this);
38260 // Implements the default empty TriggerField.onTriggerClick function
38261 onTriggerClick : function(){
38265 if(this.isExpanded()){
38267 if (!this.blockFocus) {
38272 this.hasFocus = true;
38273 if(this.triggerAction == 'all') {
38274 this.doQuery(this.allQuery, true);
38276 this.doQuery(this.getRawValue());
38278 if (!this.blockFocus) {
38283 listKeyPress : function(e)
38285 //Roo.log('listkeypress');
38286 // scroll to first matching element based on key pres..
38287 if (e.isSpecialKey()) {
38290 var k = String.fromCharCode(e.getKey()).toUpperCase();
38293 var csel = this.view.getSelectedNodes();
38294 var cselitem = false;
38296 var ix = this.view.indexOf(csel[0]);
38297 cselitem = this.store.getAt(ix);
38298 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
38304 this.store.each(function(v) {
38306 // start at existing selection.
38307 if (cselitem.id == v.id) {
38313 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
38314 match = this.store.indexOf(v);
38319 if (match === false) {
38320 return true; // no more action?
38323 this.view.select(match);
38324 var sn = Roo.get(this.view.getSelectedNodes()[0])
38325 sn.scrollIntoView(sn.dom.parentNode, false);
38329 * @cfg {Boolean} grow
38333 * @cfg {Number} growMin
38337 * @cfg {Number} growMax
38346 * Ext JS Library 1.1.1
38347 * Copyright(c) 2006-2007, Ext JS, LLC.
38349 * Originally Released Under LGPL - original licence link has changed is not relivant.
38352 * <script type="text/javascript">
38355 * @class Roo.form.Checkbox
38356 * @extends Roo.form.Field
38357 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
38359 * Creates a new Checkbox
38360 * @param {Object} config Configuration options
38362 Roo.form.Checkbox = function(config){
38363 Roo.form.Checkbox.superclass.constructor.call(this, config);
38367 * Fires when the checkbox is checked or unchecked.
38368 * @param {Roo.form.Checkbox} this This checkbox
38369 * @param {Boolean} checked The new checked value
38375 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38377 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38379 focusClass : undefined,
38381 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38383 fieldClass: "x-form-field",
38385 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38389 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38390 * {tag: "input", type: "checkbox", autocomplete: "off"})
38392 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38394 * @cfg {String} boxLabel The text that appears beside the checkbox
38398 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38402 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38404 valueOff: '0', // value when not checked..
38406 actionMode : 'viewEl',
38409 itemCls : 'x-menu-check-item x-form-item',
38410 groupClass : 'x-menu-group-item',
38411 inputType : 'hidden',
38414 inSetChecked: false, // check that we are not calling self...
38416 inputElement: false, // real input element?
38417 basedOn: false, // ????
38419 isFormField: true, // not sure where this is needed!!!!
38421 onResize : function(){
38422 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38423 if(!this.boxLabel){
38424 this.el.alignTo(this.wrap, 'c-c');
38428 initEvents : function(){
38429 Roo.form.Checkbox.superclass.initEvents.call(this);
38430 this.el.on("click", this.onClick, this);
38431 this.el.on("change", this.onClick, this);
38435 getResizeEl : function(){
38439 getPositionEl : function(){
38444 onRender : function(ct, position){
38445 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38447 if(this.inputValue !== undefined){
38448 this.el.dom.value = this.inputValue;
38451 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38452 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38453 var viewEl = this.wrap.createChild({
38454 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38455 this.viewEl = viewEl;
38456 this.wrap.on('click', this.onClick, this);
38458 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38459 this.el.on('propertychange', this.setFromHidden, this); //ie
38464 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38465 // viewEl.on('click', this.onClick, this);
38467 //if(this.checked){
38468 this.setChecked(this.checked);
38470 //this.checked = this.el.dom;
38476 initValue : Roo.emptyFn,
38479 * Returns the checked state of the checkbox.
38480 * @return {Boolean} True if checked, else false
38482 getValue : function(){
38484 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38486 return this.valueOff;
38491 onClick : function(){
38492 this.setChecked(!this.checked);
38494 //if(this.el.dom.checked != this.checked){
38495 // this.setValue(this.el.dom.checked);
38500 * Sets the checked state of the checkbox.
38501 * On is always based on a string comparison between inputValue and the param.
38502 * @param {Boolean/String} value - the value to set
38503 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38505 setValue : function(v,suppressEvent){
38508 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38509 //if(this.el && this.el.dom){
38510 // this.el.dom.checked = this.checked;
38511 // this.el.dom.defaultChecked = this.checked;
38513 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38514 //this.fireEvent("check", this, this.checked);
38517 setChecked : function(state,suppressEvent)
38519 if (this.inSetChecked) {
38520 this.checked = state;
38526 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38528 this.checked = state;
38529 if(suppressEvent !== true){
38530 this.fireEvent('check', this, state);
38532 this.inSetChecked = true;
38533 this.el.dom.value = state ? this.inputValue : this.valueOff;
38534 this.inSetChecked = false;
38537 // handle setting of hidden value by some other method!!?!?
38538 setFromHidden: function()
38543 //console.log("SET FROM HIDDEN");
38544 //alert('setFrom hidden');
38545 this.setValue(this.el.dom.value);
38548 onDestroy : function()
38551 Roo.get(this.viewEl).remove();
38554 Roo.form.Checkbox.superclass.onDestroy.call(this);
38559 * Ext JS Library 1.1.1
38560 * Copyright(c) 2006-2007, Ext JS, LLC.
38562 * Originally Released Under LGPL - original licence link has changed is not relivant.
38565 * <script type="text/javascript">
38569 * @class Roo.form.Radio
38570 * @extends Roo.form.Checkbox
38571 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38572 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38574 * Creates a new Radio
38575 * @param {Object} config Configuration options
38577 Roo.form.Radio = function(){
38578 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38580 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38581 inputType: 'radio',
38584 * If this radio is part of a group, it will return the selected value
38587 getGroupValue : function(){
38588 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38590 });//<script type="text/javascript">
38593 * Ext JS Library 1.1.1
38594 * Copyright(c) 2006-2007, Ext JS, LLC.
38595 * licensing@extjs.com
38597 * http://www.extjs.com/license
38603 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38604 * - IE ? - no idea how much works there.
38612 * @class Ext.form.HtmlEditor
38613 * @extends Ext.form.Field
38614 * Provides a lightweight HTML Editor component.
38615 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38617 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38618 * supported by this editor.</b><br/><br/>
38619 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38620 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38622 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38624 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38628 * @cfg {String} createLinkText The default text for the create link prompt
38630 createLinkText : 'Please enter the URL for the link:',
38632 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38634 defaultLinkValue : 'http:/'+'/',
38637 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
38642 * @cfg {Number} height (in pixels)
38646 * @cfg {Number} width (in pixels)
38651 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
38654 stylesheets: false,
38659 // private properties
38660 validationEvent : false,
38662 initialized : false,
38664 sourceEditMode : false,
38665 onFocus : Roo.emptyFn,
38667 hideMode:'offsets',
38669 defaultAutoCreate : { // modified by initCompnoent..
38671 style:"width:500px;height:300px;",
38672 autocomplete: "off"
38676 initComponent : function(){
38679 * @event initialize
38680 * Fires when the editor is fully initialized (including the iframe)
38681 * @param {HtmlEditor} this
38686 * Fires when the editor is first receives the focus. Any insertion must wait
38687 * until after this event.
38688 * @param {HtmlEditor} this
38692 * @event beforesync
38693 * Fires before the textarea is updated with content from the editor iframe. Return false
38694 * to cancel the sync.
38695 * @param {HtmlEditor} this
38696 * @param {String} html
38700 * @event beforepush
38701 * Fires before the iframe editor is updated with content from the textarea. Return false
38702 * to cancel the push.
38703 * @param {HtmlEditor} this
38704 * @param {String} html
38709 * Fires when the textarea is updated with content from the editor iframe.
38710 * @param {HtmlEditor} this
38711 * @param {String} html
38716 * Fires when the iframe editor is updated with content from the textarea.
38717 * @param {HtmlEditor} this
38718 * @param {String} html
38722 * @event editmodechange
38723 * Fires when the editor switches edit modes
38724 * @param {HtmlEditor} this
38725 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38727 editmodechange: true,
38729 * @event editorevent
38730 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38731 * @param {HtmlEditor} this
38735 this.defaultAutoCreate = {
38737 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
38738 autocomplete: "off"
38743 * Protected method that will not generally be called directly. It
38744 * is called when the editor creates its toolbar. Override this method if you need to
38745 * add custom toolbar buttons.
38746 * @param {HtmlEditor} editor
38748 createToolbar : function(editor){
38749 if (!editor.toolbars || !editor.toolbars.length) {
38750 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38753 for (var i =0 ; i < editor.toolbars.length;i++) {
38754 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38755 editor.toolbars[i].init(editor);
38762 * Protected method that will not generally be called directly. It
38763 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38764 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38766 getDocMarkup : function(){
38769 if (this.stylesheets === false) {
38771 Roo.get(document.head).select('style').each(function(node) {
38772 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
38775 Roo.get(document.head).select('link').each(function(node) {
38776 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
38779 } else if (!this.stylesheets.length) {
38781 st = '<style type="text/css">' +
38782 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
38785 Roo.each(this.stylesheets, function(s) {
38786 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
38791 return '<html><head>' + st +
38792 //<style type="text/css">' +
38793 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
38795 ' </head><body></body></html>';
38799 onRender : function(ct, position)
38802 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38803 this.el.dom.style.border = '0 none';
38804 this.el.dom.setAttribute('tabIndex', -1);
38805 this.el.addClass('x-hidden');
38806 if(Roo.isIE){ // fix IE 1px bogus margin
38807 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38809 this.wrap = this.el.wrap({
38810 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38813 if (this.resizable) {
38814 this.resizeEl = new Roo.Resizable(this.wrap, {
38818 minHeight : this.height,
38819 height: this.height,
38820 handles : this.resizable,
38823 resize : function(r, w, h) {
38824 _t.onResize(w,h); // -something
38831 this.frameId = Roo.id();
38833 this.createToolbar(this);
38837 var iframe = this.wrap.createChild({
38840 name: this.frameId,
38841 frameBorder : 'no',
38842 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38846 // console.log(iframe);
38847 //this.wrap.dom.appendChild(iframe);
38849 this.iframe = iframe.dom;
38851 this.assignDocWin();
38853 this.doc.designMode = 'on';
38856 this.doc.write(this.getDocMarkup());
38860 var task = { // must defer to wait for browser to be ready
38862 //console.log("run task?" + this.doc.readyState);
38863 this.assignDocWin();
38864 if(this.doc.body || this.doc.readyState == 'complete'){
38866 this.doc.designMode="on";
38870 Roo.TaskMgr.stop(task);
38871 this.initEditor.defer(10, this);
38878 Roo.TaskMgr.start(task);
38881 this.setSize(this.wrap.getSize());
38883 if (this.resizeEl) {
38884 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
38885 // should trigger onReize..
38890 onResize : function(w, h)
38892 //Roo.log('resize: ' +w + ',' + h );
38893 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38894 if(this.el && this.iframe){
38895 if(typeof w == 'number'){
38896 var aw = w - this.wrap.getFrameWidth('lr');
38897 this.el.setWidth(this.adjustWidth('textarea', aw));
38898 this.iframe.style.width = aw + 'px';
38900 if(typeof h == 'number'){
38902 for (var i =0; i < this.toolbars.length;i++) {
38903 // fixme - ask toolbars for heights?
38904 tbh += this.toolbars[i].tb.el.getHeight();
38905 if (this.toolbars[i].footer) {
38906 tbh += this.toolbars[i].footer.el.getHeight();
38913 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38914 ah -= 5; // knock a few pixes off for look..
38915 this.el.setHeight(this.adjustWidth('textarea', ah));
38916 this.iframe.style.height = ah + 'px';
38918 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38925 * Toggles the editor between standard and source edit mode.
38926 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38928 toggleSourceEdit : function(sourceEditMode){
38930 this.sourceEditMode = sourceEditMode === true;
38932 if(this.sourceEditMode){
38935 this.iframe.className = 'x-hidden';
38936 this.el.removeClass('x-hidden');
38937 this.el.dom.removeAttribute('tabIndex');
38942 this.iframe.className = '';
38943 this.el.addClass('x-hidden');
38944 this.el.dom.setAttribute('tabIndex', -1);
38947 this.setSize(this.wrap.getSize());
38948 this.fireEvent('editmodechange', this, this.sourceEditMode);
38951 // private used internally
38952 createLink : function(){
38953 var url = prompt(this.createLinkText, this.defaultLinkValue);
38954 if(url && url != 'http:/'+'/'){
38955 this.relayCmd('createlink', url);
38959 // private (for BoxComponent)
38960 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38962 // private (for BoxComponent)
38963 getResizeEl : function(){
38967 // private (for BoxComponent)
38968 getPositionEl : function(){
38973 initEvents : function(){
38974 this.originalValue = this.getValue();
38978 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38981 markInvalid : Roo.emptyFn,
38983 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38986 clearInvalid : Roo.emptyFn,
38988 setValue : function(v){
38989 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38994 * Protected method that will not generally be called directly. If you need/want
38995 * custom HTML cleanup, this is the method you should override.
38996 * @param {String} html The HTML to be cleaned
38997 * return {String} The cleaned HTML
38999 cleanHtml : function(html){
39000 html = String(html);
39001 if(html.length > 5){
39002 if(Roo.isSafari){ // strip safari nonsense
39003 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
39006 if(html == ' '){
39013 * Protected method that will not generally be called directly. Syncs the contents
39014 * of the editor iframe with the textarea.
39016 syncValue : function(){
39017 if(this.initialized){
39018 var bd = (this.doc.body || this.doc.documentElement);
39019 this.cleanUpPaste();
39020 var html = bd.innerHTML;
39022 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
39023 var m = bs.match(/text-align:(.*?);/i);
39025 html = '<div style="'+m[0]+'">' + html + '</div>';
39028 html = this.cleanHtml(html);
39029 if(this.fireEvent('beforesync', this, html) !== false){
39030 this.el.dom.value = html;
39031 this.fireEvent('sync', this, html);
39037 * Protected method that will not generally be called directly. Pushes the value of the textarea
39038 * into the iframe editor.
39040 pushValue : function(){
39041 if(this.initialized){
39042 var v = this.el.dom.value;
39047 if(this.fireEvent('beforepush', this, v) !== false){
39048 var d = (this.doc.body || this.doc.documentElement);
39050 this.cleanUpPaste();
39051 this.el.dom.value = d.innerHTML;
39052 this.fireEvent('push', this, v);
39058 deferFocus : function(){
39059 this.focus.defer(10, this);
39063 focus : function(){
39064 if(this.win && !this.sourceEditMode){
39071 assignDocWin: function()
39073 var iframe = this.iframe;
39076 this.doc = iframe.contentWindow.document;
39077 this.win = iframe.contentWindow;
39079 if (!Roo.get(this.frameId)) {
39082 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
39083 this.win = Roo.get(this.frameId).dom.contentWindow;
39088 initEditor : function(){
39089 //console.log("INIT EDITOR");
39090 this.assignDocWin();
39094 this.doc.designMode="on";
39096 this.doc.write(this.getDocMarkup());
39099 var dbody = (this.doc.body || this.doc.documentElement);
39100 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
39101 // this copies styles from the containing element into thsi one..
39102 // not sure why we need all of this..
39103 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
39104 ss['background-attachment'] = 'fixed'; // w3c
39105 dbody.bgProperties = 'fixed'; // ie
39106 Roo.DomHelper.applyStyles(dbody, ss);
39107 Roo.EventManager.on(this.doc, {
39108 //'mousedown': this.onEditorEvent,
39109 'mouseup': this.onEditorEvent,
39110 'dblclick': this.onEditorEvent,
39111 'click': this.onEditorEvent,
39112 'keyup': this.onEditorEvent,
39117 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
39119 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
39120 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
39122 this.initialized = true;
39124 this.fireEvent('initialize', this);
39129 onDestroy : function(){
39135 for (var i =0; i < this.toolbars.length;i++) {
39136 // fixme - ask toolbars for heights?
39137 this.toolbars[i].onDestroy();
39140 this.wrap.dom.innerHTML = '';
39141 this.wrap.remove();
39146 onFirstFocus : function(){
39148 this.assignDocWin();
39151 this.activated = true;
39152 for (var i =0; i < this.toolbars.length;i++) {
39153 this.toolbars[i].onFirstFocus();
39156 if(Roo.isGecko){ // prevent silly gecko errors
39158 var s = this.win.getSelection();
39159 if(!s.focusNode || s.focusNode.nodeType != 3){
39160 var r = s.getRangeAt(0);
39161 r.selectNodeContents((this.doc.body || this.doc.documentElement));
39166 this.execCmd('useCSS', true);
39167 this.execCmd('styleWithCSS', false);
39170 this.fireEvent('activate', this);
39174 adjustFont: function(btn){
39175 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
39176 //if(Roo.isSafari){ // safari
39179 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
39180 if(Roo.isSafari){ // safari
39181 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
39182 v = (v < 10) ? 10 : v;
39183 v = (v > 48) ? 48 : v;
39184 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
39189 v = Math.max(1, v+adjust);
39191 this.execCmd('FontSize', v );
39194 onEditorEvent : function(e){
39195 this.fireEvent('editorevent', this, e);
39196 // this.updateToolbar();
39200 insertTag : function(tg)
39202 // could be a bit smarter... -> wrap the current selected tRoo..
39204 this.execCmd("formatblock", tg);
39208 insertText : function(txt)
39212 range = this.createRange();
39213 range.deleteContents();
39214 //alert(Sender.getAttribute('label'));
39216 range.insertNode(this.doc.createTextNode(txt));
39220 relayBtnCmd : function(btn){
39221 this.relayCmd(btn.cmd);
39225 * Executes a Midas editor command on the editor document and performs necessary focus and
39226 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
39227 * @param {String} cmd The Midas command
39228 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
39230 relayCmd : function(cmd, value){
39232 this.execCmd(cmd, value);
39233 this.fireEvent('editorevent', this);
39234 //this.updateToolbar();
39239 * Executes a Midas editor command directly on the editor document.
39240 * For visual commands, you should use {@link #relayCmd} instead.
39241 * <b>This should only be called after the editor is initialized.</b>
39242 * @param {String} cmd The Midas command
39243 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
39245 execCmd : function(cmd, value){
39246 this.doc.execCommand(cmd, false, value === undefined ? null : value);
39252 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
39254 * @param {String} text
39256 insertAtCursor : function(text){
39257 if(!this.activated){
39262 var r = this.doc.selection.createRange();
39269 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
39271 this.execCmd('InsertHTML', text);
39276 mozKeyPress : function(e){
39278 var c = e.getCharCode(), cmd;
39281 c = String.fromCharCode(c).toLowerCase();
39292 this.cleanUpPaste.defer(100, this);
39300 e.preventDefault();
39308 fixKeys : function(){ // load time branching for fastest keydown performance
39310 return function(e){
39311 var k = e.getKey(), r;
39314 r = this.doc.selection.createRange();
39317 r.pasteHTML('    ');
39324 r = this.doc.selection.createRange();
39326 var target = r.parentElement();
39327 if(!target || target.tagName.toLowerCase() != 'li'){
39329 r.pasteHTML('<br />');
39335 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39336 this.cleanUpPaste.defer(100, this);
39342 }else if(Roo.isOpera){
39343 return function(e){
39344 var k = e.getKey();
39348 this.execCmd('InsertHTML','    ');
39351 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39352 this.cleanUpPaste.defer(100, this);
39357 }else if(Roo.isSafari){
39358 return function(e){
39359 var k = e.getKey();
39363 this.execCmd('InsertText','\t');
39367 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39368 this.cleanUpPaste.defer(100, this);
39376 getAllAncestors: function()
39378 var p = this.getSelectedNode();
39381 a.push(p); // push blank onto stack..
39382 p = this.getParentElement();
39386 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
39390 a.push(this.doc.body);
39394 lastSelNode : false,
39397 getSelection : function()
39399 this.assignDocWin();
39400 return Roo.isIE ? this.doc.selection : this.win.getSelection();
39403 getSelectedNode: function()
39405 // this may only work on Gecko!!!
39407 // should we cache this!!!!
39412 var range = this.createRange(this.getSelection()).cloneRange();
39415 var parent = range.parentElement();
39417 var testRange = range.duplicate();
39418 testRange.moveToElementText(parent);
39419 if (testRange.inRange(range)) {
39422 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
39425 parent = parent.parentElement;
39430 // is ancestor a text element.
39431 var ac = range.commonAncestorContainer;
39432 if (ac.nodeType == 3) {
39433 ac = ac.parentNode;
39436 var ar = ac.childNodes;
39439 var other_nodes = [];
39440 var has_other_nodes = false;
39441 for (var i=0;i<ar.length;i++) {
39442 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
39445 // fullly contained node.
39447 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
39452 // probably selected..
39453 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
39454 other_nodes.push(ar[i]);
39458 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39463 has_other_nodes = true;
39465 if (!nodes.length && other_nodes.length) {
39466 nodes= other_nodes;
39468 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39474 createRange: function(sel)
39476 // this has strange effects when using with
39477 // top toolbar - not sure if it's a great idea.
39478 //this.editor.contentWindow.focus();
39479 if (typeof sel != "undefined") {
39481 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39483 return this.doc.createRange();
39486 return this.doc.createRange();
39489 getParentElement: function()
39492 this.assignDocWin();
39493 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39495 var range = this.createRange(sel);
39498 var p = range.commonAncestorContainer;
39499 while (p.nodeType == 3) { // text node
39510 * Range intersection.. the hard stuff...
39514 * [ -- selected range --- ]
39518 * if end is before start or hits it. fail.
39519 * if start is after end or hits it fail.
39521 * if either hits (but other is outside. - then it's not
39527 // @see http://www.thismuchiknow.co.uk/?p=64.
39528 rangeIntersectsNode : function(range, node)
39530 var nodeRange = node.ownerDocument.createRange();
39532 nodeRange.selectNode(node);
39534 nodeRange.selectNodeContents(node);
39537 var rangeStartRange = range.cloneRange();
39538 rangeStartRange.collapse(true);
39540 var rangeEndRange = range.cloneRange();
39541 rangeEndRange.collapse(false);
39543 var nodeStartRange = nodeRange.cloneRange();
39544 nodeStartRange.collapse(true);
39546 var nodeEndRange = nodeRange.cloneRange();
39547 nodeEndRange.collapse(false);
39549 return rangeStartRange.compareBoundaryPoints(
39550 Range.START_TO_START, nodeEndRange) == -1 &&
39551 rangeEndRange.compareBoundaryPoints(
39552 Range.START_TO_START, nodeStartRange) == 1;
39556 rangeCompareNode : function(range, node)
39558 var nodeRange = node.ownerDocument.createRange();
39560 nodeRange.selectNode(node);
39562 nodeRange.selectNodeContents(node);
39566 range.collapse(true);
39568 nodeRange.collapse(true);
39570 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
39571 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
39573 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
39575 var nodeIsBefore = ss == 1;
39576 var nodeIsAfter = ee == -1;
39578 if (nodeIsBefore && nodeIsAfter)
39580 if (!nodeIsBefore && nodeIsAfter)
39581 return 1; //right trailed.
39583 if (nodeIsBefore && !nodeIsAfter)
39584 return 2; // left trailed.
39589 // private? - in a new class?
39590 cleanUpPaste : function()
39592 // cleans up the whole document..
39593 // console.log('cleanuppaste');
39594 this.cleanUpChildren(this.doc.body);
39595 this.doc.body.innerHTML = this.cleanWordChars(this.doc.body.innerHTML);
39599 cleanWordChars : function(input) {
39600 var he = Roo.form.HtmlEditor;
39602 var output = input;
39603 Roo.each(he.swapCodes, function(sw) {
39605 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
39606 output = output.replace(swapper, sw[1]);
39612 cleanUpChildren : function (n)
39614 if (!n.childNodes.length) {
39617 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39618 this.cleanUpChild(n.childNodes[i]);
39625 cleanUpChild : function (node)
39627 //console.log(node);
39628 if (node.nodeName == "#text") {
39629 // clean up silly Windows -- stuff?
39632 if (node.nodeName == "#comment") {
39633 node.parentNode.removeChild(node);
39634 // clean up silly Windows -- stuff?
39638 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39640 node.parentNode.removeChild(node);
39645 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
39647 // remove <a name=....> as rendering on yahoo mailer is bored with this.
39649 if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
39650 remove_keep_children = true;
39653 if (remove_keep_children) {
39654 this.cleanUpChildren(node);
39655 // inserts everything just before this node...
39656 while (node.childNodes.length) {
39657 var cn = node.childNodes[0];
39658 node.removeChild(cn);
39659 node.parentNode.insertBefore(cn, node);
39661 node.parentNode.removeChild(node);
39665 if (!node.attributes || !node.attributes.length) {
39666 this.cleanUpChildren(node);
39670 function cleanAttr(n,v)
39673 if (v.match(/^\./) || v.match(/^\//)) {
39676 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39679 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39680 node.removeAttribute(n);
39684 function cleanStyle(n,v)
39686 if (v.match(/expression/)) { //XSS?? should we even bother..
39687 node.removeAttribute(n);
39692 var parts = v.split(/;/);
39693 Roo.each(parts, function(p) {
39694 p = p.replace(/\s+/g,'');
39698 var l = p.split(':').shift().replace(/\s+/g,'');
39700 // only allow 'c whitelisted system attributes'
39701 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39702 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39703 node.removeAttribute(n);
39713 for (var i = node.attributes.length-1; i > -1 ; i--) {
39714 var a = node.attributes[i];
39716 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39717 node.removeAttribute(a.name);
39720 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39721 cleanAttr(a.name,a.value); // fixme..
39724 if (a.name == 'style') {
39725 cleanStyle(a.name,a.value);
39727 /// clean up MS crap..
39728 // tecnically this should be a list of valid class'es..
39731 if (a.name == 'class') {
39732 if (a.value.match(/^Mso/)) {
39733 node.className = '';
39736 if (a.value.match(/body/)) {
39737 node.className = '';
39747 this.cleanUpChildren(node);
39753 // hide stuff that is not compatible
39767 * @event specialkey
39771 * @cfg {String} fieldClass @hide
39774 * @cfg {String} focusClass @hide
39777 * @cfg {String} autoCreate @hide
39780 * @cfg {String} inputType @hide
39783 * @cfg {String} invalidClass @hide
39786 * @cfg {String} invalidText @hide
39789 * @cfg {String} msgFx @hide
39792 * @cfg {String} validateOnBlur @hide
39796 Roo.form.HtmlEditor.white = [
39797 'area', 'br', 'img', 'input', 'hr', 'wbr',
39799 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39800 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39801 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39802 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39803 'table', 'ul', 'xmp',
39805 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39808 'dir', 'menu', 'ol', 'ul', 'dl',
39814 Roo.form.HtmlEditor.black = [
39815 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39817 'base', 'basefont', 'bgsound', 'blink', 'body',
39818 'frame', 'frameset', 'head', 'html', 'ilayer',
39819 'iframe', 'layer', 'link', 'meta', 'object',
39820 'script', 'style' ,'title', 'xml' // clean later..
39822 Roo.form.HtmlEditor.clean = [
39823 'script', 'style', 'title', 'xml'
39825 Roo.form.HtmlEditor.remove = [
39830 Roo.form.HtmlEditor.ablack = [
39834 Roo.form.HtmlEditor.aclean = [
39835 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39839 Roo.form.HtmlEditor.pwhite= [
39840 'http', 'https', 'mailto'
39843 // white listed style attributes.
39844 Roo.form.HtmlEditor.cwhite= [
39850 Roo.form.HtmlEditor.swapCodes =[
39861 // <script type="text/javascript">
39864 * Ext JS Library 1.1.1
39865 * Copyright(c) 2006-2007, Ext JS, LLC.
39871 * @class Roo.form.HtmlEditorToolbar1
39876 new Roo.form.HtmlEditor({
39879 new Roo.form.HtmlEditorToolbar1({
39880 disable : { fonts: 1 , format: 1, ..., ... , ...],
39886 * @cfg {Object} disable List of elements to disable..
39887 * @cfg {Array} btns List of additional buttons.
39891 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39894 Roo.form.HtmlEditor.ToolbarStandard = function(config)
39897 Roo.apply(this, config);
39899 // default disabled, based on 'good practice'..
39900 this.disable = this.disable || {};
39901 Roo.applyIf(this.disable, {
39904 specialElements : true
39908 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39909 // dont call parent... till later.
39912 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
39920 * @cfg {Object} disable List of toolbar elements to disable
39925 * @cfg {Array} fontFamilies An array of available font families
39943 // "á" , ?? a acute?
39948 "°" // , // degrees
39950 // "é" , // e ecute
39951 // "ú" , // u ecute?
39954 specialElements : [
39956 text: "Insert Table",
39959 ihtml : '<table><tr><td>Cell</td></tr></table>'
39963 text: "Insert Image",
39966 ihtml : '<img src="about:blank"/>'
39975 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
39976 "input:submit", "input:button", "select", "textarea", "label" ],
39979 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
39981 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39984 * @cfg {String} defaultFont default font to use.
39986 defaultFont: 'tahoma',
39988 fontSelect : false,
39991 formatCombo : false,
39993 init : function(editor)
39995 this.editor = editor;
39998 var fid = editor.frameId;
40000 function btn(id, toggle, handler){
40001 var xid = fid + '-'+ id ;
40005 cls : 'x-btn-icon x-edit-'+id,
40006 enableToggle:toggle !== false,
40007 scope: editor, // was editor...
40008 handler:handler||editor.relayBtnCmd,
40009 clickEvent:'mousedown',
40010 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40017 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
40019 // stop form submits
40020 tb.el.on('click', function(e){
40021 e.preventDefault(); // what does this do?
40024 if(!this.disable.font && !Roo.isSafari){
40025 /* why no safari for fonts
40026 editor.fontSelect = tb.el.createChild({
40029 cls:'x-font-select',
40030 html: editor.createFontOptions()
40032 editor.fontSelect.on('change', function(){
40033 var font = editor.fontSelect.dom.value;
40034 editor.relayCmd('fontname', font);
40035 editor.deferFocus();
40038 editor.fontSelect.dom,
40043 if(!this.disable.formats){
40044 this.formatCombo = new Roo.form.ComboBox({
40045 store: new Roo.data.SimpleStore({
40048 data : this.formats // from states.js
40051 //autoCreate : {tag: "div", size: "20"},
40052 displayField:'tag',
40056 triggerAction: 'all',
40057 emptyText:'Add tag',
40058 selectOnFocus:true,
40061 'select': function(c, r, i) {
40062 editor.insertTag(r.get('tag'));
40068 tb.addField(this.formatCombo);
40072 if(!this.disable.format){
40079 if(!this.disable.fontSize){
40084 btn('increasefontsize', false, editor.adjustFont),
40085 btn('decreasefontsize', false, editor.adjustFont)
40090 if(!this.disable.colors){
40093 id:editor.frameId +'-forecolor',
40094 cls:'x-btn-icon x-edit-forecolor',
40095 clickEvent:'mousedown',
40096 tooltip: this.buttonTips['forecolor'] || undefined,
40098 menu : new Roo.menu.ColorMenu({
40099 allowReselect: true,
40100 focus: Roo.emptyFn,
40103 selectHandler: function(cp, color){
40104 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
40105 editor.deferFocus();
40108 clickEvent:'mousedown'
40111 id:editor.frameId +'backcolor',
40112 cls:'x-btn-icon x-edit-backcolor',
40113 clickEvent:'mousedown',
40114 tooltip: this.buttonTips['backcolor'] || undefined,
40116 menu : new Roo.menu.ColorMenu({
40117 focus: Roo.emptyFn,
40120 allowReselect: true,
40121 selectHandler: function(cp, color){
40123 editor.execCmd('useCSS', false);
40124 editor.execCmd('hilitecolor', color);
40125 editor.execCmd('useCSS', true);
40126 editor.deferFocus();
40128 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
40129 Roo.isSafari || Roo.isIE ? '#'+color : color);
40130 editor.deferFocus();
40134 clickEvent:'mousedown'
40139 // now add all the items...
40142 if(!this.disable.alignments){
40145 btn('justifyleft'),
40146 btn('justifycenter'),
40147 btn('justifyright')
40151 //if(!Roo.isSafari){
40152 if(!this.disable.links){
40155 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
40159 if(!this.disable.lists){
40162 btn('insertorderedlist'),
40163 btn('insertunorderedlist')
40166 if(!this.disable.sourceEdit){
40169 btn('sourceedit', true, function(btn){
40170 this.toggleSourceEdit(btn.pressed);
40177 // special menu.. - needs to be tidied up..
40178 if (!this.disable.special) {
40181 cls: 'x-edit-none',
40187 for (var i =0; i < this.specialChars.length; i++) {
40188 smenu.menu.items.push({
40190 html: this.specialChars[i],
40191 handler: function(a,b) {
40192 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
40205 if (!this.disable.specialElements) {
40208 cls: 'x-edit-none',
40213 for (var i =0; i < this.specialElements.length; i++) {
40214 semenu.menu.items.push(
40216 handler: function(a,b) {
40217 editor.insertAtCursor(this.ihtml);
40219 }, this.specialElements[i])
40231 for(var i =0; i< this.btns.length;i++) {
40232 var b = this.btns[i];
40233 b.cls = 'x-edit-none';
40242 // disable everything...
40244 this.tb.items.each(function(item){
40245 if(item.id != editor.frameId+ '-sourceedit'){
40249 this.rendered = true;
40251 // the all the btns;
40252 editor.on('editorevent', this.updateToolbar, this);
40253 // other toolbars need to implement this..
40254 //editor.on('editmodechange', this.updateToolbar, this);
40260 * Protected method that will not generally be called directly. It triggers
40261 * a toolbar update by reading the markup state of the current selection in the editor.
40263 updateToolbar: function(){
40265 if(!this.editor.activated){
40266 this.editor.onFirstFocus();
40270 var btns = this.tb.items.map,
40271 doc = this.editor.doc,
40272 frameId = this.editor.frameId;
40274 if(!this.disable.font && !Roo.isSafari){
40276 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
40277 if(name != this.fontSelect.dom.value){
40278 this.fontSelect.dom.value = name;
40282 if(!this.disable.format){
40283 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
40284 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
40285 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
40287 if(!this.disable.alignments){
40288 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
40289 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
40290 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
40292 if(!Roo.isSafari && !this.disable.lists){
40293 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
40294 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
40297 var ans = this.editor.getAllAncestors();
40298 if (this.formatCombo) {
40301 var store = this.formatCombo.store;
40302 this.formatCombo.setValue("");
40303 for (var i =0; i < ans.length;i++) {
40304 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
40306 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
40314 // hides menus... - so this cant be on a menu...
40315 Roo.menu.MenuMgr.hideAll();
40317 //this.editorsyncValue();
40321 createFontOptions : function(){
40322 var buf = [], fs = this.fontFamilies, ff, lc;
40323 for(var i = 0, len = fs.length; i< len; i++){
40325 lc = ff.toLowerCase();
40327 '<option value="',lc,'" style="font-family:',ff,';"',
40328 (this.defaultFont == lc ? ' selected="true">' : '>'),
40333 return buf.join('');
40336 toggleSourceEdit : function(sourceEditMode){
40337 if(sourceEditMode === undefined){
40338 sourceEditMode = !this.sourceEditMode;
40340 this.sourceEditMode = sourceEditMode === true;
40341 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
40342 // just toggle the button?
40343 if(btn.pressed !== this.editor.sourceEditMode){
40344 btn.toggle(this.editor.sourceEditMode);
40348 if(this.sourceEditMode){
40349 this.tb.items.each(function(item){
40350 if(item.cmd != 'sourceedit'){
40356 if(this.initialized){
40357 this.tb.items.each(function(item){
40363 // tell the editor that it's been pressed..
40364 this.editor.toggleSourceEdit(sourceEditMode);
40368 * Object collection of toolbar tooltips for the buttons in the editor. The key
40369 * is the command id associated with that button and the value is a valid QuickTips object.
40374 title: 'Bold (Ctrl+B)',
40375 text: 'Make the selected text bold.',
40376 cls: 'x-html-editor-tip'
40379 title: 'Italic (Ctrl+I)',
40380 text: 'Make the selected text italic.',
40381 cls: 'x-html-editor-tip'
40389 title: 'Bold (Ctrl+B)',
40390 text: 'Make the selected text bold.',
40391 cls: 'x-html-editor-tip'
40394 title: 'Italic (Ctrl+I)',
40395 text: 'Make the selected text italic.',
40396 cls: 'x-html-editor-tip'
40399 title: 'Underline (Ctrl+U)',
40400 text: 'Underline the selected text.',
40401 cls: 'x-html-editor-tip'
40403 increasefontsize : {
40404 title: 'Grow Text',
40405 text: 'Increase the font size.',
40406 cls: 'x-html-editor-tip'
40408 decreasefontsize : {
40409 title: 'Shrink Text',
40410 text: 'Decrease the font size.',
40411 cls: 'x-html-editor-tip'
40414 title: 'Text Highlight Color',
40415 text: 'Change the background color of the selected text.',
40416 cls: 'x-html-editor-tip'
40419 title: 'Font Color',
40420 text: 'Change the color of the selected text.',
40421 cls: 'x-html-editor-tip'
40424 title: 'Align Text Left',
40425 text: 'Align text to the left.',
40426 cls: 'x-html-editor-tip'
40429 title: 'Center Text',
40430 text: 'Center text in the editor.',
40431 cls: 'x-html-editor-tip'
40434 title: 'Align Text Right',
40435 text: 'Align text to the right.',
40436 cls: 'x-html-editor-tip'
40438 insertunorderedlist : {
40439 title: 'Bullet List',
40440 text: 'Start a bulleted list.',
40441 cls: 'x-html-editor-tip'
40443 insertorderedlist : {
40444 title: 'Numbered List',
40445 text: 'Start a numbered list.',
40446 cls: 'x-html-editor-tip'
40449 title: 'Hyperlink',
40450 text: 'Make the selected text a hyperlink.',
40451 cls: 'x-html-editor-tip'
40454 title: 'Source Edit',
40455 text: 'Switch to source editing mode.',
40456 cls: 'x-html-editor-tip'
40460 onDestroy : function(){
40463 this.tb.items.each(function(item){
40465 item.menu.removeAll();
40467 item.menu.el.destroy();
40475 onFirstFocus: function() {
40476 this.tb.items.each(function(item){
40485 // <script type="text/javascript">
40488 * Ext JS Library 1.1.1
40489 * Copyright(c) 2006-2007, Ext JS, LLC.
40496 * @class Roo.form.HtmlEditor.ToolbarContext
40501 new Roo.form.HtmlEditor({
40504 { xtype: 'ToolbarStandard', styles : {} }
40505 { xtype: 'ToolbarContext', disable : {} }
40511 * @config : {Object} disable List of elements to disable.. (not done yet.)
40512 * @config : {Object} styles Map of styles available.
40516 Roo.form.HtmlEditor.ToolbarContext = function(config)
40519 Roo.apply(this, config);
40520 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
40521 // dont call parent... till later.
40522 this.styles = this.styles || {};
40524 Roo.form.HtmlEditor.ToolbarContext.types = {
40536 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
40598 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
40603 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40657 // should we really allow this??
40658 // should this just be
40673 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40681 * @cfg {Object} disable List of toolbar elements to disable
40686 * @cfg {Object} styles List of styles
40687 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
40689 * These must be defined in the page, so they get rendered correctly..
40700 init : function(editor)
40702 this.editor = editor;
40705 var fid = editor.frameId;
40707 function btn(id, toggle, handler){
40708 var xid = fid + '-'+ id ;
40712 cls : 'x-btn-icon x-edit-'+id,
40713 enableToggle:toggle !== false,
40714 scope: editor, // was editor...
40715 handler:handler||editor.relayBtnCmd,
40716 clickEvent:'mousedown',
40717 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40721 // create a new element.
40722 var wdiv = editor.wrap.createChild({
40724 }, editor.wrap.dom.firstChild.nextSibling, true);
40726 // can we do this more than once??
40728 // stop form submits
40731 // disable everything...
40732 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40733 this.toolbars = {};
40735 for (var i in ty) {
40737 this.toolbars[i] = this.buildToolbar(ty[i],i);
40739 this.tb = this.toolbars.BODY;
40741 this.buildFooter();
40742 this.footer.show();
40744 this.rendered = true;
40746 // the all the btns;
40747 editor.on('editorevent', this.updateToolbar, this);
40748 // other toolbars need to implement this..
40749 //editor.on('editmodechange', this.updateToolbar, this);
40755 * Protected method that will not generally be called directly. It triggers
40756 * a toolbar update by reading the markup state of the current selection in the editor.
40758 updateToolbar: function(ignore_a,ignore_b,sel){
40761 if(!this.editor.activated){
40762 this.editor.onFirstFocus();
40765 var updateFooter = sel ? false : true;
40768 var ans = this.editor.getAllAncestors();
40771 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40774 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40775 sel = sel ? sel : this.editor.doc.body;
40776 sel = sel.tagName.length ? sel : this.editor.doc.body;
40779 // pick a menu that exists..
40780 var tn = sel.tagName.toUpperCase();
40781 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40783 tn = sel.tagName.toUpperCase();
40785 var lastSel = this.tb.selectedNode
40787 this.tb.selectedNode = sel;
40789 // if current menu does not match..
40790 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
40793 ///console.log("show: " + tn);
40794 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
40797 this.tb.items.first().el.innerHTML = tn + ': ';
40800 // update attributes
40801 if (this.tb.fields) {
40802 this.tb.fields.each(function(e) {
40803 e.setValue(sel.getAttribute(e.name));
40808 var st = this.tb.fields.item(0);
40809 st.store.removeAll();
40810 var cn = sel.className.split(/\s+/);
40813 if (this.styles['*']) {
40815 Roo.each(this.styles['*'], function(v) {
40816 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
40819 if (this.styles[tn]) {
40820 Roo.each(this.styles[tn], function(v) {
40821 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
40825 st.store.loadData(avs);
40829 // flag our selected Node.
40830 this.tb.selectedNode = sel;
40833 Roo.menu.MenuMgr.hideAll();
40837 if (!updateFooter) {
40840 // update the footer
40844 this.footerEls = ans.reverse();
40845 Roo.each(this.footerEls, function(a,i) {
40846 if (!a) { return; }
40847 html += html.length ? ' > ' : '';
40849 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
40854 var sz = this.footDisp.up('td').getSize();
40855 this.footDisp.dom.style.width = (sz.width -10) + 'px';
40856 this.footDisp.dom.style.marginLeft = '5px';
40858 this.footDisp.dom.style.overflow = 'hidden';
40860 this.footDisp.dom.innerHTML = html;
40862 //this.editorsyncValue();
40867 onDestroy : function(){
40870 this.tb.items.each(function(item){
40872 item.menu.removeAll();
40874 item.menu.el.destroy();
40882 onFirstFocus: function() {
40883 // need to do this for all the toolbars..
40884 this.tb.items.each(function(item){
40888 buildToolbar: function(tlist, nm)
40890 var editor = this.editor;
40891 // create a new element.
40892 var wdiv = editor.wrap.createChild({
40894 }, editor.wrap.dom.firstChild.nextSibling, true);
40897 var tb = new Roo.Toolbar(wdiv);
40900 tb.add(nm+ ": ");
40905 // this needs a multi-select checkbox...
40906 tb.addField( new Roo.form.ComboBox({
40907 store: new Roo.data.SimpleStore({
40909 fields: ['val', 'selected'],
40912 name : 'className',
40913 displayField:'val',
40917 triggerAction: 'all',
40918 emptyText:'Select Style',
40919 selectOnFocus:true,
40922 'select': function(c, r, i) {
40923 // initial support only for on class per el..
40924 tb.selectedNode.className = r ? r.get('val') : '';
40933 for (var i in tlist) {
40935 var item = tlist[i];
40936 tb.add(item.title + ": ");
40942 // opts == pulldown..
40943 tb.addField( new Roo.form.ComboBox({
40944 store: new Roo.data.SimpleStore({
40950 displayField:'val',
40954 triggerAction: 'all',
40955 emptyText:'Select',
40956 selectOnFocus:true,
40957 width: item.width ? item.width : 130,
40959 'select': function(c, r, i) {
40960 tb.selectedNode.setAttribute(c.name, r.get('val'));
40969 tb.addField( new Roo.form.TextField({
40972 //allowBlank:false,
40977 tb.addField( new Roo.form.TextField({
40983 'change' : function(f, nv, ov) {
40984 tb.selectedNode.setAttribute(f.name, nv);
40990 tb.el.on('click', function(e){
40991 e.preventDefault(); // what does this do?
40993 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40996 // dont need to disable them... as they will get hidden
41001 buildFooter : function()
41004 var fel = this.editor.wrap.createChild();
41005 this.footer = new Roo.Toolbar(fel);
41006 // toolbar has scrolly on left / right?
41007 var footDisp= new Roo.Toolbar.Fill();
41013 handler : function() {
41014 _t.footDisp.scrollTo('left',0,true)
41018 this.footer.add( footDisp );
41023 handler : function() {
41025 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
41029 var fel = Roo.get(footDisp.el);
41030 fel.addClass('x-editor-context');
41031 this.footDispWrap = fel;
41032 this.footDispWrap.overflow = 'hidden';
41034 this.footDisp = fel.createChild();
41035 this.footDispWrap.on('click', this.onContextClick, this)
41039 onContextClick : function (ev,dom)
41041 ev.preventDefault();
41042 var cn = dom.className;
41044 if (!cn.match(/x-ed-loc-/)) {
41047 var n = cn.split('-').pop();
41048 var ans = this.footerEls;
41052 var range = this.editor.createRange();
41054 range.selectNodeContents(sel);
41055 //range.selectNode(sel);
41058 var selection = this.editor.getSelection();
41059 selection.removeAllRanges();
41060 selection.addRange(range);
41064 this.updateToolbar(null, null, sel);
41081 * Ext JS Library 1.1.1
41082 * Copyright(c) 2006-2007, Ext JS, LLC.
41084 * Originally Released Under LGPL - original licence link has changed is not relivant.
41087 * <script type="text/javascript">
41091 * @class Roo.form.BasicForm
41092 * @extends Roo.util.Observable
41093 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
41095 * @param {String/HTMLElement/Roo.Element} el The form element or its id
41096 * @param {Object} config Configuration options
41098 Roo.form.BasicForm = function(el, config){
41099 this.allItems = [];
41100 this.childForms = [];
41101 Roo.apply(this, config);
41103 * The Roo.form.Field items in this form.
41104 * @type MixedCollection
41108 this.items = new Roo.util.MixedCollection(false, function(o){
41109 return o.id || (o.id = Roo.id());
41113 * @event beforeaction
41114 * Fires before any action is performed. Return false to cancel the action.
41115 * @param {Form} this
41116 * @param {Action} action The action to be performed
41118 beforeaction: true,
41120 * @event actionfailed
41121 * Fires when an action fails.
41122 * @param {Form} this
41123 * @param {Action} action The action that failed
41125 actionfailed : true,
41127 * @event actioncomplete
41128 * Fires when an action is completed.
41129 * @param {Form} this
41130 * @param {Action} action The action that completed
41132 actioncomplete : true
41137 Roo.form.BasicForm.superclass.constructor.call(this);
41140 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
41142 * @cfg {String} method
41143 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
41146 * @cfg {DataReader} reader
41147 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
41148 * This is optional as there is built-in support for processing JSON.
41151 * @cfg {DataReader} errorReader
41152 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
41153 * This is completely optional as there is built-in support for processing JSON.
41156 * @cfg {String} url
41157 * The URL to use for form actions if one isn't supplied in the action options.
41160 * @cfg {Boolean} fileUpload
41161 * Set to true if this form is a file upload.
41165 * @cfg {Object} baseParams
41166 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
41171 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
41176 activeAction : null,
41179 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
41180 * or setValues() data instead of when the form was first created.
41182 trackResetOnLoad : false,
41186 * childForms - used for multi-tab forms
41189 childForms : false,
41192 * allItems - full list of fields.
41198 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
41199 * element by passing it or its id or mask the form itself by passing in true.
41202 waitMsgTarget : false,
41205 initEl : function(el){
41206 this.el = Roo.get(el);
41207 this.id = this.el.id || Roo.id();
41208 this.el.on('submit', this.onSubmit, this);
41209 this.el.addClass('x-form');
41213 onSubmit : function(e){
41218 * Returns true if client-side validation on the form is successful.
41221 isValid : function(){
41223 this.items.each(function(f){
41232 * Returns true if any fields in this form have changed since their original load.
41235 isDirty : function(){
41237 this.items.each(function(f){
41247 * Performs a predefined action (submit or load) or custom actions you define on this form.
41248 * @param {String} actionName The name of the action type
41249 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
41250 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
41251 * accept other config options):
41253 Property Type Description
41254 ---------------- --------------- ----------------------------------------------------------------------------------
41255 url String The url for the action (defaults to the form's url)
41256 method String The form method to use (defaults to the form's method, or POST if not defined)
41257 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
41258 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
41259 validate the form on the client (defaults to false)
41261 * @return {BasicForm} this
41263 doAction : function(action, options){
41264 if(typeof action == 'string'){
41265 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
41267 if(this.fireEvent('beforeaction', this, action) !== false){
41268 this.beforeAction(action);
41269 action.run.defer(100, action);
41275 * Shortcut to do a submit action.
41276 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
41277 * @return {BasicForm} this
41279 submit : function(options){
41280 this.doAction('submit', options);
41285 * Shortcut to do a load action.
41286 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
41287 * @return {BasicForm} this
41289 load : function(options){
41290 this.doAction('load', options);
41295 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
41296 * @param {Record} record The record to edit
41297 * @return {BasicForm} this
41299 updateRecord : function(record){
41300 record.beginEdit();
41301 var fs = record.fields;
41302 fs.each(function(f){
41303 var field = this.findField(f.name);
41305 record.set(f.name, field.getValue());
41313 * Loads an Roo.data.Record into this form.
41314 * @param {Record} record The record to load
41315 * @return {BasicForm} this
41317 loadRecord : function(record){
41318 this.setValues(record.data);
41323 beforeAction : function(action){
41324 var o = action.options;
41327 if(this.waitMsgTarget === true){
41328 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
41329 }else if(this.waitMsgTarget){
41330 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
41331 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
41333 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
41339 afterAction : function(action, success){
41340 this.activeAction = null;
41341 var o = action.options;
41343 if(this.waitMsgTarget === true){
41345 }else if(this.waitMsgTarget){
41346 this.waitMsgTarget.unmask();
41348 Roo.MessageBox.updateProgress(1);
41349 Roo.MessageBox.hide();
41356 Roo.callback(o.success, o.scope, [this, action]);
41357 this.fireEvent('actioncomplete', this, action);
41360 Roo.callback(o.failure, o.scope, [this, action]);
41361 // show an error message if no failed handler is set..
41362 if (!this.hasListener('actionfailed')) {
41363 Roo.MessageBox.alert("Error",
41364 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
41365 action.result.errorMsg :
41366 "Saving Failed, please check your entries"
41370 this.fireEvent('actionfailed', this, action);
41376 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
41377 * @param {String} id The value to search for
41380 findField : function(id){
41381 var field = this.items.get(id);
41383 this.items.each(function(f){
41384 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
41390 return field || null;
41394 * Add a secondary form to this one,
41395 * Used to provide tabbed forms. One form is primary, with hidden values
41396 * which mirror the elements from the other forms.
41398 * @param {Roo.form.Form} form to add.
41401 addForm : function(form)
41404 if (this.childForms.indexOf(form) > -1) {
41408 this.childForms.push(form);
41410 Roo.each(form.allItems, function (fe) {
41412 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
41413 if (this.findField(n)) { // already added..
41416 var add = new Roo.form.Hidden({
41419 add.render(this.el);
41426 * Mark fields in this form invalid in bulk.
41427 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
41428 * @return {BasicForm} this
41430 markInvalid : function(errors){
41431 if(errors instanceof Array){
41432 for(var i = 0, len = errors.length; i < len; i++){
41433 var fieldError = errors[i];
41434 var f = this.findField(fieldError.id);
41436 f.markInvalid(fieldError.msg);
41442 if(typeof errors[id] != 'function' && (field = this.findField(id))){
41443 field.markInvalid(errors[id]);
41447 Roo.each(this.childForms || [], function (f) {
41448 f.markInvalid(errors);
41455 * Set values for fields in this form in bulk.
41456 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
41457 * @return {BasicForm} this
41459 setValues : function(values){
41460 if(values instanceof Array){ // array of objects
41461 for(var i = 0, len = values.length; i < len; i++){
41463 var f = this.findField(v.id);
41465 f.setValue(v.value);
41466 if(this.trackResetOnLoad){
41467 f.originalValue = f.getValue();
41471 }else{ // object hash
41474 if(typeof values[id] != 'function' && (field = this.findField(id))){
41476 if (field.setFromData &&
41477 field.valueField &&
41478 field.displayField &&
41479 // combos' with local stores can
41480 // be queried via setValue()
41481 // to set their value..
41482 (field.store && !field.store.isLocal)
41486 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
41487 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
41488 field.setFromData(sd);
41491 field.setValue(values[id]);
41495 if(this.trackResetOnLoad){
41496 field.originalValue = field.getValue();
41502 Roo.each(this.childForms || [], function (f) {
41503 f.setValues(values);
41510 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
41511 * they are returned as an array.
41512 * @param {Boolean} asString
41515 getValues : function(asString){
41516 if (this.childForms) {
41517 // copy values from the child forms
41518 Roo.each(this.childForms, function (f) {
41519 this.setValues(f.getValues());
41525 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
41526 if(asString === true){
41529 return Roo.urlDecode(fs);
41533 * Returns the fields in this form as an object with key/value pairs.
41534 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
41537 getFieldValues : function(with_hidden)
41539 if (this.childForms) {
41540 // copy values from the child forms
41541 // should this call getFieldValues - probably not as we do not currently copy
41542 // hidden fields when we generate..
41543 Roo.each(this.childForms, function (f) {
41544 this.setValues(f.getValues());
41549 this.items.each(function(f){
41550 if (!f.getName()) {
41553 var v = f.getValue();
41554 // not sure if this supported any more..
41555 if ((typeof(v) == 'object') && f.getRawValue) {
41556 v = f.getRawValue() ; // dates..
41558 // combo boxes where name != hiddenName...
41559 if (f.name != f.getName()) {
41560 ret[f.name] = f.getRawValue();
41562 ret[f.getName()] = v;
41569 * Clears all invalid messages in this form.
41570 * @return {BasicForm} this
41572 clearInvalid : function(){
41573 this.items.each(function(f){
41577 Roo.each(this.childForms || [], function (f) {
41586 * Resets this form.
41587 * @return {BasicForm} this
41589 reset : function(){
41590 this.items.each(function(f){
41594 Roo.each(this.childForms || [], function (f) {
41603 * Add Roo.form components to this form.
41604 * @param {Field} field1
41605 * @param {Field} field2 (optional)
41606 * @param {Field} etc (optional)
41607 * @return {BasicForm} this
41610 this.items.addAll(Array.prototype.slice.call(arguments, 0));
41616 * Removes a field from the items collection (does NOT remove its markup).
41617 * @param {Field} field
41618 * @return {BasicForm} this
41620 remove : function(field){
41621 this.items.remove(field);
41626 * Looks at the fields in this form, checks them for an id attribute,
41627 * and calls applyTo on the existing dom element with that id.
41628 * @return {BasicForm} this
41630 render : function(){
41631 this.items.each(function(f){
41632 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
41640 * Calls {@link Ext#apply} for all fields in this form with the passed object.
41641 * @param {Object} values
41642 * @return {BasicForm} this
41644 applyToFields : function(o){
41645 this.items.each(function(f){
41652 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
41653 * @param {Object} values
41654 * @return {BasicForm} this
41656 applyIfToFields : function(o){
41657 this.items.each(function(f){
41665 Roo.BasicForm = Roo.form.BasicForm;/*
41667 * Ext JS Library 1.1.1
41668 * Copyright(c) 2006-2007, Ext JS, LLC.
41670 * Originally Released Under LGPL - original licence link has changed is not relivant.
41673 * <script type="text/javascript">
41677 * @class Roo.form.Form
41678 * @extends Roo.form.BasicForm
41679 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
41681 * @param {Object} config Configuration options
41683 Roo.form.Form = function(config){
41685 if (config.items) {
41686 xitems = config.items;
41687 delete config.items;
41691 Roo.form.Form.superclass.constructor.call(this, null, config);
41692 this.url = this.url || this.action;
41694 this.root = new Roo.form.Layout(Roo.applyIf({
41698 this.active = this.root;
41700 * Array of all the buttons that have been added to this form via {@link addButton}
41704 this.allItems = [];
41707 * @event clientvalidation
41708 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
41709 * @param {Form} this
41710 * @param {Boolean} valid true if the form has passed client-side validation
41712 clientvalidation: true,
41715 * Fires when the form is rendered
41716 * @param {Roo.form.Form} form
41721 if (this.progressUrl) {
41722 // push a hidden field onto the list of fields..
41726 name : 'UPLOAD_IDENTIFIER'
41731 Roo.each(xitems, this.addxtype, this);
41737 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
41739 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
41742 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
41745 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
41747 buttonAlign:'center',
41750 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
41755 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
41756 * This property cascades to child containers if not set.
41761 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
41762 * fires a looping event with that state. This is required to bind buttons to the valid
41763 * state using the config value formBind:true on the button.
41765 monitorValid : false,
41768 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
41773 * @cfg {String} progressUrl - Url to return progress data
41776 progressUrl : false,
41779 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
41780 * fields are added and the column is closed. If no fields are passed the column remains open
41781 * until end() is called.
41782 * @param {Object} config The config to pass to the column
41783 * @param {Field} field1 (optional)
41784 * @param {Field} field2 (optional)
41785 * @param {Field} etc (optional)
41786 * @return Column The column container object
41788 column : function(c){
41789 var col = new Roo.form.Column(c);
41791 if(arguments.length > 1){ // duplicate code required because of Opera
41792 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41799 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
41800 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
41801 * until end() is called.
41802 * @param {Object} config The config to pass to the fieldset
41803 * @param {Field} field1 (optional)
41804 * @param {Field} field2 (optional)
41805 * @param {Field} etc (optional)
41806 * @return FieldSet The fieldset container object
41808 fieldset : function(c){
41809 var fs = new Roo.form.FieldSet(c);
41811 if(arguments.length > 1){ // duplicate code required because of Opera
41812 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41819 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
41820 * fields are added and the container is closed. If no fields are passed the container remains open
41821 * until end() is called.
41822 * @param {Object} config The config to pass to the Layout
41823 * @param {Field} field1 (optional)
41824 * @param {Field} field2 (optional)
41825 * @param {Field} etc (optional)
41826 * @return Layout The container object
41828 container : function(c){
41829 var l = new Roo.form.Layout(c);
41831 if(arguments.length > 1){ // duplicate code required because of Opera
41832 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41839 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41840 * @param {Object} container A Roo.form.Layout or subclass of Layout
41841 * @return {Form} this
41843 start : function(c){
41844 // cascade label info
41845 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
41846 this.active.stack.push(c);
41847 c.ownerCt = this.active;
41853 * Closes the current open container
41854 * @return {Form} this
41857 if(this.active == this.root){
41860 this.active = this.active.ownerCt;
41865 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
41866 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
41867 * as the label of the field.
41868 * @param {Field} field1
41869 * @param {Field} field2 (optional)
41870 * @param {Field} etc. (optional)
41871 * @return {Form} this
41874 this.active.stack.push.apply(this.active.stack, arguments);
41875 this.allItems.push.apply(this.allItems,arguments);
41877 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
41878 if(a[i].isFormField){
41883 Roo.form.Form.superclass.add.apply(this, r);
41893 * Find any element that has been added to a form, using it's ID or name
41894 * This can include framesets, columns etc. along with regular fields..
41895 * @param {String} id - id or name to find.
41897 * @return {Element} e - or false if nothing found.
41899 findbyId : function(id)
41905 Roo.each(this.allItems, function(f){
41906 if (f.id == id || f.name == id ){
41917 * Render this form into the passed container. This should only be called once!
41918 * @param {String/HTMLElement/Element} container The element this component should be rendered into
41919 * @return {Form} this
41921 render : function(ct)
41927 var o = this.autoCreate || {
41929 method : this.method || 'POST',
41930 id : this.id || Roo.id()
41932 this.initEl(ct.createChild(o));
41934 this.root.render(this.el);
41938 this.items.each(function(f){
41939 f.render('x-form-el-'+f.id);
41942 if(this.buttons.length > 0){
41943 // tables are required to maintain order and for correct IE layout
41944 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
41945 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
41946 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
41948 var tr = tb.getElementsByTagName('tr')[0];
41949 for(var i = 0, len = this.buttons.length; i < len; i++) {
41950 var b = this.buttons[i];
41951 var td = document.createElement('td');
41952 td.className = 'x-form-btn-td';
41953 b.render(tr.appendChild(td));
41956 if(this.monitorValid){ // initialize after render
41957 this.startMonitoring();
41959 this.fireEvent('rendered', this);
41964 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
41965 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
41966 * object or a valid Roo.DomHelper element config
41967 * @param {Function} handler The function called when the button is clicked
41968 * @param {Object} scope (optional) The scope of the handler function
41969 * @return {Roo.Button}
41971 addButton : function(config, handler, scope){
41975 minWidth: this.minButtonWidth,
41978 if(typeof config == "string"){
41981 Roo.apply(bc, config);
41983 var btn = new Roo.Button(null, bc);
41984 this.buttons.push(btn);
41989 * Adds a series of form elements (using the xtype property as the factory method.
41990 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41991 * @param {Object} config
41994 addxtype : function()
41996 var ar = Array.prototype.slice.call(arguments, 0);
41998 for(var i = 0; i < ar.length; i++) {
42000 continue; // skip -- if this happends something invalid got sent, we
42001 // should ignore it, as basically that interface element will not show up
42002 // and that should be pretty obvious!!
42005 if (Roo.form[ar[i].xtype]) {
42007 var fe = Roo.factory(ar[i], Roo.form);
42013 fe.store.form = this;
42018 this.allItems.push(fe);
42019 if (fe.items && fe.addxtype) {
42020 fe.addxtype.apply(fe, fe.items);
42030 // console.log('adding ' + ar[i].xtype);
42032 if (ar[i].xtype == 'Button') {
42033 //console.log('adding button');
42034 //console.log(ar[i]);
42035 this.addButton(ar[i]);
42036 this.allItems.push(fe);
42040 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
42041 alert('end is not supported on xtype any more, use items');
42043 // //console.log('adding end');
42051 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
42052 * option "monitorValid"
42054 startMonitoring : function(){
42057 Roo.TaskMgr.start({
42058 run : this.bindHandler,
42059 interval : this.monitorPoll || 200,
42066 * Stops monitoring of the valid state of this form
42068 stopMonitoring : function(){
42069 this.bound = false;
42073 bindHandler : function(){
42075 return false; // stops binding
42078 this.items.each(function(f){
42079 if(!f.isValid(true)){
42084 for(var i = 0, len = this.buttons.length; i < len; i++){
42085 var btn = this.buttons[i];
42086 if(btn.formBind === true && btn.disabled === valid){
42087 btn.setDisabled(!valid);
42090 this.fireEvent('clientvalidation', this, valid);
42104 Roo.Form = Roo.form.Form;
42107 * Ext JS Library 1.1.1
42108 * Copyright(c) 2006-2007, Ext JS, LLC.
42110 * Originally Released Under LGPL - original licence link has changed is not relivant.
42113 * <script type="text/javascript">
42117 * @class Roo.form.Action
42118 * Internal Class used to handle form actions
42120 * @param {Roo.form.BasicForm} el The form element or its id
42121 * @param {Object} config Configuration options
42125 // define the action interface
42126 Roo.form.Action = function(form, options){
42128 this.options = options || {};
42131 * Client Validation Failed
42134 Roo.form.Action.CLIENT_INVALID = 'client';
42136 * Server Validation Failed
42139 Roo.form.Action.SERVER_INVALID = 'server';
42141 * Connect to Server Failed
42144 Roo.form.Action.CONNECT_FAILURE = 'connect';
42146 * Reading Data from Server Failed
42149 Roo.form.Action.LOAD_FAILURE = 'load';
42151 Roo.form.Action.prototype = {
42153 failureType : undefined,
42154 response : undefined,
42155 result : undefined,
42157 // interface method
42158 run : function(options){
42162 // interface method
42163 success : function(response){
42167 // interface method
42168 handleResponse : function(response){
42172 // default connection failure
42173 failure : function(response){
42175 this.response = response;
42176 this.failureType = Roo.form.Action.CONNECT_FAILURE;
42177 this.form.afterAction(this, false);
42180 processResponse : function(response){
42181 this.response = response;
42182 if(!response.responseText){
42185 this.result = this.handleResponse(response);
42186 return this.result;
42189 // utility functions used internally
42190 getUrl : function(appendParams){
42191 var url = this.options.url || this.form.url || this.form.el.dom.action;
42193 var p = this.getParams();
42195 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
42201 getMethod : function(){
42202 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
42205 getParams : function(){
42206 var bp = this.form.baseParams;
42207 var p = this.options.params;
42209 if(typeof p == "object"){
42210 p = Roo.urlEncode(Roo.applyIf(p, bp));
42211 }else if(typeof p == 'string' && bp){
42212 p += '&' + Roo.urlEncode(bp);
42215 p = Roo.urlEncode(bp);
42220 createCallback : function(){
42222 success: this.success,
42223 failure: this.failure,
42225 timeout: (this.form.timeout*1000),
42226 upload: this.form.fileUpload ? this.success : undefined
42231 Roo.form.Action.Submit = function(form, options){
42232 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
42235 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
42238 haveProgress : false,
42239 uploadComplete : false,
42241 // uploadProgress indicator.
42242 uploadProgress : function()
42244 if (!this.form.progressUrl) {
42248 if (!this.haveProgress) {
42249 Roo.MessageBox.progress("Uploading", "Uploading");
42251 if (this.uploadComplete) {
42252 Roo.MessageBox.hide();
42256 this.haveProgress = true;
42258 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
42260 var c = new Roo.data.Connection();
42262 url : this.form.progressUrl,
42267 success : function(req){
42268 //console.log(data);
42272 rdata = Roo.decode(req.responseText)
42274 Roo.log("Invalid data from server..");
42278 if (!rdata || !rdata.success) {
42282 var data = rdata.data;
42284 if (this.uploadComplete) {
42285 Roo.MessageBox.hide();
42290 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
42291 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
42294 this.uploadProgress.defer(2000,this);
42297 failure: function(data) {
42298 Roo.log('progress url failed ');
42309 // run get Values on the form, so it syncs any secondary forms.
42310 this.form.getValues();
42312 var o = this.options;
42313 var method = this.getMethod();
42314 var isPost = method == 'POST';
42315 if(o.clientValidation === false || this.form.isValid()){
42317 if (this.form.progressUrl) {
42318 this.form.findField('UPLOAD_IDENTIFIER').setValue(
42319 (new Date() * 1) + '' + Math.random());
42324 Roo.Ajax.request(Roo.apply(this.createCallback(), {
42325 form:this.form.el.dom,
42326 url:this.getUrl(!isPost),
42328 params:isPost ? this.getParams() : null,
42329 isUpload: this.form.fileUpload
42332 this.uploadProgress();
42334 }else if (o.clientValidation !== false){ // client validation failed
42335 this.failureType = Roo.form.Action.CLIENT_INVALID;
42336 this.form.afterAction(this, false);
42340 success : function(response)
42342 this.uploadComplete= true;
42343 if (this.haveProgress) {
42344 Roo.MessageBox.hide();
42348 var result = this.processResponse(response);
42349 if(result === true || result.success){
42350 this.form.afterAction(this, true);
42354 this.form.markInvalid(result.errors);
42355 this.failureType = Roo.form.Action.SERVER_INVALID;
42357 this.form.afterAction(this, false);
42359 failure : function(response)
42361 this.uploadComplete= true;
42362 if (this.haveProgress) {
42363 Roo.MessageBox.hide();
42366 this.response = response;
42367 this.failureType = Roo.form.Action.CONNECT_FAILURE;
42368 this.form.afterAction(this, false);
42371 handleResponse : function(response){
42372 if(this.form.errorReader){
42373 var rs = this.form.errorReader.read(response);
42376 for(var i = 0, len = rs.records.length; i < len; i++) {
42377 var r = rs.records[i];
42378 errors[i] = r.data;
42381 if(errors.length < 1){
42385 success : rs.success,
42391 ret = Roo.decode(response.responseText);
42395 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
42405 Roo.form.Action.Load = function(form, options){
42406 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
42407 this.reader = this.form.reader;
42410 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
42415 Roo.Ajax.request(Roo.apply(
42416 this.createCallback(), {
42417 method:this.getMethod(),
42418 url:this.getUrl(false),
42419 params:this.getParams()
42423 success : function(response){
42425 var result = this.processResponse(response);
42426 if(result === true || !result.success || !result.data){
42427 this.failureType = Roo.form.Action.LOAD_FAILURE;
42428 this.form.afterAction(this, false);
42431 this.form.clearInvalid();
42432 this.form.setValues(result.data);
42433 this.form.afterAction(this, true);
42436 handleResponse : function(response){
42437 if(this.form.reader){
42438 var rs = this.form.reader.read(response);
42439 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
42441 success : rs.success,
42445 return Roo.decode(response.responseText);
42449 Roo.form.Action.ACTION_TYPES = {
42450 'load' : Roo.form.Action.Load,
42451 'submit' : Roo.form.Action.Submit
42454 * Ext JS Library 1.1.1
42455 * Copyright(c) 2006-2007, Ext JS, LLC.
42457 * Originally Released Under LGPL - original licence link has changed is not relivant.
42460 * <script type="text/javascript">
42464 * @class Roo.form.Layout
42465 * @extends Roo.Component
42466 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
42468 * @param {Object} config Configuration options
42470 Roo.form.Layout = function(config){
42472 if (config.items) {
42473 xitems = config.items;
42474 delete config.items;
42476 Roo.form.Layout.superclass.constructor.call(this, config);
42478 Roo.each(xitems, this.addxtype, this);
42482 Roo.extend(Roo.form.Layout, Roo.Component, {
42484 * @cfg {String/Object} autoCreate
42485 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
42488 * @cfg {String/Object/Function} style
42489 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
42490 * a function which returns such a specification.
42493 * @cfg {String} labelAlign
42494 * Valid values are "left," "top" and "right" (defaults to "left")
42497 * @cfg {Number} labelWidth
42498 * Fixed width in pixels of all field labels (defaults to undefined)
42501 * @cfg {Boolean} clear
42502 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
42506 * @cfg {String} labelSeparator
42507 * The separator to use after field labels (defaults to ':')
42509 labelSeparator : ':',
42511 * @cfg {Boolean} hideLabels
42512 * True to suppress the display of field labels in this layout (defaults to false)
42514 hideLabels : false,
42517 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
42522 onRender : function(ct, position){
42523 if(this.el){ // from markup
42524 this.el = Roo.get(this.el);
42525 }else { // generate
42526 var cfg = this.getAutoCreate();
42527 this.el = ct.createChild(cfg, position);
42530 this.el.applyStyles(this.style);
42532 if(this.labelAlign){
42533 this.el.addClass('x-form-label-'+this.labelAlign);
42535 if(this.hideLabels){
42536 this.labelStyle = "display:none";
42537 this.elementStyle = "padding-left:0;";
42539 if(typeof this.labelWidth == 'number'){
42540 this.labelStyle = "width:"+this.labelWidth+"px;";
42541 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
42543 if(this.labelAlign == 'top'){
42544 this.labelStyle = "width:auto;";
42545 this.elementStyle = "padding-left:0;";
42548 var stack = this.stack;
42549 var slen = stack.length;
42551 if(!this.fieldTpl){
42552 var t = new Roo.Template(
42553 '<div class="x-form-item {5}">',
42554 '<label for="{0}" style="{2}">{1}{4}</label>',
42555 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
42557 '</div><div class="x-form-clear-left"></div>'
42559 t.disableFormats = true;
42561 Roo.form.Layout.prototype.fieldTpl = t;
42563 for(var i = 0; i < slen; i++) {
42564 if(stack[i].isFormField){
42565 this.renderField(stack[i]);
42567 this.renderComponent(stack[i]);
42572 this.el.createChild({cls:'x-form-clear'});
42577 renderField : function(f){
42578 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
42581 f.labelStyle||this.labelStyle||'', //2
42582 this.elementStyle||'', //3
42583 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
42584 f.itemCls||this.itemCls||'' //5
42585 ], true).getPrevSibling());
42589 renderComponent : function(c){
42590 c.render(c.isLayout ? this.el : this.el.createChild());
42593 * Adds a object form elements (using the xtype property as the factory method.)
42594 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
42595 * @param {Object} config
42597 addxtype : function(o)
42599 // create the lement.
42600 o.form = this.form;
42601 var fe = Roo.factory(o, Roo.form);
42602 this.form.allItems.push(fe);
42603 this.stack.push(fe);
42605 if (fe.isFormField) {
42606 this.form.items.add(fe);
42614 * @class Roo.form.Column
42615 * @extends Roo.form.Layout
42616 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
42618 * @param {Object} config Configuration options
42620 Roo.form.Column = function(config){
42621 Roo.form.Column.superclass.constructor.call(this, config);
42624 Roo.extend(Roo.form.Column, Roo.form.Layout, {
42626 * @cfg {Number/String} width
42627 * The fixed width of the column in pixels or CSS value (defaults to "auto")
42630 * @cfg {String/Object} autoCreate
42631 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
42635 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
42638 onRender : function(ct, position){
42639 Roo.form.Column.superclass.onRender.call(this, ct, position);
42641 this.el.setWidth(this.width);
42648 * @class Roo.form.Row
42649 * @extends Roo.form.Layout
42650 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
42652 * @param {Object} config Configuration options
42656 Roo.form.Row = function(config){
42657 Roo.form.Row.superclass.constructor.call(this, config);
42660 Roo.extend(Roo.form.Row, Roo.form.Layout, {
42662 * @cfg {Number/String} width
42663 * The fixed width of the column in pixels or CSS value (defaults to "auto")
42666 * @cfg {Number/String} height
42667 * The fixed height of the column in pixels or CSS value (defaults to "auto")
42669 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
42673 onRender : function(ct, position){
42674 //console.log('row render');
42676 var t = new Roo.Template(
42677 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
42678 '<label for="{0}" style="{2}">{1}{4}</label>',
42679 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
42683 t.disableFormats = true;
42685 Roo.form.Layout.prototype.rowTpl = t;
42687 this.fieldTpl = this.rowTpl;
42689 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
42690 var labelWidth = 100;
42692 if ((this.labelAlign != 'top')) {
42693 if (typeof this.labelWidth == 'number') {
42694 labelWidth = this.labelWidth
42696 this.padWidth = 20 + labelWidth;
42700 Roo.form.Column.superclass.onRender.call(this, ct, position);
42702 this.el.setWidth(this.width);
42705 this.el.setHeight(this.height);
42710 renderField : function(f){
42711 f.fieldEl = this.fieldTpl.append(this.el, [
42712 f.id, f.fieldLabel,
42713 f.labelStyle||this.labelStyle||'',
42714 this.elementStyle||'',
42715 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
42716 f.itemCls||this.itemCls||'',
42717 f.width ? f.width + this.padWidth : 160 + this.padWidth
42724 * @class Roo.form.FieldSet
42725 * @extends Roo.form.Layout
42726 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
42728 * @param {Object} config Configuration options
42730 Roo.form.FieldSet = function(config){
42731 Roo.form.FieldSet.superclass.constructor.call(this, config);
42734 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
42736 * @cfg {String} legend
42737 * The text to display as the legend for the FieldSet (defaults to '')
42740 * @cfg {String/Object} autoCreate
42741 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
42745 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
42748 onRender : function(ct, position){
42749 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
42751 this.setLegend(this.legend);
42756 setLegend : function(text){
42758 this.el.child('legend').update(text);
42763 * Ext JS Library 1.1.1
42764 * Copyright(c) 2006-2007, Ext JS, LLC.
42766 * Originally Released Under LGPL - original licence link has changed is not relivant.
42769 * <script type="text/javascript">
42772 * @class Roo.form.VTypes
42773 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
42776 Roo.form.VTypes = function(){
42777 // closure these in so they are only created once.
42778 var alpha = /^[a-zA-Z_]+$/;
42779 var alphanum = /^[a-zA-Z0-9_]+$/;
42780 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
42781 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
42783 // All these messages and functions are configurable
42786 * The function used to validate email addresses
42787 * @param {String} value The email address
42789 'email' : function(v){
42790 return email.test(v);
42793 * The error text to display when the email validation function returns false
42796 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
42798 * The keystroke filter mask to be applied on email input
42801 'emailMask' : /[a-z0-9_\.\-@]/i,
42804 * The function used to validate URLs
42805 * @param {String} value The URL
42807 'url' : function(v){
42808 return url.test(v);
42811 * The error text to display when the url validation function returns false
42814 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
42817 * The function used to validate alpha values
42818 * @param {String} value The value
42820 'alpha' : function(v){
42821 return alpha.test(v);
42824 * The error text to display when the alpha validation function returns false
42827 'alphaText' : 'This field should only contain letters and _',
42829 * The keystroke filter mask to be applied on alpha input
42832 'alphaMask' : /[a-z_]/i,
42835 * The function used to validate alphanumeric values
42836 * @param {String} value The value
42838 'alphanum' : function(v){
42839 return alphanum.test(v);
42842 * The error text to display when the alphanumeric validation function returns false
42845 'alphanumText' : 'This field should only contain letters, numbers and _',
42847 * The keystroke filter mask to be applied on alphanumeric input
42850 'alphanumMask' : /[a-z0-9_]/i
42852 }();//<script type="text/javascript">
42855 * @class Roo.form.FCKeditor
42856 * @extends Roo.form.TextArea
42857 * Wrapper around the FCKEditor http://www.fckeditor.net
42859 * Creates a new FCKeditor
42860 * @param {Object} config Configuration options
42862 Roo.form.FCKeditor = function(config){
42863 Roo.form.FCKeditor.superclass.constructor.call(this, config);
42866 * @event editorinit
42867 * Fired when the editor is initialized - you can add extra handlers here..
42868 * @param {FCKeditor} this
42869 * @param {Object} the FCK object.
42876 Roo.form.FCKeditor.editors = { };
42877 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
42879 //defaultAutoCreate : {
42880 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
42884 * @cfg {Object} fck options - see fck manual for details.
42889 * @cfg {Object} fck toolbar set (Basic or Default)
42891 toolbarSet : 'Basic',
42893 * @cfg {Object} fck BasePath
42895 basePath : '/fckeditor/',
42903 onRender : function(ct, position)
42906 this.defaultAutoCreate = {
42908 style:"width:300px;height:60px;",
42909 autocomplete: "off"
42912 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
42915 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
42916 if(this.preventScrollbars){
42917 this.el.setStyle("overflow", "hidden");
42919 this.el.setHeight(this.growMin);
42922 //console.log('onrender' + this.getId() );
42923 Roo.form.FCKeditor.editors[this.getId()] = this;
42926 this.replaceTextarea() ;
42930 getEditor : function() {
42931 return this.fckEditor;
42934 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
42935 * @param {Mixed} value The value to set
42939 setValue : function(value)
42941 //console.log('setValue: ' + value);
42943 if(typeof(value) == 'undefined') { // not sure why this is happending...
42946 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42948 //if(!this.el || !this.getEditor()) {
42949 // this.value = value;
42950 //this.setValue.defer(100,this,[value]);
42954 if(!this.getEditor()) {
42958 this.getEditor().SetData(value);
42965 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
42966 * @return {Mixed} value The field value
42968 getValue : function()
42971 if (this.frame && this.frame.dom.style.display == 'none') {
42972 return Roo.form.FCKeditor.superclass.getValue.call(this);
42975 if(!this.el || !this.getEditor()) {
42977 // this.getValue.defer(100,this);
42982 var value=this.getEditor().GetData();
42983 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42984 return Roo.form.FCKeditor.superclass.getValue.call(this);
42990 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
42991 * @return {Mixed} value The field value
42993 getRawValue : function()
42995 if (this.frame && this.frame.dom.style.display == 'none') {
42996 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42999 if(!this.el || !this.getEditor()) {
43000 //this.getRawValue.defer(100,this);
43007 var value=this.getEditor().GetData();
43008 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
43009 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
43013 setSize : function(w,h) {
43017 //if (this.frame && this.frame.dom.style.display == 'none') {
43018 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
43021 //if(!this.el || !this.getEditor()) {
43022 // this.setSize.defer(100,this, [w,h]);
43028 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
43030 this.frame.dom.setAttribute('width', w);
43031 this.frame.dom.setAttribute('height', h);
43032 this.frame.setSize(w,h);
43036 toggleSourceEdit : function(value) {
43040 this.el.dom.style.display = value ? '' : 'none';
43041 this.frame.dom.style.display = value ? 'none' : '';
43046 focus: function(tag)
43048 if (this.frame.dom.style.display == 'none') {
43049 return Roo.form.FCKeditor.superclass.focus.call(this);
43051 if(!this.el || !this.getEditor()) {
43052 this.focus.defer(100,this, [tag]);
43059 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
43060 this.getEditor().Focus();
43062 if (!this.getEditor().Selection.GetSelection()) {
43063 this.focus.defer(100,this, [tag]);
43068 var r = this.getEditor().EditorDocument.createRange();
43069 r.setStart(tgs[0],0);
43070 r.setEnd(tgs[0],0);
43071 this.getEditor().Selection.GetSelection().removeAllRanges();
43072 this.getEditor().Selection.GetSelection().addRange(r);
43073 this.getEditor().Focus();
43080 replaceTextarea : function()
43082 if ( document.getElementById( this.getId() + '___Frame' ) )
43084 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
43086 // We must check the elements firstly using the Id and then the name.
43087 var oTextarea = document.getElementById( this.getId() );
43089 var colElementsByName = document.getElementsByName( this.getId() ) ;
43091 oTextarea.style.display = 'none' ;
43093 if ( oTextarea.tabIndex ) {
43094 this.TabIndex = oTextarea.tabIndex ;
43097 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
43098 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
43099 this.frame = Roo.get(this.getId() + '___Frame')
43102 _getConfigHtml : function()
43106 for ( var o in this.fckconfig ) {
43107 sConfig += sConfig.length > 0 ? '&' : '';
43108 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
43111 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
43115 _getIFrameHtml : function()
43117 var sFile = 'fckeditor.html' ;
43118 /* no idea what this is about..
43121 if ( (/fcksource=true/i).test( window.top.location.search ) )
43122 sFile = 'fckeditor.original.html' ;
43127 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
43128 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
43131 var html = '<iframe id="' + this.getId() +
43132 '___Frame" src="' + sLink +
43133 '" width="' + this.width +
43134 '" height="' + this.height + '"' +
43135 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
43136 ' frameborder="0" scrolling="no"></iframe>' ;
43141 _insertHtmlBefore : function( html, element )
43143 if ( element.insertAdjacentHTML ) {
43145 element.insertAdjacentHTML( 'beforeBegin', html ) ;
43147 var oRange = document.createRange() ;
43148 oRange.setStartBefore( element ) ;
43149 var oFragment = oRange.createContextualFragment( html );
43150 element.parentNode.insertBefore( oFragment, element ) ;
43163 //Roo.reg('fckeditor', Roo.form.FCKeditor);
43165 function FCKeditor_OnComplete(editorInstance){
43166 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
43167 f.fckEditor = editorInstance;
43168 //console.log("loaded");
43169 f.fireEvent('editorinit', f, editorInstance);
43189 //<script type="text/javascript">
43191 * @class Roo.form.GridField
43192 * @extends Roo.form.Field
43193 * Embed a grid (or editable grid into a form)
43196 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
43198 * xgrid.store = Roo.data.Store
43199 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
43200 * xgrid.store.reader = Roo.data.JsonReader
43204 * Creates a new GridField
43205 * @param {Object} config Configuration options
43207 Roo.form.GridField = function(config){
43208 Roo.form.GridField.superclass.constructor.call(this, config);
43212 Roo.extend(Roo.form.GridField, Roo.form.Field, {
43214 * @cfg {Number} width - used to restrict width of grid..
43218 * @cfg {Number} height - used to restrict height of grid..
43222 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
43228 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43229 * {tag: "input", type: "checkbox", autocomplete: "off"})
43231 // defaultAutoCreate : { tag: 'div' },
43232 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
43234 * @cfg {String} addTitle Text to include for adding a title.
43238 onResize : function(){
43239 Roo.form.Field.superclass.onResize.apply(this, arguments);
43242 initEvents : function(){
43243 // Roo.form.Checkbox.superclass.initEvents.call(this);
43244 // has no events...
43249 getResizeEl : function(){
43253 getPositionEl : function(){
43258 onRender : function(ct, position){
43260 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
43261 var style = this.style;
43264 Roo.form.GridField.superclass.onRender.call(this, ct, position);
43265 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
43266 this.viewEl = this.wrap.createChild({ tag: 'div' });
43268 this.viewEl.applyStyles(style);
43271 this.viewEl.setWidth(this.width);
43274 this.viewEl.setHeight(this.height);
43276 //if(this.inputValue !== undefined){
43277 //this.setValue(this.value);
43280 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
43283 this.grid.render();
43284 this.grid.getDataSource().on('remove', this.refreshValue, this);
43285 this.grid.getDataSource().on('update', this.refreshValue, this);
43286 this.grid.on('afteredit', this.refreshValue, this);
43292 * Sets the value of the item.
43293 * @param {String} either an object or a string..
43295 setValue : function(v){
43297 v = v || []; // empty set..
43298 // this does not seem smart - it really only affects memoryproxy grids..
43299 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
43300 var ds = this.grid.getDataSource();
43301 // assumes a json reader..
43303 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
43304 ds.loadData( data);
43306 // clear selection so it does not get stale.
43307 if (this.grid.sm) {
43308 this.grid.sm.clearSelections();
43311 Roo.form.GridField.superclass.setValue.call(this, v);
43312 this.refreshValue();
43313 // should load data in the grid really....
43317 refreshValue: function() {
43319 this.grid.getDataSource().each(function(r) {
43322 this.el.dom.value = Roo.encode(val);
43330 * Ext JS Library 1.1.1
43331 * Copyright(c) 2006-2007, Ext JS, LLC.
43333 * Originally Released Under LGPL - original licence link has changed is not relivant.
43336 * <script type="text/javascript">
43339 * @class Roo.form.DisplayField
43340 * @extends Roo.form.Field
43341 * A generic Field to display non-editable data.
43343 * Creates a new Display Field item.
43344 * @param {Object} config Configuration options
43346 Roo.form.DisplayField = function(config){
43347 Roo.form.DisplayField.superclass.constructor.call(this, config);
43351 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
43352 inputType: 'hidden',
43358 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43360 focusClass : undefined,
43362 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43364 fieldClass: 'x-form-field',
43367 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
43369 valueRenderer: undefined,
43373 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43374 * {tag: "input", type: "checkbox", autocomplete: "off"})
43377 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
43379 onResize : function(){
43380 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
43384 initEvents : function(){
43385 // Roo.form.Checkbox.superclass.initEvents.call(this);
43386 // has no events...
43391 getResizeEl : function(){
43395 getPositionEl : function(){
43400 onRender : function(ct, position){
43402 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
43403 //if(this.inputValue !== undefined){
43404 this.wrap = this.el.wrap();
43406 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
43408 if (this.bodyStyle) {
43409 this.viewEl.applyStyles(this.bodyStyle);
43411 //this.viewEl.setStyle('padding', '2px');
43413 this.setValue(this.value);
43418 initValue : Roo.emptyFn,
43423 onClick : function(){
43428 * Sets the checked state of the checkbox.
43429 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
43431 setValue : function(v){
43433 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
43434 // this might be called before we have a dom element..
43435 if (!this.viewEl) {
43438 this.viewEl.dom.innerHTML = html;
43439 Roo.form.DisplayField.superclass.setValue.call(this, v);
43449 * @class Roo.form.DayPicker
43450 * @extends Roo.form.Field
43451 * A Day picker show [M] [T] [W] ....
43453 * Creates a new Day Picker
43454 * @param {Object} config Configuration options
43456 Roo.form.DayPicker= function(config){
43457 Roo.form.DayPicker.superclass.constructor.call(this, config);
43461 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
43463 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43465 focusClass : undefined,
43467 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43469 fieldClass: "x-form-field",
43472 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43473 * {tag: "input", type: "checkbox", autocomplete: "off"})
43475 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
43478 actionMode : 'viewEl',
43482 inputType : 'hidden',
43485 inputElement: false, // real input element?
43486 basedOn: false, // ????
43488 isFormField: true, // not sure where this is needed!!!!
43490 onResize : function(){
43491 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
43492 if(!this.boxLabel){
43493 this.el.alignTo(this.wrap, 'c-c');
43497 initEvents : function(){
43498 Roo.form.Checkbox.superclass.initEvents.call(this);
43499 this.el.on("click", this.onClick, this);
43500 this.el.on("change", this.onClick, this);
43504 getResizeEl : function(){
43508 getPositionEl : function(){
43514 onRender : function(ct, position){
43515 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43517 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
43519 var r1 = '<table><tr>';
43520 var r2 = '<tr class="x-form-daypick-icons">';
43521 for (var i=0; i < 7; i++) {
43522 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
43523 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
43526 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
43527 viewEl.select('img').on('click', this.onClick, this);
43528 this.viewEl = viewEl;
43531 // this will not work on Chrome!!!
43532 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43533 this.el.on('propertychange', this.setFromHidden, this); //ie
43541 initValue : Roo.emptyFn,
43544 * Returns the checked state of the checkbox.
43545 * @return {Boolean} True if checked, else false
43547 getValue : function(){
43548 return this.el.dom.value;
43553 onClick : function(e){
43554 //this.setChecked(!this.checked);
43555 Roo.get(e.target).toggleClass('x-menu-item-checked');
43556 this.refreshValue();
43557 //if(this.el.dom.checked != this.checked){
43558 // this.setValue(this.el.dom.checked);
43563 refreshValue : function()
43566 this.viewEl.select('img',true).each(function(e,i,n) {
43567 val += e.is(".x-menu-item-checked") ? String(n) : '';
43569 this.setValue(val, true);
43573 * Sets the checked state of the checkbox.
43574 * On is always based on a string comparison between inputValue and the param.
43575 * @param {Boolean/String} value - the value to set
43576 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
43578 setValue : function(v,suppressEvent){
43579 if (!this.el.dom) {
43582 var old = this.el.dom.value ;
43583 this.el.dom.value = v;
43584 if (suppressEvent) {
43588 // update display..
43589 this.viewEl.select('img',true).each(function(e,i,n) {
43591 var on = e.is(".x-menu-item-checked");
43592 var newv = v.indexOf(String(n)) > -1;
43594 e.toggleClass('x-menu-item-checked');
43600 this.fireEvent('change', this, v, old);
43605 // handle setting of hidden value by some other method!!?!?
43606 setFromHidden: function()
43611 //console.log("SET FROM HIDDEN");
43612 //alert('setFrom hidden');
43613 this.setValue(this.el.dom.value);
43616 onDestroy : function()
43619 Roo.get(this.viewEl).remove();
43622 Roo.form.DayPicker.superclass.onDestroy.call(this);
43626 * RooJS Library 1.1.1
43627 * Copyright(c) 2008-2011 Alan Knowles
43634 * @class Roo.form.ComboCheck
43635 * @extends Roo.form.ComboBox
43636 * A combobox for multiple select items.
43638 * FIXME - could do with a reset button..
43641 * Create a new ComboCheck
43642 * @param {Object} config Configuration options
43644 Roo.form.ComboCheck = function(config){
43645 Roo.form.ComboCheck.superclass.constructor.call(this, config);
43646 // should verify some data...
43648 // hiddenName = required..
43649 // displayField = required
43650 // valudField == required
43651 var req= [ 'hiddenName', 'displayField', 'valueField' ];
43653 Roo.each(req, function(e) {
43654 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
43655 throw "Roo.form.ComboCheck : missing value for: " + e;
43662 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
43667 selectedClass: 'x-menu-item-checked',
43670 onRender : function(ct, position){
43676 var cls = 'x-combo-list';
43679 this.tpl = new Roo.Template({
43680 html : '<div class="'+cls+'-item x-menu-check-item">' +
43681 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
43682 '<span>{' + this.displayField + '}</span>' +
43689 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
43690 this.view.singleSelect = false;
43691 this.view.multiSelect = true;
43692 this.view.toggleSelect = true;
43693 this.pageTb.add(new Roo.Toolbar.Fill(), {
43696 handler: function()
43703 onViewOver : function(e, t){
43709 onViewClick : function(doFocus,index){
43713 select: function () {
43714 //Roo.log("SELECT CALLED");
43717 selectByValue : function(xv, scrollIntoView){
43718 var ar = this.getValueArray();
43721 Roo.each(ar, function(v) {
43722 if(v === undefined || v === null){
43725 var r = this.findRecord(this.valueField, v);
43727 sels.push(this.store.indexOf(r))
43731 this.view.select(sels);
43737 onSelect : function(record, index){
43738 // Roo.log("onselect Called");
43739 // this is only called by the clear button now..
43740 this.view.clearSelections();
43741 this.setValue('[]');
43742 if (this.value != this.valueBefore) {
43743 this.fireEvent('change', this, this.value, this.valueBefore);
43746 getValueArray : function()
43751 //Roo.log(this.value);
43752 if (typeof(this.value) == 'undefined') {
43755 var ar = Roo.decode(this.value);
43756 return ar instanceof Array ? ar : []; //?? valid?
43759 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
43764 expand : function ()
43766 Roo.form.ComboCheck.superclass.expand.call(this);
43767 this.valueBefore = this.value;
43772 collapse : function(){
43773 Roo.form.ComboCheck.superclass.collapse.call(this);
43774 var sl = this.view.getSelectedIndexes();
43775 var st = this.store;
43779 Roo.each(sl, function(i) {
43781 nv.push(r.get(this.valueField));
43783 this.setValue(Roo.encode(nv));
43784 if (this.value != this.valueBefore) {
43786 this.fireEvent('change', this, this.value, this.valueBefore);
43791 setValue : function(v){
43795 var vals = this.getValueArray();
43797 Roo.each(vals, function(k) {
43798 var r = this.findRecord(this.valueField, k);
43800 tv.push(r.data[this.displayField]);
43801 }else if(this.valueNotFoundText !== undefined){
43802 tv.push( this.valueNotFoundText );
43807 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
43808 this.hiddenField.value = v;
43812 });//<script type="text/javasscript">
43816 * @class Roo.DDView
43817 * A DnD enabled version of Roo.View.
43818 * @param {Element/String} container The Element in which to create the View.
43819 * @param {String} tpl The template string used to create the markup for each element of the View
43820 * @param {Object} config The configuration properties. These include all the config options of
43821 * {@link Roo.View} plus some specific to this class.<br>
43823 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
43824 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
43826 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
43827 .x-view-drag-insert-above {
43828 border-top:1px dotted #3366cc;
43830 .x-view-drag-insert-below {
43831 border-bottom:1px dotted #3366cc;
43837 Roo.DDView = function(container, tpl, config) {
43838 Roo.DDView.superclass.constructor.apply(this, arguments);
43839 this.getEl().setStyle("outline", "0px none");
43840 this.getEl().unselectable();
43841 if (this.dragGroup) {
43842 this.setDraggable(this.dragGroup.split(","));
43844 if (this.dropGroup) {
43845 this.setDroppable(this.dropGroup.split(","));
43847 if (this.deletable) {
43848 this.setDeletable();
43850 this.isDirtyFlag = false;
43856 Roo.extend(Roo.DDView, Roo.View, {
43857 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
43858 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
43859 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
43860 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
43864 reset: Roo.emptyFn,
43866 clearInvalid: Roo.form.Field.prototype.clearInvalid,
43868 validate: function() {
43872 destroy: function() {
43873 this.purgeListeners();
43874 this.getEl.removeAllListeners();
43875 this.getEl().remove();
43876 if (this.dragZone) {
43877 if (this.dragZone.destroy) {
43878 this.dragZone.destroy();
43881 if (this.dropZone) {
43882 if (this.dropZone.destroy) {
43883 this.dropZone.destroy();
43888 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
43889 getName: function() {
43893 /** Loads the View from a JSON string representing the Records to put into the Store. */
43894 setValue: function(v) {
43896 throw "DDView.setValue(). DDView must be constructed with a valid Store";
43899 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
43900 this.store.proxy = new Roo.data.MemoryProxy(data);
43904 /** @return {String} a parenthesised list of the ids of the Records in the View. */
43905 getValue: function() {
43907 this.store.each(function(rec) {
43908 result += rec.id + ',';
43910 return result.substr(0, result.length - 1) + ')';
43913 getIds: function() {
43914 var i = 0, result = new Array(this.store.getCount());
43915 this.store.each(function(rec) {
43916 result[i++] = rec.id;
43921 isDirty: function() {
43922 return this.isDirtyFlag;
43926 * Part of the Roo.dd.DropZone interface. If no target node is found, the
43927 * whole Element becomes the target, and this causes the drop gesture to append.
43929 getTargetFromEvent : function(e) {
43930 var target = e.getTarget();
43931 while ((target !== null) && (target.parentNode != this.el.dom)) {
43932 target = target.parentNode;
43935 target = this.el.dom.lastChild || this.el.dom;
43941 * Create the drag data which consists of an object which has the property "ddel" as
43942 * the drag proxy element.
43944 getDragData : function(e) {
43945 var target = this.findItemFromChild(e.getTarget());
43947 this.handleSelection(e);
43948 var selNodes = this.getSelectedNodes();
43951 copy: this.copy || (this.allowCopy && e.ctrlKey),
43955 var selectedIndices = this.getSelectedIndexes();
43956 for (var i = 0; i < selectedIndices.length; i++) {
43957 dragData.records.push(this.store.getAt(selectedIndices[i]));
43959 if (selNodes.length == 1) {
43960 dragData.ddel = target.cloneNode(true); // the div element
43962 var div = document.createElement('div'); // create the multi element drag "ghost"
43963 div.className = 'multi-proxy';
43964 for (var i = 0, len = selNodes.length; i < len; i++) {
43965 div.appendChild(selNodes[i].cloneNode(true));
43967 dragData.ddel = div;
43969 //console.log(dragData)
43970 //console.log(dragData.ddel.innerHTML)
43973 //console.log('nodragData')
43977 /** Specify to which ddGroup items in this DDView may be dragged. */
43978 setDraggable: function(ddGroup) {
43979 if (ddGroup instanceof Array) {
43980 Roo.each(ddGroup, this.setDraggable, this);
43983 if (this.dragZone) {
43984 this.dragZone.addToGroup(ddGroup);
43986 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
43987 containerScroll: true,
43991 // Draggability implies selection. DragZone's mousedown selects the element.
43992 if (!this.multiSelect) { this.singleSelect = true; }
43994 // Wire the DragZone's handlers up to methods in *this*
43995 this.dragZone.getDragData = this.getDragData.createDelegate(this);
43999 /** Specify from which ddGroup this DDView accepts drops. */
44000 setDroppable: function(ddGroup) {
44001 if (ddGroup instanceof Array) {
44002 Roo.each(ddGroup, this.setDroppable, this);
44005 if (this.dropZone) {
44006 this.dropZone.addToGroup(ddGroup);
44008 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
44009 containerScroll: true,
44013 // Wire the DropZone's handlers up to methods in *this*
44014 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
44015 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
44016 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
44017 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
44018 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
44022 /** Decide whether to drop above or below a View node. */
44023 getDropPoint : function(e, n, dd){
44024 if (n == this.el.dom) { return "above"; }
44025 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
44026 var c = t + (b - t) / 2;
44027 var y = Roo.lib.Event.getPageY(e);
44035 onNodeEnter : function(n, dd, e, data){
44039 onNodeOver : function(n, dd, e, data){
44040 var pt = this.getDropPoint(e, n, dd);
44041 // set the insert point style on the target node
44042 var dragElClass = this.dropNotAllowed;
44045 if (pt == "above"){
44046 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
44047 targetElClass = "x-view-drag-insert-above";
44049 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
44050 targetElClass = "x-view-drag-insert-below";
44052 if (this.lastInsertClass != targetElClass){
44053 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
44054 this.lastInsertClass = targetElClass;
44057 return dragElClass;
44060 onNodeOut : function(n, dd, e, data){
44061 this.removeDropIndicators(n);
44064 onNodeDrop : function(n, dd, e, data){
44065 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
44068 var pt = this.getDropPoint(e, n, dd);
44069 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
44070 if (pt == "below") { insertAt++; }
44071 for (var i = 0; i < data.records.length; i++) {
44072 var r = data.records[i];
44073 var dup = this.store.getById(r.id);
44074 if (dup && (dd != this.dragZone)) {
44075 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
44078 this.store.insert(insertAt++, r.copy());
44080 data.source.isDirtyFlag = true;
44082 this.store.insert(insertAt++, r);
44084 this.isDirtyFlag = true;
44087 this.dragZone.cachedTarget = null;
44091 removeDropIndicators : function(n){
44093 Roo.fly(n).removeClass([
44094 "x-view-drag-insert-above",
44095 "x-view-drag-insert-below"]);
44096 this.lastInsertClass = "_noclass";
44101 * Utility method. Add a delete option to the DDView's context menu.
44102 * @param {String} imageUrl The URL of the "delete" icon image.
44104 setDeletable: function(imageUrl) {
44105 if (!this.singleSelect && !this.multiSelect) {
44106 this.singleSelect = true;
44108 var c = this.getContextMenu();
44109 this.contextMenu.on("itemclick", function(item) {
44112 this.remove(this.getSelectedIndexes());
44116 this.contextMenu.add({
44123 /** Return the context menu for this DDView. */
44124 getContextMenu: function() {
44125 if (!this.contextMenu) {
44126 // Create the View's context menu
44127 this.contextMenu = new Roo.menu.Menu({
44128 id: this.id + "-contextmenu"
44130 this.el.on("contextmenu", this.showContextMenu, this);
44132 return this.contextMenu;
44135 disableContextMenu: function() {
44136 if (this.contextMenu) {
44137 this.el.un("contextmenu", this.showContextMenu, this);
44141 showContextMenu: function(e, item) {
44142 item = this.findItemFromChild(e.getTarget());
44145 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
44146 this.contextMenu.showAt(e.getXY());
44151 * Remove {@link Roo.data.Record}s at the specified indices.
44152 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
44154 remove: function(selectedIndices) {
44155 selectedIndices = [].concat(selectedIndices);
44156 for (var i = 0; i < selectedIndices.length; i++) {
44157 var rec = this.store.getAt(selectedIndices[i]);
44158 this.store.remove(rec);
44163 * Double click fires the event, but also, if this is draggable, and there is only one other
44164 * related DropZone, it transfers the selected node.
44166 onDblClick : function(e){
44167 var item = this.findItemFromChild(e.getTarget());
44169 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
44172 if (this.dragGroup) {
44173 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
44174 while (targets.indexOf(this.dropZone) > -1) {
44175 targets.remove(this.dropZone);
44177 if (targets.length == 1) {
44178 this.dragZone.cachedTarget = null;
44179 var el = Roo.get(targets[0].getEl());
44180 var box = el.getBox(true);
44181 targets[0].onNodeDrop(el.dom, {
44183 xy: [box.x, box.y + box.height - 1]
44184 }, null, this.getDragData(e));
44190 handleSelection: function(e) {
44191 this.dragZone.cachedTarget = null;
44192 var item = this.findItemFromChild(e.getTarget());
44194 this.clearSelections(true);
44197 if (item && (this.multiSelect || this.singleSelect)){
44198 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
44199 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
44200 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
44201 this.unselect(item);
44203 this.select(item, this.multiSelect && e.ctrlKey);
44204 this.lastSelection = item;
44209 onItemClick : function(item, index, e){
44210 if(this.fireEvent("beforeclick", this, index, item, e) === false){
44216 unselect : function(nodeInfo, suppressEvent){
44217 var node = this.getNode(nodeInfo);
44218 if(node && this.isSelected(node)){
44219 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
44220 Roo.fly(node).removeClass(this.selectedClass);
44221 this.selections.remove(node);
44222 if(!suppressEvent){
44223 this.fireEvent("selectionchange", this, this.selections);
44231 * Ext JS Library 1.1.1
44232 * Copyright(c) 2006-2007, Ext JS, LLC.
44234 * Originally Released Under LGPL - original licence link has changed is not relivant.
44237 * <script type="text/javascript">
44241 * @class Roo.LayoutManager
44242 * @extends Roo.util.Observable
44243 * Base class for layout managers.
44245 Roo.LayoutManager = function(container, config){
44246 Roo.LayoutManager.superclass.constructor.call(this);
44247 this.el = Roo.get(container);
44248 // ie scrollbar fix
44249 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
44250 document.body.scroll = "no";
44251 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
44252 this.el.position('relative');
44254 this.id = this.el.id;
44255 this.el.addClass("x-layout-container");
44256 /** false to disable window resize monitoring @type Boolean */
44257 this.monitorWindowResize = true;
44262 * Fires when a layout is performed.
44263 * @param {Roo.LayoutManager} this
44267 * @event regionresized
44268 * Fires when the user resizes a region.
44269 * @param {Roo.LayoutRegion} region The resized region
44270 * @param {Number} newSize The new size (width for east/west, height for north/south)
44272 "regionresized" : true,
44274 * @event regioncollapsed
44275 * Fires when a region is collapsed.
44276 * @param {Roo.LayoutRegion} region The collapsed region
44278 "regioncollapsed" : true,
44280 * @event regionexpanded
44281 * Fires when a region is expanded.
44282 * @param {Roo.LayoutRegion} region The expanded region
44284 "regionexpanded" : true
44286 this.updating = false;
44287 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
44290 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
44292 * Returns true if this layout is currently being updated
44293 * @return {Boolean}
44295 isUpdating : function(){
44296 return this.updating;
44300 * Suspend the LayoutManager from doing auto-layouts while
44301 * making multiple add or remove calls
44303 beginUpdate : function(){
44304 this.updating = true;
44308 * Restore auto-layouts and optionally disable the manager from performing a layout
44309 * @param {Boolean} noLayout true to disable a layout update
44311 endUpdate : function(noLayout){
44312 this.updating = false;
44318 layout: function(){
44322 onRegionResized : function(region, newSize){
44323 this.fireEvent("regionresized", region, newSize);
44327 onRegionCollapsed : function(region){
44328 this.fireEvent("regioncollapsed", region);
44331 onRegionExpanded : function(region){
44332 this.fireEvent("regionexpanded", region);
44336 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
44337 * performs box-model adjustments.
44338 * @return {Object} The size as an object {width: (the width), height: (the height)}
44340 getViewSize : function(){
44342 if(this.el.dom != document.body){
44343 size = this.el.getSize();
44345 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
44347 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
44348 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
44353 * Returns the Element this layout is bound to.
44354 * @return {Roo.Element}
44356 getEl : function(){
44361 * Returns the specified region.
44362 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
44363 * @return {Roo.LayoutRegion}
44365 getRegion : function(target){
44366 return this.regions[target.toLowerCase()];
44369 onWindowResize : function(){
44370 if(this.monitorWindowResize){
44376 * Ext JS Library 1.1.1
44377 * Copyright(c) 2006-2007, Ext JS, LLC.
44379 * Originally Released Under LGPL - original licence link has changed is not relivant.
44382 * <script type="text/javascript">
44385 * @class Roo.BorderLayout
44386 * @extends Roo.LayoutManager
44387 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
44388 * please see: <br><br>
44389 * <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>
44390 * <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>
44393 var layout = new Roo.BorderLayout(document.body, {
44427 preferredTabWidth: 150
44432 var CP = Roo.ContentPanel;
44434 layout.beginUpdate();
44435 layout.add("north", new CP("north", "North"));
44436 layout.add("south", new CP("south", {title: "South", closable: true}));
44437 layout.add("west", new CP("west", {title: "West"}));
44438 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
44439 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
44440 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
44441 layout.getRegion("center").showPanel("center1");
44442 layout.endUpdate();
44445 <b>The container the layout is rendered into can be either the body element or any other element.
44446 If it is not the body element, the container needs to either be an absolute positioned element,
44447 or you will need to add "position:relative" to the css of the container. You will also need to specify
44448 the container size if it is not the body element.</b>
44451 * Create a new BorderLayout
44452 * @param {String/HTMLElement/Element} container The container this layout is bound to
44453 * @param {Object} config Configuration options
44455 Roo.BorderLayout = function(container, config){
44456 config = config || {};
44457 Roo.BorderLayout.superclass.constructor.call(this, container, config);
44458 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
44459 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
44460 var target = this.factory.validRegions[i];
44461 if(config[target]){
44462 this.addRegion(target, config[target]);
44467 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
44469 * Creates and adds a new region if it doesn't already exist.
44470 * @param {String} target The target region key (north, south, east, west or center).
44471 * @param {Object} config The regions config object
44472 * @return {BorderLayoutRegion} The new region
44474 addRegion : function(target, config){
44475 if(!this.regions[target]){
44476 var r = this.factory.create(target, this, config);
44477 this.bindRegion(target, r);
44479 return this.regions[target];
44483 bindRegion : function(name, r){
44484 this.regions[name] = r;
44485 r.on("visibilitychange", this.layout, this);
44486 r.on("paneladded", this.layout, this);
44487 r.on("panelremoved", this.layout, this);
44488 r.on("invalidated", this.layout, this);
44489 r.on("resized", this.onRegionResized, this);
44490 r.on("collapsed", this.onRegionCollapsed, this);
44491 r.on("expanded", this.onRegionExpanded, this);
44495 * Performs a layout update.
44497 layout : function(){
44498 if(this.updating) return;
44499 var size = this.getViewSize();
44500 var w = size.width;
44501 var h = size.height;
44506 //var x = 0, y = 0;
44508 var rs = this.regions;
44509 var north = rs["north"];
44510 var south = rs["south"];
44511 var west = rs["west"];
44512 var east = rs["east"];
44513 var center = rs["center"];
44514 //if(this.hideOnLayout){ // not supported anymore
44515 //c.el.setStyle("display", "none");
44517 if(north && north.isVisible()){
44518 var b = north.getBox();
44519 var m = north.getMargins();
44520 b.width = w - (m.left+m.right);
44523 centerY = b.height + b.y + m.bottom;
44524 centerH -= centerY;
44525 north.updateBox(this.safeBox(b));
44527 if(south && south.isVisible()){
44528 var b = south.getBox();
44529 var m = south.getMargins();
44530 b.width = w - (m.left+m.right);
44532 var totalHeight = (b.height + m.top + m.bottom);
44533 b.y = h - totalHeight + m.top;
44534 centerH -= totalHeight;
44535 south.updateBox(this.safeBox(b));
44537 if(west && west.isVisible()){
44538 var b = west.getBox();
44539 var m = west.getMargins();
44540 b.height = centerH - (m.top+m.bottom);
44542 b.y = centerY + m.top;
44543 var totalWidth = (b.width + m.left + m.right);
44544 centerX += totalWidth;
44545 centerW -= totalWidth;
44546 west.updateBox(this.safeBox(b));
44548 if(east && east.isVisible()){
44549 var b = east.getBox();
44550 var m = east.getMargins();
44551 b.height = centerH - (m.top+m.bottom);
44552 var totalWidth = (b.width + m.left + m.right);
44553 b.x = w - totalWidth + m.left;
44554 b.y = centerY + m.top;
44555 centerW -= totalWidth;
44556 east.updateBox(this.safeBox(b));
44559 var m = center.getMargins();
44561 x: centerX + m.left,
44562 y: centerY + m.top,
44563 width: centerW - (m.left+m.right),
44564 height: centerH - (m.top+m.bottom)
44566 //if(this.hideOnLayout){
44567 //center.el.setStyle("display", "block");
44569 center.updateBox(this.safeBox(centerBox));
44572 this.fireEvent("layout", this);
44576 safeBox : function(box){
44577 box.width = Math.max(0, box.width);
44578 box.height = Math.max(0, box.height);
44583 * Adds a ContentPanel (or subclass) to this layout.
44584 * @param {String} target The target region key (north, south, east, west or center).
44585 * @param {Roo.ContentPanel} panel The panel to add
44586 * @return {Roo.ContentPanel} The added panel
44588 add : function(target, panel){
44590 target = target.toLowerCase();
44591 return this.regions[target].add(panel);
44595 * Remove a ContentPanel (or subclass) to this layout.
44596 * @param {String} target The target region key (north, south, east, west or center).
44597 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
44598 * @return {Roo.ContentPanel} The removed panel
44600 remove : function(target, panel){
44601 target = target.toLowerCase();
44602 return this.regions[target].remove(panel);
44606 * Searches all regions for a panel with the specified id
44607 * @param {String} panelId
44608 * @return {Roo.ContentPanel} The panel or null if it wasn't found
44610 findPanel : function(panelId){
44611 var rs = this.regions;
44612 for(var target in rs){
44613 if(typeof rs[target] != "function"){
44614 var p = rs[target].getPanel(panelId);
44624 * Searches all regions for a panel with the specified id and activates (shows) it.
44625 * @param {String/ContentPanel} panelId The panels id or the panel itself
44626 * @return {Roo.ContentPanel} The shown panel or null
44628 showPanel : function(panelId) {
44629 var rs = this.regions;
44630 for(var target in rs){
44631 var r = rs[target];
44632 if(typeof r != "function"){
44633 if(r.hasPanel(panelId)){
44634 return r.showPanel(panelId);
44642 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
44643 * @param {Roo.state.Provider} provider (optional) An alternate state provider
44645 restoreState : function(provider){
44647 provider = Roo.state.Manager;
44649 var sm = new Roo.LayoutStateManager();
44650 sm.init(this, provider);
44654 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
44655 * object should contain properties for each region to add ContentPanels to, and each property's value should be
44656 * a valid ContentPanel config object. Example:
44658 // Create the main layout
44659 var layout = new Roo.BorderLayout('main-ct', {
44670 // Create and add multiple ContentPanels at once via configs
44673 id: 'source-files',
44675 title:'Ext Source Files',
44688 * @param {Object} regions An object containing ContentPanel configs by region name
44690 batchAdd : function(regions){
44691 this.beginUpdate();
44692 for(var rname in regions){
44693 var lr = this.regions[rname];
44695 this.addTypedPanels(lr, regions[rname]);
44702 addTypedPanels : function(lr, ps){
44703 if(typeof ps == 'string'){
44704 lr.add(new Roo.ContentPanel(ps));
44706 else if(ps instanceof Array){
44707 for(var i =0, len = ps.length; i < len; i++){
44708 this.addTypedPanels(lr, ps[i]);
44711 else if(!ps.events){ // raw config?
44713 delete ps.el; // prevent conflict
44714 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
44716 else { // panel object assumed!
44721 * Adds a xtype elements to the layout.
44725 xtype : 'ContentPanel',
44732 xtype : 'NestedLayoutPanel',
44738 items : [ ... list of content panels or nested layout panels.. ]
44742 * @param {Object} cfg Xtype definition of item to add.
44744 addxtype : function(cfg)
44746 // basically accepts a pannel...
44747 // can accept a layout region..!?!?
44748 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
44750 if (!cfg.xtype.match(/Panel$/)) {
44755 if (typeof(cfg.region) == 'undefined') {
44756 Roo.log("Failed to add Panel, region was not set");
44760 var region = cfg.region;
44766 xitems = cfg.items;
44773 case 'ContentPanel': // ContentPanel (el, cfg)
44774 case 'ScrollPanel': // ContentPanel (el, cfg)
44775 if(cfg.autoCreate) {
44776 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
44778 var el = this.el.createChild();
44779 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
44782 this.add(region, ret);
44786 case 'TreePanel': // our new panel!
44787 cfg.el = this.el.createChild();
44788 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
44789 this.add(region, ret);
44792 case 'NestedLayoutPanel':
44793 // create a new Layout (which is a Border Layout...
44794 var el = this.el.createChild();
44795 var clayout = cfg.layout;
44797 clayout.items = clayout.items || [];
44798 // replace this exitems with the clayout ones..
44799 xitems = clayout.items;
44802 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
44803 cfg.background = false;
44805 var layout = new Roo.BorderLayout(el, clayout);
44807 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
44808 //console.log('adding nested layout panel ' + cfg.toSource());
44809 this.add(region, ret);
44810 nb = {}; /// find first...
44815 // needs grid and region
44817 //var el = this.getRegion(region).el.createChild();
44818 var el = this.el.createChild();
44819 // create the grid first...
44821 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
44823 if (region == 'center' && this.active ) {
44824 cfg.background = false;
44826 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
44828 this.add(region, ret);
44829 if (cfg.background) {
44830 ret.on('activate', function(gp) {
44831 if (!gp.grid.rendered) {
44844 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
44846 // GridPanel (grid, cfg)
44849 this.beginUpdate();
44852 Roo.each(xitems, function(i) {
44853 region = nb && i.region && !i.background ? i.region : false;
44855 var add = ret.addxtype(i);
44863 // make the last non-background panel active..
44864 //if (nb) { Roo.log(nb); }
44868 region = this.getRegion(r);
44880 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
44881 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
44882 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
44883 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
44886 var CP = Roo.ContentPanel;
44888 var layout = Roo.BorderLayout.create({
44892 panels: [new CP("north", "North")]
44901 panels: [new CP("west", {title: "West"})]
44910 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
44919 panels: [new CP("south", {title: "South", closable: true})]
44926 preferredTabWidth: 150,
44928 new CP("center1", {title: "Close Me", closable: true}),
44929 new CP("center2", {title: "Center Panel", closable: false})
44934 layout.getRegion("center").showPanel("center1");
44939 Roo.BorderLayout.create = function(config, targetEl){
44940 var layout = new Roo.BorderLayout(targetEl || document.body, config);
44941 layout.beginUpdate();
44942 var regions = Roo.BorderLayout.RegionFactory.validRegions;
44943 for(var j = 0, jlen = regions.length; j < jlen; j++){
44944 var lr = regions[j];
44945 if(layout.regions[lr] && config[lr].panels){
44946 var r = layout.regions[lr];
44947 var ps = config[lr].panels;
44948 layout.addTypedPanels(r, ps);
44951 layout.endUpdate();
44956 Roo.BorderLayout.RegionFactory = {
44958 validRegions : ["north","south","east","west","center"],
44961 create : function(target, mgr, config){
44962 target = target.toLowerCase();
44963 if(config.lightweight || config.basic){
44964 return new Roo.BasicLayoutRegion(mgr, config, target);
44968 return new Roo.NorthLayoutRegion(mgr, config);
44970 return new Roo.SouthLayoutRegion(mgr, config);
44972 return new Roo.EastLayoutRegion(mgr, config);
44974 return new Roo.WestLayoutRegion(mgr, config);
44976 return new Roo.CenterLayoutRegion(mgr, config);
44978 throw 'Layout region "'+target+'" not supported.';
44982 * Ext JS Library 1.1.1
44983 * Copyright(c) 2006-2007, Ext JS, LLC.
44985 * Originally Released Under LGPL - original licence link has changed is not relivant.
44988 * <script type="text/javascript">
44992 * @class Roo.BasicLayoutRegion
44993 * @extends Roo.util.Observable
44994 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
44995 * and does not have a titlebar, tabs or any other features. All it does is size and position
44996 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
44998 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
45000 this.position = pos;
45003 * @scope Roo.BasicLayoutRegion
45007 * @event beforeremove
45008 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
45009 * @param {Roo.LayoutRegion} this
45010 * @param {Roo.ContentPanel} panel The panel
45011 * @param {Object} e The cancel event object
45013 "beforeremove" : true,
45015 * @event invalidated
45016 * Fires when the layout for this region is changed.
45017 * @param {Roo.LayoutRegion} this
45019 "invalidated" : true,
45021 * @event visibilitychange
45022 * Fires when this region is shown or hidden
45023 * @param {Roo.LayoutRegion} this
45024 * @param {Boolean} visibility true or false
45026 "visibilitychange" : true,
45028 * @event paneladded
45029 * Fires when a panel is added.
45030 * @param {Roo.LayoutRegion} this
45031 * @param {Roo.ContentPanel} panel The panel
45033 "paneladded" : true,
45035 * @event panelremoved
45036 * Fires when a panel is removed.
45037 * @param {Roo.LayoutRegion} this
45038 * @param {Roo.ContentPanel} panel The panel
45040 "panelremoved" : true,
45043 * Fires when this region is collapsed.
45044 * @param {Roo.LayoutRegion} this
45046 "collapsed" : true,
45049 * Fires when this region is expanded.
45050 * @param {Roo.LayoutRegion} this
45055 * Fires when this region is slid into view.
45056 * @param {Roo.LayoutRegion} this
45058 "slideshow" : true,
45061 * Fires when this region slides out of view.
45062 * @param {Roo.LayoutRegion} this
45064 "slidehide" : true,
45066 * @event panelactivated
45067 * Fires when a panel is activated.
45068 * @param {Roo.LayoutRegion} this
45069 * @param {Roo.ContentPanel} panel The activated panel
45071 "panelactivated" : true,
45074 * Fires when the user resizes this region.
45075 * @param {Roo.LayoutRegion} this
45076 * @param {Number} newSize The new size (width for east/west, height for north/south)
45080 /** A collection of panels in this region. @type Roo.util.MixedCollection */
45081 this.panels = new Roo.util.MixedCollection();
45082 this.panels.getKey = this.getPanelId.createDelegate(this);
45084 this.activePanel = null;
45085 // ensure listeners are added...
45087 if (config.listeners || config.events) {
45088 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
45089 listeners : config.listeners || {},
45090 events : config.events || {}
45094 if(skipConfig !== true){
45095 this.applyConfig(config);
45099 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
45100 getPanelId : function(p){
45104 applyConfig : function(config){
45105 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
45106 this.config = config;
45111 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
45112 * the width, for horizontal (north, south) the height.
45113 * @param {Number} newSize The new width or height
45115 resizeTo : function(newSize){
45116 var el = this.el ? this.el :
45117 (this.activePanel ? this.activePanel.getEl() : null);
45119 switch(this.position){
45122 el.setWidth(newSize);
45123 this.fireEvent("resized", this, newSize);
45127 el.setHeight(newSize);
45128 this.fireEvent("resized", this, newSize);
45134 getBox : function(){
45135 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
45138 getMargins : function(){
45139 return this.margins;
45142 updateBox : function(box){
45144 var el = this.activePanel.getEl();
45145 el.dom.style.left = box.x + "px";
45146 el.dom.style.top = box.y + "px";
45147 this.activePanel.setSize(box.width, box.height);
45151 * Returns the container element for this region.
45152 * @return {Roo.Element}
45154 getEl : function(){
45155 return this.activePanel;
45159 * Returns true if this region is currently visible.
45160 * @return {Boolean}
45162 isVisible : function(){
45163 return this.activePanel ? true : false;
45166 setActivePanel : function(panel){
45167 panel = this.getPanel(panel);
45168 if(this.activePanel && this.activePanel != panel){
45169 this.activePanel.setActiveState(false);
45170 this.activePanel.getEl().setLeftTop(-10000,-10000);
45172 this.activePanel = panel;
45173 panel.setActiveState(true);
45175 panel.setSize(this.box.width, this.box.height);
45177 this.fireEvent("panelactivated", this, panel);
45178 this.fireEvent("invalidated");
45182 * Show the specified panel.
45183 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
45184 * @return {Roo.ContentPanel} The shown panel or null
45186 showPanel : function(panel){
45187 if(panel = this.getPanel(panel)){
45188 this.setActivePanel(panel);
45194 * Get the active panel for this region.
45195 * @return {Roo.ContentPanel} The active panel or null
45197 getActivePanel : function(){
45198 return this.activePanel;
45202 * Add the passed ContentPanel(s)
45203 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
45204 * @return {Roo.ContentPanel} The panel added (if only one was added)
45206 add : function(panel){
45207 if(arguments.length > 1){
45208 for(var i = 0, len = arguments.length; i < len; i++) {
45209 this.add(arguments[i]);
45213 if(this.hasPanel(panel)){
45214 this.showPanel(panel);
45217 var el = panel.getEl();
45218 if(el.dom.parentNode != this.mgr.el.dom){
45219 this.mgr.el.dom.appendChild(el.dom);
45221 if(panel.setRegion){
45222 panel.setRegion(this);
45224 this.panels.add(panel);
45225 el.setStyle("position", "absolute");
45226 if(!panel.background){
45227 this.setActivePanel(panel);
45228 if(this.config.initialSize && this.panels.getCount()==1){
45229 this.resizeTo(this.config.initialSize);
45232 this.fireEvent("paneladded", this, panel);
45237 * Returns true if the panel is in this region.
45238 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45239 * @return {Boolean}
45241 hasPanel : function(panel){
45242 if(typeof panel == "object"){ // must be panel obj
45243 panel = panel.getId();
45245 return this.getPanel(panel) ? true : false;
45249 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
45250 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45251 * @param {Boolean} preservePanel Overrides the config preservePanel option
45252 * @return {Roo.ContentPanel} The panel that was removed
45254 remove : function(panel, preservePanel){
45255 panel = this.getPanel(panel);
45260 this.fireEvent("beforeremove", this, panel, e);
45261 if(e.cancel === true){
45264 var panelId = panel.getId();
45265 this.panels.removeKey(panelId);
45270 * Returns the panel specified or null if it's not in this region.
45271 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45272 * @return {Roo.ContentPanel}
45274 getPanel : function(id){
45275 if(typeof id == "object"){ // must be panel obj
45278 return this.panels.get(id);
45282 * Returns this regions position (north/south/east/west/center).
45285 getPosition: function(){
45286 return this.position;
45290 * Ext JS Library 1.1.1
45291 * Copyright(c) 2006-2007, Ext JS, LLC.
45293 * Originally Released Under LGPL - original licence link has changed is not relivant.
45296 * <script type="text/javascript">
45300 * @class Roo.LayoutRegion
45301 * @extends Roo.BasicLayoutRegion
45302 * This class represents a region in a layout manager.
45303 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
45304 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
45305 * @cfg {Boolean} floatable False to disable floating (defaults to true)
45306 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
45307 * @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})
45308 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
45309 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
45310 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
45311 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
45312 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
45313 * @cfg {String} title The title for the region (overrides panel titles)
45314 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
45315 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
45316 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
45317 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
45318 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
45319 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
45320 * the space available, similar to FireFox 1.5 tabs (defaults to false)
45321 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
45322 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
45323 * @cfg {Boolean} showPin True to show a pin button
45324 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
45325 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
45326 * @cfg {Boolean} disableTabTips True to disable tab tooltips
45327 * @cfg {Number} width For East/West panels
45328 * @cfg {Number} height For North/South panels
45329 * @cfg {Boolean} split To show the splitter
45330 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
45332 Roo.LayoutRegion = function(mgr, config, pos){
45333 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
45334 var dh = Roo.DomHelper;
45335 /** This region's container element
45336 * @type Roo.Element */
45337 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
45338 /** This region's title element
45339 * @type Roo.Element */
45341 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
45342 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
45343 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
45345 this.titleEl.enableDisplayMode();
45346 /** This region's title text element
45347 * @type HTMLElement */
45348 this.titleTextEl = this.titleEl.dom.firstChild;
45349 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
45350 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
45351 this.closeBtn.enableDisplayMode();
45352 this.closeBtn.on("click", this.closeClicked, this);
45353 this.closeBtn.hide();
45355 this.createBody(config);
45356 this.visible = true;
45357 this.collapsed = false;
45359 if(config.hideWhenEmpty){
45361 this.on("paneladded", this.validateVisibility, this);
45362 this.on("panelremoved", this.validateVisibility, this);
45364 this.applyConfig(config);
45367 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
45369 createBody : function(){
45370 /** This region's body element
45371 * @type Roo.Element */
45372 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
45375 applyConfig : function(c){
45376 if(c.collapsible && this.position != "center" && !this.collapsedEl){
45377 var dh = Roo.DomHelper;
45378 if(c.titlebar !== false){
45379 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
45380 this.collapseBtn.on("click", this.collapse, this);
45381 this.collapseBtn.enableDisplayMode();
45383 if(c.showPin === true || this.showPin){
45384 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
45385 this.stickBtn.enableDisplayMode();
45386 this.stickBtn.on("click", this.expand, this);
45387 this.stickBtn.hide();
45390 /** This region's collapsed element
45391 * @type Roo.Element */
45392 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
45393 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
45395 if(c.floatable !== false){
45396 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
45397 this.collapsedEl.on("click", this.collapseClick, this);
45400 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
45401 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
45402 id: "message", unselectable: "on", style:{"float":"left"}});
45403 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
45405 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
45406 this.expandBtn.on("click", this.expand, this);
45408 if(this.collapseBtn){
45409 this.collapseBtn.setVisible(c.collapsible == true);
45411 this.cmargins = c.cmargins || this.cmargins ||
45412 (this.position == "west" || this.position == "east" ?
45413 {top: 0, left: 2, right:2, bottom: 0} :
45414 {top: 2, left: 0, right:0, bottom: 2});
45415 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
45416 this.bottomTabs = c.tabPosition != "top";
45417 this.autoScroll = c.autoScroll || false;
45418 if(this.autoScroll){
45419 this.bodyEl.setStyle("overflow", "auto");
45421 this.bodyEl.setStyle("overflow", "hidden");
45423 //if(c.titlebar !== false){
45424 if((!c.titlebar && !c.title) || c.titlebar === false){
45425 this.titleEl.hide();
45427 this.titleEl.show();
45429 this.titleTextEl.innerHTML = c.title;
45433 this.duration = c.duration || .30;
45434 this.slideDuration = c.slideDuration || .45;
45437 this.collapse(true);
45444 * Returns true if this region is currently visible.
45445 * @return {Boolean}
45447 isVisible : function(){
45448 return this.visible;
45452 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
45453 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
45455 setCollapsedTitle : function(title){
45456 title = title || " ";
45457 if(this.collapsedTitleTextEl){
45458 this.collapsedTitleTextEl.innerHTML = title;
45462 getBox : function(){
45464 if(!this.collapsed){
45465 b = this.el.getBox(false, true);
45467 b = this.collapsedEl.getBox(false, true);
45472 getMargins : function(){
45473 return this.collapsed ? this.cmargins : this.margins;
45476 highlight : function(){
45477 this.el.addClass("x-layout-panel-dragover");
45480 unhighlight : function(){
45481 this.el.removeClass("x-layout-panel-dragover");
45484 updateBox : function(box){
45486 if(!this.collapsed){
45487 this.el.dom.style.left = box.x + "px";
45488 this.el.dom.style.top = box.y + "px";
45489 this.updateBody(box.width, box.height);
45491 this.collapsedEl.dom.style.left = box.x + "px";
45492 this.collapsedEl.dom.style.top = box.y + "px";
45493 this.collapsedEl.setSize(box.width, box.height);
45496 this.tabs.autoSizeTabs();
45500 updateBody : function(w, h){
45502 this.el.setWidth(w);
45503 w -= this.el.getBorderWidth("rl");
45504 if(this.config.adjustments){
45505 w += this.config.adjustments[0];
45509 this.el.setHeight(h);
45510 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
45511 h -= this.el.getBorderWidth("tb");
45512 if(this.config.adjustments){
45513 h += this.config.adjustments[1];
45515 this.bodyEl.setHeight(h);
45517 h = this.tabs.syncHeight(h);
45520 if(this.panelSize){
45521 w = w !== null ? w : this.panelSize.width;
45522 h = h !== null ? h : this.panelSize.height;
45524 if(this.activePanel){
45525 var el = this.activePanel.getEl();
45526 w = w !== null ? w : el.getWidth();
45527 h = h !== null ? h : el.getHeight();
45528 this.panelSize = {width: w, height: h};
45529 this.activePanel.setSize(w, h);
45531 if(Roo.isIE && this.tabs){
45532 this.tabs.el.repaint();
45537 * Returns the container element for this region.
45538 * @return {Roo.Element}
45540 getEl : function(){
45545 * Hides this region.
45548 if(!this.collapsed){
45549 this.el.dom.style.left = "-2000px";
45552 this.collapsedEl.dom.style.left = "-2000px";
45553 this.collapsedEl.hide();
45555 this.visible = false;
45556 this.fireEvent("visibilitychange", this, false);
45560 * Shows this region if it was previously hidden.
45563 if(!this.collapsed){
45566 this.collapsedEl.show();
45568 this.visible = true;
45569 this.fireEvent("visibilitychange", this, true);
45572 closeClicked : function(){
45573 if(this.activePanel){
45574 this.remove(this.activePanel);
45578 collapseClick : function(e){
45580 e.stopPropagation();
45583 e.stopPropagation();
45589 * Collapses this region.
45590 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
45592 collapse : function(skipAnim){
45593 if(this.collapsed) return;
45594 this.collapsed = true;
45596 this.split.el.hide();
45598 if(this.config.animate && skipAnim !== true){
45599 this.fireEvent("invalidated", this);
45600 this.animateCollapse();
45602 this.el.setLocation(-20000,-20000);
45604 this.collapsedEl.show();
45605 this.fireEvent("collapsed", this);
45606 this.fireEvent("invalidated", this);
45610 animateCollapse : function(){
45615 * Expands this region if it was previously collapsed.
45616 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
45617 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
45619 expand : function(e, skipAnim){
45620 if(e) e.stopPropagation();
45621 if(!this.collapsed || this.el.hasActiveFx()) return;
45623 this.afterSlideIn();
45626 this.collapsed = false;
45627 if(this.config.animate && skipAnim !== true){
45628 this.animateExpand();
45632 this.split.el.show();
45634 this.collapsedEl.setLocation(-2000,-2000);
45635 this.collapsedEl.hide();
45636 this.fireEvent("invalidated", this);
45637 this.fireEvent("expanded", this);
45641 animateExpand : function(){
45645 initTabs : function()
45647 this.bodyEl.setStyle("overflow", "hidden");
45648 var ts = new Roo.TabPanel(
45651 tabPosition: this.bottomTabs ? 'bottom' : 'top',
45652 disableTooltips: this.config.disableTabTips,
45653 toolbar : this.config.toolbar
45656 if(this.config.hideTabs){
45657 ts.stripWrap.setDisplayed(false);
45660 ts.resizeTabs = this.config.resizeTabs === true;
45661 ts.minTabWidth = this.config.minTabWidth || 40;
45662 ts.maxTabWidth = this.config.maxTabWidth || 250;
45663 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
45664 ts.monitorResize = false;
45665 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
45666 ts.bodyEl.addClass('x-layout-tabs-body');
45667 this.panels.each(this.initPanelAsTab, this);
45670 initPanelAsTab : function(panel){
45671 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
45672 this.config.closeOnTab && panel.isClosable());
45673 if(panel.tabTip !== undefined){
45674 ti.setTooltip(panel.tabTip);
45676 ti.on("activate", function(){
45677 this.setActivePanel(panel);
45679 if(this.config.closeOnTab){
45680 ti.on("beforeclose", function(t, e){
45682 this.remove(panel);
45688 updatePanelTitle : function(panel, title){
45689 if(this.activePanel == panel){
45690 this.updateTitle(title);
45693 var ti = this.tabs.getTab(panel.getEl().id);
45695 if(panel.tabTip !== undefined){
45696 ti.setTooltip(panel.tabTip);
45701 updateTitle : function(title){
45702 if(this.titleTextEl && !this.config.title){
45703 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
45707 setActivePanel : function(panel){
45708 panel = this.getPanel(panel);
45709 if(this.activePanel && this.activePanel != panel){
45710 this.activePanel.setActiveState(false);
45712 this.activePanel = panel;
45713 panel.setActiveState(true);
45714 if(this.panelSize){
45715 panel.setSize(this.panelSize.width, this.panelSize.height);
45718 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
45720 this.updateTitle(panel.getTitle());
45722 this.fireEvent("invalidated", this);
45724 this.fireEvent("panelactivated", this, panel);
45728 * Shows the specified panel.
45729 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
45730 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
45732 showPanel : function(panel){
45733 if(panel = this.getPanel(panel)){
45735 var tab = this.tabs.getTab(panel.getEl().id);
45736 if(tab.isHidden()){
45737 this.tabs.unhideTab(tab.id);
45741 this.setActivePanel(panel);
45748 * Get the active panel for this region.
45749 * @return {Roo.ContentPanel} The active panel or null
45751 getActivePanel : function(){
45752 return this.activePanel;
45755 validateVisibility : function(){
45756 if(this.panels.getCount() < 1){
45757 this.updateTitle(" ");
45758 this.closeBtn.hide();
45761 if(!this.isVisible()){
45768 * Adds the passed ContentPanel(s) to this region.
45769 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
45770 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
45772 add : function(panel){
45773 if(arguments.length > 1){
45774 for(var i = 0, len = arguments.length; i < len; i++) {
45775 this.add(arguments[i]);
45779 if(this.hasPanel(panel)){
45780 this.showPanel(panel);
45783 panel.setRegion(this);
45784 this.panels.add(panel);
45785 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
45786 this.bodyEl.dom.appendChild(panel.getEl().dom);
45787 if(panel.background !== true){
45788 this.setActivePanel(panel);
45790 this.fireEvent("paneladded", this, panel);
45796 this.initPanelAsTab(panel);
45798 if(panel.background !== true){
45799 this.tabs.activate(panel.getEl().id);
45801 this.fireEvent("paneladded", this, panel);
45806 * Hides the tab for the specified panel.
45807 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
45809 hidePanel : function(panel){
45810 if(this.tabs && (panel = this.getPanel(panel))){
45811 this.tabs.hideTab(panel.getEl().id);
45816 * Unhides the tab for a previously hidden panel.
45817 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
45819 unhidePanel : function(panel){
45820 if(this.tabs && (panel = this.getPanel(panel))){
45821 this.tabs.unhideTab(panel.getEl().id);
45825 clearPanels : function(){
45826 while(this.panels.getCount() > 0){
45827 this.remove(this.panels.first());
45832 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
45833 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
45834 * @param {Boolean} preservePanel Overrides the config preservePanel option
45835 * @return {Roo.ContentPanel} The panel that was removed
45837 remove : function(panel, preservePanel){
45838 panel = this.getPanel(panel);
45843 this.fireEvent("beforeremove", this, panel, e);
45844 if(e.cancel === true){
45847 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
45848 var panelId = panel.getId();
45849 this.panels.removeKey(panelId);
45851 document.body.appendChild(panel.getEl().dom);
45854 this.tabs.removeTab(panel.getEl().id);
45855 }else if (!preservePanel){
45856 this.bodyEl.dom.removeChild(panel.getEl().dom);
45858 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
45859 var p = this.panels.first();
45860 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
45861 tempEl.appendChild(p.getEl().dom);
45862 this.bodyEl.update("");
45863 this.bodyEl.dom.appendChild(p.getEl().dom);
45865 this.updateTitle(p.getTitle());
45867 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
45868 this.setActivePanel(p);
45870 panel.setRegion(null);
45871 if(this.activePanel == panel){
45872 this.activePanel = null;
45874 if(this.config.autoDestroy !== false && preservePanel !== true){
45875 try{panel.destroy();}catch(e){}
45877 this.fireEvent("panelremoved", this, panel);
45882 * Returns the TabPanel component used by this region
45883 * @return {Roo.TabPanel}
45885 getTabs : function(){
45889 createTool : function(parentEl, className){
45890 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
45891 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
45892 btn.addClassOnOver("x-layout-tools-button-over");
45897 * Ext JS Library 1.1.1
45898 * Copyright(c) 2006-2007, Ext JS, LLC.
45900 * Originally Released Under LGPL - original licence link has changed is not relivant.
45903 * <script type="text/javascript">
45909 * @class Roo.SplitLayoutRegion
45910 * @extends Roo.LayoutRegion
45911 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
45913 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
45914 this.cursor = cursor;
45915 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
45918 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
45919 splitTip : "Drag to resize.",
45920 collapsibleSplitTip : "Drag to resize. Double click to hide.",
45921 useSplitTips : false,
45923 applyConfig : function(config){
45924 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
45927 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
45928 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
45929 /** The SplitBar for this region
45930 * @type Roo.SplitBar */
45931 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
45932 this.split.on("moved", this.onSplitMove, this);
45933 this.split.useShim = config.useShim === true;
45934 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
45935 if(this.useSplitTips){
45936 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
45938 if(config.collapsible){
45939 this.split.el.on("dblclick", this.collapse, this);
45942 if(typeof config.minSize != "undefined"){
45943 this.split.minSize = config.minSize;
45945 if(typeof config.maxSize != "undefined"){
45946 this.split.maxSize = config.maxSize;
45948 if(config.hideWhenEmpty || config.hidden || config.collapsed){
45949 this.hideSplitter();
45954 getHMaxSize : function(){
45955 var cmax = this.config.maxSize || 10000;
45956 var center = this.mgr.getRegion("center");
45957 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
45960 getVMaxSize : function(){
45961 var cmax = this.config.maxSize || 10000;
45962 var center = this.mgr.getRegion("center");
45963 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
45966 onSplitMove : function(split, newSize){
45967 this.fireEvent("resized", this, newSize);
45971 * Returns the {@link Roo.SplitBar} for this region.
45972 * @return {Roo.SplitBar}
45974 getSplitBar : function(){
45979 this.hideSplitter();
45980 Roo.SplitLayoutRegion.superclass.hide.call(this);
45983 hideSplitter : function(){
45985 this.split.el.setLocation(-2000,-2000);
45986 this.split.el.hide();
45992 this.split.el.show();
45994 Roo.SplitLayoutRegion.superclass.show.call(this);
45997 beforeSlide: function(){
45998 if(Roo.isGecko){// firefox overflow auto bug workaround
45999 this.bodyEl.clip();
46000 if(this.tabs) this.tabs.bodyEl.clip();
46001 if(this.activePanel){
46002 this.activePanel.getEl().clip();
46004 if(this.activePanel.beforeSlide){
46005 this.activePanel.beforeSlide();
46011 afterSlide : function(){
46012 if(Roo.isGecko){// firefox overflow auto bug workaround
46013 this.bodyEl.unclip();
46014 if(this.tabs) this.tabs.bodyEl.unclip();
46015 if(this.activePanel){
46016 this.activePanel.getEl().unclip();
46017 if(this.activePanel.afterSlide){
46018 this.activePanel.afterSlide();
46024 initAutoHide : function(){
46025 if(this.autoHide !== false){
46026 if(!this.autoHideHd){
46027 var st = new Roo.util.DelayedTask(this.slideIn, this);
46028 this.autoHideHd = {
46029 "mouseout": function(e){
46030 if(!e.within(this.el, true)){
46034 "mouseover" : function(e){
46040 this.el.on(this.autoHideHd);
46044 clearAutoHide : function(){
46045 if(this.autoHide !== false){
46046 this.el.un("mouseout", this.autoHideHd.mouseout);
46047 this.el.un("mouseover", this.autoHideHd.mouseover);
46051 clearMonitor : function(){
46052 Roo.get(document).un("click", this.slideInIf, this);
46055 // these names are backwards but not changed for compat
46056 slideOut : function(){
46057 if(this.isSlid || this.el.hasActiveFx()){
46060 this.isSlid = true;
46061 if(this.collapseBtn){
46062 this.collapseBtn.hide();
46064 this.closeBtnState = this.closeBtn.getStyle('display');
46065 this.closeBtn.hide();
46067 this.stickBtn.show();
46070 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
46071 this.beforeSlide();
46072 this.el.setStyle("z-index", 10001);
46073 this.el.slideIn(this.getSlideAnchor(), {
46074 callback: function(){
46076 this.initAutoHide();
46077 Roo.get(document).on("click", this.slideInIf, this);
46078 this.fireEvent("slideshow", this);
46085 afterSlideIn : function(){
46086 this.clearAutoHide();
46087 this.isSlid = false;
46088 this.clearMonitor();
46089 this.el.setStyle("z-index", "");
46090 if(this.collapseBtn){
46091 this.collapseBtn.show();
46093 this.closeBtn.setStyle('display', this.closeBtnState);
46095 this.stickBtn.hide();
46097 this.fireEvent("slidehide", this);
46100 slideIn : function(cb){
46101 if(!this.isSlid || this.el.hasActiveFx()){
46105 this.isSlid = false;
46106 this.beforeSlide();
46107 this.el.slideOut(this.getSlideAnchor(), {
46108 callback: function(){
46109 this.el.setLeftTop(-10000, -10000);
46111 this.afterSlideIn();
46119 slideInIf : function(e){
46120 if(!e.within(this.el)){
46125 animateCollapse : function(){
46126 this.beforeSlide();
46127 this.el.setStyle("z-index", 20000);
46128 var anchor = this.getSlideAnchor();
46129 this.el.slideOut(anchor, {
46130 callback : function(){
46131 this.el.setStyle("z-index", "");
46132 this.collapsedEl.slideIn(anchor, {duration:.3});
46134 this.el.setLocation(-10000,-10000);
46136 this.fireEvent("collapsed", this);
46143 animateExpand : function(){
46144 this.beforeSlide();
46145 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
46146 this.el.setStyle("z-index", 20000);
46147 this.collapsedEl.hide({
46150 this.el.slideIn(this.getSlideAnchor(), {
46151 callback : function(){
46152 this.el.setStyle("z-index", "");
46155 this.split.el.show();
46157 this.fireEvent("invalidated", this);
46158 this.fireEvent("expanded", this);
46186 getAnchor : function(){
46187 return this.anchors[this.position];
46190 getCollapseAnchor : function(){
46191 return this.canchors[this.position];
46194 getSlideAnchor : function(){
46195 return this.sanchors[this.position];
46198 getAlignAdj : function(){
46199 var cm = this.cmargins;
46200 switch(this.position){
46216 getExpandAdj : function(){
46217 var c = this.collapsedEl, cm = this.cmargins;
46218 switch(this.position){
46220 return [-(cm.right+c.getWidth()+cm.left), 0];
46223 return [cm.right+c.getWidth()+cm.left, 0];
46226 return [0, -(cm.top+cm.bottom+c.getHeight())];
46229 return [0, cm.top+cm.bottom+c.getHeight()];
46235 * Ext JS Library 1.1.1
46236 * Copyright(c) 2006-2007, Ext JS, LLC.
46238 * Originally Released Under LGPL - original licence link has changed is not relivant.
46241 * <script type="text/javascript">
46244 * These classes are private internal classes
46246 Roo.CenterLayoutRegion = function(mgr, config){
46247 Roo.LayoutRegion.call(this, mgr, config, "center");
46248 this.visible = true;
46249 this.minWidth = config.minWidth || 20;
46250 this.minHeight = config.minHeight || 20;
46253 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
46255 // center panel can't be hidden
46259 // center panel can't be hidden
46262 getMinWidth: function(){
46263 return this.minWidth;
46266 getMinHeight: function(){
46267 return this.minHeight;
46272 Roo.NorthLayoutRegion = function(mgr, config){
46273 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
46275 this.split.placement = Roo.SplitBar.TOP;
46276 this.split.orientation = Roo.SplitBar.VERTICAL;
46277 this.split.el.addClass("x-layout-split-v");
46279 var size = config.initialSize || config.height;
46280 if(typeof size != "undefined"){
46281 this.el.setHeight(size);
46284 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
46285 orientation: Roo.SplitBar.VERTICAL,
46286 getBox : function(){
46287 if(this.collapsed){
46288 return this.collapsedEl.getBox();
46290 var box = this.el.getBox();
46292 box.height += this.split.el.getHeight();
46297 updateBox : function(box){
46298 if(this.split && !this.collapsed){
46299 box.height -= this.split.el.getHeight();
46300 this.split.el.setLeft(box.x);
46301 this.split.el.setTop(box.y+box.height);
46302 this.split.el.setWidth(box.width);
46304 if(this.collapsed){
46305 this.updateBody(box.width, null);
46307 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46311 Roo.SouthLayoutRegion = function(mgr, config){
46312 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
46314 this.split.placement = Roo.SplitBar.BOTTOM;
46315 this.split.orientation = Roo.SplitBar.VERTICAL;
46316 this.split.el.addClass("x-layout-split-v");
46318 var size = config.initialSize || config.height;
46319 if(typeof size != "undefined"){
46320 this.el.setHeight(size);
46323 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
46324 orientation: Roo.SplitBar.VERTICAL,
46325 getBox : function(){
46326 if(this.collapsed){
46327 return this.collapsedEl.getBox();
46329 var box = this.el.getBox();
46331 var sh = this.split.el.getHeight();
46338 updateBox : function(box){
46339 if(this.split && !this.collapsed){
46340 var sh = this.split.el.getHeight();
46343 this.split.el.setLeft(box.x);
46344 this.split.el.setTop(box.y-sh);
46345 this.split.el.setWidth(box.width);
46347 if(this.collapsed){
46348 this.updateBody(box.width, null);
46350 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46354 Roo.EastLayoutRegion = function(mgr, config){
46355 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
46357 this.split.placement = Roo.SplitBar.RIGHT;
46358 this.split.orientation = Roo.SplitBar.HORIZONTAL;
46359 this.split.el.addClass("x-layout-split-h");
46361 var size = config.initialSize || config.width;
46362 if(typeof size != "undefined"){
46363 this.el.setWidth(size);
46366 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
46367 orientation: Roo.SplitBar.HORIZONTAL,
46368 getBox : function(){
46369 if(this.collapsed){
46370 return this.collapsedEl.getBox();
46372 var box = this.el.getBox();
46374 var sw = this.split.el.getWidth();
46381 updateBox : function(box){
46382 if(this.split && !this.collapsed){
46383 var sw = this.split.el.getWidth();
46385 this.split.el.setLeft(box.x);
46386 this.split.el.setTop(box.y);
46387 this.split.el.setHeight(box.height);
46390 if(this.collapsed){
46391 this.updateBody(null, box.height);
46393 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46397 Roo.WestLayoutRegion = function(mgr, config){
46398 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
46400 this.split.placement = Roo.SplitBar.LEFT;
46401 this.split.orientation = Roo.SplitBar.HORIZONTAL;
46402 this.split.el.addClass("x-layout-split-h");
46404 var size = config.initialSize || config.width;
46405 if(typeof size != "undefined"){
46406 this.el.setWidth(size);
46409 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
46410 orientation: Roo.SplitBar.HORIZONTAL,
46411 getBox : function(){
46412 if(this.collapsed){
46413 return this.collapsedEl.getBox();
46415 var box = this.el.getBox();
46417 box.width += this.split.el.getWidth();
46422 updateBox : function(box){
46423 if(this.split && !this.collapsed){
46424 var sw = this.split.el.getWidth();
46426 this.split.el.setLeft(box.x+box.width);
46427 this.split.el.setTop(box.y);
46428 this.split.el.setHeight(box.height);
46430 if(this.collapsed){
46431 this.updateBody(null, box.height);
46433 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46438 * Ext JS Library 1.1.1
46439 * Copyright(c) 2006-2007, Ext JS, LLC.
46441 * Originally Released Under LGPL - original licence link has changed is not relivant.
46444 * <script type="text/javascript">
46449 * Private internal class for reading and applying state
46451 Roo.LayoutStateManager = function(layout){
46452 // default empty state
46461 Roo.LayoutStateManager.prototype = {
46462 init : function(layout, provider){
46463 this.provider = provider;
46464 var state = provider.get(layout.id+"-layout-state");
46466 var wasUpdating = layout.isUpdating();
46468 layout.beginUpdate();
46470 for(var key in state){
46471 if(typeof state[key] != "function"){
46472 var rstate = state[key];
46473 var r = layout.getRegion(key);
46476 r.resizeTo(rstate.size);
46478 if(rstate.collapsed == true){
46481 r.expand(null, true);
46487 layout.endUpdate();
46489 this.state = state;
46491 this.layout = layout;
46492 layout.on("regionresized", this.onRegionResized, this);
46493 layout.on("regioncollapsed", this.onRegionCollapsed, this);
46494 layout.on("regionexpanded", this.onRegionExpanded, this);
46497 storeState : function(){
46498 this.provider.set(this.layout.id+"-layout-state", this.state);
46501 onRegionResized : function(region, newSize){
46502 this.state[region.getPosition()].size = newSize;
46506 onRegionCollapsed : function(region){
46507 this.state[region.getPosition()].collapsed = true;
46511 onRegionExpanded : function(region){
46512 this.state[region.getPosition()].collapsed = false;
46517 * Ext JS Library 1.1.1
46518 * Copyright(c) 2006-2007, Ext JS, LLC.
46520 * Originally Released Under LGPL - original licence link has changed is not relivant.
46523 * <script type="text/javascript">
46526 * @class Roo.ContentPanel
46527 * @extends Roo.util.Observable
46528 * A basic ContentPanel element.
46529 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
46530 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
46531 * @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
46532 * @cfg {Boolean} closable True if the panel can be closed/removed
46533 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
46534 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
46535 * @cfg {Toolbar} toolbar A toolbar for this panel
46536 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
46537 * @cfg {String} title The title for this panel
46538 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
46539 * @cfg {String} url Calls {@link #setUrl} with this value
46540 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
46541 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
46542 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
46543 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
46546 * Create a new ContentPanel.
46547 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
46548 * @param {String/Object} config A string to set only the title or a config object
46549 * @param {String} content (optional) Set the HTML content for this panel
46550 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
46552 Roo.ContentPanel = function(el, config, content){
46556 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
46560 if (config && config.parentLayout) {
46561 el = config.parentLayout.el.createChild();
46564 if(el.autoCreate){ // xtype is available if this is called from factory
46568 this.el = Roo.get(el);
46569 if(!this.el && config && config.autoCreate){
46570 if(typeof config.autoCreate == "object"){
46571 if(!config.autoCreate.id){
46572 config.autoCreate.id = config.id||el;
46574 this.el = Roo.DomHelper.append(document.body,
46575 config.autoCreate, true);
46577 this.el = Roo.DomHelper.append(document.body,
46578 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
46581 this.closable = false;
46582 this.loaded = false;
46583 this.active = false;
46584 if(typeof config == "string"){
46585 this.title = config;
46587 Roo.apply(this, config);
46590 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
46591 this.wrapEl = this.el.wrap();
46592 this.toolbar.container = this.el.insertSibling(false, 'before');
46593 this.toolbar = new Roo.Toolbar(this.toolbar);
46599 this.resizeEl = Roo.get(this.resizeEl, true);
46601 this.resizeEl = this.el;
46606 * Fires when this panel is activated.
46607 * @param {Roo.ContentPanel} this
46611 * @event deactivate
46612 * Fires when this panel is activated.
46613 * @param {Roo.ContentPanel} this
46615 "deactivate" : true,
46619 * Fires when this panel is resized if fitToFrame is true.
46620 * @param {Roo.ContentPanel} this
46621 * @param {Number} width The width after any component adjustments
46622 * @param {Number} height The height after any component adjustments
46628 * Fires when this tab is created
46629 * @param {Roo.ContentPanel} this
46636 if(this.autoScroll){
46637 this.resizeEl.setStyle("overflow", "auto");
46639 // fix randome scrolling
46640 this.el.on('scroll', function() {
46641 Roo.log('fix random scolling');
46642 this.scrollTo('top',0);
46645 content = content || this.content;
46647 this.setContent(content);
46649 if(config && config.url){
46650 this.setUrl(this.url, this.params, this.loadOnce);
46655 Roo.ContentPanel.superclass.constructor.call(this);
46657 this.fireEvent('render', this);
46660 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
46662 setRegion : function(region){
46663 this.region = region;
46665 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
46667 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
46672 * Returns the toolbar for this Panel if one was configured.
46673 * @return {Roo.Toolbar}
46675 getToolbar : function(){
46676 return this.toolbar;
46679 setActiveState : function(active){
46680 this.active = active;
46682 this.fireEvent("deactivate", this);
46684 this.fireEvent("activate", this);
46688 * Updates this panel's element
46689 * @param {String} content The new content
46690 * @param {Boolean} loadScripts (optional) true to look for and process scripts
46692 setContent : function(content, loadScripts){
46693 this.el.update(content, loadScripts);
46696 ignoreResize : function(w, h){
46697 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
46700 this.lastSize = {width: w, height: h};
46705 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
46706 * @return {Roo.UpdateManager} The UpdateManager
46708 getUpdateManager : function(){
46709 return this.el.getUpdateManager();
46712 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
46713 * @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:
46716 url: "your-url.php",
46717 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
46718 callback: yourFunction,
46719 scope: yourObject, //(optional scope)
46722 text: "Loading...",
46727 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
46728 * 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.
46729 * @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}
46730 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
46731 * @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.
46732 * @return {Roo.ContentPanel} this
46735 var um = this.el.getUpdateManager();
46736 um.update.apply(um, arguments);
46742 * 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.
46743 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
46744 * @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)
46745 * @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)
46746 * @return {Roo.UpdateManager} The UpdateManager
46748 setUrl : function(url, params, loadOnce){
46749 if(this.refreshDelegate){
46750 this.removeListener("activate", this.refreshDelegate);
46752 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
46753 this.on("activate", this.refreshDelegate);
46754 return this.el.getUpdateManager();
46757 _handleRefresh : function(url, params, loadOnce){
46758 if(!loadOnce || !this.loaded){
46759 var updater = this.el.getUpdateManager();
46760 updater.update(url, params, this._setLoaded.createDelegate(this));
46764 _setLoaded : function(){
46765 this.loaded = true;
46769 * Returns this panel's id
46772 getId : function(){
46777 * Returns this panel's element - used by regiosn to add.
46778 * @return {Roo.Element}
46780 getEl : function(){
46781 return this.wrapEl || this.el;
46784 adjustForComponents : function(width, height){
46785 if(this.resizeEl != this.el){
46786 width -= this.el.getFrameWidth('lr');
46787 height -= this.el.getFrameWidth('tb');
46790 var te = this.toolbar.getEl();
46791 height -= te.getHeight();
46792 te.setWidth(width);
46794 if(this.adjustments){
46795 width += this.adjustments[0];
46796 height += this.adjustments[1];
46798 return {"width": width, "height": height};
46801 setSize : function(width, height){
46802 if(this.fitToFrame && !this.ignoreResize(width, height)){
46803 if(this.fitContainer && this.resizeEl != this.el){
46804 this.el.setSize(width, height);
46806 var size = this.adjustForComponents(width, height);
46807 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
46808 this.fireEvent('resize', this, size.width, size.height);
46813 * Returns this panel's title
46816 getTitle : function(){
46821 * Set this panel's title
46822 * @param {String} title
46824 setTitle : function(title){
46825 this.title = title;
46827 this.region.updatePanelTitle(this, title);
46832 * Returns true is this panel was configured to be closable
46833 * @return {Boolean}
46835 isClosable : function(){
46836 return this.closable;
46839 beforeSlide : function(){
46841 this.resizeEl.clip();
46844 afterSlide : function(){
46846 this.resizeEl.unclip();
46850 * Force a content refresh from the URL specified in the {@link #setUrl} method.
46851 * Will fail silently if the {@link #setUrl} method has not been called.
46852 * This does not activate the panel, just updates its content.
46854 refresh : function(){
46855 if(this.refreshDelegate){
46856 this.loaded = false;
46857 this.refreshDelegate();
46862 * Destroys this panel
46864 destroy : function(){
46865 this.el.removeAllListeners();
46866 var tempEl = document.createElement("span");
46867 tempEl.appendChild(this.el.dom);
46868 tempEl.innerHTML = "";
46874 * form - if the content panel contains a form - this is a reference to it.
46875 * @type {Roo.form.Form}
46879 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
46880 * This contains a reference to it.
46886 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
46896 * @param {Object} cfg Xtype definition of item to add.
46899 addxtype : function(cfg) {
46901 if (cfg.xtype.match(/^Form$/)) {
46902 var el = this.el.createChild();
46904 this.form = new Roo.form.Form(cfg);
46907 if ( this.form.allItems.length) this.form.render(el.dom);
46910 // should only have one of theses..
46911 if (['View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
46913 cfg.el = this.el.appendChild(document.createElement("div"));
46916 var ret = new Roo.factory(cfg);
46917 ret.render && ret.render(false, ''); // render blank..
46926 * @class Roo.GridPanel
46927 * @extends Roo.ContentPanel
46929 * Create a new GridPanel.
46930 * @param {Roo.grid.Grid} grid The grid for this panel
46931 * @param {String/Object} config A string to set only the panel's title, or a config object
46933 Roo.GridPanel = function(grid, config){
46936 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
46937 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
46939 this.wrapper.dom.appendChild(grid.getGridEl().dom);
46941 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
46944 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
46946 // xtype created footer. - not sure if will work as we normally have to render first..
46947 if (this.footer && !this.footer.el && this.footer.xtype) {
46949 this.footer.container = this.grid.getView().getFooterPanel(true);
46950 this.footer.dataSource = this.grid.dataSource;
46951 this.footer = Roo.factory(this.footer, Roo);
46955 grid.monitorWindowResize = false; // turn off autosizing
46956 grid.autoHeight = false;
46957 grid.autoWidth = false;
46959 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
46962 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
46963 getId : function(){
46964 return this.grid.id;
46968 * Returns the grid for this panel
46969 * @return {Roo.grid.Grid}
46971 getGrid : function(){
46975 setSize : function(width, height){
46976 if(!this.ignoreResize(width, height)){
46977 var grid = this.grid;
46978 var size = this.adjustForComponents(width, height);
46979 grid.getGridEl().setSize(size.width, size.height);
46984 beforeSlide : function(){
46985 this.grid.getView().scroller.clip();
46988 afterSlide : function(){
46989 this.grid.getView().scroller.unclip();
46992 destroy : function(){
46993 this.grid.destroy();
46995 Roo.GridPanel.superclass.destroy.call(this);
47001 * @class Roo.NestedLayoutPanel
47002 * @extends Roo.ContentPanel
47004 * Create a new NestedLayoutPanel.
47007 * @param {Roo.BorderLayout} layout The layout for this panel
47008 * @param {String/Object} config A string to set only the title or a config object
47010 Roo.NestedLayoutPanel = function(layout, config)
47012 // construct with only one argument..
47013 /* FIXME - implement nicer consturctors
47014 if (layout.layout) {
47016 layout = config.layout;
47017 delete config.layout;
47019 if (layout.xtype && !layout.getEl) {
47020 // then layout needs constructing..
47021 layout = Roo.factory(layout, Roo);
47026 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
47028 layout.monitorWindowResize = false; // turn off autosizing
47029 this.layout = layout;
47030 this.layout.getEl().addClass("x-layout-nested-layout");
47037 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
47039 setSize : function(width, height){
47040 if(!this.ignoreResize(width, height)){
47041 var size = this.adjustForComponents(width, height);
47042 var el = this.layout.getEl();
47043 el.setSize(size.width, size.height);
47044 var touch = el.dom.offsetWidth;
47045 this.layout.layout();
47046 // ie requires a double layout on the first pass
47047 if(Roo.isIE && !this.initialized){
47048 this.initialized = true;
47049 this.layout.layout();
47054 // activate all subpanels if not currently active..
47056 setActiveState : function(active){
47057 this.active = active;
47059 this.fireEvent("deactivate", this);
47063 this.fireEvent("activate", this);
47064 // not sure if this should happen before or after..
47065 if (!this.layout) {
47066 return; // should not happen..
47069 for (var r in this.layout.regions) {
47070 reg = this.layout.getRegion(r);
47071 if (reg.getActivePanel()) {
47072 //reg.showPanel(reg.getActivePanel()); // force it to activate..
47073 reg.setActivePanel(reg.getActivePanel());
47076 if (!reg.panels.length) {
47079 reg.showPanel(reg.getPanel(0));
47088 * Returns the nested BorderLayout for this panel
47089 * @return {Roo.BorderLayout}
47091 getLayout : function(){
47092 return this.layout;
47096 * Adds a xtype elements to the layout of the nested panel
47100 xtype : 'ContentPanel',
47107 xtype : 'NestedLayoutPanel',
47113 items : [ ... list of content panels or nested layout panels.. ]
47117 * @param {Object} cfg Xtype definition of item to add.
47119 addxtype : function(cfg) {
47120 return this.layout.addxtype(cfg);
47125 Roo.ScrollPanel = function(el, config, content){
47126 config = config || {};
47127 config.fitToFrame = true;
47128 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
47130 this.el.dom.style.overflow = "hidden";
47131 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
47132 this.el.removeClass("x-layout-inactive-content");
47133 this.el.on("mousewheel", this.onWheel, this);
47135 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
47136 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
47137 up.unselectable(); down.unselectable();
47138 up.on("click", this.scrollUp, this);
47139 down.on("click", this.scrollDown, this);
47140 up.addClassOnOver("x-scroller-btn-over");
47141 down.addClassOnOver("x-scroller-btn-over");
47142 up.addClassOnClick("x-scroller-btn-click");
47143 down.addClassOnClick("x-scroller-btn-click");
47144 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
47146 this.resizeEl = this.el;
47147 this.el = wrap; this.up = up; this.down = down;
47150 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
47152 wheelIncrement : 5,
47153 scrollUp : function(){
47154 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
47157 scrollDown : function(){
47158 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
47161 afterScroll : function(){
47162 var el = this.resizeEl;
47163 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
47164 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
47165 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
47168 setSize : function(){
47169 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
47170 this.afterScroll();
47173 onWheel : function(e){
47174 var d = e.getWheelDelta();
47175 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
47176 this.afterScroll();
47180 setContent : function(content, loadScripts){
47181 this.resizeEl.update(content, loadScripts);
47195 * @class Roo.TreePanel
47196 * @extends Roo.ContentPanel
47198 * Create a new TreePanel. - defaults to fit/scoll contents.
47199 * @param {String/Object} config A string to set only the panel's title, or a config object
47200 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
47202 Roo.TreePanel = function(config){
47203 var el = config.el;
47204 var tree = config.tree;
47205 delete config.tree;
47206 delete config.el; // hopefull!
47208 // wrapper for IE7 strict & safari scroll issue
47210 var treeEl = el.createChild();
47211 config.resizeEl = treeEl;
47215 Roo.TreePanel.superclass.constructor.call(this, el, config);
47218 this.tree = new Roo.tree.TreePanel(treeEl , tree);
47219 //console.log(tree);
47220 this.on('activate', function()
47222 if (this.tree.rendered) {
47225 //console.log('render tree');
47226 this.tree.render();
47229 this.on('resize', function (cp, w, h) {
47230 this.tree.innerCt.setWidth(w);
47231 this.tree.innerCt.setHeight(h);
47232 this.tree.innerCt.setStyle('overflow-y', 'auto');
47239 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
47256 * Ext JS Library 1.1.1
47257 * Copyright(c) 2006-2007, Ext JS, LLC.
47259 * Originally Released Under LGPL - original licence link has changed is not relivant.
47262 * <script type="text/javascript">
47267 * @class Roo.ReaderLayout
47268 * @extends Roo.BorderLayout
47269 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
47270 * center region containing two nested regions (a top one for a list view and one for item preview below),
47271 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
47272 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
47273 * expedites the setup of the overall layout and regions for this common application style.
47276 var reader = new Roo.ReaderLayout();
47277 var CP = Roo.ContentPanel; // shortcut for adding
47279 reader.beginUpdate();
47280 reader.add("north", new CP("north", "North"));
47281 reader.add("west", new CP("west", {title: "West"}));
47282 reader.add("east", new CP("east", {title: "East"}));
47284 reader.regions.listView.add(new CP("listView", "List"));
47285 reader.regions.preview.add(new CP("preview", "Preview"));
47286 reader.endUpdate();
47289 * Create a new ReaderLayout
47290 * @param {Object} config Configuration options
47291 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
47292 * document.body if omitted)
47294 Roo.ReaderLayout = function(config, renderTo){
47295 var c = config || {size:{}};
47296 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
47297 north: c.north !== false ? Roo.apply({
47301 }, c.north) : false,
47302 west: c.west !== false ? Roo.apply({
47310 margins:{left:5,right:0,bottom:5,top:5},
47311 cmargins:{left:5,right:5,bottom:5,top:5}
47312 }, c.west) : false,
47313 east: c.east !== false ? Roo.apply({
47321 margins:{left:0,right:5,bottom:5,top:5},
47322 cmargins:{left:5,right:5,bottom:5,top:5}
47323 }, c.east) : false,
47324 center: Roo.apply({
47325 tabPosition: 'top',
47329 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
47333 this.el.addClass('x-reader');
47335 this.beginUpdate();
47337 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
47338 south: c.preview !== false ? Roo.apply({
47345 cmargins:{top:5,left:0, right:0, bottom:0}
47346 }, c.preview) : false,
47347 center: Roo.apply({
47353 this.add('center', new Roo.NestedLayoutPanel(inner,
47354 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
47358 this.regions.preview = inner.getRegion('south');
47359 this.regions.listView = inner.getRegion('center');
47362 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
47364 * Ext JS Library 1.1.1
47365 * Copyright(c) 2006-2007, Ext JS, LLC.
47367 * Originally Released Under LGPL - original licence link has changed is not relivant.
47370 * <script type="text/javascript">
47374 * @class Roo.grid.Grid
47375 * @extends Roo.util.Observable
47376 * This class represents the primary interface of a component based grid control.
47377 * <br><br>Usage:<pre><code>
47378 var grid = new Roo.grid.Grid("my-container-id", {
47381 selModel: mySelectionModel,
47382 autoSizeColumns: true,
47383 monitorWindowResize: false,
47384 trackMouseOver: true
47389 * <b>Common Problems:</b><br/>
47390 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
47391 * element will correct this<br/>
47392 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
47393 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
47394 * are unpredictable.<br/>
47395 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
47396 * grid to calculate dimensions/offsets.<br/>
47398 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
47399 * The container MUST have some type of size defined for the grid to fill. The container will be
47400 * automatically set to position relative if it isn't already.
47401 * @param {Object} config A config object that sets properties on this grid.
47403 Roo.grid.Grid = function(container, config){
47404 // initialize the container
47405 this.container = Roo.get(container);
47406 this.container.update("");
47407 this.container.setStyle("overflow", "hidden");
47408 this.container.addClass('x-grid-container');
47410 this.id = this.container.id;
47412 Roo.apply(this, config);
47413 // check and correct shorthanded configs
47415 this.dataSource = this.ds;
47419 this.colModel = this.cm;
47423 this.selModel = this.sm;
47427 if (this.selModel) {
47428 this.selModel = Roo.factory(this.selModel, Roo.grid);
47429 this.sm = this.selModel;
47430 this.sm.xmodule = this.xmodule || false;
47432 if (typeof(this.colModel.config) == 'undefined') {
47433 this.colModel = new Roo.grid.ColumnModel(this.colModel);
47434 this.cm = this.colModel;
47435 this.cm.xmodule = this.xmodule || false;
47437 if (this.dataSource) {
47438 this.dataSource= Roo.factory(this.dataSource, Roo.data);
47439 this.ds = this.dataSource;
47440 this.ds.xmodule = this.xmodule || false;
47447 this.container.setWidth(this.width);
47451 this.container.setHeight(this.height);
47458 * The raw click event for the entire grid.
47459 * @param {Roo.EventObject} e
47464 * The raw dblclick event for the entire grid.
47465 * @param {Roo.EventObject} e
47469 * @event contextmenu
47470 * The raw contextmenu event for the entire grid.
47471 * @param {Roo.EventObject} e
47473 "contextmenu" : true,
47476 * The raw mousedown event for the entire grid.
47477 * @param {Roo.EventObject} e
47479 "mousedown" : true,
47482 * The raw mouseup event for the entire grid.
47483 * @param {Roo.EventObject} e
47488 * The raw mouseover event for the entire grid.
47489 * @param {Roo.EventObject} e
47491 "mouseover" : true,
47494 * The raw mouseout event for the entire grid.
47495 * @param {Roo.EventObject} e
47500 * The raw keypress event for the entire grid.
47501 * @param {Roo.EventObject} e
47506 * The raw keydown event for the entire grid.
47507 * @param {Roo.EventObject} e
47515 * Fires when a cell is clicked
47516 * @param {Grid} this
47517 * @param {Number} rowIndex
47518 * @param {Number} columnIndex
47519 * @param {Roo.EventObject} e
47521 "cellclick" : true,
47523 * @event celldblclick
47524 * Fires when a cell is double clicked
47525 * @param {Grid} this
47526 * @param {Number} rowIndex
47527 * @param {Number} columnIndex
47528 * @param {Roo.EventObject} e
47530 "celldblclick" : true,
47533 * Fires when a row is clicked
47534 * @param {Grid} this
47535 * @param {Number} rowIndex
47536 * @param {Roo.EventObject} e
47540 * @event rowdblclick
47541 * Fires when a row is double clicked
47542 * @param {Grid} this
47543 * @param {Number} rowIndex
47544 * @param {Roo.EventObject} e
47546 "rowdblclick" : true,
47548 * @event headerclick
47549 * Fires when a header is clicked
47550 * @param {Grid} this
47551 * @param {Number} columnIndex
47552 * @param {Roo.EventObject} e
47554 "headerclick" : true,
47556 * @event headerdblclick
47557 * Fires when a header cell is double clicked
47558 * @param {Grid} this
47559 * @param {Number} columnIndex
47560 * @param {Roo.EventObject} e
47562 "headerdblclick" : true,
47564 * @event rowcontextmenu
47565 * Fires when a row is right clicked
47566 * @param {Grid} this
47567 * @param {Number} rowIndex
47568 * @param {Roo.EventObject} e
47570 "rowcontextmenu" : true,
47572 * @event cellcontextmenu
47573 * Fires when a cell is right clicked
47574 * @param {Grid} this
47575 * @param {Number} rowIndex
47576 * @param {Number} cellIndex
47577 * @param {Roo.EventObject} e
47579 "cellcontextmenu" : true,
47581 * @event headercontextmenu
47582 * Fires when a header is right clicked
47583 * @param {Grid} this
47584 * @param {Number} columnIndex
47585 * @param {Roo.EventObject} e
47587 "headercontextmenu" : true,
47589 * @event bodyscroll
47590 * Fires when the body element is scrolled
47591 * @param {Number} scrollLeft
47592 * @param {Number} scrollTop
47594 "bodyscroll" : true,
47596 * @event columnresize
47597 * Fires when the user resizes a column
47598 * @param {Number} columnIndex
47599 * @param {Number} newSize
47601 "columnresize" : true,
47603 * @event columnmove
47604 * Fires when the user moves a column
47605 * @param {Number} oldIndex
47606 * @param {Number} newIndex
47608 "columnmove" : true,
47611 * Fires when row(s) start being dragged
47612 * @param {Grid} this
47613 * @param {Roo.GridDD} dd The drag drop object
47614 * @param {event} e The raw browser event
47616 "startdrag" : true,
47619 * Fires when a drag operation is complete
47620 * @param {Grid} this
47621 * @param {Roo.GridDD} dd The drag drop object
47622 * @param {event} e The raw browser event
47627 * Fires when dragged row(s) are dropped on a valid DD target
47628 * @param {Grid} this
47629 * @param {Roo.GridDD} dd The drag drop object
47630 * @param {String} targetId The target drag drop object
47631 * @param {event} e The raw browser event
47636 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
47637 * @param {Grid} this
47638 * @param {Roo.GridDD} dd The drag drop object
47639 * @param {String} targetId The target drag drop object
47640 * @param {event} e The raw browser event
47645 * Fires when the dragged row(s) first cross another DD target while being dragged
47646 * @param {Grid} this
47647 * @param {Roo.GridDD} dd The drag drop object
47648 * @param {String} targetId The target drag drop object
47649 * @param {event} e The raw browser event
47651 "dragenter" : true,
47654 * Fires when the dragged row(s) leave another DD target while being dragged
47655 * @param {Grid} this
47656 * @param {Roo.GridDD} dd The drag drop object
47657 * @param {String} targetId The target drag drop object
47658 * @param {event} e The raw browser event
47663 * Fires when a row is rendered, so you can change add a style to it.
47664 * @param {GridView} gridview The grid view
47665 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
47671 * Fires when the grid is rendered
47672 * @param {Grid} grid
47677 Roo.grid.Grid.superclass.constructor.call(this);
47679 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
47682 * @cfg {String} ddGroup - drag drop group.
47686 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
47688 minColumnWidth : 25,
47691 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
47692 * <b>on initial render.</b> It is more efficient to explicitly size the columns
47693 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
47695 autoSizeColumns : false,
47698 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
47700 autoSizeHeaders : true,
47703 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
47705 monitorWindowResize : true,
47708 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
47709 * rows measured to get a columns size. Default is 0 (all rows).
47711 maxRowsToMeasure : 0,
47714 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
47716 trackMouseOver : true,
47719 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
47723 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
47725 enableDragDrop : false,
47728 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
47730 enableColumnMove : true,
47733 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
47735 enableColumnHide : true,
47738 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
47740 enableRowHeightSync : false,
47743 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
47748 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
47750 autoHeight : false,
47753 * @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.
47755 autoExpandColumn : false,
47758 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
47761 autoExpandMin : 50,
47764 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
47766 autoExpandMax : 1000,
47769 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
47774 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
47778 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
47788 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
47789 * of a fixed width. Default is false.
47792 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
47795 * Called once after all setup has been completed and the grid is ready to be rendered.
47796 * @return {Roo.grid.Grid} this
47798 render : function()
47800 var c = this.container;
47801 // try to detect autoHeight/width mode
47802 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
47803 this.autoHeight = true;
47805 var view = this.getView();
47808 c.on("click", this.onClick, this);
47809 c.on("dblclick", this.onDblClick, this);
47810 c.on("contextmenu", this.onContextMenu, this);
47811 c.on("keydown", this.onKeyDown, this);
47813 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
47815 this.getSelectionModel().init(this);
47820 this.loadMask = new Roo.LoadMask(this.container,
47821 Roo.apply({store:this.dataSource}, this.loadMask));
47825 if (this.toolbar && this.toolbar.xtype) {
47826 this.toolbar.container = this.getView().getHeaderPanel(true);
47827 this.toolbar = new Roo.Toolbar(this.toolbar);
47829 if (this.footer && this.footer.xtype) {
47830 this.footer.dataSource = this.getDataSource();
47831 this.footer.container = this.getView().getFooterPanel(true);
47832 this.footer = Roo.factory(this.footer, Roo);
47834 if (this.dropTarget && this.dropTarget.xtype) {
47835 delete this.dropTarget.xtype;
47836 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
47840 this.rendered = true;
47841 this.fireEvent('render', this);
47846 * Reconfigures the grid to use a different Store and Column Model.
47847 * The View will be bound to the new objects and refreshed.
47848 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
47849 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
47851 reconfigure : function(dataSource, colModel){
47853 this.loadMask.destroy();
47854 this.loadMask = new Roo.LoadMask(this.container,
47855 Roo.apply({store:dataSource}, this.loadMask));
47857 this.view.bind(dataSource, colModel);
47858 this.dataSource = dataSource;
47859 this.colModel = colModel;
47860 this.view.refresh(true);
47864 onKeyDown : function(e){
47865 this.fireEvent("keydown", e);
47869 * Destroy this grid.
47870 * @param {Boolean} removeEl True to remove the element
47872 destroy : function(removeEl, keepListeners){
47874 this.loadMask.destroy();
47876 var c = this.container;
47877 c.removeAllListeners();
47878 this.view.destroy();
47879 this.colModel.purgeListeners();
47880 if(!keepListeners){
47881 this.purgeListeners();
47884 if(removeEl === true){
47890 processEvent : function(name, e){
47891 this.fireEvent(name, e);
47892 var t = e.getTarget();
47894 var header = v.findHeaderIndex(t);
47895 if(header !== false){
47896 this.fireEvent("header" + name, this, header, e);
47898 var row = v.findRowIndex(t);
47899 var cell = v.findCellIndex(t);
47901 this.fireEvent("row" + name, this, row, e);
47902 if(cell !== false){
47903 this.fireEvent("cell" + name, this, row, cell, e);
47910 onClick : function(e){
47911 this.processEvent("click", e);
47915 onContextMenu : function(e, t){
47916 this.processEvent("contextmenu", e);
47920 onDblClick : function(e){
47921 this.processEvent("dblclick", e);
47925 walkCells : function(row, col, step, fn, scope){
47926 var cm = this.colModel, clen = cm.getColumnCount();
47927 var ds = this.dataSource, rlen = ds.getCount(), first = true;
47939 if(fn.call(scope || this, row, col, cm) === true){
47957 if(fn.call(scope || this, row, col, cm) === true){
47969 getSelections : function(){
47970 return this.selModel.getSelections();
47974 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
47975 * but if manual update is required this method will initiate it.
47977 autoSize : function(){
47979 this.view.layout();
47980 if(this.view.adjustForScroll){
47981 this.view.adjustForScroll();
47987 * Returns the grid's underlying element.
47988 * @return {Element} The element
47990 getGridEl : function(){
47991 return this.container;
47994 // private for compatibility, overridden by editor grid
47995 stopEditing : function(){},
47998 * Returns the grid's SelectionModel.
47999 * @return {SelectionModel}
48001 getSelectionModel : function(){
48002 if(!this.selModel){
48003 this.selModel = new Roo.grid.RowSelectionModel();
48005 return this.selModel;
48009 * Returns the grid's DataSource.
48010 * @return {DataSource}
48012 getDataSource : function(){
48013 return this.dataSource;
48017 * Returns the grid's ColumnModel.
48018 * @return {ColumnModel}
48020 getColumnModel : function(){
48021 return this.colModel;
48025 * Returns the grid's GridView object.
48026 * @return {GridView}
48028 getView : function(){
48030 this.view = new Roo.grid.GridView(this.viewConfig);
48035 * Called to get grid's drag proxy text, by default returns this.ddText.
48038 getDragDropText : function(){
48039 var count = this.selModel.getCount();
48040 return String.format(this.ddText, count, count == 1 ? '' : 's');
48044 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
48045 * %0 is replaced with the number of selected rows.
48048 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
48050 * Ext JS Library 1.1.1
48051 * Copyright(c) 2006-2007, Ext JS, LLC.
48053 * Originally Released Under LGPL - original licence link has changed is not relivant.
48056 * <script type="text/javascript">
48059 Roo.grid.AbstractGridView = function(){
48063 "beforerowremoved" : true,
48064 "beforerowsinserted" : true,
48065 "beforerefresh" : true,
48066 "rowremoved" : true,
48067 "rowsinserted" : true,
48068 "rowupdated" : true,
48071 Roo.grid.AbstractGridView.superclass.constructor.call(this);
48074 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
48075 rowClass : "x-grid-row",
48076 cellClass : "x-grid-cell",
48077 tdClass : "x-grid-td",
48078 hdClass : "x-grid-hd",
48079 splitClass : "x-grid-hd-split",
48081 init: function(grid){
48083 var cid = this.grid.getGridEl().id;
48084 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
48085 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
48086 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
48087 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
48090 getColumnRenderers : function(){
48091 var renderers = [];
48092 var cm = this.grid.colModel;
48093 var colCount = cm.getColumnCount();
48094 for(var i = 0; i < colCount; i++){
48095 renderers[i] = cm.getRenderer(i);
48100 getColumnIds : function(){
48102 var cm = this.grid.colModel;
48103 var colCount = cm.getColumnCount();
48104 for(var i = 0; i < colCount; i++){
48105 ids[i] = cm.getColumnId(i);
48110 getDataIndexes : function(){
48111 if(!this.indexMap){
48112 this.indexMap = this.buildIndexMap();
48114 return this.indexMap.colToData;
48117 getColumnIndexByDataIndex : function(dataIndex){
48118 if(!this.indexMap){
48119 this.indexMap = this.buildIndexMap();
48121 return this.indexMap.dataToCol[dataIndex];
48125 * Set a css style for a column dynamically.
48126 * @param {Number} colIndex The index of the column
48127 * @param {String} name The css property name
48128 * @param {String} value The css value
48130 setCSSStyle : function(colIndex, name, value){
48131 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
48132 Roo.util.CSS.updateRule(selector, name, value);
48135 generateRules : function(cm){
48136 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
48137 Roo.util.CSS.removeStyleSheet(rulesId);
48138 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48139 var cid = cm.getColumnId(i);
48140 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
48141 this.tdSelector, cid, " {\n}\n",
48142 this.hdSelector, cid, " {\n}\n",
48143 this.splitSelector, cid, " {\n}\n");
48145 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
48149 * Ext JS Library 1.1.1
48150 * Copyright(c) 2006-2007, Ext JS, LLC.
48152 * Originally Released Under LGPL - original licence link has changed is not relivant.
48155 * <script type="text/javascript">
48159 // This is a support class used internally by the Grid components
48160 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
48162 this.view = grid.getView();
48163 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
48164 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
48166 this.setHandleElId(Roo.id(hd));
48167 this.setOuterHandleElId(Roo.id(hd2));
48169 this.scroll = false;
48171 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
48173 getDragData : function(e){
48174 var t = Roo.lib.Event.getTarget(e);
48175 var h = this.view.findHeaderCell(t);
48177 return {ddel: h.firstChild, header:h};
48182 onInitDrag : function(e){
48183 this.view.headersDisabled = true;
48184 var clone = this.dragData.ddel.cloneNode(true);
48185 clone.id = Roo.id();
48186 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
48187 this.proxy.update(clone);
48191 afterValidDrop : function(){
48193 setTimeout(function(){
48194 v.headersDisabled = false;
48198 afterInvalidDrop : function(){
48200 setTimeout(function(){
48201 v.headersDisabled = false;
48207 * Ext JS Library 1.1.1
48208 * Copyright(c) 2006-2007, Ext JS, LLC.
48210 * Originally Released Under LGPL - original licence link has changed is not relivant.
48213 * <script type="text/javascript">
48216 // This is a support class used internally by the Grid components
48217 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
48219 this.view = grid.getView();
48220 // split the proxies so they don't interfere with mouse events
48221 this.proxyTop = Roo.DomHelper.append(document.body, {
48222 cls:"col-move-top", html:" "
48224 this.proxyBottom = Roo.DomHelper.append(document.body, {
48225 cls:"col-move-bottom", html:" "
48227 this.proxyTop.hide = this.proxyBottom.hide = function(){
48228 this.setLeftTop(-100,-100);
48229 this.setStyle("visibility", "hidden");
48231 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
48232 // temporarily disabled
48233 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
48234 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
48236 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
48237 proxyOffsets : [-4, -9],
48238 fly: Roo.Element.fly,
48240 getTargetFromEvent : function(e){
48241 var t = Roo.lib.Event.getTarget(e);
48242 var cindex = this.view.findCellIndex(t);
48243 if(cindex !== false){
48244 return this.view.getHeaderCell(cindex);
48249 nextVisible : function(h){
48250 var v = this.view, cm = this.grid.colModel;
48253 if(!cm.isHidden(v.getCellIndex(h))){
48261 prevVisible : function(h){
48262 var v = this.view, cm = this.grid.colModel;
48265 if(!cm.isHidden(v.getCellIndex(h))){
48273 positionIndicator : function(h, n, e){
48274 var x = Roo.lib.Event.getPageX(e);
48275 var r = Roo.lib.Dom.getRegion(n.firstChild);
48276 var px, pt, py = r.top + this.proxyOffsets[1];
48277 if((r.right - x) <= (r.right-r.left)/2){
48278 px = r.right+this.view.borderWidth;
48284 var oldIndex = this.view.getCellIndex(h);
48285 var newIndex = this.view.getCellIndex(n);
48287 if(this.grid.colModel.isFixed(newIndex)){
48291 var locked = this.grid.colModel.isLocked(newIndex);
48296 if(oldIndex < newIndex){
48299 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
48302 px += this.proxyOffsets[0];
48303 this.proxyTop.setLeftTop(px, py);
48304 this.proxyTop.show();
48305 if(!this.bottomOffset){
48306 this.bottomOffset = this.view.mainHd.getHeight();
48308 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
48309 this.proxyBottom.show();
48313 onNodeEnter : function(n, dd, e, data){
48314 if(data.header != n){
48315 this.positionIndicator(data.header, n, e);
48319 onNodeOver : function(n, dd, e, data){
48320 var result = false;
48321 if(data.header != n){
48322 result = this.positionIndicator(data.header, n, e);
48325 this.proxyTop.hide();
48326 this.proxyBottom.hide();
48328 return result ? this.dropAllowed : this.dropNotAllowed;
48331 onNodeOut : function(n, dd, e, data){
48332 this.proxyTop.hide();
48333 this.proxyBottom.hide();
48336 onNodeDrop : function(n, dd, e, data){
48337 var h = data.header;
48339 var cm = this.grid.colModel;
48340 var x = Roo.lib.Event.getPageX(e);
48341 var r = Roo.lib.Dom.getRegion(n.firstChild);
48342 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
48343 var oldIndex = this.view.getCellIndex(h);
48344 var newIndex = this.view.getCellIndex(n);
48345 var locked = cm.isLocked(newIndex);
48349 if(oldIndex < newIndex){
48352 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
48355 cm.setLocked(oldIndex, locked, true);
48356 cm.moveColumn(oldIndex, newIndex);
48357 this.grid.fireEvent("columnmove", oldIndex, newIndex);
48365 * Ext JS Library 1.1.1
48366 * Copyright(c) 2006-2007, Ext JS, LLC.
48368 * Originally Released Under LGPL - original licence link has changed is not relivant.
48371 * <script type="text/javascript">
48375 * @class Roo.grid.GridView
48376 * @extends Roo.util.Observable
48379 * @param {Object} config
48381 Roo.grid.GridView = function(config){
48382 Roo.grid.GridView.superclass.constructor.call(this);
48385 Roo.apply(this, config);
48388 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
48391 * Override this function to apply custom css classes to rows during rendering
48392 * @param {Record} record The record
48393 * @param {Number} index
48394 * @method getRowClass
48396 rowClass : "x-grid-row",
48398 cellClass : "x-grid-col",
48400 tdClass : "x-grid-td",
48402 hdClass : "x-grid-hd",
48404 splitClass : "x-grid-split",
48406 sortClasses : ["sort-asc", "sort-desc"],
48408 enableMoveAnim : false,
48412 dh : Roo.DomHelper,
48414 fly : Roo.Element.fly,
48416 css : Roo.util.CSS,
48422 scrollIncrement : 22,
48424 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
48426 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
48428 bind : function(ds, cm){
48430 this.ds.un("load", this.onLoad, this);
48431 this.ds.un("datachanged", this.onDataChange, this);
48432 this.ds.un("add", this.onAdd, this);
48433 this.ds.un("remove", this.onRemove, this);
48434 this.ds.un("update", this.onUpdate, this);
48435 this.ds.un("clear", this.onClear, this);
48438 ds.on("load", this.onLoad, this);
48439 ds.on("datachanged", this.onDataChange, this);
48440 ds.on("add", this.onAdd, this);
48441 ds.on("remove", this.onRemove, this);
48442 ds.on("update", this.onUpdate, this);
48443 ds.on("clear", this.onClear, this);
48448 this.cm.un("widthchange", this.onColWidthChange, this);
48449 this.cm.un("headerchange", this.onHeaderChange, this);
48450 this.cm.un("hiddenchange", this.onHiddenChange, this);
48451 this.cm.un("columnmoved", this.onColumnMove, this);
48452 this.cm.un("columnlockchange", this.onColumnLock, this);
48455 this.generateRules(cm);
48456 cm.on("widthchange", this.onColWidthChange, this);
48457 cm.on("headerchange", this.onHeaderChange, this);
48458 cm.on("hiddenchange", this.onHiddenChange, this);
48459 cm.on("columnmoved", this.onColumnMove, this);
48460 cm.on("columnlockchange", this.onColumnLock, this);
48465 init: function(grid){
48466 Roo.grid.GridView.superclass.init.call(this, grid);
48468 this.bind(grid.dataSource, grid.colModel);
48470 grid.on("headerclick", this.handleHeaderClick, this);
48472 if(grid.trackMouseOver){
48473 grid.on("mouseover", this.onRowOver, this);
48474 grid.on("mouseout", this.onRowOut, this);
48476 grid.cancelTextSelection = function(){};
48477 this.gridId = grid.id;
48479 var tpls = this.templates || {};
48482 tpls.master = new Roo.Template(
48483 '<div class="x-grid" hidefocus="true">',
48484 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
48485 '<div class="x-grid-topbar"></div>',
48486 '<div class="x-grid-scroller"><div></div></div>',
48487 '<div class="x-grid-locked">',
48488 '<div class="x-grid-header">{lockedHeader}</div>',
48489 '<div class="x-grid-body">{lockedBody}</div>',
48491 '<div class="x-grid-viewport">',
48492 '<div class="x-grid-header">{header}</div>',
48493 '<div class="x-grid-body">{body}</div>',
48495 '<div class="x-grid-bottombar"></div>',
48497 '<div class="x-grid-resize-proxy"> </div>',
48500 tpls.master.disableformats = true;
48504 tpls.header = new Roo.Template(
48505 '<table border="0" cellspacing="0" cellpadding="0">',
48506 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
48509 tpls.header.disableformats = true;
48511 tpls.header.compile();
48514 tpls.hcell = new Roo.Template(
48515 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
48516 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
48519 tpls.hcell.disableFormats = true;
48521 tpls.hcell.compile();
48524 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
48525 tpls.hsplit.disableFormats = true;
48527 tpls.hsplit.compile();
48530 tpls.body = new Roo.Template(
48531 '<table border="0" cellspacing="0" cellpadding="0">',
48532 "<tbody>{rows}</tbody>",
48535 tpls.body.disableFormats = true;
48537 tpls.body.compile();
48540 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
48541 tpls.row.disableFormats = true;
48543 tpls.row.compile();
48546 tpls.cell = new Roo.Template(
48547 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
48548 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
48551 tpls.cell.disableFormats = true;
48553 tpls.cell.compile();
48555 this.templates = tpls;
48558 // remap these for backwards compat
48559 onColWidthChange : function(){
48560 this.updateColumns.apply(this, arguments);
48562 onHeaderChange : function(){
48563 this.updateHeaders.apply(this, arguments);
48565 onHiddenChange : function(){
48566 this.handleHiddenChange.apply(this, arguments);
48568 onColumnMove : function(){
48569 this.handleColumnMove.apply(this, arguments);
48571 onColumnLock : function(){
48572 this.handleLockChange.apply(this, arguments);
48575 onDataChange : function(){
48577 this.updateHeaderSortState();
48580 onClear : function(){
48584 onUpdate : function(ds, record){
48585 this.refreshRow(record);
48588 refreshRow : function(record){
48589 var ds = this.ds, index;
48590 if(typeof record == 'number'){
48592 record = ds.getAt(index);
48594 index = ds.indexOf(record);
48596 this.insertRows(ds, index, index, true);
48597 this.onRemove(ds, record, index+1, true);
48598 this.syncRowHeights(index, index);
48600 this.fireEvent("rowupdated", this, index, record);
48603 onAdd : function(ds, records, index){
48604 this.insertRows(ds, index, index + (records.length-1));
48607 onRemove : function(ds, record, index, isUpdate){
48608 if(isUpdate !== true){
48609 this.fireEvent("beforerowremoved", this, index, record);
48611 var bt = this.getBodyTable(), lt = this.getLockedTable();
48612 if(bt.rows[index]){
48613 bt.firstChild.removeChild(bt.rows[index]);
48615 if(lt.rows[index]){
48616 lt.firstChild.removeChild(lt.rows[index]);
48618 if(isUpdate !== true){
48619 this.stripeRows(index);
48620 this.syncRowHeights(index, index);
48622 this.fireEvent("rowremoved", this, index, record);
48626 onLoad : function(){
48627 this.scrollToTop();
48631 * Scrolls the grid to the top
48633 scrollToTop : function(){
48635 this.scroller.dom.scrollTop = 0;
48641 * Gets a panel in the header of the grid that can be used for toolbars etc.
48642 * After modifying the contents of this panel a call to grid.autoSize() may be
48643 * required to register any changes in size.
48644 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
48645 * @return Roo.Element
48647 getHeaderPanel : function(doShow){
48649 this.headerPanel.show();
48651 return this.headerPanel;
48655 * Gets a panel in the footer of the grid that can be used for toolbars etc.
48656 * After modifying the contents of this panel a call to grid.autoSize() may be
48657 * required to register any changes in size.
48658 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
48659 * @return Roo.Element
48661 getFooterPanel : function(doShow){
48663 this.footerPanel.show();
48665 return this.footerPanel;
48668 initElements : function(){
48669 var E = Roo.Element;
48670 var el = this.grid.getGridEl().dom.firstChild;
48671 var cs = el.childNodes;
48673 this.el = new E(el);
48675 this.focusEl = new E(el.firstChild);
48676 this.focusEl.swallowEvent("click", true);
48678 this.headerPanel = new E(cs[1]);
48679 this.headerPanel.enableDisplayMode("block");
48681 this.scroller = new E(cs[2]);
48682 this.scrollSizer = new E(this.scroller.dom.firstChild);
48684 this.lockedWrap = new E(cs[3]);
48685 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
48686 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
48688 this.mainWrap = new E(cs[4]);
48689 this.mainHd = new E(this.mainWrap.dom.firstChild);
48690 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
48692 this.footerPanel = new E(cs[5]);
48693 this.footerPanel.enableDisplayMode("block");
48695 this.resizeProxy = new E(cs[6]);
48697 this.headerSelector = String.format(
48698 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
48699 this.lockedHd.id, this.mainHd.id
48702 this.splitterSelector = String.format(
48703 '#{0} div.x-grid-split, #{1} div.x-grid-split',
48704 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
48707 idToCssName : function(s)
48709 return s.replace(/[^a-z0-9]+/ig, '-');
48712 getHeaderCell : function(index){
48713 return Roo.DomQuery.select(this.headerSelector)[index];
48716 getHeaderCellMeasure : function(index){
48717 return this.getHeaderCell(index).firstChild;
48720 getHeaderCellText : function(index){
48721 return this.getHeaderCell(index).firstChild.firstChild;
48724 getLockedTable : function(){
48725 return this.lockedBody.dom.firstChild;
48728 getBodyTable : function(){
48729 return this.mainBody.dom.firstChild;
48732 getLockedRow : function(index){
48733 return this.getLockedTable().rows[index];
48736 getRow : function(index){
48737 return this.getBodyTable().rows[index];
48740 getRowComposite : function(index){
48742 this.rowEl = new Roo.CompositeElementLite();
48744 var els = [], lrow, mrow;
48745 if(lrow = this.getLockedRow(index)){
48748 if(mrow = this.getRow(index)){
48751 this.rowEl.elements = els;
48755 * Gets the 'td' of the cell
48757 * @param {Integer} rowIndex row to select
48758 * @param {Integer} colIndex column to select
48762 getCell : function(rowIndex, colIndex){
48763 var locked = this.cm.getLockedCount();
48765 if(colIndex < locked){
48766 source = this.lockedBody.dom.firstChild;
48768 source = this.mainBody.dom.firstChild;
48769 colIndex -= locked;
48771 return source.rows[rowIndex].childNodes[colIndex];
48774 getCellText : function(rowIndex, colIndex){
48775 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
48778 getCellBox : function(cell){
48779 var b = this.fly(cell).getBox();
48780 if(Roo.isOpera){ // opera fails to report the Y
48781 b.y = cell.offsetTop + this.mainBody.getY();
48786 getCellIndex : function(cell){
48787 var id = String(cell.className).match(this.cellRE);
48789 return parseInt(id[1], 10);
48794 findHeaderIndex : function(n){
48795 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
48796 return r ? this.getCellIndex(r) : false;
48799 findHeaderCell : function(n){
48800 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
48801 return r ? r : false;
48804 findRowIndex : function(n){
48808 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
48809 return r ? r.rowIndex : false;
48812 findCellIndex : function(node){
48813 var stop = this.el.dom;
48814 while(node && node != stop){
48815 if(this.findRE.test(node.className)){
48816 return this.getCellIndex(node);
48818 node = node.parentNode;
48823 getColumnId : function(index){
48824 return this.cm.getColumnId(index);
48827 getSplitters : function()
48829 if(this.splitterSelector){
48830 return Roo.DomQuery.select(this.splitterSelector);
48836 getSplitter : function(index){
48837 return this.getSplitters()[index];
48840 onRowOver : function(e, t){
48842 if((row = this.findRowIndex(t)) !== false){
48843 this.getRowComposite(row).addClass("x-grid-row-over");
48847 onRowOut : function(e, t){
48849 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
48850 this.getRowComposite(row).removeClass("x-grid-row-over");
48854 renderHeaders : function(){
48856 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
48857 var cb = [], lb = [], sb = [], lsb = [], p = {};
48858 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48859 p.cellId = "x-grid-hd-0-" + i;
48860 p.splitId = "x-grid-csplit-0-" + i;
48861 p.id = cm.getColumnId(i);
48862 p.title = cm.getColumnTooltip(i) || "";
48863 p.value = cm.getColumnHeader(i) || "";
48864 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
48865 if(!cm.isLocked(i)){
48866 cb[cb.length] = ct.apply(p);
48867 sb[sb.length] = st.apply(p);
48869 lb[lb.length] = ct.apply(p);
48870 lsb[lsb.length] = st.apply(p);
48873 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
48874 ht.apply({cells: cb.join(""), splits:sb.join("")})];
48877 updateHeaders : function(){
48878 var html = this.renderHeaders();
48879 this.lockedHd.update(html[0]);
48880 this.mainHd.update(html[1]);
48884 * Focuses the specified row.
48885 * @param {Number} row The row index
48887 focusRow : function(row)
48889 //Roo.log('GridView.focusRow');
48890 var x = this.scroller.dom.scrollLeft;
48891 this.focusCell(row, 0, false);
48892 this.scroller.dom.scrollLeft = x;
48896 * Focuses the specified cell.
48897 * @param {Number} row The row index
48898 * @param {Number} col The column index
48899 * @param {Boolean} hscroll false to disable horizontal scrolling
48901 focusCell : function(row, col, hscroll)
48903 //Roo.log('GridView.focusCell');
48904 var el = this.ensureVisible(row, col, hscroll);
48905 this.focusEl.alignTo(el, "tl-tl");
48907 this.focusEl.focus();
48909 this.focusEl.focus.defer(1, this.focusEl);
48914 * Scrolls the specified cell into view
48915 * @param {Number} row The row index
48916 * @param {Number} col The column index
48917 * @param {Boolean} hscroll false to disable horizontal scrolling
48919 ensureVisible : function(row, col, hscroll)
48921 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
48922 //return null; //disable for testing.
48923 if(typeof row != "number"){
48924 row = row.rowIndex;
48926 if(row < 0 && row >= this.ds.getCount()){
48929 col = (col !== undefined ? col : 0);
48930 var cm = this.grid.colModel;
48931 while(cm.isHidden(col)){
48935 var el = this.getCell(row, col);
48939 var c = this.scroller.dom;
48941 var ctop = parseInt(el.offsetTop, 10);
48942 var cleft = parseInt(el.offsetLeft, 10);
48943 var cbot = ctop + el.offsetHeight;
48944 var cright = cleft + el.offsetWidth;
48946 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
48947 var stop = parseInt(c.scrollTop, 10);
48948 var sleft = parseInt(c.scrollLeft, 10);
48949 var sbot = stop + ch;
48950 var sright = sleft + c.clientWidth;
48952 Roo.log('GridView.ensureVisible:' +
48954 ' c.clientHeight:' + c.clientHeight +
48955 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
48963 c.scrollTop = ctop;
48964 //Roo.log("set scrolltop to ctop DISABLE?");
48965 }else if(cbot > sbot){
48966 //Roo.log("set scrolltop to cbot-ch");
48967 c.scrollTop = cbot-ch;
48970 if(hscroll !== false){
48972 c.scrollLeft = cleft;
48973 }else if(cright > sright){
48974 c.scrollLeft = cright-c.clientWidth;
48981 updateColumns : function(){
48982 this.grid.stopEditing();
48983 var cm = this.grid.colModel, colIds = this.getColumnIds();
48984 //var totalWidth = cm.getTotalWidth();
48986 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48987 //if(cm.isHidden(i)) continue;
48988 var w = cm.getColumnWidth(i);
48989 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48990 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48992 this.updateSplitters();
48995 generateRules : function(cm){
48996 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
48997 Roo.util.CSS.removeStyleSheet(rulesId);
48998 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48999 var cid = cm.getColumnId(i);
49001 if(cm.config[i].align){
49002 align = 'text-align:'+cm.config[i].align+';';
49005 if(cm.isHidden(i)){
49006 hidden = 'display:none;';
49008 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
49010 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
49011 this.hdSelector, cid, " {\n", align, width, "}\n",
49012 this.tdSelector, cid, " {\n",hidden,"\n}\n",
49013 this.splitSelector, cid, " {\n", hidden , "\n}\n");
49015 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
49018 updateSplitters : function(){
49019 var cm = this.cm, s = this.getSplitters();
49020 if(s){ // splitters not created yet
49021 var pos = 0, locked = true;
49022 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
49023 if(cm.isHidden(i)) continue;
49024 var w = cm.getColumnWidth(i); // make sure it's a number
49025 if(!cm.isLocked(i) && locked){
49030 s[i].style.left = (pos-this.splitOffset) + "px";
49035 handleHiddenChange : function(colModel, colIndex, hidden){
49037 this.hideColumn(colIndex);
49039 this.unhideColumn(colIndex);
49043 hideColumn : function(colIndex){
49044 var cid = this.getColumnId(colIndex);
49045 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
49046 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
49048 this.updateHeaders();
49050 this.updateSplitters();
49054 unhideColumn : function(colIndex){
49055 var cid = this.getColumnId(colIndex);
49056 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
49057 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
49060 this.updateHeaders();
49062 this.updateSplitters();
49066 insertRows : function(dm, firstRow, lastRow, isUpdate){
49067 if(firstRow == 0 && lastRow == dm.getCount()-1){
49071 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
49073 var s = this.getScrollState();
49074 var markup = this.renderRows(firstRow, lastRow);
49075 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
49076 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
49077 this.restoreScroll(s);
49079 this.fireEvent("rowsinserted", this, firstRow, lastRow);
49080 this.syncRowHeights(firstRow, lastRow);
49081 this.stripeRows(firstRow);
49087 bufferRows : function(markup, target, index){
49088 var before = null, trows = target.rows, tbody = target.tBodies[0];
49089 if(index < trows.length){
49090 before = trows[index];
49092 var b = document.createElement("div");
49093 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
49094 var rows = b.firstChild.rows;
49095 for(var i = 0, len = rows.length; i < len; i++){
49097 tbody.insertBefore(rows[0], before);
49099 tbody.appendChild(rows[0]);
49106 deleteRows : function(dm, firstRow, lastRow){
49107 if(dm.getRowCount()<1){
49108 this.fireEvent("beforerefresh", this);
49109 this.mainBody.update("");
49110 this.lockedBody.update("");
49111 this.fireEvent("refresh", this);
49113 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
49114 var bt = this.getBodyTable();
49115 var tbody = bt.firstChild;
49116 var rows = bt.rows;
49117 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
49118 tbody.removeChild(rows[firstRow]);
49120 this.stripeRows(firstRow);
49121 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
49125 updateRows : function(dataSource, firstRow, lastRow){
49126 var s = this.getScrollState();
49128 this.restoreScroll(s);
49131 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
49135 this.updateHeaderSortState();
49138 getScrollState : function(){
49140 var sb = this.scroller.dom;
49141 return {left: sb.scrollLeft, top: sb.scrollTop};
49144 stripeRows : function(startRow){
49145 if(!this.grid.stripeRows || this.ds.getCount() < 1){
49148 startRow = startRow || 0;
49149 var rows = this.getBodyTable().rows;
49150 var lrows = this.getLockedTable().rows;
49151 var cls = ' x-grid-row-alt ';
49152 for(var i = startRow, len = rows.length; i < len; i++){
49153 var row = rows[i], lrow = lrows[i];
49154 var isAlt = ((i+1) % 2 == 0);
49155 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
49156 if(isAlt == hasAlt){
49160 row.className += " x-grid-row-alt";
49162 row.className = row.className.replace("x-grid-row-alt", "");
49165 lrow.className = row.className;
49170 restoreScroll : function(state){
49171 //Roo.log('GridView.restoreScroll');
49172 var sb = this.scroller.dom;
49173 sb.scrollLeft = state.left;
49174 sb.scrollTop = state.top;
49178 syncScroll : function(){
49179 //Roo.log('GridView.syncScroll');
49180 var sb = this.scroller.dom;
49181 var sh = this.mainHd.dom;
49182 var bs = this.mainBody.dom;
49183 var lv = this.lockedBody.dom;
49184 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
49185 lv.scrollTop = bs.scrollTop = sb.scrollTop;
49188 handleScroll : function(e){
49190 var sb = this.scroller.dom;
49191 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
49195 handleWheel : function(e){
49196 var d = e.getWheelDelta();
49197 this.scroller.dom.scrollTop -= d*22;
49198 // set this here to prevent jumpy scrolling on large tables
49199 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
49203 renderRows : function(startRow, endRow){
49204 // pull in all the crap needed to render rows
49205 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
49206 var colCount = cm.getColumnCount();
49208 if(ds.getCount() < 1){
49212 // build a map for all the columns
49214 for(var i = 0; i < colCount; i++){
49215 var name = cm.getDataIndex(i);
49217 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
49218 renderer : cm.getRenderer(i),
49219 id : cm.getColumnId(i),
49220 locked : cm.isLocked(i)
49224 startRow = startRow || 0;
49225 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
49227 // records to render
49228 var rs = ds.getRange(startRow, endRow);
49230 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
49233 // As much as I hate to duplicate code, this was branched because FireFox really hates
49234 // [].join("") on strings. The performance difference was substantial enough to
49235 // branch this function
49236 doRender : Roo.isGecko ?
49237 function(cs, rs, ds, startRow, colCount, stripe){
49238 var ts = this.templates, ct = ts.cell, rt = ts.row;
49240 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
49242 var hasListener = this.grid.hasListener('rowclass');
49244 for(var j = 0, len = rs.length; j < len; j++){
49245 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
49246 for(var i = 0; i < colCount; i++){
49248 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
49250 p.css = p.attr = "";
49251 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
49252 if(p.value == undefined || p.value === "") p.value = " ";
49253 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
49254 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
49256 var markup = ct.apply(p);
49264 if(stripe && ((rowIndex+1) % 2 == 0)){
49265 alt.push("x-grid-row-alt")
49268 alt.push( " x-grid-dirty-row");
49271 if(this.getRowClass){
49272 alt.push(this.getRowClass(r, rowIndex));
49278 rowIndex : rowIndex,
49281 this.grid.fireEvent('rowclass', this, rowcfg);
49282 alt.push(rowcfg.rowClass);
49284 rp.alt = alt.join(" ");
49285 lbuf+= rt.apply(rp);
49287 buf+= rt.apply(rp);
49289 return [lbuf, buf];
49291 function(cs, rs, ds, startRow, colCount, stripe){
49292 var ts = this.templates, ct = ts.cell, rt = ts.row;
49294 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
49295 var hasListener = this.grid.hasListener('rowclass');
49297 for(var j = 0, len = rs.length; j < len; j++){
49298 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
49299 for(var i = 0; i < colCount; i++){
49301 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
49303 p.css = p.attr = "";
49304 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
49305 if(p.value == undefined || p.value === "") p.value = " ";
49306 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
49307 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
49309 var markup = ct.apply(p);
49311 cb[cb.length] = markup;
49313 lcb[lcb.length] = markup;
49317 if(stripe && ((rowIndex+1) % 2 == 0)){
49318 alt.push( "x-grid-row-alt");
49321 alt.push(" x-grid-dirty-row");
49324 if(this.getRowClass){
49325 alt.push( this.getRowClass(r, rowIndex));
49331 rowIndex : rowIndex,
49334 this.grid.fireEvent('rowclass', this, rowcfg);
49335 alt.push(rowcfg.rowClass);
49337 rp.alt = alt.join(" ");
49338 rp.cells = lcb.join("");
49339 lbuf[lbuf.length] = rt.apply(rp);
49340 rp.cells = cb.join("");
49341 buf[buf.length] = rt.apply(rp);
49343 return [lbuf.join(""), buf.join("")];
49346 renderBody : function(){
49347 var markup = this.renderRows();
49348 var bt = this.templates.body;
49349 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
49353 * Refreshes the grid
49354 * @param {Boolean} headersToo
49356 refresh : function(headersToo){
49357 this.fireEvent("beforerefresh", this);
49358 this.grid.stopEditing();
49359 var result = this.renderBody();
49360 this.lockedBody.update(result[0]);
49361 this.mainBody.update(result[1]);
49362 if(headersToo === true){
49363 this.updateHeaders();
49364 this.updateColumns();
49365 this.updateSplitters();
49366 this.updateHeaderSortState();
49368 this.syncRowHeights();
49370 this.fireEvent("refresh", this);
49373 handleColumnMove : function(cm, oldIndex, newIndex){
49374 this.indexMap = null;
49375 var s = this.getScrollState();
49376 this.refresh(true);
49377 this.restoreScroll(s);
49378 this.afterMove(newIndex);
49381 afterMove : function(colIndex){
49382 if(this.enableMoveAnim && Roo.enableFx){
49383 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
49385 // if multisort - fix sortOrder, and reload..
49386 if (this.grid.dataSource.multiSort) {
49387 // the we can call sort again..
49388 var dm = this.grid.dataSource;
49389 var cm = this.grid.colModel;
49391 for(var i = 0; i < cm.config.length; i++ ) {
49393 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
49394 continue; // dont' bother, it's not in sort list or being set.
49397 so.push(cm.config[i].dataIndex);
49400 dm.load(dm.lastOptions);
49407 updateCell : function(dm, rowIndex, dataIndex){
49408 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
49409 if(typeof colIndex == "undefined"){ // not present in grid
49412 var cm = this.grid.colModel;
49413 var cell = this.getCell(rowIndex, colIndex);
49414 var cellText = this.getCellText(rowIndex, colIndex);
49417 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
49418 id : cm.getColumnId(colIndex),
49419 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
49421 var renderer = cm.getRenderer(colIndex);
49422 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
49423 if(typeof val == "undefined" || val === "") val = " ";
49424 cellText.innerHTML = val;
49425 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
49426 this.syncRowHeights(rowIndex, rowIndex);
49429 calcColumnWidth : function(colIndex, maxRowsToMeasure){
49431 if(this.grid.autoSizeHeaders){
49432 var h = this.getHeaderCellMeasure(colIndex);
49433 maxWidth = Math.max(maxWidth, h.scrollWidth);
49436 if(this.cm.isLocked(colIndex)){
49437 tb = this.getLockedTable();
49440 tb = this.getBodyTable();
49441 index = colIndex - this.cm.getLockedCount();
49444 var rows = tb.rows;
49445 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
49446 for(var i = 0; i < stopIndex; i++){
49447 var cell = rows[i].childNodes[index].firstChild;
49448 maxWidth = Math.max(maxWidth, cell.scrollWidth);
49451 return maxWidth + /*margin for error in IE*/ 5;
49454 * Autofit a column to its content.
49455 * @param {Number} colIndex
49456 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
49458 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
49459 if(this.cm.isHidden(colIndex)){
49460 return; // can't calc a hidden column
49463 var cid = this.cm.getColumnId(colIndex);
49464 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
49465 if(this.grid.autoSizeHeaders){
49466 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
49469 var newWidth = this.calcColumnWidth(colIndex);
49470 this.cm.setColumnWidth(colIndex,
49471 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
49472 if(!suppressEvent){
49473 this.grid.fireEvent("columnresize", colIndex, newWidth);
49478 * Autofits all columns to their content and then expands to fit any extra space in the grid
49480 autoSizeColumns : function(){
49481 var cm = this.grid.colModel;
49482 var colCount = cm.getColumnCount();
49483 for(var i = 0; i < colCount; i++){
49484 this.autoSizeColumn(i, true, true);
49486 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
49489 this.updateColumns();
49495 * Autofits all columns to the grid's width proportionate with their current size
49496 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
49498 fitColumns : function(reserveScrollSpace){
49499 var cm = this.grid.colModel;
49500 var colCount = cm.getColumnCount();
49504 for (i = 0; i < colCount; i++){
49505 if(!cm.isHidden(i) && !cm.isFixed(i)){
49506 w = cm.getColumnWidth(i);
49512 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
49513 if(reserveScrollSpace){
49516 var frac = (avail - cm.getTotalWidth())/width;
49517 while (cols.length){
49520 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
49522 this.updateColumns();
49526 onRowSelect : function(rowIndex){
49527 var row = this.getRowComposite(rowIndex);
49528 row.addClass("x-grid-row-selected");
49531 onRowDeselect : function(rowIndex){
49532 var row = this.getRowComposite(rowIndex);
49533 row.removeClass("x-grid-row-selected");
49536 onCellSelect : function(row, col){
49537 var cell = this.getCell(row, col);
49539 Roo.fly(cell).addClass("x-grid-cell-selected");
49543 onCellDeselect : function(row, col){
49544 var cell = this.getCell(row, col);
49546 Roo.fly(cell).removeClass("x-grid-cell-selected");
49550 updateHeaderSortState : function(){
49552 // sort state can be single { field: xxx, direction : yyy}
49553 // or { xxx=>ASC , yyy : DESC ..... }
49556 if (!this.ds.multiSort) {
49557 var state = this.ds.getSortState();
49561 mstate[state.field] = state.direction;
49562 // FIXME... - this is not used here.. but might be elsewhere..
49563 this.sortState = state;
49566 mstate = this.ds.sortToggle;
49568 //remove existing sort classes..
49570 var sc = this.sortClasses;
49571 var hds = this.el.select(this.headerSelector).removeClass(sc);
49573 for(var f in mstate) {
49575 var sortColumn = this.cm.findColumnIndex(f);
49577 if(sortColumn != -1){
49578 var sortDir = mstate[f];
49579 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
49588 handleHeaderClick : function(g, index){
49589 if(this.headersDisabled){
49592 var dm = g.dataSource, cm = g.colModel;
49593 if(!cm.isSortable(index)){
49598 if (dm.multiSort) {
49599 // update the sortOrder
49601 for(var i = 0; i < cm.config.length; i++ ) {
49603 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
49604 continue; // dont' bother, it's not in sort list or being set.
49607 so.push(cm.config[i].dataIndex);
49613 dm.sort(cm.getDataIndex(index));
49617 destroy : function(){
49619 this.colMenu.removeAll();
49620 Roo.menu.MenuMgr.unregister(this.colMenu);
49621 this.colMenu.getEl().remove();
49622 delete this.colMenu;
49625 this.hmenu.removeAll();
49626 Roo.menu.MenuMgr.unregister(this.hmenu);
49627 this.hmenu.getEl().remove();
49630 if(this.grid.enableColumnMove){
49631 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
49633 for(var dd in dds){
49634 if(!dds[dd].config.isTarget && dds[dd].dragElId){
49635 var elid = dds[dd].dragElId;
49637 Roo.get(elid).remove();
49638 } else if(dds[dd].config.isTarget){
49639 dds[dd].proxyTop.remove();
49640 dds[dd].proxyBottom.remove();
49643 if(Roo.dd.DDM.locationCache[dd]){
49644 delete Roo.dd.DDM.locationCache[dd];
49647 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
49650 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
49651 this.bind(null, null);
49652 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
49655 handleLockChange : function(){
49656 this.refresh(true);
49659 onDenyColumnLock : function(){
49663 onDenyColumnHide : function(){
49667 handleHdMenuClick : function(item){
49668 var index = this.hdCtxIndex;
49669 var cm = this.cm, ds = this.ds;
49672 ds.sort(cm.getDataIndex(index), "ASC");
49675 ds.sort(cm.getDataIndex(index), "DESC");
49678 var lc = cm.getLockedCount();
49679 if(cm.getColumnCount(true) <= lc+1){
49680 this.onDenyColumnLock();
49684 cm.setLocked(index, true, true);
49685 cm.moveColumn(index, lc);
49686 this.grid.fireEvent("columnmove", index, lc);
49688 cm.setLocked(index, true);
49692 var lc = cm.getLockedCount();
49693 if((lc-1) != index){
49694 cm.setLocked(index, false, true);
49695 cm.moveColumn(index, lc-1);
49696 this.grid.fireEvent("columnmove", index, lc-1);
49698 cm.setLocked(index, false);
49702 index = cm.getIndexById(item.id.substr(4));
49704 if(item.checked && cm.getColumnCount(true) <= 1){
49705 this.onDenyColumnHide();
49708 cm.setHidden(index, item.checked);
49714 beforeColMenuShow : function(){
49715 var cm = this.cm, colCount = cm.getColumnCount();
49716 this.colMenu.removeAll();
49717 for(var i = 0; i < colCount; i++){
49718 this.colMenu.add(new Roo.menu.CheckItem({
49719 id: "col-"+cm.getColumnId(i),
49720 text: cm.getColumnHeader(i),
49721 checked: !cm.isHidden(i),
49727 handleHdCtx : function(g, index, e){
49729 var hd = this.getHeaderCell(index);
49730 this.hdCtxIndex = index;
49731 var ms = this.hmenu.items, cm = this.cm;
49732 ms.get("asc").setDisabled(!cm.isSortable(index));
49733 ms.get("desc").setDisabled(!cm.isSortable(index));
49734 if(this.grid.enableColLock !== false){
49735 ms.get("lock").setDisabled(cm.isLocked(index));
49736 ms.get("unlock").setDisabled(!cm.isLocked(index));
49738 this.hmenu.show(hd, "tl-bl");
49741 handleHdOver : function(e){
49742 var hd = this.findHeaderCell(e.getTarget());
49743 if(hd && !this.headersDisabled){
49744 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
49745 this.fly(hd).addClass("x-grid-hd-over");
49750 handleHdOut : function(e){
49751 var hd = this.findHeaderCell(e.getTarget());
49753 this.fly(hd).removeClass("x-grid-hd-over");
49757 handleSplitDblClick : function(e, t){
49758 var i = this.getCellIndex(t);
49759 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
49760 this.autoSizeColumn(i, true);
49765 render : function(){
49768 var colCount = cm.getColumnCount();
49770 if(this.grid.monitorWindowResize === true){
49771 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
49773 var header = this.renderHeaders();
49774 var body = this.templates.body.apply({rows:""});
49775 var html = this.templates.master.apply({
49778 lockedHeader: header[0],
49782 //this.updateColumns();
49784 this.grid.getGridEl().dom.innerHTML = html;
49786 this.initElements();
49788 // a kludge to fix the random scolling effect in webkit
49789 this.el.on("scroll", function() {
49790 this.el.dom.scrollTop=0; // hopefully not recursive..
49793 this.scroller.on("scroll", this.handleScroll, this);
49794 this.lockedBody.on("mousewheel", this.handleWheel, this);
49795 this.mainBody.on("mousewheel", this.handleWheel, this);
49797 this.mainHd.on("mouseover", this.handleHdOver, this);
49798 this.mainHd.on("mouseout", this.handleHdOut, this);
49799 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
49800 {delegate: "."+this.splitClass});
49802 this.lockedHd.on("mouseover", this.handleHdOver, this);
49803 this.lockedHd.on("mouseout", this.handleHdOut, this);
49804 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
49805 {delegate: "."+this.splitClass});
49807 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
49808 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
49811 this.updateSplitters();
49813 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
49814 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
49815 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
49818 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
49819 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
49821 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
49822 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
49824 if(this.grid.enableColLock !== false){
49825 this.hmenu.add('-',
49826 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
49827 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
49830 if(this.grid.enableColumnHide !== false){
49832 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
49833 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
49834 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
49836 this.hmenu.add('-',
49837 {id:"columns", text: this.columnsText, menu: this.colMenu}
49840 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
49842 this.grid.on("headercontextmenu", this.handleHdCtx, this);
49845 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
49846 this.dd = new Roo.grid.GridDragZone(this.grid, {
49847 ddGroup : this.grid.ddGroup || 'GridDD'
49852 for(var i = 0; i < colCount; i++){
49853 if(cm.isHidden(i)){
49854 this.hideColumn(i);
49856 if(cm.config[i].align){
49857 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
49858 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
49862 this.updateHeaderSortState();
49864 this.beforeInitialResize();
49867 // two part rendering gives faster view to the user
49868 this.renderPhase2.defer(1, this);
49871 renderPhase2 : function(){
49872 // render the rows now
49874 if(this.grid.autoSizeColumns){
49875 this.autoSizeColumns();
49879 beforeInitialResize : function(){
49883 onColumnSplitterMoved : function(i, w){
49884 this.userResized = true;
49885 var cm = this.grid.colModel;
49886 cm.setColumnWidth(i, w, true);
49887 var cid = cm.getColumnId(i);
49888 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
49889 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
49890 this.updateSplitters();
49892 this.grid.fireEvent("columnresize", i, w);
49895 syncRowHeights : function(startIndex, endIndex){
49896 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
49897 startIndex = startIndex || 0;
49898 var mrows = this.getBodyTable().rows;
49899 var lrows = this.getLockedTable().rows;
49900 var len = mrows.length-1;
49901 endIndex = Math.min(endIndex || len, len);
49902 for(var i = startIndex; i <= endIndex; i++){
49903 var m = mrows[i], l = lrows[i];
49904 var h = Math.max(m.offsetHeight, l.offsetHeight);
49905 m.style.height = l.style.height = h + "px";
49910 layout : function(initialRender, is2ndPass){
49912 var auto = g.autoHeight;
49913 var scrollOffset = 16;
49914 var c = g.getGridEl(), cm = this.cm,
49915 expandCol = g.autoExpandColumn,
49917 //c.beginMeasure();
49919 if(!c.dom.offsetWidth){ // display:none?
49921 this.lockedWrap.show();
49922 this.mainWrap.show();
49927 var hasLock = this.cm.isLocked(0);
49929 var tbh = this.headerPanel.getHeight();
49930 var bbh = this.footerPanel.getHeight();
49933 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
49934 var newHeight = ch + c.getBorderWidth("tb");
49936 newHeight = Math.min(g.maxHeight, newHeight);
49938 c.setHeight(newHeight);
49942 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
49945 var s = this.scroller;
49947 var csize = c.getSize(true);
49949 this.el.setSize(csize.width, csize.height);
49951 this.headerPanel.setWidth(csize.width);
49952 this.footerPanel.setWidth(csize.width);
49954 var hdHeight = this.mainHd.getHeight();
49955 var vw = csize.width;
49956 var vh = csize.height - (tbh + bbh);
49960 var bt = this.getBodyTable();
49961 var ltWidth = hasLock ?
49962 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
49964 var scrollHeight = bt.offsetHeight;
49965 var scrollWidth = ltWidth + bt.offsetWidth;
49966 var vscroll = false, hscroll = false;
49968 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
49970 var lw = this.lockedWrap, mw = this.mainWrap;
49971 var lb = this.lockedBody, mb = this.mainBody;
49973 setTimeout(function(){
49974 var t = s.dom.offsetTop;
49975 var w = s.dom.clientWidth,
49976 h = s.dom.clientHeight;
49979 lw.setSize(ltWidth, h);
49981 mw.setLeftTop(ltWidth, t);
49982 mw.setSize(w-ltWidth, h);
49984 lb.setHeight(h-hdHeight);
49985 mb.setHeight(h-hdHeight);
49987 if(is2ndPass !== true && !gv.userResized && expandCol){
49988 // high speed resize without full column calculation
49990 var ci = cm.getIndexById(expandCol);
49992 ci = cm.findColumnIndex(expandCol);
49994 ci = Math.max(0, ci); // make sure it's got at least the first col.
49995 var expandId = cm.getColumnId(ci);
49996 var tw = cm.getTotalWidth(false);
49997 var currentWidth = cm.getColumnWidth(ci);
49998 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
49999 if(currentWidth != cw){
50000 cm.setColumnWidth(ci, cw, true);
50001 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
50002 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
50003 gv.updateSplitters();
50004 gv.layout(false, true);
50016 onWindowResize : function(){
50017 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
50023 appendFooter : function(parentEl){
50027 sortAscText : "Sort Ascending",
50028 sortDescText : "Sort Descending",
50029 lockText : "Lock Column",
50030 unlockText : "Unlock Column",
50031 columnsText : "Columns"
50035 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
50036 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
50037 this.proxy.el.addClass('x-grid3-col-dd');
50040 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
50041 handleMouseDown : function(e){
50045 callHandleMouseDown : function(e){
50046 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
50051 * Ext JS Library 1.1.1
50052 * Copyright(c) 2006-2007, Ext JS, LLC.
50054 * Originally Released Under LGPL - original licence link has changed is not relivant.
50057 * <script type="text/javascript">
50061 // This is a support class used internally by the Grid components
50062 Roo.grid.SplitDragZone = function(grid, hd, hd2){
50064 this.view = grid.getView();
50065 this.proxy = this.view.resizeProxy;
50066 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
50067 "gridSplitters" + this.grid.getGridEl().id, {
50068 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
50070 this.setHandleElId(Roo.id(hd));
50071 this.setOuterHandleElId(Roo.id(hd2));
50072 this.scroll = false;
50074 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
50075 fly: Roo.Element.fly,
50077 b4StartDrag : function(x, y){
50078 this.view.headersDisabled = true;
50079 this.proxy.setHeight(this.view.mainWrap.getHeight());
50080 var w = this.cm.getColumnWidth(this.cellIndex);
50081 var minw = Math.max(w-this.grid.minColumnWidth, 0);
50082 this.resetConstraints();
50083 this.setXConstraint(minw, 1000);
50084 this.setYConstraint(0, 0);
50085 this.minX = x - minw;
50086 this.maxX = x + 1000;
50088 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
50092 handleMouseDown : function(e){
50093 ev = Roo.EventObject.setEvent(e);
50094 var t = this.fly(ev.getTarget());
50095 if(t.hasClass("x-grid-split")){
50096 this.cellIndex = this.view.getCellIndex(t.dom);
50097 this.split = t.dom;
50098 this.cm = this.grid.colModel;
50099 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
50100 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
50105 endDrag : function(e){
50106 this.view.headersDisabled = false;
50107 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
50108 var diff = endX - this.startPos;
50109 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
50112 autoOffset : function(){
50113 this.setDelta(0,0);
50117 * Ext JS Library 1.1.1
50118 * Copyright(c) 2006-2007, Ext JS, LLC.
50120 * Originally Released Under LGPL - original licence link has changed is not relivant.
50123 * <script type="text/javascript">
50127 // This is a support class used internally by the Grid components
50128 Roo.grid.GridDragZone = function(grid, config){
50129 this.view = grid.getView();
50130 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
50131 if(this.view.lockedBody){
50132 this.setHandleElId(Roo.id(this.view.mainBody.dom));
50133 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
50135 this.scroll = false;
50137 this.ddel = document.createElement('div');
50138 this.ddel.className = 'x-grid-dd-wrap';
50141 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
50142 ddGroup : "GridDD",
50144 getDragData : function(e){
50145 var t = Roo.lib.Event.getTarget(e);
50146 var rowIndex = this.view.findRowIndex(t);
50147 if(rowIndex !== false){
50148 var sm = this.grid.selModel;
50149 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
50150 // sm.mouseDown(e, t);
50152 if (e.hasModifier()){
50153 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
50155 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
50160 onInitDrag : function(e){
50161 var data = this.dragData;
50162 this.ddel.innerHTML = this.grid.getDragDropText();
50163 this.proxy.update(this.ddel);
50164 // fire start drag?
50167 afterRepair : function(){
50168 this.dragging = false;
50171 getRepairXY : function(e, data){
50175 onEndDrag : function(data, e){
50179 onValidDrop : function(dd, e, id){
50184 beforeInvalidDrop : function(e, id){
50189 * Ext JS Library 1.1.1
50190 * Copyright(c) 2006-2007, Ext JS, LLC.
50192 * Originally Released Under LGPL - original licence link has changed is not relivant.
50195 * <script type="text/javascript">
50200 * @class Roo.grid.ColumnModel
50201 * @extends Roo.util.Observable
50202 * This is the default implementation of a ColumnModel used by the Grid. It defines
50203 * the columns in the grid.
50206 var colModel = new Roo.grid.ColumnModel([
50207 {header: "Ticker", width: 60, sortable: true, locked: true},
50208 {header: "Company Name", width: 150, sortable: true},
50209 {header: "Market Cap.", width: 100, sortable: true},
50210 {header: "$ Sales", width: 100, sortable: true, renderer: money},
50211 {header: "Employees", width: 100, sortable: true, resizable: false}
50216 * The config options listed for this class are options which may appear in each
50217 * individual column definition.
50218 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
50220 * @param {Object} config An Array of column config objects. See this class's
50221 * config objects for details.
50223 Roo.grid.ColumnModel = function(config){
50225 * The config passed into the constructor
50227 this.config = config;
50230 // if no id, create one
50231 // if the column does not have a dataIndex mapping,
50232 // map it to the order it is in the config
50233 for(var i = 0, len = config.length; i < len; i++){
50235 if(typeof c.dataIndex == "undefined"){
50238 if(typeof c.renderer == "string"){
50239 c.renderer = Roo.util.Format[c.renderer];
50241 if(typeof c.id == "undefined"){
50244 if(c.editor && c.editor.xtype){
50245 c.editor = Roo.factory(c.editor, Roo.grid);
50247 if(c.editor && c.editor.isFormField){
50248 c.editor = new Roo.grid.GridEditor(c.editor);
50250 this.lookup[c.id] = c;
50254 * The width of columns which have no width specified (defaults to 100)
50257 this.defaultWidth = 100;
50260 * Default sortable of columns which have no sortable specified (defaults to false)
50263 this.defaultSortable = false;
50267 * @event widthchange
50268 * Fires when the width of a column changes.
50269 * @param {ColumnModel} this
50270 * @param {Number} columnIndex The column index
50271 * @param {Number} newWidth The new width
50273 "widthchange": true,
50275 * @event headerchange
50276 * Fires when the text of a header changes.
50277 * @param {ColumnModel} this
50278 * @param {Number} columnIndex The column index
50279 * @param {Number} newText The new header text
50281 "headerchange": true,
50283 * @event hiddenchange
50284 * Fires when a column is hidden or "unhidden".
50285 * @param {ColumnModel} this
50286 * @param {Number} columnIndex The column index
50287 * @param {Boolean} hidden true if hidden, false otherwise
50289 "hiddenchange": true,
50291 * @event columnmoved
50292 * Fires when a column is moved.
50293 * @param {ColumnModel} this
50294 * @param {Number} oldIndex
50295 * @param {Number} newIndex
50297 "columnmoved" : true,
50299 * @event columlockchange
50300 * Fires when a column's locked state is changed
50301 * @param {ColumnModel} this
50302 * @param {Number} colIndex
50303 * @param {Boolean} locked true if locked
50305 "columnlockchange" : true
50307 Roo.grid.ColumnModel.superclass.constructor.call(this);
50309 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
50311 * @cfg {String} header The header text to display in the Grid view.
50314 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
50315 * {@link Roo.data.Record} definition from which to draw the column's value. If not
50316 * specified, the column's index is used as an index into the Record's data Array.
50319 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
50320 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
50323 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
50324 * Defaults to the value of the {@link #defaultSortable} property.
50325 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
50328 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
50331 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
50334 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
50337 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
50340 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
50341 * given the cell's data value. See {@link #setRenderer}. If not specified, the
50342 * default renderer uses the raw data value.
50345 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
50348 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
50352 * Returns the id of the column at the specified index.
50353 * @param {Number} index The column index
50354 * @return {String} the id
50356 getColumnId : function(index){
50357 return this.config[index].id;
50361 * Returns the column for a specified id.
50362 * @param {String} id The column id
50363 * @return {Object} the column
50365 getColumnById : function(id){
50366 return this.lookup[id];
50371 * Returns the column for a specified dataIndex.
50372 * @param {String} dataIndex The column dataIndex
50373 * @return {Object|Boolean} the column or false if not found
50375 getColumnByDataIndex: function(dataIndex){
50376 var index = this.findColumnIndex(dataIndex);
50377 return index > -1 ? this.config[index] : false;
50381 * Returns the index for a specified column id.
50382 * @param {String} id The column id
50383 * @return {Number} the index, or -1 if not found
50385 getIndexById : function(id){
50386 for(var i = 0, len = this.config.length; i < len; i++){
50387 if(this.config[i].id == id){
50395 * Returns the index for a specified column dataIndex.
50396 * @param {String} dataIndex The column dataIndex
50397 * @return {Number} the index, or -1 if not found
50400 findColumnIndex : function(dataIndex){
50401 for(var i = 0, len = this.config.length; i < len; i++){
50402 if(this.config[i].dataIndex == dataIndex){
50410 moveColumn : function(oldIndex, newIndex){
50411 var c = this.config[oldIndex];
50412 this.config.splice(oldIndex, 1);
50413 this.config.splice(newIndex, 0, c);
50414 this.dataMap = null;
50415 this.fireEvent("columnmoved", this, oldIndex, newIndex);
50418 isLocked : function(colIndex){
50419 return this.config[colIndex].locked === true;
50422 setLocked : function(colIndex, value, suppressEvent){
50423 if(this.isLocked(colIndex) == value){
50426 this.config[colIndex].locked = value;
50427 if(!suppressEvent){
50428 this.fireEvent("columnlockchange", this, colIndex, value);
50432 getTotalLockedWidth : function(){
50433 var totalWidth = 0;
50434 for(var i = 0; i < this.config.length; i++){
50435 if(this.isLocked(i) && !this.isHidden(i)){
50436 this.totalWidth += this.getColumnWidth(i);
50442 getLockedCount : function(){
50443 for(var i = 0, len = this.config.length; i < len; i++){
50444 if(!this.isLocked(i)){
50451 * Returns the number of columns.
50454 getColumnCount : function(visibleOnly){
50455 if(visibleOnly === true){
50457 for(var i = 0, len = this.config.length; i < len; i++){
50458 if(!this.isHidden(i)){
50464 return this.config.length;
50468 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
50469 * @param {Function} fn
50470 * @param {Object} scope (optional)
50471 * @return {Array} result
50473 getColumnsBy : function(fn, scope){
50475 for(var i = 0, len = this.config.length; i < len; i++){
50476 var c = this.config[i];
50477 if(fn.call(scope||this, c, i) === true){
50485 * Returns true if the specified column is sortable.
50486 * @param {Number} col The column index
50487 * @return {Boolean}
50489 isSortable : function(col){
50490 if(typeof this.config[col].sortable == "undefined"){
50491 return this.defaultSortable;
50493 return this.config[col].sortable;
50497 * Returns the rendering (formatting) function defined for the column.
50498 * @param {Number} col The column index.
50499 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
50501 getRenderer : function(col){
50502 if(!this.config[col].renderer){
50503 return Roo.grid.ColumnModel.defaultRenderer;
50505 return this.config[col].renderer;
50509 * Sets the rendering (formatting) function for a column.
50510 * @param {Number} col The column index
50511 * @param {Function} fn The function to use to process the cell's raw data
50512 * to return HTML markup for the grid view. The render function is called with
50513 * the following parameters:<ul>
50514 * <li>Data value.</li>
50515 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
50516 * <li>css A CSS style string to apply to the table cell.</li>
50517 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
50518 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
50519 * <li>Row index</li>
50520 * <li>Column index</li>
50521 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
50523 setRenderer : function(col, fn){
50524 this.config[col].renderer = fn;
50528 * Returns the width for the specified column.
50529 * @param {Number} col The column index
50532 getColumnWidth : function(col){
50533 return this.config[col].width * 1 || this.defaultWidth;
50537 * Sets the width for a column.
50538 * @param {Number} col The column index
50539 * @param {Number} width The new width
50541 setColumnWidth : function(col, width, suppressEvent){
50542 this.config[col].width = width;
50543 this.totalWidth = null;
50544 if(!suppressEvent){
50545 this.fireEvent("widthchange", this, col, width);
50550 * Returns the total width of all columns.
50551 * @param {Boolean} includeHidden True to include hidden column widths
50554 getTotalWidth : function(includeHidden){
50555 if(!this.totalWidth){
50556 this.totalWidth = 0;
50557 for(var i = 0, len = this.config.length; i < len; i++){
50558 if(includeHidden || !this.isHidden(i)){
50559 this.totalWidth += this.getColumnWidth(i);
50563 return this.totalWidth;
50567 * Returns the header for the specified column.
50568 * @param {Number} col The column index
50571 getColumnHeader : function(col){
50572 return this.config[col].header;
50576 * Sets the header for a column.
50577 * @param {Number} col The column index
50578 * @param {String} header The new header
50580 setColumnHeader : function(col, header){
50581 this.config[col].header = header;
50582 this.fireEvent("headerchange", this, col, header);
50586 * Returns the tooltip for the specified column.
50587 * @param {Number} col The column index
50590 getColumnTooltip : function(col){
50591 return this.config[col].tooltip;
50594 * Sets the tooltip for a column.
50595 * @param {Number} col The column index
50596 * @param {String} tooltip The new tooltip
50598 setColumnTooltip : function(col, tooltip){
50599 this.config[col].tooltip = tooltip;
50603 * Returns the dataIndex for the specified column.
50604 * @param {Number} col The column index
50607 getDataIndex : function(col){
50608 return this.config[col].dataIndex;
50612 * Sets the dataIndex for a column.
50613 * @param {Number} col The column index
50614 * @param {Number} dataIndex The new dataIndex
50616 setDataIndex : function(col, dataIndex){
50617 this.config[col].dataIndex = dataIndex;
50623 * Returns true if the cell is editable.
50624 * @param {Number} colIndex The column index
50625 * @param {Number} rowIndex The row index
50626 * @return {Boolean}
50628 isCellEditable : function(colIndex, rowIndex){
50629 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
50633 * Returns the editor defined for the cell/column.
50634 * return false or null to disable editing.
50635 * @param {Number} colIndex The column index
50636 * @param {Number} rowIndex The row index
50639 getCellEditor : function(colIndex, rowIndex){
50640 return this.config[colIndex].editor;
50644 * Sets if a column is editable.
50645 * @param {Number} col The column index
50646 * @param {Boolean} editable True if the column is editable
50648 setEditable : function(col, editable){
50649 this.config[col].editable = editable;
50654 * Returns true if the column is hidden.
50655 * @param {Number} colIndex The column index
50656 * @return {Boolean}
50658 isHidden : function(colIndex){
50659 return this.config[colIndex].hidden;
50664 * Returns true if the column width cannot be changed
50666 isFixed : function(colIndex){
50667 return this.config[colIndex].fixed;
50671 * Returns true if the column can be resized
50672 * @return {Boolean}
50674 isResizable : function(colIndex){
50675 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
50678 * Sets if a column is hidden.
50679 * @param {Number} colIndex The column index
50680 * @param {Boolean} hidden True if the column is hidden
50682 setHidden : function(colIndex, hidden){
50683 this.config[colIndex].hidden = hidden;
50684 this.totalWidth = null;
50685 this.fireEvent("hiddenchange", this, colIndex, hidden);
50689 * Sets the editor for a column.
50690 * @param {Number} col The column index
50691 * @param {Object} editor The editor object
50693 setEditor : function(col, editor){
50694 this.config[col].editor = editor;
50698 Roo.grid.ColumnModel.defaultRenderer = function(value){
50699 if(typeof value == "string" && value.length < 1){
50705 // Alias for backwards compatibility
50706 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
50709 * Ext JS Library 1.1.1
50710 * Copyright(c) 2006-2007, Ext JS, LLC.
50712 * Originally Released Under LGPL - original licence link has changed is not relivant.
50715 * <script type="text/javascript">
50719 * @class Roo.grid.AbstractSelectionModel
50720 * @extends Roo.util.Observable
50721 * Abstract base class for grid SelectionModels. It provides the interface that should be
50722 * implemented by descendant classes. This class should not be directly instantiated.
50725 Roo.grid.AbstractSelectionModel = function(){
50726 this.locked = false;
50727 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
50730 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
50731 /** @ignore Called by the grid automatically. Do not call directly. */
50732 init : function(grid){
50738 * Locks the selections.
50741 this.locked = true;
50745 * Unlocks the selections.
50747 unlock : function(){
50748 this.locked = false;
50752 * Returns true if the selections are locked.
50753 * @return {Boolean}
50755 isLocked : function(){
50756 return this.locked;
50760 * Ext JS Library 1.1.1
50761 * Copyright(c) 2006-2007, Ext JS, LLC.
50763 * Originally Released Under LGPL - original licence link has changed is not relivant.
50766 * <script type="text/javascript">
50769 * @extends Roo.grid.AbstractSelectionModel
50770 * @class Roo.grid.RowSelectionModel
50771 * The default SelectionModel used by {@link Roo.grid.Grid}.
50772 * It supports multiple selections and keyboard selection/navigation.
50774 * @param {Object} config
50776 Roo.grid.RowSelectionModel = function(config){
50777 Roo.apply(this, config);
50778 this.selections = new Roo.util.MixedCollection(false, function(o){
50783 this.lastActive = false;
50787 * @event selectionchange
50788 * Fires when the selection changes
50789 * @param {SelectionModel} this
50791 "selectionchange" : true,
50793 * @event afterselectionchange
50794 * Fires after the selection changes (eg. by key press or clicking)
50795 * @param {SelectionModel} this
50797 "afterselectionchange" : true,
50799 * @event beforerowselect
50800 * Fires when a row is selected being selected, return false to cancel.
50801 * @param {SelectionModel} this
50802 * @param {Number} rowIndex The selected index
50803 * @param {Boolean} keepExisting False if other selections will be cleared
50805 "beforerowselect" : true,
50808 * Fires when a row is selected.
50809 * @param {SelectionModel} this
50810 * @param {Number} rowIndex The selected index
50811 * @param {Roo.data.Record} r The record
50813 "rowselect" : true,
50815 * @event rowdeselect
50816 * Fires when a row is deselected.
50817 * @param {SelectionModel} this
50818 * @param {Number} rowIndex The selected index
50820 "rowdeselect" : true
50822 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
50823 this.locked = false;
50826 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
50828 * @cfg {Boolean} singleSelect
50829 * True to allow selection of only one row at a time (defaults to false)
50831 singleSelect : false,
50834 initEvents : function(){
50836 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
50837 this.grid.on("mousedown", this.handleMouseDown, this);
50838 }else{ // allow click to work like normal
50839 this.grid.on("rowclick", this.handleDragableRowClick, this);
50842 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
50843 "up" : function(e){
50845 this.selectPrevious(e.shiftKey);
50846 }else if(this.last !== false && this.lastActive !== false){
50847 var last = this.last;
50848 this.selectRange(this.last, this.lastActive-1);
50849 this.grid.getView().focusRow(this.lastActive);
50850 if(last !== false){
50854 this.selectFirstRow();
50856 this.fireEvent("afterselectionchange", this);
50858 "down" : function(e){
50860 this.selectNext(e.shiftKey);
50861 }else if(this.last !== false && this.lastActive !== false){
50862 var last = this.last;
50863 this.selectRange(this.last, this.lastActive+1);
50864 this.grid.getView().focusRow(this.lastActive);
50865 if(last !== false){
50869 this.selectFirstRow();
50871 this.fireEvent("afterselectionchange", this);
50876 var view = this.grid.view;
50877 view.on("refresh", this.onRefresh, this);
50878 view.on("rowupdated", this.onRowUpdated, this);
50879 view.on("rowremoved", this.onRemove, this);
50883 onRefresh : function(){
50884 var ds = this.grid.dataSource, i, v = this.grid.view;
50885 var s = this.selections;
50886 s.each(function(r){
50887 if((i = ds.indexOfId(r.id)) != -1){
50896 onRemove : function(v, index, r){
50897 this.selections.remove(r);
50901 onRowUpdated : function(v, index, r){
50902 if(this.isSelected(r)){
50903 v.onRowSelect(index);
50909 * @param {Array} records The records to select
50910 * @param {Boolean} keepExisting (optional) True to keep existing selections
50912 selectRecords : function(records, keepExisting){
50914 this.clearSelections();
50916 var ds = this.grid.dataSource;
50917 for(var i = 0, len = records.length; i < len; i++){
50918 this.selectRow(ds.indexOf(records[i]), true);
50923 * Gets the number of selected rows.
50926 getCount : function(){
50927 return this.selections.length;
50931 * Selects the first row in the grid.
50933 selectFirstRow : function(){
50938 * Select the last row.
50939 * @param {Boolean} keepExisting (optional) True to keep existing selections
50941 selectLastRow : function(keepExisting){
50942 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
50946 * Selects the row immediately following the last selected row.
50947 * @param {Boolean} keepExisting (optional) True to keep existing selections
50949 selectNext : function(keepExisting){
50950 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
50951 this.selectRow(this.last+1, keepExisting);
50952 this.grid.getView().focusRow(this.last);
50957 * Selects the row that precedes the last selected row.
50958 * @param {Boolean} keepExisting (optional) True to keep existing selections
50960 selectPrevious : function(keepExisting){
50962 this.selectRow(this.last-1, keepExisting);
50963 this.grid.getView().focusRow(this.last);
50968 * Returns the selected records
50969 * @return {Array} Array of selected records
50971 getSelections : function(){
50972 return [].concat(this.selections.items);
50976 * Returns the first selected record.
50979 getSelected : function(){
50980 return this.selections.itemAt(0);
50985 * Clears all selections.
50987 clearSelections : function(fast){
50988 if(this.locked) return;
50990 var ds = this.grid.dataSource;
50991 var s = this.selections;
50992 s.each(function(r){
50993 this.deselectRow(ds.indexOfId(r.id));
50997 this.selections.clear();
51004 * Selects all rows.
51006 selectAll : function(){
51007 if(this.locked) return;
51008 this.selections.clear();
51009 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
51010 this.selectRow(i, true);
51015 * Returns True if there is a selection.
51016 * @return {Boolean}
51018 hasSelection : function(){
51019 return this.selections.length > 0;
51023 * Returns True if the specified row is selected.
51024 * @param {Number/Record} record The record or index of the record to check
51025 * @return {Boolean}
51027 isSelected : function(index){
51028 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
51029 return (r && this.selections.key(r.id) ? true : false);
51033 * Returns True if the specified record id is selected.
51034 * @param {String} id The id of record to check
51035 * @return {Boolean}
51037 isIdSelected : function(id){
51038 return (this.selections.key(id) ? true : false);
51042 handleMouseDown : function(e, t){
51043 var view = this.grid.getView(), rowIndex;
51044 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
51047 if(e.shiftKey && this.last !== false){
51048 var last = this.last;
51049 this.selectRange(last, rowIndex, e.ctrlKey);
51050 this.last = last; // reset the last
51051 view.focusRow(rowIndex);
51053 var isSelected = this.isSelected(rowIndex);
51054 if(e.button !== 0 && isSelected){
51055 view.focusRow(rowIndex);
51056 }else if(e.ctrlKey && isSelected){
51057 this.deselectRow(rowIndex);
51058 }else if(!isSelected){
51059 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
51060 view.focusRow(rowIndex);
51063 this.fireEvent("afterselectionchange", this);
51066 handleDragableRowClick : function(grid, rowIndex, e)
51068 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
51069 this.selectRow(rowIndex, false);
51070 grid.view.focusRow(rowIndex);
51071 this.fireEvent("afterselectionchange", this);
51076 * Selects multiple rows.
51077 * @param {Array} rows Array of the indexes of the row to select
51078 * @param {Boolean} keepExisting (optional) True to keep existing selections
51080 selectRows : function(rows, keepExisting){
51082 this.clearSelections();
51084 for(var i = 0, len = rows.length; i < len; i++){
51085 this.selectRow(rows[i], true);
51090 * Selects a range of rows. All rows in between startRow and endRow are also selected.
51091 * @param {Number} startRow The index of the first row in the range
51092 * @param {Number} endRow The index of the last row in the range
51093 * @param {Boolean} keepExisting (optional) True to retain existing selections
51095 selectRange : function(startRow, endRow, keepExisting){
51096 if(this.locked) return;
51098 this.clearSelections();
51100 if(startRow <= endRow){
51101 for(var i = startRow; i <= endRow; i++){
51102 this.selectRow(i, true);
51105 for(var i = startRow; i >= endRow; i--){
51106 this.selectRow(i, true);
51112 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
51113 * @param {Number} startRow The index of the first row in the range
51114 * @param {Number} endRow The index of the last row in the range
51116 deselectRange : function(startRow, endRow, preventViewNotify){
51117 if(this.locked) return;
51118 for(var i = startRow; i <= endRow; i++){
51119 this.deselectRow(i, preventViewNotify);
51125 * @param {Number} row The index of the row to select
51126 * @param {Boolean} keepExisting (optional) True to keep existing selections
51128 selectRow : function(index, keepExisting, preventViewNotify){
51129 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
51130 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
51131 if(!keepExisting || this.singleSelect){
51132 this.clearSelections();
51134 var r = this.grid.dataSource.getAt(index);
51135 this.selections.add(r);
51136 this.last = this.lastActive = index;
51137 if(!preventViewNotify){
51138 this.grid.getView().onRowSelect(index);
51140 this.fireEvent("rowselect", this, index, r);
51141 this.fireEvent("selectionchange", this);
51147 * @param {Number} row The index of the row to deselect
51149 deselectRow : function(index, preventViewNotify){
51150 if(this.locked) return;
51151 if(this.last == index){
51154 if(this.lastActive == index){
51155 this.lastActive = false;
51157 var r = this.grid.dataSource.getAt(index);
51158 this.selections.remove(r);
51159 if(!preventViewNotify){
51160 this.grid.getView().onRowDeselect(index);
51162 this.fireEvent("rowdeselect", this, index);
51163 this.fireEvent("selectionchange", this);
51167 restoreLast : function(){
51169 this.last = this._last;
51174 acceptsNav : function(row, col, cm){
51175 return !cm.isHidden(col) && cm.isCellEditable(col, row);
51179 onEditorKey : function(field, e){
51180 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
51185 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
51187 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
51189 }else if(k == e.ENTER && !e.ctrlKey){
51193 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
51195 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
51197 }else if(k == e.ESC){
51201 g.startEditing(newCell[0], newCell[1]);
51206 * Ext JS Library 1.1.1
51207 * Copyright(c) 2006-2007, Ext JS, LLC.
51209 * Originally Released Under LGPL - original licence link has changed is not relivant.
51212 * <script type="text/javascript">
51215 * @class Roo.grid.CellSelectionModel
51216 * @extends Roo.grid.AbstractSelectionModel
51217 * This class provides the basic implementation for cell selection in a grid.
51219 * @param {Object} config The object containing the configuration of this model.
51220 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
51222 Roo.grid.CellSelectionModel = function(config){
51223 Roo.apply(this, config);
51225 this.selection = null;
51229 * @event beforerowselect
51230 * Fires before a cell is selected.
51231 * @param {SelectionModel} this
51232 * @param {Number} rowIndex The selected row index
51233 * @param {Number} colIndex The selected cell index
51235 "beforecellselect" : true,
51237 * @event cellselect
51238 * Fires when a cell is selected.
51239 * @param {SelectionModel} this
51240 * @param {Number} rowIndex The selected row index
51241 * @param {Number} colIndex The selected cell index
51243 "cellselect" : true,
51245 * @event selectionchange
51246 * Fires when the active selection changes.
51247 * @param {SelectionModel} this
51248 * @param {Object} selection null for no selection or an object (o) with two properties
51250 <li>o.record: the record object for the row the selection is in</li>
51251 <li>o.cell: An array of [rowIndex, columnIndex]</li>
51254 "selectionchange" : true,
51257 * Fires when the tab (or enter) was pressed on the last editable cell
51258 * You can use this to trigger add new row.
51259 * @param {SelectionModel} this
51263 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
51266 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
51268 enter_is_tab: false,
51271 initEvents : function(){
51272 this.grid.on("mousedown", this.handleMouseDown, this);
51273 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
51274 var view = this.grid.view;
51275 view.on("refresh", this.onViewChange, this);
51276 view.on("rowupdated", this.onRowUpdated, this);
51277 view.on("beforerowremoved", this.clearSelections, this);
51278 view.on("beforerowsinserted", this.clearSelections, this);
51279 if(this.grid.isEditor){
51280 this.grid.on("beforeedit", this.beforeEdit, this);
51285 beforeEdit : function(e){
51286 this.select(e.row, e.column, false, true, e.record);
51290 onRowUpdated : function(v, index, r){
51291 if(this.selection && this.selection.record == r){
51292 v.onCellSelect(index, this.selection.cell[1]);
51297 onViewChange : function(){
51298 this.clearSelections(true);
51302 * Returns the currently selected cell,.
51303 * @return {Array} The selected cell (row, column) or null if none selected.
51305 getSelectedCell : function(){
51306 return this.selection ? this.selection.cell : null;
51310 * Clears all selections.
51311 * @param {Boolean} true to prevent the gridview from being notified about the change.
51313 clearSelections : function(preventNotify){
51314 var s = this.selection;
51316 if(preventNotify !== true){
51317 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
51319 this.selection = null;
51320 this.fireEvent("selectionchange", this, null);
51325 * Returns true if there is a selection.
51326 * @return {Boolean}
51328 hasSelection : function(){
51329 return this.selection ? true : false;
51333 handleMouseDown : function(e, t){
51334 var v = this.grid.getView();
51335 if(this.isLocked()){
51338 var row = v.findRowIndex(t);
51339 var cell = v.findCellIndex(t);
51340 if(row !== false && cell !== false){
51341 this.select(row, cell);
51347 * @param {Number} rowIndex
51348 * @param {Number} collIndex
51350 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
51351 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
51352 this.clearSelections();
51353 r = r || this.grid.dataSource.getAt(rowIndex);
51356 cell : [rowIndex, colIndex]
51358 if(!preventViewNotify){
51359 var v = this.grid.getView();
51360 v.onCellSelect(rowIndex, colIndex);
51361 if(preventFocus !== true){
51362 v.focusCell(rowIndex, colIndex);
51365 this.fireEvent("cellselect", this, rowIndex, colIndex);
51366 this.fireEvent("selectionchange", this, this.selection);
51371 isSelectable : function(rowIndex, colIndex, cm){
51372 return !cm.isHidden(colIndex);
51376 handleKeyDown : function(e){
51377 //Roo.log('Cell Sel Model handleKeyDown');
51378 if(!e.isNavKeyPress()){
51381 var g = this.grid, s = this.selection;
51384 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
51386 this.select(cell[0], cell[1]);
51391 var walk = function(row, col, step){
51392 return g.walkCells(row, col, step, sm.isSelectable, sm);
51394 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
51401 // handled by onEditorKey
51402 if (g.isEditor && g.editing) {
51406 newCell = walk(r, c-1, -1);
51408 newCell = walk(r, c+1, 1);
51413 newCell = walk(r+1, c, 1);
51417 newCell = walk(r-1, c, -1);
51421 newCell = walk(r, c+1, 1);
51425 newCell = walk(r, c-1, -1);
51430 if(g.isEditor && !g.editing){
51431 g.startEditing(r, c);
51440 this.select(newCell[0], newCell[1]);
51446 acceptsNav : function(row, col, cm){
51447 return !cm.isHidden(col) && cm.isCellEditable(col, row);
51451 * @param {Number} field (not used) - as it's normally used as a listener
51452 * @param {Number} e - event - fake it by using
51454 * var e = Roo.EventObjectImpl.prototype;
51455 * e.keyCode = e.TAB
51459 onEditorKey : function(field, e){
51461 var k = e.getKey(),
51464 ed = g.activeEditor,
51466 ///Roo.log('onEditorKey' + k);
51469 if (this.enter_is_tab && k == e.ENTER) {
51475 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
51477 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
51483 }else if(k == e.ENTER && !e.ctrlKey){
51486 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
51487 }else if(k == e.ESC){
51493 //Roo.log('next cell after edit');
51494 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
51495 } else if (forward) {
51496 // tabbed past last
51497 this.fireEvent.defer(100, this, ['tabend',this]);
51502 * Ext JS Library 1.1.1
51503 * Copyright(c) 2006-2007, Ext JS, LLC.
51505 * Originally Released Under LGPL - original licence link has changed is not relivant.
51508 * <script type="text/javascript">
51512 * @class Roo.grid.EditorGrid
51513 * @extends Roo.grid.Grid
51514 * Class for creating and editable grid.
51515 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51516 * The container MUST have some type of size defined for the grid to fill. The container will be
51517 * automatically set to position relative if it isn't already.
51518 * @param {Object} dataSource The data model to bind to
51519 * @param {Object} colModel The column model with info about this grid's columns
51521 Roo.grid.EditorGrid = function(container, config){
51522 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
51523 this.getGridEl().addClass("xedit-grid");
51525 if(!this.selModel){
51526 this.selModel = new Roo.grid.CellSelectionModel();
51529 this.activeEditor = null;
51533 * @event beforeedit
51534 * Fires before cell editing is triggered. The edit event object has the following properties <br />
51535 * <ul style="padding:5px;padding-left:16px;">
51536 * <li>grid - This grid</li>
51537 * <li>record - The record being edited</li>
51538 * <li>field - The field name being edited</li>
51539 * <li>value - The value for the field being edited.</li>
51540 * <li>row - The grid row index</li>
51541 * <li>column - The grid column index</li>
51542 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
51544 * @param {Object} e An edit event (see above for description)
51546 "beforeedit" : true,
51549 * Fires after a cell is edited. <br />
51550 * <ul style="padding:5px;padding-left:16px;">
51551 * <li>grid - This grid</li>
51552 * <li>record - The record being edited</li>
51553 * <li>field - The field name being edited</li>
51554 * <li>value - The value being set</li>
51555 * <li>originalValue - The original value for the field, before the edit.</li>
51556 * <li>row - The grid row index</li>
51557 * <li>column - The grid column index</li>
51559 * @param {Object} e An edit event (see above for description)
51561 "afteredit" : true,
51563 * @event validateedit
51564 * Fires after a cell is edited, but before the value is set in the record.
51565 * You can use this to modify the value being set in the field, Return false
51566 * to cancel the change. The edit event object has the following properties <br />
51567 * <ul style="padding:5px;padding-left:16px;">
51568 * <li>editor - This editor</li>
51569 * <li>grid - This grid</li>
51570 * <li>record - The record being edited</li>
51571 * <li>field - The field name being edited</li>
51572 * <li>value - The value being set</li>
51573 * <li>originalValue - The original value for the field, before the edit.</li>
51574 * <li>row - The grid row index</li>
51575 * <li>column - The grid column index</li>
51576 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
51578 * @param {Object} e An edit event (see above for description)
51580 "validateedit" : true
51582 this.on("bodyscroll", this.stopEditing, this);
51583 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
51586 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
51588 * @cfg {Number} clicksToEdit
51589 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
51596 trackMouseOver: false, // causes very odd FF errors
51598 onCellDblClick : function(g, row, col){
51599 this.startEditing(row, col);
51602 onEditComplete : function(ed, value, startValue){
51603 this.editing = false;
51604 this.activeEditor = null;
51605 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
51607 var field = this.colModel.getDataIndex(ed.col);
51612 originalValue: startValue,
51619 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
51622 if(String(value) !== String(startValue)){
51624 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
51625 r.set(field, e.value);
51626 // if we are dealing with a combo box..
51627 // then we also set the 'name' colum to be the displayField
51628 if (ed.field.displayField && ed.field.name) {
51629 r.set(ed.field.name, ed.field.el.dom.value);
51632 delete e.cancel; //?? why!!!
51633 this.fireEvent("afteredit", e);
51636 this.fireEvent("afteredit", e); // always fire it!
51638 this.view.focusCell(ed.row, ed.col);
51642 * Starts editing the specified for the specified row/column
51643 * @param {Number} rowIndex
51644 * @param {Number} colIndex
51646 startEditing : function(row, col){
51647 this.stopEditing();
51648 if(this.colModel.isCellEditable(col, row)){
51649 this.view.ensureVisible(row, col, true);
51651 var r = this.dataSource.getAt(row);
51652 var field = this.colModel.getDataIndex(col);
51653 var cell = Roo.get(this.view.getCell(row,col));
51658 value: r.data[field],
51663 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
51664 this.editing = true;
51665 var ed = this.colModel.getCellEditor(col, row);
51671 ed.render(ed.parentEl || document.body);
51677 (function(){ // complex but required for focus issues in safari, ie and opera
51681 ed.on("complete", this.onEditComplete, this, {single: true});
51682 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
51683 this.activeEditor = ed;
51684 var v = r.data[field];
51685 ed.startEdit(this.view.getCell(row, col), v);
51686 // combo's with 'displayField and name set
51687 if (ed.field.displayField && ed.field.name) {
51688 ed.field.el.dom.value = r.data[ed.field.name];
51692 }).defer(50, this);
51698 * Stops any active editing
51700 stopEditing : function(){
51701 if(this.activeEditor){
51702 this.activeEditor.completeEdit();
51704 this.activeEditor = null;
51708 * Ext JS Library 1.1.1
51709 * Copyright(c) 2006-2007, Ext JS, LLC.
51711 * Originally Released Under LGPL - original licence link has changed is not relivant.
51714 * <script type="text/javascript">
51717 // private - not really -- you end up using it !
51718 // This is a support class used internally by the Grid components
51721 * @class Roo.grid.GridEditor
51722 * @extends Roo.Editor
51723 * Class for creating and editable grid elements.
51724 * @param {Object} config any settings (must include field)
51726 Roo.grid.GridEditor = function(field, config){
51727 if (!config && field.field) {
51729 field = Roo.factory(config.field, Roo.form);
51731 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
51732 field.monitorTab = false;
51735 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
51738 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
51741 alignment: "tl-tl",
51744 cls: "x-small-editor x-grid-editor",
51749 * Ext JS Library 1.1.1
51750 * Copyright(c) 2006-2007, Ext JS, LLC.
51752 * Originally Released Under LGPL - original licence link has changed is not relivant.
51755 * <script type="text/javascript">
51760 Roo.grid.PropertyRecord = Roo.data.Record.create([
51761 {name:'name',type:'string'}, 'value'
51765 Roo.grid.PropertyStore = function(grid, source){
51767 this.store = new Roo.data.Store({
51768 recordType : Roo.grid.PropertyRecord
51770 this.store.on('update', this.onUpdate, this);
51772 this.setSource(source);
51774 Roo.grid.PropertyStore.superclass.constructor.call(this);
51779 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
51780 setSource : function(o){
51782 this.store.removeAll();
51785 if(this.isEditableValue(o[k])){
51786 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
51789 this.store.loadRecords({records: data}, {}, true);
51792 onUpdate : function(ds, record, type){
51793 if(type == Roo.data.Record.EDIT){
51794 var v = record.data['value'];
51795 var oldValue = record.modified['value'];
51796 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
51797 this.source[record.id] = v;
51799 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
51806 getProperty : function(row){
51807 return this.store.getAt(row);
51810 isEditableValue: function(val){
51811 if(val && val instanceof Date){
51813 }else if(typeof val == 'object' || typeof val == 'function'){
51819 setValue : function(prop, value){
51820 this.source[prop] = value;
51821 this.store.getById(prop).set('value', value);
51824 getSource : function(){
51825 return this.source;
51829 Roo.grid.PropertyColumnModel = function(grid, store){
51832 g.PropertyColumnModel.superclass.constructor.call(this, [
51833 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
51834 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
51836 this.store = store;
51837 this.bselect = Roo.DomHelper.append(document.body, {
51838 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
51839 {tag: 'option', value: 'true', html: 'true'},
51840 {tag: 'option', value: 'false', html: 'false'}
51843 Roo.id(this.bselect);
51846 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
51847 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
51848 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
51849 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
51850 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
51852 this.renderCellDelegate = this.renderCell.createDelegate(this);
51853 this.renderPropDelegate = this.renderProp.createDelegate(this);
51856 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
51860 valueText : 'Value',
51862 dateFormat : 'm/j/Y',
51865 renderDate : function(dateVal){
51866 return dateVal.dateFormat(this.dateFormat);
51869 renderBool : function(bVal){
51870 return bVal ? 'true' : 'false';
51873 isCellEditable : function(colIndex, rowIndex){
51874 return colIndex == 1;
51877 getRenderer : function(col){
51879 this.renderCellDelegate : this.renderPropDelegate;
51882 renderProp : function(v){
51883 return this.getPropertyName(v);
51886 renderCell : function(val){
51888 if(val instanceof Date){
51889 rv = this.renderDate(val);
51890 }else if(typeof val == 'boolean'){
51891 rv = this.renderBool(val);
51893 return Roo.util.Format.htmlEncode(rv);
51896 getPropertyName : function(name){
51897 var pn = this.grid.propertyNames;
51898 return pn && pn[name] ? pn[name] : name;
51901 getCellEditor : function(colIndex, rowIndex){
51902 var p = this.store.getProperty(rowIndex);
51903 var n = p.data['name'], val = p.data['value'];
51905 if(typeof(this.grid.customEditors[n]) == 'string'){
51906 return this.editors[this.grid.customEditors[n]];
51908 if(typeof(this.grid.customEditors[n]) != 'undefined'){
51909 return this.grid.customEditors[n];
51911 if(val instanceof Date){
51912 return this.editors['date'];
51913 }else if(typeof val == 'number'){
51914 return this.editors['number'];
51915 }else if(typeof val == 'boolean'){
51916 return this.editors['boolean'];
51918 return this.editors['string'];
51924 * @class Roo.grid.PropertyGrid
51925 * @extends Roo.grid.EditorGrid
51926 * This class represents the interface of a component based property grid control.
51927 * <br><br>Usage:<pre><code>
51928 var grid = new Roo.grid.PropertyGrid("my-container-id", {
51936 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51937 * The container MUST have some type of size defined for the grid to fill. The container will be
51938 * automatically set to position relative if it isn't already.
51939 * @param {Object} config A config object that sets properties on this grid.
51941 Roo.grid.PropertyGrid = function(container, config){
51942 config = config || {};
51943 var store = new Roo.grid.PropertyStore(this);
51944 this.store = store;
51945 var cm = new Roo.grid.PropertyColumnModel(this, store);
51946 store.store.sort('name', 'ASC');
51947 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
51950 enableColLock:false,
51951 enableColumnMove:false,
51953 trackMouseOver: false,
51956 this.getGridEl().addClass('x-props-grid');
51957 this.lastEditRow = null;
51958 this.on('columnresize', this.onColumnResize, this);
51961 * @event beforepropertychange
51962 * Fires before a property changes (return false to stop?)
51963 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
51964 * @param {String} id Record Id
51965 * @param {String} newval New Value
51966 * @param {String} oldval Old Value
51968 "beforepropertychange": true,
51970 * @event propertychange
51971 * Fires after a property changes
51972 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
51973 * @param {String} id Record Id
51974 * @param {String} newval New Value
51975 * @param {String} oldval Old Value
51977 "propertychange": true
51979 this.customEditors = this.customEditors || {};
51981 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
51984 * @cfg {Object} customEditors map of colnames=> custom editors.
51985 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
51986 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
51987 * false disables editing of the field.
51991 * @cfg {Object} propertyNames map of property Names to their displayed value
51994 render : function(){
51995 Roo.grid.PropertyGrid.superclass.render.call(this);
51996 this.autoSize.defer(100, this);
51999 autoSize : function(){
52000 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
52002 this.view.fitColumns();
52006 onColumnResize : function(){
52007 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
52011 * Sets the data for the Grid
52012 * accepts a Key => Value object of all the elements avaiable.
52013 * @param {Object} data to appear in grid.
52015 setSource : function(source){
52016 this.store.setSource(source);
52020 * Gets all the data from the grid.
52021 * @return {Object} data data stored in grid
52023 getSource : function(){
52024 return this.store.getSource();
52028 * Ext JS Library 1.1.1
52029 * Copyright(c) 2006-2007, Ext JS, LLC.
52031 * Originally Released Under LGPL - original licence link has changed is not relivant.
52034 * <script type="text/javascript">
52038 * @class Roo.LoadMask
52039 * A simple utility class for generically masking elements while loading data. If the element being masked has
52040 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
52041 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
52042 * element's UpdateManager load indicator and will be destroyed after the initial load.
52044 * Create a new LoadMask
52045 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
52046 * @param {Object} config The config object
52048 Roo.LoadMask = function(el, config){
52049 this.el = Roo.get(el);
52050 Roo.apply(this, config);
52052 this.store.on('beforeload', this.onBeforeLoad, this);
52053 this.store.on('load', this.onLoad, this);
52054 this.store.on('loadexception', this.onLoadException, this);
52055 this.removeMask = false;
52057 var um = this.el.getUpdateManager();
52058 um.showLoadIndicator = false; // disable the default indicator
52059 um.on('beforeupdate', this.onBeforeLoad, this);
52060 um.on('update', this.onLoad, this);
52061 um.on('failure', this.onLoad, this);
52062 this.removeMask = true;
52066 Roo.LoadMask.prototype = {
52068 * @cfg {Boolean} removeMask
52069 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
52070 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
52073 * @cfg {String} msg
52074 * The text to display in a centered loading message box (defaults to 'Loading...')
52076 msg : 'Loading...',
52078 * @cfg {String} msgCls
52079 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
52081 msgCls : 'x-mask-loading',
52084 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
52090 * Disables the mask to prevent it from being displayed
52092 disable : function(){
52093 this.disabled = true;
52097 * Enables the mask so that it can be displayed
52099 enable : function(){
52100 this.disabled = false;
52103 onLoadException : function()
52105 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
52106 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
52108 this.el.unmask(this.removeMask);
52111 onLoad : function()
52113 this.el.unmask(this.removeMask);
52117 onBeforeLoad : function(){
52118 if(!this.disabled){
52119 this.el.mask(this.msg, this.msgCls);
52124 destroy : function(){
52126 this.store.un('beforeload', this.onBeforeLoad, this);
52127 this.store.un('load', this.onLoad, this);
52128 this.store.un('loadexception', this.onLoadException, this);
52130 var um = this.el.getUpdateManager();
52131 um.un('beforeupdate', this.onBeforeLoad, this);
52132 um.un('update', this.onLoad, this);
52133 um.un('failure', this.onLoad, this);
52138 * Ext JS Library 1.1.1
52139 * Copyright(c) 2006-2007, Ext JS, LLC.
52141 * Originally Released Under LGPL - original licence link has changed is not relivant.
52144 * <script type="text/javascript">
52146 Roo.XTemplate = function(){
52147 Roo.XTemplate.superclass.constructor.apply(this, arguments);
52150 s = ['<tpl>', s, '</tpl>'].join('');
52152 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
52154 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
52155 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
52156 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
52160 while(m = s.match(re)){
52161 var m2 = m[0].match(nameRe);
52162 var m3 = m[0].match(ifRe);
52163 var m4 = m[0].match(execRe);
52164 var exp = null, fn = null, exec = null;
52165 var name = m2 && m2[1] ? m2[1] : '';
52167 exp = m3 && m3[1] ? m3[1] : null;
52169 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
52173 exp = m4 && m4[1] ? m4[1] : null;
52175 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
52180 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
52181 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
52182 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
52192 s = s.replace(m[0], '{xtpl'+ id + '}');
52195 for(var i = tpls.length-1; i >= 0; --i){
52196 this.compileTpl(tpls[i]);
52198 this.master = tpls[tpls.length-1];
52201 Roo.extend(Roo.XTemplate, Roo.Template, {
52203 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
52205 applySubTemplate : function(id, values, parent){
52206 var t = this.tpls[id];
52207 if(t.test && !t.test.call(this, values, parent)){
52210 if(t.exec && t.exec.call(this, values, parent)){
52213 var vs = t.target ? t.target.call(this, values, parent) : values;
52214 parent = t.target ? values : parent;
52215 if(t.target && vs instanceof Array){
52217 for(var i = 0, len = vs.length; i < len; i++){
52218 buf[buf.length] = t.compiled.call(this, vs[i], parent);
52220 return buf.join('');
52222 return t.compiled.call(this, vs, parent);
52225 compileTpl : function(tpl){
52226 var fm = Roo.util.Format;
52227 var useF = this.disableFormats !== true;
52228 var sep = Roo.isGecko ? "+" : ",";
52229 var fn = function(m, name, format, args){
52230 if(name.substr(0, 4) == 'xtpl'){
52231 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
52234 if(name.indexOf('.') != -1){
52237 v = "values['" + name + "']";
52239 if(format && useF){
52240 args = args ? ',' + args : "";
52241 if(format.substr(0, 5) != "this."){
52242 format = "fm." + format + '(';
52244 format = 'this.call("'+ format.substr(5) + '", ';
52248 args= ''; format = "("+v+" === undefined ? '' : ";
52250 return "'"+ sep + format + v + args + ")"+sep+"'";
52253 // branched to use + in gecko and [].join() in others
52255 body = "tpl.compiled = function(values, parent){ return '" +
52256 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
52259 body = ["tpl.compiled = function(values, parent){ return ['"];
52260 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
52261 body.push("'].join('');};");
52262 body = body.join('');
52264 /** eval:var:zzzzzzz */
52269 applyTemplate : function(values){
52270 return this.master.compiled.call(this, values, {});
52274 apply : function(){
52275 return this.applyTemplate.apply(this, arguments);
52278 compile : function(){return this;}
52281 Roo.XTemplate.from = function(el){
52282 el = Roo.getDom(el);
52283 return new Roo.XTemplate(el.value || el.innerHTML);
52285 * Original code for Roojs - LGPL
52286 * <script type="text/javascript">
52290 * @class Roo.XComponent
52291 * A delayed Element creator...
52292 * Or a way to group chunks of interface together.
52294 * Mypart.xyx = new Roo.XComponent({
52296 parent : 'Mypart.xyz', // empty == document.element.!!
52300 disabled : function() {}
52302 tree : function() { // return an tree of xtype declared components
52306 xtype : 'NestedLayoutPanel',
52313 * It can be used to build a big heiracy, with parent etc.
52314 * or you can just use this to render a single compoent to a dom element
52315 * MYPART.render(Roo.Element | String(id) | dom_element )
52317 * @extends Roo.util.Observable
52319 * @param cfg {Object} configuration of component
52322 Roo.XComponent = function(cfg) {
52323 Roo.apply(this, cfg);
52327 * Fires when this the componnt is built
52328 * @param {Roo.XComponent} c the component
52332 * @event buildcomplete
52333 * Fires on the top level element when all elements have been built
52334 * @param {Roo.XComponent} c the top level component.
52336 'buildcomplete' : true
52339 this.region = this.region || 'center'; // default..
52340 Roo.XComponent.register(this);
52341 this.modules = false;
52342 this.el = false; // where the layout goes..
52346 Roo.extend(Roo.XComponent, Roo.util.Observable, {
52349 * The created element (with Roo.factory())
52350 * @type {Roo.Layout}
52356 * for BC - use el in new code
52357 * @type {Roo.Layout}
52363 * for BC - use el in new code
52364 * @type {Roo.Layout}
52369 * @cfg {Function|boolean} disabled
52370 * If this module is disabled by some rule, return true from the funtion
52375 * @cfg {String} parent
52376 * Name of parent element which it get xtype added to..
52381 * @cfg {String} order
52382 * Used to set the order in which elements are created (usefull for multiple tabs)
52387 * @cfg {String} name
52388 * String to display while loading.
52392 * @cfg {String} region
52393 * Region to render component to (defaults to center)
52398 * @cfg {Array} items
52399 * A single item array - the first element is the root of the tree..
52400 * It's done this way to stay compatible with the Xtype system...
52407 * render element to dom or tree
52408 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
52411 render : function(el)
52415 var hp = this.parent ? 1 : 0;
52417 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
52418 // if parent is a '#.....' string, then let's use that..
52419 var ename = this.parent.substr(1)
52420 this.parent = false;
52421 el = Roo.get(ename);
52423 Roo.log("Warning - element can not be found :#" + ename );
52429 if (!this.parent) {
52431 el = el ? Roo.get(el) : false;
52433 // it's a top level one..
52435 el : new Roo.BorderLayout(el || document.body, {
52441 tabPosition: 'top',
52442 //resizeTabs: true,
52443 alwaysShowTabs: el && hp? false : true,
52444 hideTabs: el || !hp ? true : false,
52453 var tree = this.tree();
52454 tree.region = tree.region || this.region;
52455 this.el = this.parent.el.addxtype(tree);
52456 this.fireEvent('built', this);
52458 this.panel = this.el;
52459 this.layout = this.panel.layout;
52465 Roo.apply(Roo.XComponent, {
52468 * @property buildCompleted
52469 * True when the builder has completed building the interface.
52472 buildCompleted : false,
52475 * @property topModule
52476 * the upper most module - uses document.element as it's constructor.
52483 * @property modules
52484 * array of modules to be created by registration system.
52485 * @type {Array} of Roo.XComponent
52490 * @property elmodules
52491 * array of modules to be created by which use #ID
52492 * @type {Array} of Roo.XComponent
52499 * Register components to be built later.
52501 * This solves the following issues
52502 * - Building is not done on page load, but after an authentication process has occured.
52503 * - Interface elements are registered on page load
52504 * - Parent Interface elements may not be loaded before child, so this handles that..
52511 module : 'Pman.Tab.projectMgr',
52513 parent : 'Pman.layout',
52514 disabled : false, // or use a function..
52517 * * @param {Object} details about module
52519 register : function(obj) {
52520 this.modules.push(obj);
52524 * convert a string to an object..
52525 * eg. 'AAA.BBB' -> finds AAA.BBB
52529 toObject : function(str)
52531 if (!str || typeof(str) == 'object') {
52534 if (str.substring(0,1) == '#') {
52538 var ar = str.split('.');
52543 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
52545 throw "Module not found : " + str;
52549 throw "Module not found : " + str;
52551 Roo.each(ar, function(e) {
52552 if (typeof(o[e]) == 'undefined') {
52553 throw "Module not found : " + str;
52564 * move modules into their correct place in the tree..
52567 preBuild : function ()
52570 Roo.each(this.modules , function (obj)
52572 var opar = obj.parent;
52574 obj.parent = this.toObject(opar);
52576 Roo.log(e.toString());
52581 this.topModule = obj;
52584 if (typeof(obj.parent) == 'string') {
52585 this.elmodules.push(obj);
52588 if (obj.parent.constructor != Roo.XComponent) {
52589 Roo.log("Object Parent is not instance of XComponent:" + obj.name)
52591 if (!obj.parent.modules) {
52592 obj.parent.modules = new Roo.util.MixedCollection(false,
52593 function(o) { return o.order + '' }
52597 obj.parent.modules.add(obj);
52602 * make a list of modules to build.
52603 * @return {Array} list of modules.
52606 buildOrder : function()
52609 var cmp = function(a,b) {
52610 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
52612 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
52613 throw "No top level modules to build";
52616 // make a flat list in order of modules to build.
52617 var mods = this.topModule ? [ this.topModule ] : [];
52618 Roo.each(this.elmodules,function(e) { mods.push(e) });
52621 // add modules to their parents..
52622 var addMod = function(m) {
52623 // Roo.debug && Roo.log(m.modKey);
52627 m.modules.keySort('ASC', cmp );
52628 m.modules.each(addMod);
52630 // not sure if this is used any more..
52632 m.finalize.name = m.name + " (clean up) ";
52633 mods.push(m.finalize);
52637 if (this.topModule) {
52638 this.topModule.modules.keySort('ASC', cmp );
52639 this.topModule.modules.each(addMod);
52645 * Build the registered modules.
52646 * @param {Object} parent element.
52647 * @param {Function} optional method to call after module has been added.
52655 var mods = this.buildOrder();
52657 //this.allmods = mods;
52658 //Roo.debug && Roo.log(mods);
52660 if (!mods.length) { // should not happen
52661 throw "NO modules!!!";
52666 // flash it up as modal - so we store the mask!?
52667 Roo.MessageBox.show({ title: 'loading' });
52668 Roo.MessageBox.show({
52669 title: "Please wait...",
52670 msg: "Building Interface...",
52677 var total = mods.length;
52680 var progressRun = function() {
52681 if (!mods.length) {
52682 Roo.debug && Roo.log('hide?');
52683 Roo.MessageBox.hide();
52684 if (_this.topModule) {
52685 _this.topModule.fireEvent('buildcomplete', _this.topModule);
52691 var m = mods.shift();
52694 Roo.debug && Roo.log(m);
52695 // not sure if this is supported any more.. - modules that are are just function
52696 if (typeof(m) == 'function') {
52698 return progressRun.defer(10, _this);
52703 Roo.MessageBox.updateProgress(
52704 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
52706 (m.name ? (' - ' + m.name) : '')
52710 // is the module disabled?
52711 var disabled = (typeof(m.disabled) == 'function') ?
52712 m.disabled.call(m.module.disabled) : m.disabled;
52716 return progressRun(); // we do not update the display!
52722 // it's 10 on top level, and 1 on others??? why...
52723 return progressRun.defer(10, _this);
52726 progressRun.defer(1, _this);
52737 //<script type="text/javascript">
52742 * @extends Roo.LayoutDialog
52743 * A generic Login Dialog..... - only one needed in theory!?!?
52745 * Fires XComponent builder on success...
52748 * username,password, lang = for login actions.
52749 * check = 1 for periodic checking that sesion is valid.
52750 * passwordRequest = email request password
52751 * logout = 1 = to logout
52753 * Affects: (this id="????" elements)
52754 * loading (removed) (used to indicate application is loading)
52755 * loading-mask (hides) (used to hide application when it's building loading)
52761 * Myapp.login = Roo.Login({
52777 Roo.Login = function(cfg)
52783 Roo.apply(this,cfg);
52785 Roo.onReady(function() {
52791 Roo.Login.superclass.constructor.call(this, this);
52792 //this.addxtype(this.items[0]);
52798 Roo.extend(Roo.Login, Roo.LayoutDialog, {
52801 * @cfg {String} method
52802 * Method used to query for login details.
52807 * @cfg {String} url
52808 * URL to query login data. - eg. baseURL + '/Login.php'
52814 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
52819 * @property checkFails
52820 * Number of times we have attempted to get authentication check, and failed.
52825 * @property intervalID
52826 * The window interval that does the constant login checking.
52832 onLoad : function() // called on page load...
52836 if (Roo.get('loading')) { // clear any loading indicator..
52837 Roo.get('loading').remove();
52840 //this.switchLang('en'); // set the language to english..
52843 success: function(response, opts) { // check successfull...
52845 var res = this.processResponse(response);
52846 this.checkFails =0;
52847 if (!res.success) { // error!
52848 this.checkFails = 5;
52849 //console.log('call failure');
52850 return this.failure(response,opts);
52853 if (!res.data.id) { // id=0 == login failure.
52854 return this.show();
52858 //console.log(success);
52859 this.fillAuth(res.data);
52860 this.checkFails =0;
52861 Roo.XComponent.build();
52863 failure : this.show
52869 check: function(cfg) // called every so often to refresh cookie etc..
52871 if (cfg.again) { // could be undefined..
52874 this.checkFails = 0;
52877 if (this.sending) {
52878 if ( this.checkFails > 4) {
52879 Roo.MessageBox.alert("Error",
52880 "Error getting authentication status. - try reloading, or wait a while", function() {
52881 _this.sending = false;
52886 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
52889 this.sending = true;
52896 method: this.method,
52897 success: cfg.success || this.success,
52898 failure : cfg.failure || this.failure,
52908 window.onbeforeunload = function() { }; // false does not work for IE..
52918 failure : function() {
52919 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
52920 document.location = document.location.toString() + '?ts=' + Math.random();
52924 success : function() {
52925 _this.user = false;
52926 this.checkFails =0;
52928 document.location = document.location.toString() + '?ts=' + Math.random();
52935 processResponse : function (response)
52939 res = Roo.decode(response.responseText);
52941 if (typeof(res) != 'object') {
52942 res = { success : false, errorMsg : res, errors : true };
52944 if (typeof(res.success) == 'undefined') {
52945 res.success = false;
52949 res = { success : false, errorMsg : response.responseText, errors : true };
52954 success : function(response, opts) // check successfull...
52956 this.sending = false;
52957 var res = this.processResponse(response);
52958 if (!res.success) {
52959 return this.failure(response, opts);
52961 if (!res.data || !res.data.id) {
52962 return this.failure(response,opts);
52964 //console.log(res);
52965 this.fillAuth(res.data);
52967 this.checkFails =0;
52972 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
52974 this.authUser = -1;
52975 this.sending = false;
52976 var res = this.processResponse(response);
52977 //console.log(res);
52978 if ( this.checkFails > 2) {
52980 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
52981 "Error getting authentication status. - try reloading");
52984 opts.callCfg.again = true;
52985 this.check.defer(1000, this, [ opts.callCfg ]);
52991 fillAuth: function(au) {
52992 this.startAuthCheck();
52993 this.authUserId = au.id;
52994 this.authUser = au;
52995 this.lastChecked = new Date();
52996 this.fireEvent('refreshed', au);
52997 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
52998 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
52999 au.lang = au.lang || 'en';
53000 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
53001 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
53002 this.switchLang(au.lang );
53005 // open system... - -on setyp..
53006 if (this.authUserId < 0) {
53007 Roo.MessageBox.alert("Warning",
53008 "This is an open system - please set up a admin user with a password.");
53011 //Pman.onload(); // which should do nothing if it's a re-auth result...
53016 startAuthCheck : function() // starter for timeout checking..
53018 if (this.intervalID) { // timer already in place...
53022 this.intervalID = window.setInterval(function() {
53023 _this.check(false);
53024 }, 120000); // every 120 secs = 2mins..
53030 switchLang : function (lang)
53032 _T = typeof(_T) == 'undefined' ? false : _T;
53033 if (!_T || !lang.length) {
53037 if (!_T && lang != 'en') {
53038 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
53042 if (typeof(_T.en) == 'undefined') {
53044 Roo.apply(_T.en, _T);
53047 if (typeof(_T[lang]) == 'undefined') {
53048 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
53053 Roo.apply(_T, _T[lang]);
53054 // just need to set the text values for everything...
53056 /* this will not work ...
53060 function formLabel(name, val) {
53061 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
53064 formLabel('password', "Password"+':');
53065 formLabel('username', "Email Address"+':');
53066 formLabel('lang', "Language"+':');
53067 this.dialog.setTitle("Login");
53068 this.dialog.buttons[0].setText("Forgot Password");
53069 this.dialog.buttons[1].setText("Login");
53088 collapsible: false,
53090 center: { // needed??
53093 // tabPosition: 'top',
53096 alwaysShowTabs: false
53100 show : function(dlg)
53102 //console.log(this);
53103 this.form = this.layout.getRegion('center').activePanel.form;
53104 this.form.dialog = dlg;
53105 this.buttons[0].form = this.form;
53106 this.buttons[0].dialog = dlg;
53107 this.buttons[1].form = this.form;
53108 this.buttons[1].dialog = dlg;
53110 //this.resizeToLogo.defer(1000,this);
53111 // this is all related to resizing for logos..
53112 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
53114 // this.resizeToLogo.defer(1000,this);
53117 //var w = Ext.lib.Dom.getViewWidth() - 100;
53118 //var h = Ext.lib.Dom.getViewHeight() - 100;
53119 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
53121 if (this.disabled) {
53126 if (this.user.id < 0) { // used for inital setup situations.
53130 if (this.intervalID) {
53131 // remove the timer
53132 window.clearInterval(this.intervalID);
53133 this.intervalID = false;
53137 if (Roo.get('loading')) {
53138 Roo.get('loading').remove();
53140 if (Roo.get('loading-mask')) {
53141 Roo.get('loading-mask').hide();
53144 //incomming._node = tnode;
53146 //this.dialog.modal = !modal;
53147 //this.dialog.show();
53151 this.form.setValues({
53152 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
53153 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
53156 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
53157 if (this.form.findField('username').getValue().length > 0 ){
53158 this.form.findField('password').focus();
53160 this.form.findField('username').focus();
53168 xtype : 'ContentPanel',
53180 style : 'margin: 10px;',
53183 actionfailed : function(f, act) {
53184 // form can return { errors: .... }
53186 //act.result.errors // invalid form element list...
53187 //act.result.errorMsg// invalid form element list...
53189 this.dialog.el.unmask();
53190 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
53191 "Login failed - communication error - try again.");
53194 actioncomplete: function(re, act) {
53196 Roo.state.Manager.set(
53197 this.dialog.realm + '.username',
53198 this.findField('username').getValue()
53200 Roo.state.Manager.set(
53201 this.dialog.realm + '.lang',
53202 this.findField('lang').getValue()
53205 this.dialog.fillAuth(act.result.data);
53207 this.dialog.hide();
53209 if (Roo.get('loading-mask')) {
53210 Roo.get('loading-mask').show();
53212 Roo.XComponent.build();
53220 xtype : 'TextField',
53222 fieldLabel: "Email Address",
53225 autoCreate : {tag: "input", type: "text", size: "20"}
53228 xtype : 'TextField',
53230 fieldLabel: "Password",
53231 inputType: 'password',
53234 autoCreate : {tag: "input", type: "text", size: "20"},
53236 specialkey : function(e,ev) {
53237 if (ev.keyCode == 13) {
53238 this.form.dialog.el.mask("Logging in");
53239 this.form.doAction('submit', {
53240 url: this.form.dialog.url,
53241 method: this.form.dialog.method
53248 xtype : 'ComboBox',
53250 fieldLabel: "Language",
53253 xtype : 'SimpleStore',
53254 fields: ['lang', 'ldisp'],
53256 [ 'en', 'English' ],
53257 [ 'zh_HK' , '\u7E41\u4E2D' ],
53258 [ 'zh_CN', '\u7C21\u4E2D' ]
53262 valueField : 'lang',
53263 hiddenName: 'lang',
53265 displayField:'ldisp',
53269 triggerAction: 'all',
53270 emptyText:'Select a Language...',
53271 selectOnFocus:true,
53273 select : function(cb, rec, ix) {
53274 this.form.switchLang(rec.data.lang);
53290 text : "Forgot Password",
53292 click : function() {
53293 //console.log(this);
53294 var n = this.form.findField('username').getValue();
53296 Roo.MessageBox.alert("Error", "Fill in your email address");
53300 url: this.dialog.url,
53304 method: this.dialog.method,
53305 success: function(response, opts) { // check successfull...
53307 var res = this.dialog.processResponse(response);
53308 if (!res.success) { // error!
53309 Roo.MessageBox.alert("Error" ,
53310 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
53313 Roo.MessageBox.alert("Notice" ,
53314 "Please check you email for the Password Reset message");
53316 failure : function() {
53317 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
53330 click : function () {
53332 this.dialog.el.mask("Logging in");
53333 this.form.doAction('submit', {
53334 url: this.dialog.url,
53335 method: this.dialog.method