4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
89 * Turn on debugging output (currently only the factory uses this)
96 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
99 enableGarbageCollector : true,
102 * True to automatically purge event listeners after uncaching an element (defaults to false).
103 * Note: this only happens if enableGarbageCollector is true.
106 enableListenerCollection:false,
109 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110 * the IE insecure content warning (defaults to javascript:false).
113 SSL_SECURE_URL : "javascript:false",
116 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
120 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
122 emptyFn : function(){},
125 * Copies all the properties of config to obj if they don't already exist.
126 * @param {Object} obj The receiver of the properties
127 * @param {Object} config The source of the properties
128 * @return {Object} returns obj
130 applyIf : function(o, c){
133 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
140 * Applies event listeners to elements by selectors when the document is ready.
141 * The event name is specified with an @ suffix.
144 // add a listener for click on all anchors in element with id foo
145 '#foo a@click' : function(e, t){
149 // add the same listener to multiple selectors (separated by comma BEFORE the @)
150 '#foo a, #bar span.some-class@mouseover' : function(){
155 * @param {Object} obj The list of behaviors to apply
157 addBehaviors : function(o){
159 Roo.onReady(function(){
164 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
166 var parts = b.split('@');
167 if(parts[1]){ // for Object prototype breakers
170 cache[s] = Roo.select(s);
172 cache[s].on(parts[1], o[b]);
179 * Generates unique ids. If the element already has an id, it is unchanged
180 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182 * @return {String} The generated Id.
184 id : function(el, prefix){
185 prefix = prefix || "roo-gen";
187 var id = prefix + (++idSeed);
188 return el ? (el.id ? el.id : (el.id = id)) : id;
193 * Extends one class with another class and optionally overrides members with the passed literal. This class
194 * also adds the function "override()" to the class that can be used to override
195 * members on an instance.
196 * @param {Object} subclass The class inheriting the functionality
197 * @param {Object} superclass The class being extended
198 * @param {Object} overrides (optional) A literal with members
203 var io = function(o){
208 return function(sb, sp, overrides){
209 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
212 sb = function(){sp.apply(this, arguments);};
214 var F = function(){}, sbp, spp = sp.prototype;
216 sbp = sb.prototype = new F();
220 if(spp.constructor == Object.prototype.constructor){
225 sb.override = function(o){
229 Roo.override(sb, overrides);
235 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
237 Roo.override(MyClass, {
238 newMethod1: function(){
241 newMethod2: function(foo){
246 * @param {Object} origclass The class to override
247 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
248 * containing one or more methods.
251 override : function(origclass, overrides){
253 var p = origclass.prototype;
254 for(var method in overrides){
255 p[method] = overrides[method];
260 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
266 * @param {String} namespace1
267 * @param {String} namespace2
268 * @param {String} etc
271 namespace : function(){
272 var a=arguments, o=null, i, j, d, rt;
273 for (i=0; i<a.length; ++i) {
277 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278 for (j=1; j<d.length; ++j) {
279 o[d[j]]=o[d[j]] || {};
285 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
290 * @param {String} classname
291 * @param {String} namespace (optional)
295 factory : function(c, ns)
297 // no xtype, no ns or c.xns - or forced off by c.xns
298 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
301 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302 if (c.constructor == ns[c.xtype]) {// already created...
306 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307 var ret = new ns[c.xtype](c);
311 c.xns = false; // prevent recursion..
315 * Logs to console if it can.
317 * @param {String|Object} string
322 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
329 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
333 urlEncode : function(o){
339 var ov = o[key], k = Roo.encodeURIComponent(key);
340 var type = typeof ov;
341 if(type == 'undefined'){
343 }else if(type != "function" && type != "object"){
344 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345 }else if(ov instanceof Array){
347 for(var i = 0, len = ov.length; i < len; i++) {
348 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
359 * Safe version of encodeURIComponent
360 * @param {String} data
364 encodeURIComponent : function (data)
367 return encodeURIComponent(data);
368 } catch(e) {} // should be an uri encode error.
370 if (data == '' || data == null){
373 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374 function nibble_to_hex(nibble){
375 var chars = '0123456789ABCDEF';
376 return chars.charAt(nibble);
378 data = data.toString();
380 for(var i=0; i<data.length; i++){
381 var c = data.charCodeAt(i);
382 var bs = new Array();
385 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388 bs[3] = 0x80 | (c & 0x3F);
389 }else if (c > 0x800){
391 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393 bs[2] = 0x80 | (c & 0x3F);
396 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397 bs[1] = 0x80 | (c & 0x3F);
402 for(var j=0; j<bs.length; j++){
404 var hex = nibble_to_hex((b & 0xF0) >>> 4)
405 + nibble_to_hex(b &0x0F);
414 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415 * @param {String} string
416 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417 * @return {Object} A literal with members
419 urlDecode : function(string, overwrite){
420 if(!string || !string.length){
424 var pairs = string.split('&');
425 var pair, name, value;
426 for(var i = 0, len = pairs.length; i < len; i++){
427 pair = pairs[i].split('=');
428 name = decodeURIComponent(pair[0]);
429 value = decodeURIComponent(pair[1]);
430 if(overwrite !== true){
431 if(typeof obj[name] == "undefined"){
433 }else if(typeof obj[name] == "string"){
434 obj[name] = [obj[name]];
435 obj[name].push(value);
437 obj[name].push(value);
447 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448 * passed array is not really an array, your function is called once with it.
449 * The supplied function is called with (Object item, Number index, Array allItems).
450 * @param {Array/NodeList/Mixed} array
451 * @param {Function} fn
452 * @param {Object} scope
454 each : function(array, fn, scope){
455 if(typeof array.length == "undefined" || typeof array == "string"){
458 for(var i = 0, len = array.length; i < len; i++){
459 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
464 combine : function(){
465 var as = arguments, l = as.length, r = [];
466 for(var i = 0; i < l; i++){
468 if(a instanceof Array){
470 }else if(a.length !== undefined && !a.substr){
471 r = r.concat(Array.prototype.slice.call(a, 0));
480 * Escapes the passed string for use in a regular expression
481 * @param {String} str
484 escapeRe : function(s) {
485 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
489 callback : function(cb, scope, args, delay){
490 if(typeof cb == "function"){
492 cb.defer(delay, scope, args || []);
494 cb.apply(scope, args || []);
500 * Return the dom node for the passed string (id), dom node, or Roo.Element
501 * @param {String/HTMLElement/Roo.Element} el
502 * @return HTMLElement
504 getDom : function(el){
508 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
512 * Shorthand for {@link Roo.ComponentMgr#get}
514 * @return Roo.Component
516 getCmp : function(id){
517 return Roo.ComponentMgr.get(id);
520 num : function(v, defaultValue){
521 if(typeof v != 'number'){
527 destroy : function(){
528 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
532 as.removeAllListeners();
536 if(typeof as.purgeListeners == 'function'){
539 if(typeof as.destroy == 'function'){
546 // inpired by a similar function in mootools library
548 * Returns the type of object that is passed in. If the object passed in is null or undefined it
549 * return false otherwise it returns one of the following values:<ul>
550 * <li><b>string</b>: If the object passed is a string</li>
551 * <li><b>number</b>: If the object passed is a number</li>
552 * <li><b>boolean</b>: If the object passed is a boolean value</li>
553 * <li><b>function</b>: If the object passed is a function reference</li>
554 * <li><b>object</b>: If the object passed is an object</li>
555 * <li><b>array</b>: If the object passed is an array</li>
556 * <li><b>regexp</b>: If the object passed is a regular expression</li>
557 * <li><b>element</b>: If the object passed is a DOM Element</li>
558 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561 * @param {Mixed} object
565 if(o === undefined || o === null){
572 if(t == 'object' && o.nodeName) {
574 case 1: return 'element';
575 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
578 if(t == 'object' || t == 'function') {
579 switch(o.constructor) {
580 case Array: return 'array';
581 case RegExp: return 'regexp';
583 if(typeof o.length == 'number' && typeof o.item == 'function') {
591 * Returns true if the passed value is null, undefined or an empty string (optional).
592 * @param {Mixed} value The value to test
593 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
596 isEmpty : function(v, allowBlank){
597 return v === null || v === undefined || (!allowBlank ? v === '' : false);
611 isBorderBox : isBorderBox,
613 isWindows : isWindows,
620 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
621 * you may want to set this to true.
624 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
629 * Selects a single element as a Roo Element
630 * This is about as close as you can get to jQuery's $('do crazy stuff')
631 * @param {String} selector The selector/xpath query
632 * @param {Node} root (optional) The start of the query (defaults to document).
633 * @return {Roo.Element}
635 selectNode : function(selector, root)
637 var node = Roo.DomQuery.selectNode(selector,root);
638 return node ? Roo.get(node) : new Roo.Element(false);
646 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
647 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
650 * Ext JS Library 1.1.1
651 * Copyright(c) 2006-2007, Ext JS, LLC.
653 * Originally Released Under LGPL - original licence link has changed is not relivant.
656 * <script type="text/javascript">
660 // wrappedn so fnCleanup is not in global scope...
662 function fnCleanUp() {
663 var p = Function.prototype;
664 delete p.createSequence;
666 delete p.createDelegate;
667 delete p.createCallback;
668 delete p.createInterceptor;
670 window.detachEvent("onunload", fnCleanUp);
672 window.attachEvent("onunload", fnCleanUp);
679 * These functions are available on every Function object (any JavaScript function).
681 Roo.apply(Function.prototype, {
683 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
684 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
685 * Will create a function that is bound to those 2 args.
686 * @return {Function} The new function
688 createCallback : function(/*args...*/){
689 // make args available, in function below
690 var args = arguments;
693 return method.apply(window, args);
698 * Creates a delegate (callback) that sets the scope to obj.
699 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
700 * Will create a function that is automatically scoped to this.
701 * @param {Object} obj (optional) The object for which the scope is set
702 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
703 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
704 * if a number the args are inserted at the specified position
705 * @return {Function} The new function
707 createDelegate : function(obj, args, appendArgs){
710 var callArgs = args || arguments;
711 if(appendArgs === true){
712 callArgs = Array.prototype.slice.call(arguments, 0);
713 callArgs = callArgs.concat(args);
714 }else if(typeof appendArgs == "number"){
715 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
716 var applyArgs = [appendArgs, 0].concat(args); // create method call params
717 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
719 return method.apply(obj || window, callArgs);
724 * Calls this function after the number of millseconds specified.
725 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
726 * @param {Object} obj (optional) The object for which the scope is set
727 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
728 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
729 * if a number the args are inserted at the specified position
730 * @return {Number} The timeout id that can be used with clearTimeout
732 defer : function(millis, obj, args, appendArgs){
733 var fn = this.createDelegate(obj, args, appendArgs);
735 return setTimeout(fn, millis);
741 * Create a combined function call sequence of the original function + the passed function.
742 * The resulting function returns the results of the original function.
743 * The passed fcn is called with the parameters of the original function
744 * @param {Function} fcn The function to sequence
745 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
746 * @return {Function} The new function
748 createSequence : function(fcn, scope){
749 if(typeof fcn != "function"){
754 var retval = method.apply(this || window, arguments);
755 fcn.apply(scope || this || window, arguments);
761 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
762 * The resulting function returns the results of the original function.
763 * The passed fcn is called with the parameters of the original function.
765 * @param {Function} fcn The function to call before the original
766 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
767 * @return {Function} The new function
769 createInterceptor : function(fcn, scope){
770 if(typeof fcn != "function"){
777 if(fcn.apply(scope || this || window, arguments) === false){
780 return method.apply(this || window, arguments);
786 * Ext JS Library 1.1.1
787 * Copyright(c) 2006-2007, Ext JS, LLC.
789 * Originally Released Under LGPL - original licence link has changed is not relivant.
792 * <script type="text/javascript">
795 Roo.applyIf(String, {
800 * Escapes the passed string for ' and \
801 * @param {String} string The string to escape
802 * @return {String} The escaped string
805 escape : function(string) {
806 return string.replace(/('|\\)/g, "\\$1");
810 * Pads the left side of a string with a specified character. This is especially useful
811 * for normalizing number and date strings. Example usage:
813 var s = String.leftPad('123', 5, '0');
814 // s now contains the string: '00123'
816 * @param {String} string The original string
817 * @param {Number} size The total length of the output string
818 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
819 * @return {String} The padded string
822 leftPad : function (val, size, ch) {
823 var result = new String(val);
824 if(ch === null || ch === undefined || ch === '') {
827 while (result.length < size) {
828 result = ch + result;
834 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
835 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
837 var cls = 'my-class', text = 'Some text';
838 var s = String.format('<div class="{0}">{1}</div>', cls, text);
839 // s now contains the string: '<div class="my-class">Some text</div>'
841 * @param {String} string The tokenized string to be formatted
842 * @param {String} value1 The value to replace token {0}
843 * @param {String} value2 Etc...
844 * @return {String} The formatted string
847 format : function(format){
848 var args = Array.prototype.slice.call(arguments, 1);
849 return format.replace(/\{(\d+)\}/g, function(m, i){
850 return Roo.util.Format.htmlEncode(args[i]);
856 * Utility function that allows you to easily switch a string between two alternating values. The passed value
857 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
858 * they are already different, the first value passed in is returned. Note that this method returns the new value
859 * but does not change the current string.
861 // alternate sort directions
862 sort = sort.toggle('ASC', 'DESC');
864 // instead of conditional logic:
865 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
867 * @param {String} value The value to compare to the current string
868 * @param {String} other The new value to use if the string already equals the first value passed in
869 * @return {String} The new value
872 String.prototype.toggle = function(value, other){
873 return this == value ? other : value;
876 * Ext JS Library 1.1.1
877 * Copyright(c) 2006-2007, Ext JS, LLC.
879 * Originally Released Under LGPL - original licence link has changed is not relivant.
882 * <script type="text/javascript">
888 Roo.applyIf(Number.prototype, {
890 * Checks whether or not the current number is within a desired range. If the number is already within the
891 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
892 * exceeded. Note that this method returns the constrained value but does not change the current number.
893 * @param {Number} min The minimum number in the range
894 * @param {Number} max The maximum number in the range
895 * @return {Number} The constrained value if outside the range, otherwise the current value
897 constrain : function(min, max){
898 return Math.min(Math.max(this, min), max);
902 * Ext JS Library 1.1.1
903 * Copyright(c) 2006-2007, Ext JS, LLC.
905 * Originally Released Under LGPL - original licence link has changed is not relivant.
908 * <script type="text/javascript">
913 Roo.applyIf(Array.prototype, {
915 * Checks whether or not the specified object exists in the array.
916 * @param {Object} o The object to check for
917 * @return {Number} The index of o in the array (or -1 if it is not found)
919 indexOf : function(o){
920 for (var i = 0, len = this.length; i < len; i++){
921 if(this[i] == o) return i;
927 * Removes the specified object from the array. If the object is not found nothing happens.
928 * @param {Object} o The object to remove
930 remove : function(o){
931 var index = this.indexOf(o);
933 this.splice(index, 1);
937 * Map (JS 1.6 compatibility)
938 * @param {Function} function to call
942 var len = this.length >>> 0;
943 if (typeof fun != "function")
944 throw new TypeError();
946 var res = new Array(len);
947 var thisp = arguments[1];
948 for (var i = 0; i < len; i++)
951 res[i] = fun.call(thisp, this[i], i, this);
962 * Ext JS Library 1.1.1
963 * Copyright(c) 2006-2007, Ext JS, LLC.
965 * Originally Released Under LGPL - original licence link has changed is not relivant.
968 * <script type="text/javascript">
974 * The date parsing and format syntax is a subset of
975 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
976 * supported will provide results equivalent to their PHP versions.
978 * Following is the list of all currently supported formats:
981 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
983 Format Output Description
984 ------ ---------- --------------------------------------------------------------
985 d 10 Day of the month, 2 digits with leading zeros
986 D Wed A textual representation of a day, three letters
987 j 10 Day of the month without leading zeros
988 l Wednesday A full textual representation of the day of the week
989 S th English ordinal day of month suffix, 2 chars (use with j)
990 w 3 Numeric representation of the day of the week
991 z 9 The julian date, or day of the year (0-365)
992 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
993 F January A full textual representation of the month
994 m 01 Numeric representation of a month, with leading zeros
995 M Jan Month name abbreviation, three letters
996 n 1 Numeric representation of a month, without leading zeros
997 t 31 Number of days in the given month
998 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
999 Y 2007 A full numeric representation of a year, 4 digits
1000 y 07 A two digit representation of a year
1001 a pm Lowercase Ante meridiem and Post meridiem
1002 A PM Uppercase Ante meridiem and Post meridiem
1003 g 3 12-hour format of an hour without leading zeros
1004 G 15 24-hour format of an hour without leading zeros
1005 h 03 12-hour format of an hour with leading zeros
1006 H 15 24-hour format of an hour with leading zeros
1007 i 05 Minutes with leading zeros
1008 s 01 Seconds, with leading zeros
1009 O -0600 Difference to Greenwich time (GMT) in hours
1010 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1011 T CST Timezone setting of the machine running the code
1012 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1015 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1017 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1018 document.write(dt.format('Y-m-d')); //2007-01-10
1019 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1020 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1023 * Here are some standard date/time patterns that you might find helpful. They
1024 * are not part of the source of Date.js, but to use them you can simply copy this
1025 * block of code into any script that is included after Date.js and they will also become
1026 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1029 ISO8601Long:"Y-m-d H:i:s",
1030 ISO8601Short:"Y-m-d",
1032 LongDate: "l, F d, Y",
1033 FullDateTime: "l, F d, Y g:i:s A",
1036 LongTime: "g:i:s A",
1037 SortableDateTime: "Y-m-d\\TH:i:s",
1038 UniversalSortableDateTime: "Y-m-d H:i:sO",
1045 var dt = new Date();
1046 document.write(dt.format(Date.patterns.ShortDate));
1051 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1052 * They generate precompiled functions from date formats instead of parsing and
1053 * processing the pattern every time you format a date. These functions are available
1054 * on every Date object (any javascript function).
1056 * The original article and download are here:
1057 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1064 Returns the number of milliseconds between this date and date
1065 @param {Date} date (optional) Defaults to now
1066 @return {Number} The diff in milliseconds
1067 @member Date getElapsed
1069 Date.prototype.getElapsed = function(date) {
1070 return Math.abs((date || new Date()).getTime()-this.getTime());
1072 // was in date file..
1076 Date.parseFunctions = {count:0};
1078 Date.parseRegexes = [];
1080 Date.formatFunctions = {count:0};
1083 Date.prototype.dateFormat = function(format) {
1084 if (Date.formatFunctions[format] == null) {
1085 Date.createNewFormat(format);
1087 var func = Date.formatFunctions[format];
1088 return this[func]();
1093 * Formats a date given the supplied format string
1094 * @param {String} format The format string
1095 * @return {String} The formatted date
1098 Date.prototype.format = Date.prototype.dateFormat;
1101 Date.createNewFormat = function(format) {
1102 var funcName = "format" + Date.formatFunctions.count++;
1103 Date.formatFunctions[format] = funcName;
1104 var code = "Date.prototype." + funcName + " = function(){return ";
1105 var special = false;
1107 for (var i = 0; i < format.length; ++i) {
1108 ch = format.charAt(i);
1109 if (!special && ch == "\\") {
1114 code += "'" + String.escape(ch) + "' + ";
1117 code += Date.getFormatCode(ch);
1120 /** eval:var:zzzzzzzzzzzzz */
1121 eval(code.substring(0, code.length - 3) + ";}");
1125 Date.getFormatCode = function(character) {
1126 switch (character) {
1128 return "String.leftPad(this.getDate(), 2, '0') + ";
1130 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1132 return "this.getDate() + ";
1134 return "Date.dayNames[this.getDay()] + ";
1136 return "this.getSuffix() + ";
1138 return "this.getDay() + ";
1140 return "this.getDayOfYear() + ";
1142 return "this.getWeekOfYear() + ";
1144 return "Date.monthNames[this.getMonth()] + ";
1146 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1148 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1150 return "(this.getMonth() + 1) + ";
1152 return "this.getDaysInMonth() + ";
1154 return "(this.isLeapYear() ? 1 : 0) + ";
1156 return "this.getFullYear() + ";
1158 return "('' + this.getFullYear()).substring(2, 4) + ";
1160 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1162 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1164 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1166 return "this.getHours() + ";
1168 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1170 return "String.leftPad(this.getHours(), 2, '0') + ";
1172 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1174 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1176 return "this.getGMTOffset() + ";
1178 return "this.getGMTColonOffset() + ";
1180 return "this.getTimezone() + ";
1182 return "(this.getTimezoneOffset() * -60) + ";
1184 return "'" + String.escape(character) + "' + ";
1189 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1190 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1191 * the date format that is not specified will default to the current date value for that part. Time parts can also
1192 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1193 * string or the parse operation will fail.
1196 //dt = Fri May 25 2007 (current date)
1197 var dt = new Date();
1199 //dt = Thu May 25 2006 (today's month/day in 2006)
1200 dt = Date.parseDate("2006", "Y");
1202 //dt = Sun Jan 15 2006 (all date parts specified)
1203 dt = Date.parseDate("2006-1-15", "Y-m-d");
1205 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1206 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1208 * @param {String} input The unparsed date as a string
1209 * @param {String} format The format the date is in
1210 * @return {Date} The parsed date
1213 Date.parseDate = function(input, format) {
1214 if (Date.parseFunctions[format] == null) {
1215 Date.createParser(format);
1217 var func = Date.parseFunctions[format];
1218 return Date[func](input);
1223 Date.createParser = function(format) {
1224 var funcName = "parse" + Date.parseFunctions.count++;
1225 var regexNum = Date.parseRegexes.length;
1226 var currentGroup = 1;
1227 Date.parseFunctions[format] = funcName;
1229 var code = "Date." + funcName + " = function(input){\n"
1230 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1231 + "var d = new Date();\n"
1232 + "y = d.getFullYear();\n"
1233 + "m = d.getMonth();\n"
1234 + "d = d.getDate();\n"
1235 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1236 + "if (results && results.length > 0) {";
1239 var special = false;
1241 for (var i = 0; i < format.length; ++i) {
1242 ch = format.charAt(i);
1243 if (!special && ch == "\\") {
1248 regex += String.escape(ch);
1251 var obj = Date.formatCodeToRegex(ch, currentGroup);
1252 currentGroup += obj.g;
1254 if (obj.g && obj.c) {
1260 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1261 + "{v = new Date(y, m, d, h, i, s);}\n"
1262 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1263 + "{v = new Date(y, m, d, h, i);}\n"
1264 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1265 + "{v = new Date(y, m, d, h);}\n"
1266 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1267 + "{v = new Date(y, m, d);}\n"
1268 + "else if (y >= 0 && m >= 0)\n"
1269 + "{v = new Date(y, m);}\n"
1270 + "else if (y >= 0)\n"
1271 + "{v = new Date(y);}\n"
1272 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1273 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1274 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1277 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1278 /** eval:var:zzzzzzzzzzzzz */
1283 Date.formatCodeToRegex = function(character, currentGroup) {
1284 switch (character) {
1288 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1291 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1292 s:"(\\d{1,2})"}; // day of month without leading zeroes
1295 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1296 s:"(\\d{2})"}; // day of month with leading zeroes
1300 s:"(?:" + Date.dayNames.join("|") + ")"};
1304 s:"(?:st|nd|rd|th)"};
1319 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1320 s:"(" + Date.monthNames.join("|") + ")"};
1323 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1324 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1327 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1328 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1331 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1332 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1343 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1347 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1348 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1352 c:"if (results[" + currentGroup + "] == 'am') {\n"
1353 + "if (h == 12) { h = 0; }\n"
1354 + "} else { if (h < 12) { h += 12; }}",
1358 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1359 + "if (h == 12) { h = 0; }\n"
1360 + "} else { if (h < 12) { h += 12; }}",
1365 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1366 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1370 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1371 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1374 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1378 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1383 "o = results[", currentGroup, "];\n",
1384 "var sn = o.substring(0,1);\n", // get + / - sign
1385 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1386 "var mn = o.substring(3,5) % 60;\n", // get minutes
1387 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1388 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1394 "o = results[", currentGroup, "];\n",
1395 "var sn = o.substring(0,1);\n",
1396 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1397 "var mn = o.substring(4,6) % 60;\n",
1398 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1399 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1405 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1408 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1409 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1410 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1414 s:String.escape(character)};
1419 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1420 * @return {String} The abbreviated timezone name (e.g. 'CST')
1422 Date.prototype.getTimezone = function() {
1423 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1427 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1428 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1430 Date.prototype.getGMTOffset = function() {
1431 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1432 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1433 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1437 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1438 * @return {String} 2-characters representing hours and 2-characters representing minutes
1439 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1441 Date.prototype.getGMTColonOffset = function() {
1442 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1443 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1445 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1449 * Get the numeric day number of the year, adjusted for leap year.
1450 * @return {Number} 0 through 364 (365 in leap years)
1452 Date.prototype.getDayOfYear = function() {
1454 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1455 for (var i = 0; i < this.getMonth(); ++i) {
1456 num += Date.daysInMonth[i];
1458 return num + this.getDate() - 1;
1462 * Get the string representation of the numeric week number of the year
1463 * (equivalent to the format specifier 'W').
1464 * @return {String} '00' through '52'
1466 Date.prototype.getWeekOfYear = function() {
1467 // Skip to Thursday of this week
1468 var now = this.getDayOfYear() + (4 - this.getDay());
1469 // Find the first Thursday of the year
1470 var jan1 = new Date(this.getFullYear(), 0, 1);
1471 var then = (7 - jan1.getDay() + 4);
1472 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1476 * Whether or not the current date is in a leap year.
1477 * @return {Boolean} True if the current date is in a leap year, else false
1479 Date.prototype.isLeapYear = function() {
1480 var year = this.getFullYear();
1481 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1485 * Get the first day of the current month, adjusted for leap year. The returned value
1486 * is the numeric day index within the week (0-6) which can be used in conjunction with
1487 * the {@link #monthNames} array to retrieve the textual day name.
1490 var dt = new Date('1/10/2007');
1491 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1493 * @return {Number} The day number (0-6)
1495 Date.prototype.getFirstDayOfMonth = function() {
1496 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1497 return (day < 0) ? (day + 7) : day;
1501 * Get the last day of the current month, adjusted for leap year. The returned value
1502 * is the numeric day index within the week (0-6) which can be used in conjunction with
1503 * the {@link #monthNames} array to retrieve the textual day name.
1506 var dt = new Date('1/10/2007');
1507 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1509 * @return {Number} The day number (0-6)
1511 Date.prototype.getLastDayOfMonth = function() {
1512 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1513 return (day < 0) ? (day + 7) : day;
1518 * Get the first date of this date's month
1521 Date.prototype.getFirstDateOfMonth = function() {
1522 return new Date(this.getFullYear(), this.getMonth(), 1);
1526 * Get the last date of this date's month
1529 Date.prototype.getLastDateOfMonth = function() {
1530 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1533 * Get the number of days in the current month, adjusted for leap year.
1534 * @return {Number} The number of days in the month
1536 Date.prototype.getDaysInMonth = function() {
1537 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1538 return Date.daysInMonth[this.getMonth()];
1542 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1543 * @return {String} 'st, 'nd', 'rd' or 'th'
1545 Date.prototype.getSuffix = function() {
1546 switch (this.getDate()) {
1563 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1566 * An array of textual month names.
1567 * Override these values for international dates, for example...
1568 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1587 * An array of textual day names.
1588 * Override these values for international dates, for example...
1589 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1605 Date.monthNumbers = {
1620 * Creates and returns a new Date instance with the exact same date value as the called instance.
1621 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1622 * variable will also be changed. When the intention is to create a new variable that will not
1623 * modify the original instance, you should create a clone.
1625 * Example of correctly cloning a date:
1628 var orig = new Date('10/1/2006');
1631 document.write(orig); //returns 'Thu Oct 05 2006'!
1634 var orig = new Date('10/1/2006');
1635 var copy = orig.clone();
1637 document.write(orig); //returns 'Thu Oct 01 2006'
1639 * @return {Date} The new Date instance
1641 Date.prototype.clone = function() {
1642 return new Date(this.getTime());
1646 * Clears any time information from this date
1647 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1648 @return {Date} this or the clone
1650 Date.prototype.clearTime = function(clone){
1652 return this.clone().clearTime();
1657 this.setMilliseconds(0);
1662 // safari setMonth is broken
1664 Date.brokenSetMonth = Date.prototype.setMonth;
1665 Date.prototype.setMonth = function(num){
1667 var n = Math.ceil(-num);
1668 var back_year = Math.ceil(n/12);
1669 var month = (n % 12) ? 12 - n % 12 : 0 ;
1670 this.setFullYear(this.getFullYear() - back_year);
1671 return Date.brokenSetMonth.call(this, month);
1673 return Date.brokenSetMonth.apply(this, arguments);
1678 /** Date interval constant
1682 /** Date interval constant
1686 /** Date interval constant
1690 /** Date interval constant
1694 /** Date interval constant
1698 /** Date interval constant
1702 /** Date interval constant
1708 * Provides a convenient method of performing basic date arithmetic. This method
1709 * does not modify the Date instance being called - it creates and returns
1710 * a new Date instance containing the resulting date value.
1715 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1716 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1718 //Negative values will subtract correctly:
1719 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1720 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1722 //You can even chain several calls together in one line!
1723 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1724 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1727 * @param {String} interval A valid date interval enum value
1728 * @param {Number} value The amount to add to the current date
1729 * @return {Date} The new Date instance
1731 Date.prototype.add = function(interval, value){
1732 var d = this.clone();
1733 if (!interval || value === 0) return d;
1734 switch(interval.toLowerCase()){
1736 d.setMilliseconds(this.getMilliseconds() + value);
1739 d.setSeconds(this.getSeconds() + value);
1742 d.setMinutes(this.getMinutes() + value);
1745 d.setHours(this.getHours() + value);
1748 d.setDate(this.getDate() + value);
1751 var day = this.getDate();
1753 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1756 d.setMonth(this.getMonth() + value);
1759 d.setFullYear(this.getFullYear() + value);
1766 * Ext JS Library 1.1.1
1767 * Copyright(c) 2006-2007, Ext JS, LLC.
1769 * Originally Released Under LGPL - original licence link has changed is not relivant.
1772 * <script type="text/javascript">
1776 getViewWidth : function(full) {
1777 return full ? this.getDocumentWidth() : this.getViewportWidth();
1780 getViewHeight : function(full) {
1781 return full ? this.getDocumentHeight() : this.getViewportHeight();
1784 getDocumentHeight: function() {
1785 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1786 return Math.max(scrollHeight, this.getViewportHeight());
1789 getDocumentWidth: function() {
1790 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1791 return Math.max(scrollWidth, this.getViewportWidth());
1794 getViewportHeight: function() {
1795 var height = self.innerHeight;
1796 var mode = document.compatMode;
1798 if ((mode || Roo.isIE) && !Roo.isOpera) {
1799 height = (mode == "CSS1Compat") ?
1800 document.documentElement.clientHeight :
1801 document.body.clientHeight;
1807 getViewportWidth: function() {
1808 var width = self.innerWidth;
1809 var mode = document.compatMode;
1811 if (mode || Roo.isIE) {
1812 width = (mode == "CSS1Compat") ?
1813 document.documentElement.clientWidth :
1814 document.body.clientWidth;
1819 isAncestor : function(p, c) {
1826 if (p.contains && !Roo.isSafari) {
1827 return p.contains(c);
1828 } else if (p.compareDocumentPosition) {
1829 return !!(p.compareDocumentPosition(c) & 16);
1831 var parent = c.parentNode;
1836 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1839 parent = parent.parentNode;
1845 getRegion : function(el) {
1846 return Roo.lib.Region.getRegion(el);
1849 getY : function(el) {
1850 return this.getXY(el)[1];
1853 getX : function(el) {
1854 return this.getXY(el)[0];
1857 getXY : function(el) {
1858 var p, pe, b, scroll, bd = document.body;
1859 el = Roo.getDom(el);
1860 var fly = Roo.lib.AnimBase.fly;
1861 if (el.getBoundingClientRect) {
1862 b = el.getBoundingClientRect();
1863 scroll = fly(document).getScroll();
1864 return [b.left + scroll.left, b.top + scroll.top];
1870 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1877 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1884 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1885 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1892 if (p != el && pe.getStyle('overflow') != 'visible') {
1900 if (Roo.isSafari && hasAbsolute) {
1905 if (Roo.isGecko && !hasAbsolute) {
1907 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1908 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1912 while (p && p != bd) {
1913 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1925 setXY : function(el, xy) {
1926 el = Roo.fly(el, '_setXY');
1928 var pts = el.translatePoints(xy);
1929 if (xy[0] !== false) {
1930 el.dom.style.left = pts.left + "px";
1932 if (xy[1] !== false) {
1933 el.dom.style.top = pts.top + "px";
1937 setX : function(el, x) {
1938 this.setXY(el, [x, false]);
1941 setY : function(el, y) {
1942 this.setXY(el, [false, y]);
1946 * Portions of this file are based on pieces of Yahoo User Interface Library
1947 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1948 * YUI licensed under the BSD License:
1949 * http://developer.yahoo.net/yui/license.txt
1950 * <script type="text/javascript">
1954 Roo.lib.Event = function() {
1955 var loadComplete = false;
1957 var unloadListeners = [];
1959 var onAvailStack = [];
1961 var lastError = null;
1974 startInterval: function() {
1975 if (!this._interval) {
1977 var callback = function() {
1978 self._tryPreloadAttach();
1980 this._interval = setInterval(callback, this.POLL_INTERVAL);
1985 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1986 onAvailStack.push({ id: p_id,
1989 override: p_override,
1990 checkReady: false });
1992 retryCount = this.POLL_RETRYS;
1993 this.startInterval();
1997 addListener: function(el, eventName, fn) {
1998 el = Roo.getDom(el);
2003 if ("unload" == eventName) {
2004 unloadListeners[unloadListeners.length] =
2005 [el, eventName, fn];
2009 var wrappedFn = function(e) {
2010 return fn(Roo.lib.Event.getEvent(e));
2013 var li = [el, eventName, fn, wrappedFn];
2015 var index = listeners.length;
2016 listeners[index] = li;
2018 this.doAdd(el, eventName, wrappedFn, false);
2024 removeListener: function(el, eventName, fn) {
2027 el = Roo.getDom(el);
2030 return this.purgeElement(el, false, eventName);
2034 if ("unload" == eventName) {
2036 for (i = 0,len = unloadListeners.length; i < len; i++) {
2037 var li = unloadListeners[i];
2040 li[1] == eventName &&
2042 unloadListeners.splice(i, 1);
2050 var cacheItem = null;
2053 var index = arguments[3];
2055 if ("undefined" == typeof index) {
2056 index = this._getCacheIndex(el, eventName, fn);
2060 cacheItem = listeners[index];
2063 if (!el || !cacheItem) {
2067 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2069 delete listeners[index][this.WFN];
2070 delete listeners[index][this.FN];
2071 listeners.splice(index, 1);
2078 getTarget: function(ev, resolveTextNode) {
2079 ev = ev.browserEvent || ev;
2080 var t = ev.target || ev.srcElement;
2081 return this.resolveTextNode(t);
2085 resolveTextNode: function(node) {
2086 if (Roo.isSafari && node && 3 == node.nodeType) {
2087 return node.parentNode;
2094 getPageX: function(ev) {
2095 ev = ev.browserEvent || ev;
2097 if (!x && 0 !== x) {
2098 x = ev.clientX || 0;
2101 x += this.getScroll()[1];
2109 getPageY: function(ev) {
2110 ev = ev.browserEvent || ev;
2112 if (!y && 0 !== y) {
2113 y = ev.clientY || 0;
2116 y += this.getScroll()[0];
2125 getXY: function(ev) {
2126 ev = ev.browserEvent || ev;
2127 return [this.getPageX(ev), this.getPageY(ev)];
2131 getRelatedTarget: function(ev) {
2132 ev = ev.browserEvent || ev;
2133 var t = ev.relatedTarget;
2135 if (ev.type == "mouseout") {
2137 } else if (ev.type == "mouseover") {
2142 return this.resolveTextNode(t);
2146 getTime: function(ev) {
2147 ev = ev.browserEvent || ev;
2149 var t = new Date().getTime();
2153 this.lastError = ex;
2162 stopEvent: function(ev) {
2163 this.stopPropagation(ev);
2164 this.preventDefault(ev);
2168 stopPropagation: function(ev) {
2169 ev = ev.browserEvent || ev;
2170 if (ev.stopPropagation) {
2171 ev.stopPropagation();
2173 ev.cancelBubble = true;
2178 preventDefault: function(ev) {
2179 ev = ev.browserEvent || ev;
2180 if(ev.preventDefault) {
2181 ev.preventDefault();
2183 ev.returnValue = false;
2188 getEvent: function(e) {
2189 var ev = e || window.event;
2191 var c = this.getEvent.caller;
2193 ev = c.arguments[0];
2194 if (ev && Event == ev.constructor) {
2204 getCharCode: function(ev) {
2205 ev = ev.browserEvent || ev;
2206 return ev.charCode || ev.keyCode || 0;
2210 _getCacheIndex: function(el, eventName, fn) {
2211 for (var i = 0,len = listeners.length; i < len; ++i) {
2212 var li = listeners[i];
2214 li[this.FN] == fn &&
2215 li[this.EL] == el &&
2216 li[this.TYPE] == eventName) {
2228 getEl: function(id) {
2229 return document.getElementById(id);
2233 clearCache: function() {
2237 _load: function(e) {
2238 loadComplete = true;
2239 var EU = Roo.lib.Event;
2243 EU.doRemove(window, "load", EU._load);
2248 _tryPreloadAttach: function() {
2257 var tryAgain = !loadComplete;
2259 tryAgain = (retryCount > 0);
2264 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2265 var item = onAvailStack[i];
2267 var el = this.getEl(item.id);
2270 if (!item.checkReady ||
2273 (document && document.body)) {
2276 if (item.override) {
2277 if (item.override === true) {
2280 scope = item.override;
2283 item.fn.call(scope, item.obj);
2284 onAvailStack[i] = null;
2287 notAvail.push(item);
2292 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2296 this.startInterval();
2298 clearInterval(this._interval);
2299 this._interval = null;
2302 this.locked = false;
2309 purgeElement: function(el, recurse, eventName) {
2310 var elListeners = this.getListeners(el, eventName);
2312 for (var i = 0,len = elListeners.length; i < len; ++i) {
2313 var l = elListeners[i];
2314 this.removeListener(el, l.type, l.fn);
2318 if (recurse && el && el.childNodes) {
2319 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2320 this.purgeElement(el.childNodes[i], recurse, eventName);
2326 getListeners: function(el, eventName) {
2327 var results = [], searchLists;
2329 searchLists = [listeners, unloadListeners];
2330 } else if (eventName == "unload") {
2331 searchLists = [unloadListeners];
2333 searchLists = [listeners];
2336 for (var j = 0; j < searchLists.length; ++j) {
2337 var searchList = searchLists[j];
2338 if (searchList && searchList.length > 0) {
2339 for (var i = 0,len = searchList.length; i < len; ++i) {
2340 var l = searchList[i];
2341 if (l && l[this.EL] === el &&
2342 (!eventName || eventName === l[this.TYPE])) {
2347 adjust: l[this.ADJ_SCOPE],
2355 return (results.length) ? results : null;
2359 _unload: function(e) {
2361 var EU = Roo.lib.Event, i, j, l, len, index;
2363 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2364 l = unloadListeners[i];
2367 if (l[EU.ADJ_SCOPE]) {
2368 if (l[EU.ADJ_SCOPE] === true) {
2371 scope = l[EU.ADJ_SCOPE];
2374 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2375 unloadListeners[i] = null;
2381 unloadListeners = null;
2383 if (listeners && listeners.length > 0) {
2384 j = listeners.length;
2387 l = listeners[index];
2389 EU.removeListener(l[EU.EL], l[EU.TYPE],
2399 EU.doRemove(window, "unload", EU._unload);
2404 getScroll: function() {
2405 var dd = document.documentElement, db = document.body;
2406 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2407 return [dd.scrollTop, dd.scrollLeft];
2409 return [db.scrollTop, db.scrollLeft];
2416 doAdd: function () {
2417 if (window.addEventListener) {
2418 return function(el, eventName, fn, capture) {
2419 el.addEventListener(eventName, fn, (capture));
2421 } else if (window.attachEvent) {
2422 return function(el, eventName, fn, capture) {
2423 el.attachEvent("on" + eventName, fn);
2432 doRemove: function() {
2433 if (window.removeEventListener) {
2434 return function (el, eventName, fn, capture) {
2435 el.removeEventListener(eventName, fn, (capture));
2437 } else if (window.detachEvent) {
2438 return function (el, eventName, fn) {
2439 el.detachEvent("on" + eventName, fn);
2451 var E = Roo.lib.Event;
2452 E.on = E.addListener;
2453 E.un = E.removeListener;
2455 if (document && document.body) {
2458 E.doAdd(window, "load", E._load);
2460 E.doAdd(window, "unload", E._unload);
2461 E._tryPreloadAttach();
2465 * Portions of this file are based on pieces of Yahoo User Interface Library
2466 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2467 * YUI licensed under the BSD License:
2468 * http://developer.yahoo.net/yui/license.txt
2469 * <script type="text/javascript">
2475 * @class Roo.lib.Ajax
2482 request : function(method, uri, cb, data, options) {
2484 var hs = options.headers;
2487 if(hs.hasOwnProperty(h)){
2488 this.initHeader(h, hs[h], false);
2492 if(options.xmlData){
2493 this.initHeader('Content-Type', 'text/xml', false);
2495 data = options.xmlData;
2499 return this.asyncRequest(method, uri, cb, data);
2502 serializeForm : function(form) {
2503 if(typeof form == 'string') {
2504 form = (document.getElementById(form) || document.forms[form]);
2507 var el, name, val, disabled, data = '', hasSubmit = false;
2508 for (var i = 0; i < form.elements.length; i++) {
2509 el = form.elements[i];
2510 disabled = form.elements[i].disabled;
2511 name = form.elements[i].name;
2512 val = form.elements[i].value;
2514 if (!disabled && name){
2518 case 'select-multiple':
2519 for (var j = 0; j < el.options.length; j++) {
2520 if (el.options[j].selected) {
2522 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2525 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2533 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2546 if(hasSubmit == false) {
2547 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2552 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2557 data = data.substr(0, data.length - 1);
2565 useDefaultHeader:true,
2567 defaultPostHeader:'application/x-www-form-urlencoded',
2569 useDefaultXhrHeader:true,
2571 defaultXhrHeader:'XMLHttpRequest',
2573 hasDefaultHeaders:true,
2585 setProgId:function(id)
2587 this.activeX.unshift(id);
2590 setDefaultPostHeader:function(b)
2592 this.useDefaultHeader = b;
2595 setDefaultXhrHeader:function(b)
2597 this.useDefaultXhrHeader = b;
2600 setPollingInterval:function(i)
2602 if (typeof i == 'number' && isFinite(i)) {
2603 this.pollInterval = i;
2607 createXhrObject:function(transactionId)
2613 http = new XMLHttpRequest();
2615 obj = { conn:http, tId:transactionId };
2619 for (var i = 0; i < this.activeX.length; ++i) {
2623 http = new ActiveXObject(this.activeX[i]);
2625 obj = { conn:http, tId:transactionId };
2638 getConnectionObject:function()
2641 var tId = this.transactionId;
2645 o = this.createXhrObject(tId);
2647 this.transactionId++;
2658 asyncRequest:function(method, uri, callback, postData)
2660 var o = this.getConnectionObject();
2666 o.conn.open(method, uri, true);
2668 if (this.useDefaultXhrHeader) {
2669 if (!this.defaultHeaders['X-Requested-With']) {
2670 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2674 if(postData && this.useDefaultHeader){
2675 this.initHeader('Content-Type', this.defaultPostHeader);
2678 if (this.hasDefaultHeaders || this.hasHeaders) {
2682 this.handleReadyState(o, callback);
2683 o.conn.send(postData || null);
2689 handleReadyState:function(o, callback)
2693 if (callback && callback.timeout) {
2694 this.timeout[o.tId] = window.setTimeout(function() {
2695 oConn.abort(o, callback, true);
2696 }, callback.timeout);
2699 this.poll[o.tId] = window.setInterval(
2701 if (o.conn && o.conn.readyState == 4) {
2702 window.clearInterval(oConn.poll[o.tId]);
2703 delete oConn.poll[o.tId];
2705 if(callback && callback.timeout) {
2706 window.clearTimeout(oConn.timeout[o.tId]);
2707 delete oConn.timeout[o.tId];
2710 oConn.handleTransactionResponse(o, callback);
2713 , this.pollInterval);
2716 handleTransactionResponse:function(o, callback, isAbort)
2720 this.releaseObject(o);
2724 var httpStatus, responseObject;
2728 if (o.conn.status !== undefined && o.conn.status != 0) {
2729 httpStatus = o.conn.status;
2741 if (httpStatus >= 200 && httpStatus < 300) {
2742 responseObject = this.createResponseObject(o, callback.argument);
2743 if (callback.success) {
2744 if (!callback.scope) {
2745 callback.success(responseObject);
2750 callback.success.apply(callback.scope, [responseObject]);
2755 switch (httpStatus) {
2763 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2764 if (callback.failure) {
2765 if (!callback.scope) {
2766 callback.failure(responseObject);
2769 callback.failure.apply(callback.scope, [responseObject]);
2774 responseObject = this.createResponseObject(o, callback.argument);
2775 if (callback.failure) {
2776 if (!callback.scope) {
2777 callback.failure(responseObject);
2780 callback.failure.apply(callback.scope, [responseObject]);
2786 this.releaseObject(o);
2787 responseObject = null;
2790 createResponseObject:function(o, callbackArg)
2797 var headerStr = o.conn.getAllResponseHeaders();
2798 var header = headerStr.split('\n');
2799 for (var i = 0; i < header.length; i++) {
2800 var delimitPos = header[i].indexOf(':');
2801 if (delimitPos != -1) {
2802 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2810 obj.status = o.conn.status;
2811 obj.statusText = o.conn.statusText;
2812 obj.getResponseHeader = headerObj;
2813 obj.getAllResponseHeaders = headerStr;
2814 obj.responseText = o.conn.responseText;
2815 obj.responseXML = o.conn.responseXML;
2817 if (typeof callbackArg !== undefined) {
2818 obj.argument = callbackArg;
2824 createExceptionObject:function(tId, callbackArg, isAbort)
2827 var COMM_ERROR = 'communication failure';
2828 var ABORT_CODE = -1;
2829 var ABORT_ERROR = 'transaction aborted';
2835 obj.status = ABORT_CODE;
2836 obj.statusText = ABORT_ERROR;
2839 obj.status = COMM_CODE;
2840 obj.statusText = COMM_ERROR;
2844 obj.argument = callbackArg;
2850 initHeader:function(label, value, isDefault)
2852 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2854 if (headerObj[label] === undefined) {
2855 headerObj[label] = value;
2860 headerObj[label] = value + "," + headerObj[label];
2864 this.hasDefaultHeaders = true;
2867 this.hasHeaders = true;
2872 setHeader:function(o)
2874 if (this.hasDefaultHeaders) {
2875 for (var prop in this.defaultHeaders) {
2876 if (this.defaultHeaders.hasOwnProperty(prop)) {
2877 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2882 if (this.hasHeaders) {
2883 for (var prop in this.headers) {
2884 if (this.headers.hasOwnProperty(prop)) {
2885 o.conn.setRequestHeader(prop, this.headers[prop]);
2889 this.hasHeaders = false;
2893 resetDefaultHeaders:function() {
2894 delete this.defaultHeaders;
2895 this.defaultHeaders = {};
2896 this.hasDefaultHeaders = false;
2899 abort:function(o, callback, isTimeout)
2901 if(this.isCallInProgress(o)) {
2903 window.clearInterval(this.poll[o.tId]);
2904 delete this.poll[o.tId];
2906 delete this.timeout[o.tId];
2909 this.handleTransactionResponse(o, callback, true);
2919 isCallInProgress:function(o)
2922 return o.conn.readyState != 4 && o.conn.readyState != 0;
2931 releaseObject:function(o)
2940 'MSXML2.XMLHTTP.3.0',
2948 * Portions of this file are based on pieces of Yahoo User Interface Library
2949 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2950 * YUI licensed under the BSD License:
2951 * http://developer.yahoo.net/yui/license.txt
2952 * <script type="text/javascript">
2956 Roo.lib.Region = function(t, r, b, l) {
2966 Roo.lib.Region.prototype = {
2967 contains : function(region) {
2968 return ( region.left >= this.left &&
2969 region.right <= this.right &&
2970 region.top >= this.top &&
2971 region.bottom <= this.bottom );
2975 getArea : function() {
2976 return ( (this.bottom - this.top) * (this.right - this.left) );
2979 intersect : function(region) {
2980 var t = Math.max(this.top, region.top);
2981 var r = Math.min(this.right, region.right);
2982 var b = Math.min(this.bottom, region.bottom);
2983 var l = Math.max(this.left, region.left);
2985 if (b >= t && r >= l) {
2986 return new Roo.lib.Region(t, r, b, l);
2991 union : function(region) {
2992 var t = Math.min(this.top, region.top);
2993 var r = Math.max(this.right, region.right);
2994 var b = Math.max(this.bottom, region.bottom);
2995 var l = Math.min(this.left, region.left);
2997 return new Roo.lib.Region(t, r, b, l);
3000 adjust : function(t, l, b, r) {
3009 Roo.lib.Region.getRegion = function(el) {
3010 var p = Roo.lib.Dom.getXY(el);
3013 var r = p[0] + el.offsetWidth;
3014 var b = p[1] + el.offsetHeight;
3017 return new Roo.lib.Region(t, r, b, l);
3020 * Portions of this file are based on pieces of Yahoo User Interface Library
3021 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3022 * YUI licensed under the BSD License:
3023 * http://developer.yahoo.net/yui/license.txt
3024 * <script type="text/javascript">
3027 //@@dep Roo.lib.Region
3030 Roo.lib.Point = function(x, y) {
3031 if (x instanceof Array) {
3035 this.x = this.right = this.left = this[0] = x;
3036 this.y = this.top = this.bottom = this[1] = y;
3039 Roo.lib.Point.prototype = new Roo.lib.Region();
3041 * Portions of this file are based on pieces of Yahoo User Interface Library
3042 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3043 * YUI licensed under the BSD License:
3044 * http://developer.yahoo.net/yui/license.txt
3045 * <script type="text/javascript">
3052 scroll : function(el, args, duration, easing, cb, scope) {
3053 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3056 motion : function(el, args, duration, easing, cb, scope) {
3057 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3060 color : function(el, args, duration, easing, cb, scope) {
3061 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3064 run : function(el, args, duration, easing, cb, scope, type) {
3065 type = type || Roo.lib.AnimBase;
3066 if (typeof easing == "string") {
3067 easing = Roo.lib.Easing[easing];
3069 var anim = new type(el, args, duration, easing);
3070 anim.animateX(function() {
3071 Roo.callback(cb, scope);
3077 * Portions of this file are based on pieces of Yahoo User Interface Library
3078 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3079 * YUI licensed under the BSD License:
3080 * http://developer.yahoo.net/yui/license.txt
3081 * <script type="text/javascript">
3089 if (!libFlyweight) {
3090 libFlyweight = new Roo.Element.Flyweight();
3092 libFlyweight.dom = el;
3093 return libFlyweight;
3096 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3100 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3102 this.init(el, attributes, duration, method);
3106 Roo.lib.AnimBase.fly = fly;
3110 Roo.lib.AnimBase.prototype = {
3112 toString: function() {
3113 var el = this.getEl();
3114 var id = el.id || el.tagName;
3115 return ("Anim " + id);
3119 noNegatives: /width|height|opacity|padding/i,
3120 offsetAttribute: /^((width|height)|(top|left))$/,
3121 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3122 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3126 doMethod: function(attr, start, end) {
3127 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3131 setAttribute: function(attr, val, unit) {
3132 if (this.patterns.noNegatives.test(attr)) {
3133 val = (val > 0) ? val : 0;
3136 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3140 getAttribute: function(attr) {
3141 var el = this.getEl();
3142 var val = fly(el).getStyle(attr);
3144 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3145 return parseFloat(val);
3148 var a = this.patterns.offsetAttribute.exec(attr) || [];
3149 var pos = !!( a[3] );
3150 var box = !!( a[2] );
3153 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3154 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3163 getDefaultUnit: function(attr) {
3164 if (this.patterns.defaultUnit.test(attr)) {
3171 animateX : function(callback, scope) {
3172 var f = function() {
3173 this.onComplete.removeListener(f);
3174 if (typeof callback == "function") {
3175 callback.call(scope || this, this);
3178 this.onComplete.addListener(f, this);
3183 setRuntimeAttribute: function(attr) {
3186 var attributes = this.attributes;
3188 this.runtimeAttributes[attr] = {};
3190 var isset = function(prop) {
3191 return (typeof prop !== 'undefined');
3194 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3198 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3201 if (isset(attributes[attr]['to'])) {
3202 end = attributes[attr]['to'];
3203 } else if (isset(attributes[attr]['by'])) {
3204 if (start.constructor == Array) {
3206 for (var i = 0, len = start.length; i < len; ++i) {
3207 end[i] = start[i] + attributes[attr]['by'][i];
3210 end = start + attributes[attr]['by'];
3214 this.runtimeAttributes[attr].start = start;
3215 this.runtimeAttributes[attr].end = end;
3218 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3222 init: function(el, attributes, duration, method) {
3224 var isAnimated = false;
3227 var startTime = null;
3230 var actualFrames = 0;
3233 el = Roo.getDom(el);
3236 this.attributes = attributes || {};
3239 this.duration = duration || 1;
3242 this.method = method || Roo.lib.Easing.easeNone;
3245 this.useSeconds = true;
3248 this.currentFrame = 0;
3251 this.totalFrames = Roo.lib.AnimMgr.fps;
3254 this.getEl = function() {
3259 this.isAnimated = function() {
3264 this.getStartTime = function() {
3268 this.runtimeAttributes = {};
3271 this.animate = function() {
3272 if (this.isAnimated()) {
3276 this.currentFrame = 0;
3278 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3280 Roo.lib.AnimMgr.registerElement(this);
3284 this.stop = function(finish) {
3286 this.currentFrame = this.totalFrames;
3287 this._onTween.fire();
3289 Roo.lib.AnimMgr.stop(this);
3292 var onStart = function() {
3293 this.onStart.fire();
3295 this.runtimeAttributes = {};
3296 for (var attr in this.attributes) {
3297 this.setRuntimeAttribute(attr);
3302 startTime = new Date();
3306 var onTween = function() {
3308 duration: new Date() - this.getStartTime(),
3309 currentFrame: this.currentFrame
3312 data.toString = function() {
3314 'duration: ' + data.duration +
3315 ', currentFrame: ' + data.currentFrame
3319 this.onTween.fire(data);
3321 var runtimeAttributes = this.runtimeAttributes;
3323 for (var attr in runtimeAttributes) {
3324 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3330 var onComplete = function() {
3331 var actual_duration = (new Date() - startTime) / 1000 ;
3334 duration: actual_duration,
3335 frames: actualFrames,
3336 fps: actualFrames / actual_duration
3339 data.toString = function() {
3341 'duration: ' + data.duration +
3342 ', frames: ' + data.frames +
3343 ', fps: ' + data.fps
3349 this.onComplete.fire(data);
3353 this._onStart = new Roo.util.Event(this);
3354 this.onStart = new Roo.util.Event(this);
3355 this.onTween = new Roo.util.Event(this);
3356 this._onTween = new Roo.util.Event(this);
3357 this.onComplete = new Roo.util.Event(this);
3358 this._onComplete = new Roo.util.Event(this);
3359 this._onStart.addListener(onStart);
3360 this._onTween.addListener(onTween);
3361 this._onComplete.addListener(onComplete);
3366 * Portions of this file are based on pieces of Yahoo User Interface Library
3367 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3368 * YUI licensed under the BSD License:
3369 * http://developer.yahoo.net/yui/license.txt
3370 * <script type="text/javascript">
3374 Roo.lib.AnimMgr = new function() {
3391 this.registerElement = function(tween) {
3392 queue[queue.length] = tween;
3394 tween._onStart.fire();
3399 this.unRegister = function(tween, index) {
3400 tween._onComplete.fire();
3401 index = index || getIndex(tween);
3403 queue.splice(index, 1);
3407 if (tweenCount <= 0) {
3413 this.start = function() {
3414 if (thread === null) {
3415 thread = setInterval(this.run, this.delay);
3420 this.stop = function(tween) {
3422 clearInterval(thread);
3424 for (var i = 0, len = queue.length; i < len; ++i) {
3425 if (queue[0].isAnimated()) {
3426 this.unRegister(queue[0], 0);
3435 this.unRegister(tween);
3440 this.run = function() {
3441 for (var i = 0, len = queue.length; i < len; ++i) {
3442 var tween = queue[i];
3443 if (!tween || !tween.isAnimated()) {
3447 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3449 tween.currentFrame += 1;
3451 if (tween.useSeconds) {
3452 correctFrame(tween);
3454 tween._onTween.fire();
3457 Roo.lib.AnimMgr.stop(tween, i);
3462 var getIndex = function(anim) {
3463 for (var i = 0, len = queue.length; i < len; ++i) {
3464 if (queue[i] == anim) {
3472 var correctFrame = function(tween) {
3473 var frames = tween.totalFrames;
3474 var frame = tween.currentFrame;
3475 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3476 var elapsed = (new Date() - tween.getStartTime());
3479 if (elapsed < tween.duration * 1000) {
3480 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3482 tweak = frames - (frame + 1);
3484 if (tweak > 0 && isFinite(tweak)) {
3485 if (tween.currentFrame + tweak >= frames) {
3486 tweak = frames - (frame + 1);
3489 tween.currentFrame += tweak;
3493 * Portions of this file are based on pieces of Yahoo User Interface Library
3494 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3495 * YUI licensed under the BSD License:
3496 * http://developer.yahoo.net/yui/license.txt
3497 * <script type="text/javascript">
3500 Roo.lib.Bezier = new function() {
3502 this.getPosition = function(points, t) {
3503 var n = points.length;
3506 for (var i = 0; i < n; ++i) {
3507 tmp[i] = [points[i][0], points[i][1]];
3510 for (var j = 1; j < n; ++j) {
3511 for (i = 0; i < n - j; ++i) {
3512 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3513 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3517 return [ tmp[0][0], tmp[0][1] ];
3521 * Portions of this file are based on pieces of Yahoo User Interface Library
3522 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3523 * YUI licensed under the BSD License:
3524 * http://developer.yahoo.net/yui/license.txt
3525 * <script type="text/javascript">
3530 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3531 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3534 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3536 var fly = Roo.lib.AnimBase.fly;
3538 var superclass = Y.ColorAnim.superclass;
3539 var proto = Y.ColorAnim.prototype;
3541 proto.toString = function() {
3542 var el = this.getEl();
3543 var id = el.id || el.tagName;
3544 return ("ColorAnim " + id);
3547 proto.patterns.color = /color$/i;
3548 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3549 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3550 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3551 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3554 proto.parseColor = function(s) {
3555 if (s.length == 3) {
3559 var c = this.patterns.hex.exec(s);
3560 if (c && c.length == 4) {
3561 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3564 c = this.patterns.rgb.exec(s);
3565 if (c && c.length == 4) {
3566 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3569 c = this.patterns.hex3.exec(s);
3570 if (c && c.length == 4) {
3571 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3576 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3577 proto.getAttribute = function(attr) {
3578 var el = this.getEl();
3579 if (this.patterns.color.test(attr)) {
3580 var val = fly(el).getStyle(attr);
3582 if (this.patterns.transparent.test(val)) {
3583 var parent = el.parentNode;
3584 val = fly(parent).getStyle(attr);
3586 while (parent && this.patterns.transparent.test(val)) {
3587 parent = parent.parentNode;
3588 val = fly(parent).getStyle(attr);
3589 if (parent.tagName.toUpperCase() == 'HTML') {
3595 val = superclass.getAttribute.call(this, attr);
3600 proto.getAttribute = function(attr) {
3601 var el = this.getEl();
3602 if (this.patterns.color.test(attr)) {
3603 var val = fly(el).getStyle(attr);
3605 if (this.patterns.transparent.test(val)) {
3606 var parent = el.parentNode;
3607 val = fly(parent).getStyle(attr);
3609 while (parent && this.patterns.transparent.test(val)) {
3610 parent = parent.parentNode;
3611 val = fly(parent).getStyle(attr);
3612 if (parent.tagName.toUpperCase() == 'HTML') {
3618 val = superclass.getAttribute.call(this, attr);
3624 proto.doMethod = function(attr, start, end) {
3627 if (this.patterns.color.test(attr)) {
3629 for (var i = 0, len = start.length; i < len; ++i) {
3630 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3633 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3636 val = superclass.doMethod.call(this, attr, start, end);
3642 proto.setRuntimeAttribute = function(attr) {
3643 superclass.setRuntimeAttribute.call(this, attr);
3645 if (this.patterns.color.test(attr)) {
3646 var attributes = this.attributes;
3647 var start = this.parseColor(this.runtimeAttributes[attr].start);
3648 var end = this.parseColor(this.runtimeAttributes[attr].end);
3650 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3651 end = this.parseColor(attributes[attr].by);
3653 for (var i = 0, len = start.length; i < len; ++i) {
3654 end[i] = start[i] + end[i];
3658 this.runtimeAttributes[attr].start = start;
3659 this.runtimeAttributes[attr].end = end;
3665 * Portions of this file are based on pieces of Yahoo User Interface Library
3666 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3667 * YUI licensed under the BSD License:
3668 * http://developer.yahoo.net/yui/license.txt
3669 * <script type="text/javascript">
3675 easeNone: function (t, b, c, d) {
3676 return c * t / d + b;
3680 easeIn: function (t, b, c, d) {
3681 return c * (t /= d) * t + b;
3685 easeOut: function (t, b, c, d) {
3686 return -c * (t /= d) * (t - 2) + b;
3690 easeBoth: function (t, b, c, d) {
3691 if ((t /= d / 2) < 1) {
3692 return c / 2 * t * t + b;
3695 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3699 easeInStrong: function (t, b, c, d) {
3700 return c * (t /= d) * t * t * t + b;
3704 easeOutStrong: function (t, b, c, d) {
3705 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3709 easeBothStrong: function (t, b, c, d) {
3710 if ((t /= d / 2) < 1) {
3711 return c / 2 * t * t * t * t + b;
3714 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3719 elasticIn: function (t, b, c, d, a, p) {
3723 if ((t /= d) == 1) {
3730 if (!a || a < Math.abs(c)) {
3735 var s = p / (2 * Math.PI) * Math.asin(c / a);
3738 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3742 elasticOut: function (t, b, c, d, a, p) {
3746 if ((t /= d) == 1) {
3753 if (!a || a < Math.abs(c)) {
3758 var s = p / (2 * Math.PI) * Math.asin(c / a);
3761 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3765 elasticBoth: function (t, b, c, d, a, p) {
3770 if ((t /= d / 2) == 2) {
3778 if (!a || a < Math.abs(c)) {
3783 var s = p / (2 * Math.PI) * Math.asin(c / a);
3787 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3788 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3790 return a * Math.pow(2, -10 * (t -= 1)) *
3791 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3796 backIn: function (t, b, c, d, s) {
3797 if (typeof s == 'undefined') {
3800 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3804 backOut: function (t, b, c, d, s) {
3805 if (typeof s == 'undefined') {
3808 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3812 backBoth: function (t, b, c, d, s) {
3813 if (typeof s == 'undefined') {
3817 if ((t /= d / 2 ) < 1) {
3818 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3820 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3824 bounceIn: function (t, b, c, d) {
3825 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3829 bounceOut: function (t, b, c, d) {
3830 if ((t /= d) < (1 / 2.75)) {
3831 return c * (7.5625 * t * t) + b;
3832 } else if (t < (2 / 2.75)) {
3833 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3834 } else if (t < (2.5 / 2.75)) {
3835 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3837 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3841 bounceBoth: function (t, b, c, d) {
3843 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3845 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3848 * Portions of this file are based on pieces of Yahoo User Interface Library
3849 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3850 * YUI licensed under the BSD License:
3851 * http://developer.yahoo.net/yui/license.txt
3852 * <script type="text/javascript">
3856 Roo.lib.Motion = function(el, attributes, duration, method) {
3858 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3862 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3866 var superclass = Y.Motion.superclass;
3867 var proto = Y.Motion.prototype;
3869 proto.toString = function() {
3870 var el = this.getEl();
3871 var id = el.id || el.tagName;
3872 return ("Motion " + id);
3875 proto.patterns.points = /^points$/i;
3877 proto.setAttribute = function(attr, val, unit) {
3878 if (this.patterns.points.test(attr)) {
3879 unit = unit || 'px';
3880 superclass.setAttribute.call(this, 'left', val[0], unit);
3881 superclass.setAttribute.call(this, 'top', val[1], unit);
3883 superclass.setAttribute.call(this, attr, val, unit);
3887 proto.getAttribute = function(attr) {
3888 if (this.patterns.points.test(attr)) {
3890 superclass.getAttribute.call(this, 'left'),
3891 superclass.getAttribute.call(this, 'top')
3894 val = superclass.getAttribute.call(this, attr);
3900 proto.doMethod = function(attr, start, end) {
3903 if (this.patterns.points.test(attr)) {
3904 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3905 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3907 val = superclass.doMethod.call(this, attr, start, end);
3912 proto.setRuntimeAttribute = function(attr) {
3913 if (this.patterns.points.test(attr)) {
3914 var el = this.getEl();
3915 var attributes = this.attributes;
3917 var control = attributes['points']['control'] || [];
3921 if (control.length > 0 && !(control[0] instanceof Array)) {
3922 control = [control];
3925 for (i = 0,len = control.length; i < len; ++i) {
3926 tmp[i] = control[i];
3931 Roo.fly(el).position();
3933 if (isset(attributes['points']['from'])) {
3934 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3937 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3940 start = this.getAttribute('points');
3943 if (isset(attributes['points']['to'])) {
3944 end = translateValues.call(this, attributes['points']['to'], start);
3946 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3947 for (i = 0,len = control.length; i < len; ++i) {
3948 control[i] = translateValues.call(this, control[i], start);
3952 } else if (isset(attributes['points']['by'])) {
3953 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3955 for (i = 0,len = control.length; i < len; ++i) {
3956 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3960 this.runtimeAttributes[attr] = [start];
3962 if (control.length > 0) {
3963 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3966 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3969 superclass.setRuntimeAttribute.call(this, attr);
3973 var translateValues = function(val, start) {
3974 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3975 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3980 var isset = function(prop) {
3981 return (typeof prop !== 'undefined');
3985 * Portions of this file are based on pieces of Yahoo User Interface Library
3986 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3987 * YUI licensed under the BSD License:
3988 * http://developer.yahoo.net/yui/license.txt
3989 * <script type="text/javascript">
3993 Roo.lib.Scroll = function(el, attributes, duration, method) {
3995 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3999 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4003 var superclass = Y.Scroll.superclass;
4004 var proto = Y.Scroll.prototype;
4006 proto.toString = function() {
4007 var el = this.getEl();
4008 var id = el.id || el.tagName;
4009 return ("Scroll " + id);
4012 proto.doMethod = function(attr, start, end) {
4015 if (attr == 'scroll') {
4017 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4018 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4022 val = superclass.doMethod.call(this, attr, start, end);
4027 proto.getAttribute = function(attr) {
4029 var el = this.getEl();
4031 if (attr == 'scroll') {
4032 val = [ el.scrollLeft, el.scrollTop ];
4034 val = superclass.getAttribute.call(this, attr);
4040 proto.setAttribute = function(attr, val, unit) {
4041 var el = this.getEl();
4043 if (attr == 'scroll') {
4044 el.scrollLeft = val[0];
4045 el.scrollTop = val[1];
4047 superclass.setAttribute.call(this, attr, val, unit);
4053 * Ext JS Library 1.1.1
4054 * Copyright(c) 2006-2007, Ext JS, LLC.
4056 * Originally Released Under LGPL - original licence link has changed is not relivant.
4059 * <script type="text/javascript">
4063 // nasty IE9 hack - what a pile of crap that is..
4065 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4066 Range.prototype.createContextualFragment = function (html) {
4067 var doc = window.document;
4068 var container = doc.createElement("div");
4069 container.innerHTML = html;
4070 var frag = doc.createDocumentFragment(), n;
4071 while ((n = container.firstChild)) {
4072 frag.appendChild(n);
4079 * @class Roo.DomHelper
4080 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4081 * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4084 Roo.DomHelper = function(){
4085 var tempTableEl = null;
4086 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4087 var tableRe = /^table|tbody|tr|td$/i;
4089 // build as innerHTML where available
4091 var createHtml = function(o){
4092 if(typeof o == 'string'){
4101 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4102 if(attr == "style"){
4104 if(typeof s == "function"){
4107 if(typeof s == "string"){
4108 b += ' style="' + s + '"';
4109 }else if(typeof s == "object"){
4112 if(typeof s[key] != "function"){
4113 b += key + ":" + s[key] + ";";
4120 b += ' class="' + o["cls"] + '"';
4121 }else if(attr == "htmlFor"){
4122 b += ' for="' + o["htmlFor"] + '"';
4124 b += " " + attr + '="' + o[attr] + '"';
4128 if(emptyTags.test(o.tag)){
4132 var cn = o.children || o.cn;
4134 //http://bugs.kde.org/show_bug.cgi?id=71506
4135 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4136 for(var i = 0, len = cn.length; i < len; i++) {
4137 b += createHtml(cn[i], b);
4140 b += createHtml(cn, b);
4146 b += "</" + o.tag + ">";
4153 var createDom = function(o, parentNode){
4155 // defininition craeted..
4157 if (o.ns && o.ns != 'html') {
4159 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4160 xmlns[o.ns] = o.xmlns;
4163 if (typeof(xmlns[o.ns]) == 'undefined') {
4164 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4170 if (typeof(o) == 'string') {
4171 return parentNode.appendChild(document.createTextNode(o));
4173 o.tag = o.tag || div;
4174 if (o.ns && Roo.isIE) {
4176 o.tag = o.ns + ':' + o.tag;
4179 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4180 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4183 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4184 attr == "style" || typeof o[attr] == "function") continue;
4186 if(attr=="cls" && Roo.isIE){
4187 el.className = o["cls"];
4189 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4190 else el[attr] = o[attr];
4193 Roo.DomHelper.applyStyles(el, o.style);
4194 var cn = o.children || o.cn;
4196 //http://bugs.kde.org/show_bug.cgi?id=71506
4197 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4198 for(var i = 0, len = cn.length; i < len; i++) {
4199 createDom(cn[i], el);
4206 el.innerHTML = o.html;
4209 parentNode.appendChild(el);
4214 var ieTable = function(depth, s, h, e){
4215 tempTableEl.innerHTML = [s, h, e].join('');
4216 var i = -1, el = tempTableEl;
4223 // kill repeat to save bytes
4227 tbe = '</tbody>'+te,
4233 * Nasty code for IE's broken table implementation
4235 var insertIntoTable = function(tag, where, el, html){
4237 tempTableEl = document.createElement('div');
4242 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4245 if(where == 'beforebegin'){
4249 before = el.nextSibling;
4252 node = ieTable(4, trs, html, tre);
4254 else if(tag == 'tr'){
4255 if(where == 'beforebegin'){
4258 node = ieTable(3, tbs, html, tbe);
4259 } else if(where == 'afterend'){
4260 before = el.nextSibling;
4262 node = ieTable(3, tbs, html, tbe);
4263 } else{ // INTO a TR
4264 if(where == 'afterbegin'){
4265 before = el.firstChild;
4267 node = ieTable(4, trs, html, tre);
4269 } else if(tag == 'tbody'){
4270 if(where == 'beforebegin'){
4273 node = ieTable(2, ts, html, te);
4274 } else if(where == 'afterend'){
4275 before = el.nextSibling;
4277 node = ieTable(2, ts, html, te);
4279 if(where == 'afterbegin'){
4280 before = el.firstChild;
4282 node = ieTable(3, tbs, html, tbe);
4285 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4288 if(where == 'afterbegin'){
4289 before = el.firstChild;
4291 node = ieTable(2, ts, html, te);
4293 el.insertBefore(node, before);
4298 /** True to force the use of DOM instead of html fragments @type Boolean */
4302 * Returns the markup for the passed Element(s) config
4303 * @param {Object} o The Dom object spec (and children)
4306 markup : function(o){
4307 return createHtml(o);
4311 * Applies a style specification to an element
4312 * @param {String/HTMLElement} el The element to apply styles to
4313 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4314 * a function which returns such a specification.
4316 applyStyles : function(el, styles){
4319 if(typeof styles == "string"){
4320 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4322 while ((matches = re.exec(styles)) != null){
4323 el.setStyle(matches[1], matches[2]);
4325 }else if (typeof styles == "object"){
4326 for (var style in styles){
4327 el.setStyle(style, styles[style]);
4329 }else if (typeof styles == "function"){
4330 Roo.DomHelper.applyStyles(el, styles.call());
4336 * Inserts an HTML fragment into the Dom
4337 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4338 * @param {HTMLElement} el The context element
4339 * @param {String} html The HTML fragmenet
4340 * @return {HTMLElement} The new node
4342 insertHtml : function(where, el, html){
4343 where = where.toLowerCase();
4344 if(el.insertAdjacentHTML){
4345 if(tableRe.test(el.tagName)){
4347 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4353 el.insertAdjacentHTML('BeforeBegin', html);
4354 return el.previousSibling;
4356 el.insertAdjacentHTML('AfterBegin', html);
4357 return el.firstChild;
4359 el.insertAdjacentHTML('BeforeEnd', html);
4360 return el.lastChild;
4362 el.insertAdjacentHTML('AfterEnd', html);
4363 return el.nextSibling;
4365 throw 'Illegal insertion point -> "' + where + '"';
4367 var range = el.ownerDocument.createRange();
4371 range.setStartBefore(el);
4372 frag = range.createContextualFragment(html);
4373 el.parentNode.insertBefore(frag, el);
4374 return el.previousSibling;
4377 range.setStartBefore(el.firstChild);
4378 frag = range.createContextualFragment(html);
4379 el.insertBefore(frag, el.firstChild);
4380 return el.firstChild;
4382 el.innerHTML = html;
4383 return el.firstChild;
4387 range.setStartAfter(el.lastChild);
4388 frag = range.createContextualFragment(html);
4389 el.appendChild(frag);
4390 return el.lastChild;
4392 el.innerHTML = html;
4393 return el.lastChild;
4396 range.setStartAfter(el);
4397 frag = range.createContextualFragment(html);
4398 el.parentNode.insertBefore(frag, el.nextSibling);
4399 return el.nextSibling;
4401 throw 'Illegal insertion point -> "' + where + '"';
4405 * Creates new Dom element(s) and inserts them before el
4406 * @param {String/HTMLElement/Element} el The context element
4407 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4408 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4409 * @return {HTMLElement/Roo.Element} The new node
4411 insertBefore : function(el, o, returnElement){
4412 return this.doInsert(el, o, returnElement, "beforeBegin");
4416 * Creates new Dom element(s) and inserts them after el
4417 * @param {String/HTMLElement/Element} el The context element
4418 * @param {Object} o The Dom object spec (and children)
4419 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4420 * @return {HTMLElement/Roo.Element} The new node
4422 insertAfter : function(el, o, returnElement){
4423 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4427 * Creates new Dom element(s) and inserts them as the first child of el
4428 * @param {String/HTMLElement/Element} el The context element
4429 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4430 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4431 * @return {HTMLElement/Roo.Element} The new node
4433 insertFirst : function(el, o, returnElement){
4434 return this.doInsert(el, o, returnElement, "afterBegin");
4438 doInsert : function(el, o, returnElement, pos, sibling){
4439 el = Roo.getDom(el);
4441 if(this.useDom || o.ns){
4442 newNode = createDom(o, null);
4443 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4445 var html = createHtml(o);
4446 newNode = this.insertHtml(pos, el, html);
4448 return returnElement ? Roo.get(newNode, true) : newNode;
4452 * Creates new Dom element(s) and appends them to el
4453 * @param {String/HTMLElement/Element} el The context element
4454 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4455 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4456 * @return {HTMLElement/Roo.Element} The new node
4458 append : function(el, o, returnElement){
4459 el = Roo.getDom(el);
4461 if(this.useDom || o.ns){
4462 newNode = createDom(o, null);
4463 el.appendChild(newNode);
4465 var html = createHtml(o);
4466 newNode = this.insertHtml("beforeEnd", el, html);
4468 return returnElement ? Roo.get(newNode, true) : newNode;
4472 * Creates new Dom element(s) and overwrites the contents of el with them
4473 * @param {String/HTMLElement/Element} el The context element
4474 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4475 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4476 * @return {HTMLElement/Roo.Element} The new node
4478 overwrite : function(el, o, returnElement){
4479 el = Roo.getDom(el);
4482 while (el.childNodes.length) {
4483 el.removeChild(el.firstChild);
4487 el.innerHTML = createHtml(o);
4490 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4494 * Creates a new Roo.DomHelper.Template from the Dom object spec
4495 * @param {Object} o The Dom object spec (and children)
4496 * @return {Roo.DomHelper.Template} The new template
4498 createTemplate : function(o){
4499 var html = createHtml(o);
4500 return new Roo.Template(html);
4506 * Ext JS Library 1.1.1
4507 * Copyright(c) 2006-2007, Ext JS, LLC.
4509 * Originally Released Under LGPL - original licence link has changed is not relivant.
4512 * <script type="text/javascript">
4516 * @class Roo.Template
4517 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4518 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4521 var t = new Roo.Template({
4522 html : '<div name="{id}">' +
4523 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4525 myformat: function (value, allValues) {
4526 return 'XX' + value;
4529 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4531 * For more information see this blog post with examples: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>.
4533 * @param {Object} cfg - Configuration object.
4535 Roo.Template = function(cfg){
4537 if(cfg instanceof Array){
4539 }else if(arguments.length > 1){
4540 cfg = Array.prototype.join.call(arguments, "");
4544 if (typeof(cfg) == 'object') {
4553 Roo.Template.prototype = {
4556 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4560 * Returns an HTML fragment of this template with the specified values applied.
4561 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4562 * @return {String} The HTML fragment
4564 applyTemplate : function(values){
4568 return this.compiled(values);
4570 var useF = this.disableFormats !== true;
4571 var fm = Roo.util.Format, tpl = this;
4572 var fn = function(m, name, format, args){
4574 if(format.substr(0, 5) == "this."){
4575 return tpl.call(format.substr(5), values[name], values);
4578 // quoted values are required for strings in compiled templates,
4579 // but for non compiled we need to strip them
4580 // quoted reversed for jsmin
4581 var re = /^\s*['"](.*)["']\s*$/;
4582 args = args.split(',');
4583 for(var i = 0, len = args.length; i < len; i++){
4584 args[i] = args[i].replace(re, "$1");
4586 args = [values[name]].concat(args);
4588 args = [values[name]];
4590 return fm[format].apply(fm, args);
4593 return values[name] !== undefined ? values[name] : "";
4596 return this.html.replace(this.re, fn);
4605 * Sets the HTML used as the template and optionally compiles it.
4606 * @param {String} html
4607 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4608 * @return {Roo.Template} this
4610 set : function(html, compile){
4612 this.compiled = null;
4620 * True to disable format functions (defaults to false)
4623 disableFormats : false,
4626 * The regular expression used to match template variables
4630 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4633 * Compiles the template into an internal function, eliminating the RegEx overhead.
4634 * @return {Roo.Template} this
4636 compile : function(){
4637 var fm = Roo.util.Format;
4638 var useF = this.disableFormats !== true;
4639 var sep = Roo.isGecko ? "+" : ",";
4640 var fn = function(m, name, format, args){
4642 args = args ? ',' + args : "";
4643 if(format.substr(0, 5) != "this."){
4644 format = "fm." + format + '(';
4646 format = 'this.call("'+ format.substr(5) + '", ';
4650 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4652 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4655 // branched to use + in gecko and [].join() in others
4657 body = "this.compiled = function(values){ return '" +
4658 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4661 body = ["this.compiled = function(values){ return ['"];
4662 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4663 body.push("'].join('');};");
4664 body = body.join('');
4674 // private function used to call members
4675 call : function(fnName, value, allValues){
4676 return this[fnName](value, allValues);
4680 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4681 * @param {String/HTMLElement/Roo.Element} el The context element
4682 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4683 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4684 * @return {HTMLElement/Roo.Element} The new node or Element
4686 insertFirst: function(el, values, returnElement){
4687 return this.doInsert('afterBegin', el, values, returnElement);
4691 * Applies the supplied values to the template and inserts the new node(s) before el.
4692 * @param {String/HTMLElement/Roo.Element} el The context element
4693 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4694 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4695 * @return {HTMLElement/Roo.Element} The new node or Element
4697 insertBefore: function(el, values, returnElement){
4698 return this.doInsert('beforeBegin', el, values, returnElement);
4702 * Applies the supplied values to the template and inserts the new node(s) after el.
4703 * @param {String/HTMLElement/Roo.Element} el The context element
4704 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4705 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4706 * @return {HTMLElement/Roo.Element} The new node or Element
4708 insertAfter : function(el, values, returnElement){
4709 return this.doInsert('afterEnd', el, values, returnElement);
4713 * Applies the supplied values to the template and appends the new node(s) to el.
4714 * @param {String/HTMLElement/Roo.Element} el The context element
4715 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4716 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4717 * @return {HTMLElement/Roo.Element} The new node or Element
4719 append : function(el, values, returnElement){
4720 return this.doInsert('beforeEnd', el, values, returnElement);
4723 doInsert : function(where, el, values, returnEl){
4724 el = Roo.getDom(el);
4725 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4726 return returnEl ? Roo.get(newNode, true) : newNode;
4730 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4731 * @param {String/HTMLElement/Roo.Element} el The context element
4732 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4733 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4734 * @return {HTMLElement/Roo.Element} The new node or Element
4736 overwrite : function(el, values, returnElement){
4737 el = Roo.getDom(el);
4738 el.innerHTML = this.applyTemplate(values);
4739 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4743 * Alias for {@link #applyTemplate}
4746 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4749 Roo.DomHelper.Template = Roo.Template;
4752 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4753 * @param {String/HTMLElement} el A DOM element or its id
4754 * @returns {Roo.Template} The created template
4757 Roo.Template.from = function(el){
4758 el = Roo.getDom(el);
4759 return new Roo.Template(el.value || el.innerHTML);
4762 * Ext JS Library 1.1.1
4763 * Copyright(c) 2006-2007, Ext JS, LLC.
4765 * Originally Released Under LGPL - original licence link has changed is not relivant.
4768 * <script type="text/javascript">
4773 * This is code is also distributed under MIT license for use
4774 * with jQuery and prototype JavaScript libraries.
4777 * @class Roo.DomQuery
4778 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4780 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4783 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4785 <h4>Element Selectors:</h4>
4787 <li> <b>*</b> any element</li>
4788 <li> <b>E</b> an element with the tag E</li>
4789 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4790 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4791 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4792 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4794 <h4>Attribute Selectors:</h4>
4795 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4797 <li> <b>E[foo]</b> has an attribute "foo"</li>
4798 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4799 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4800 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4801 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4802 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4803 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4805 <h4>Pseudo Classes:</h4>
4807 <li> <b>E:first-child</b> E is the first child of its parent</li>
4808 <li> <b>E:last-child</b> E is the last child of its parent</li>
4809 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4810 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4811 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4812 <li> <b>E:only-child</b> E is the only child of its parent</li>
4813 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4814 <li> <b>E:first</b> the first E in the resultset</li>
4815 <li> <b>E:last</b> the last E in the resultset</li>
4816 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4817 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4818 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4819 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4820 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4821 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4822 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4823 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4824 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4826 <h4>CSS Value Selectors:</h4>
4828 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4829 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4830 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4831 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4832 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4833 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4837 Roo.DomQuery = function(){
4838 var cache = {}, simpleCache = {}, valueCache = {};
4839 var nonSpace = /\S/;
4840 var trimRe = /^\s+|\s+$/g;
4841 var tplRe = /\{(\d+)\}/g;
4842 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4843 var tagTokenRe = /^(#)?([\w-\*]+)/;
4844 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4846 function child(p, index){
4848 var n = p.firstChild;
4850 if(n.nodeType == 1){
4861 while((n = n.nextSibling) && n.nodeType != 1);
4866 while((n = n.previousSibling) && n.nodeType != 1);
4870 function children(d){
4871 var n = d.firstChild, ni = -1;
4873 var nx = n.nextSibling;
4874 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4884 function byClassName(c, a, v){
4888 var r = [], ri = -1, cn;
4889 for(var i = 0, ci; ci = c[i]; i++){
4890 if((' '+ci.className+' ').indexOf(v) != -1){
4897 function attrValue(n, attr){
4898 if(!n.tagName && typeof n.length != "undefined"){
4907 if(attr == "class" || attr == "className"){
4910 return n.getAttribute(attr) || n[attr];
4914 function getNodes(ns, mode, tagName){
4915 var result = [], ri = -1, cs;
4919 tagName = tagName || "*";
4920 if(typeof ns.getElementsByTagName != "undefined"){
4924 for(var i = 0, ni; ni = ns[i]; i++){
4925 cs = ni.getElementsByTagName(tagName);
4926 for(var j = 0, ci; ci = cs[j]; j++){
4930 }else if(mode == "/" || mode == ">"){
4931 var utag = tagName.toUpperCase();
4932 for(var i = 0, ni, cn; ni = ns[i]; i++){
4933 cn = ni.children || ni.childNodes;
4934 for(var j = 0, cj; cj = cn[j]; j++){
4935 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4940 }else if(mode == "+"){
4941 var utag = tagName.toUpperCase();
4942 for(var i = 0, n; n = ns[i]; i++){
4943 while((n = n.nextSibling) && n.nodeType != 1);
4944 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4948 }else if(mode == "~"){
4949 for(var i = 0, n; n = ns[i]; i++){
4950 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4959 function concat(a, b){
4963 for(var i = 0, l = b.length; i < l; i++){
4969 function byTag(cs, tagName){
4970 if(cs.tagName || cs == document){
4976 var r = [], ri = -1;
4977 tagName = tagName.toLowerCase();
4978 for(var i = 0, ci; ci = cs[i]; i++){
4979 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4986 function byId(cs, attr, id){
4987 if(cs.tagName || cs == document){
4993 var r = [], ri = -1;
4994 for(var i = 0,ci; ci = cs[i]; i++){
4995 if(ci && ci.id == id){
5003 function byAttribute(cs, attr, value, op, custom){
5004 var r = [], ri = -1, st = custom=="{";
5005 var f = Roo.DomQuery.operators[op];
5006 for(var i = 0, ci; ci = cs[i]; i++){
5009 a = Roo.DomQuery.getStyle(ci, attr);
5011 else if(attr == "class" || attr == "className"){
5013 }else if(attr == "for"){
5015 }else if(attr == "href"){
5016 a = ci.getAttribute("href", 2);
5018 a = ci.getAttribute(attr);
5020 if((f && f(a, value)) || (!f && a)){
5027 function byPseudo(cs, name, value){
5028 return Roo.DomQuery.pseudos[name](cs, value);
5031 // This is for IE MSXML which does not support expandos.
5032 // IE runs the same speed using setAttribute, however FF slows way down
5033 // and Safari completely fails so they need to continue to use expandos.
5034 var isIE = window.ActiveXObject ? true : false;
5036 // this eval is stop the compressor from
5037 // renaming the variable to something shorter
5039 /** eval:var:batch */
5044 function nodupIEXml(cs){
5046 cs[0].setAttribute("_nodup", d);
5048 for(var i = 1, len = cs.length; i < len; i++){
5050 if(!c.getAttribute("_nodup") != d){
5051 c.setAttribute("_nodup", d);
5055 for(var i = 0, len = cs.length; i < len; i++){
5056 cs[i].removeAttribute("_nodup");
5065 var len = cs.length, c, i, r = cs, cj, ri = -1;
5066 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5069 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5070 return nodupIEXml(cs);
5074 for(i = 1; c = cs[i]; i++){
5079 for(var j = 0; j < i; j++){
5082 for(j = i+1; cj = cs[j]; j++){
5094 function quickDiffIEXml(c1, c2){
5096 for(var i = 0, len = c1.length; i < len; i++){
5097 c1[i].setAttribute("_qdiff", d);
5100 for(var i = 0, len = c2.length; i < len; i++){
5101 if(c2[i].getAttribute("_qdiff") != d){
5102 r[r.length] = c2[i];
5105 for(var i = 0, len = c1.length; i < len; i++){
5106 c1[i].removeAttribute("_qdiff");
5111 function quickDiff(c1, c2){
5112 var len1 = c1.length;
5116 if(isIE && c1[0].selectSingleNode){
5117 return quickDiffIEXml(c1, c2);
5120 for(var i = 0; i < len1; i++){
5124 for(var i = 0, len = c2.length; i < len; i++){
5125 if(c2[i]._qdiff != d){
5126 r[r.length] = c2[i];
5132 function quickId(ns, mode, root, id){
5134 var d = root.ownerDocument || root;
5135 return d.getElementById(id);
5137 ns = getNodes(ns, mode, "*");
5138 return byId(ns, null, id);
5142 getStyle : function(el, name){
5143 return Roo.fly(el).getStyle(name);
5146 * Compiles a selector/xpath query into a reusable function. The returned function
5147 * takes one parameter "root" (optional), which is the context node from where the query should start.
5148 * @param {String} selector The selector/xpath query
5149 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5150 * @return {Function}
5152 compile : function(path, type){
5153 type = type || "select";
5155 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5156 var q = path, mode, lq;
5157 var tk = Roo.DomQuery.matchers;
5158 var tklen = tk.length;
5161 // accept leading mode switch
5162 var lmode = q.match(modeRe);
5163 if(lmode && lmode[1]){
5164 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5165 q = q.replace(lmode[1], "");
5167 // strip leading slashes
5168 while(path.substr(0, 1)=="/"){
5169 path = path.substr(1);
5172 while(q && lq != q){
5174 var tm = q.match(tagTokenRe);
5175 if(type == "select"){
5178 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5180 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5182 q = q.replace(tm[0], "");
5183 }else if(q.substr(0, 1) != '@'){
5184 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5189 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5191 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5193 q = q.replace(tm[0], "");
5196 while(!(mm = q.match(modeRe))){
5197 var matched = false;
5198 for(var j = 0; j < tklen; j++){
5200 var m = q.match(t.re);
5202 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5205 q = q.replace(m[0], "");
5210 // prevent infinite loop on bad selector
5212 throw 'Error parsing selector, parsing failed at "' + q + '"';
5216 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5217 q = q.replace(mm[1], "");
5220 fn[fn.length] = "return nodup(n);\n}";
5223 * list of variables that need from compression as they are used by eval.
5233 * eval:var:byClassName
5235 * eval:var:byAttribute
5236 * eval:var:attrValue
5244 * Selects a group of elements.
5245 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5246 * @param {Node} root (optional) The start of the query (defaults to document).
5249 select : function(path, root, type){
5250 if(!root || root == document){
5253 if(typeof root == "string"){
5254 root = document.getElementById(root);
5256 var paths = path.split(",");
5258 for(var i = 0, len = paths.length; i < len; i++){
5259 var p = paths[i].replace(trimRe, "");
5261 cache[p] = Roo.DomQuery.compile(p);
5263 throw p + " is not a valid selector";
5266 var result = cache[p](root);
5267 if(result && result != document){
5268 results = results.concat(result);
5271 if(paths.length > 1){
5272 return nodup(results);
5278 * Selects a single element.
5279 * @param {String} selector The selector/xpath query
5280 * @param {Node} root (optional) The start of the query (defaults to document).
5283 selectNode : function(path, root){
5284 return Roo.DomQuery.select(path, root)[0];
5288 * Selects the value of a node, optionally replacing null with the defaultValue.
5289 * @param {String} selector The selector/xpath query
5290 * @param {Node} root (optional) The start of the query (defaults to document).
5291 * @param {String} defaultValue
5293 selectValue : function(path, root, defaultValue){
5294 path = path.replace(trimRe, "");
5295 if(!valueCache[path]){
5296 valueCache[path] = Roo.DomQuery.compile(path, "select");
5298 var n = valueCache[path](root);
5299 n = n[0] ? n[0] : n;
5300 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5301 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5305 * Selects the value of a node, parsing integers and floats.
5306 * @param {String} selector The selector/xpath query
5307 * @param {Node} root (optional) The start of the query (defaults to document).
5308 * @param {Number} defaultValue
5311 selectNumber : function(path, root, defaultValue){
5312 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5313 return parseFloat(v);
5317 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5318 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5319 * @param {String} selector The simple selector to test
5322 is : function(el, ss){
5323 if(typeof el == "string"){
5324 el = document.getElementById(el);
5326 var isArray = (el instanceof Array);
5327 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5328 return isArray ? (result.length == el.length) : (result.length > 0);
5332 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5333 * @param {Array} el An array of elements to filter
5334 * @param {String} selector The simple selector to test
5335 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5336 * the selector instead of the ones that match
5339 filter : function(els, ss, nonMatches){
5340 ss = ss.replace(trimRe, "");
5341 if(!simpleCache[ss]){
5342 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5344 var result = simpleCache[ss](els);
5345 return nonMatches ? quickDiff(result, els) : result;
5349 * Collection of matching regular expressions and code snippets.
5353 select: 'n = byClassName(n, null, " {1} ");'
5355 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5356 select: 'n = byPseudo(n, "{1}", "{2}");'
5358 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5359 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5362 select: 'n = byId(n, null, "{1}");'
5365 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5370 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5371 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5374 "=" : function(a, v){
5377 "!=" : function(a, v){
5380 "^=" : function(a, v){
5381 return a && a.substr(0, v.length) == v;
5383 "$=" : function(a, v){
5384 return a && a.substr(a.length-v.length) == v;
5386 "*=" : function(a, v){
5387 return a && a.indexOf(v) !== -1;
5389 "%=" : function(a, v){
5390 return (a % v) == 0;
5392 "|=" : function(a, v){
5393 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5395 "~=" : function(a, v){
5396 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5401 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5402 * and the argument (if any) supplied in the selector.
5405 "first-child" : function(c){
5406 var r = [], ri = -1, n;
5407 for(var i = 0, ci; ci = n = c[i]; i++){
5408 while((n = n.previousSibling) && n.nodeType != 1);
5416 "last-child" : function(c){
5417 var r = [], ri = -1, n;
5418 for(var i = 0, ci; ci = n = c[i]; i++){
5419 while((n = n.nextSibling) && n.nodeType != 1);
5427 "nth-child" : function(c, a) {
5428 var r = [], ri = -1;
5429 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5430 var f = (m[1] || 1) - 0, l = m[2] - 0;
5431 for(var i = 0, n; n = c[i]; i++){
5432 var pn = n.parentNode;
5433 if (batch != pn._batch) {
5435 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5436 if(cn.nodeType == 1){
5443 if (l == 0 || n.nodeIndex == l){
5446 } else if ((n.nodeIndex + l) % f == 0){
5454 "only-child" : function(c){
5455 var r = [], ri = -1;;
5456 for(var i = 0, ci; ci = c[i]; i++){
5457 if(!prev(ci) && !next(ci)){
5464 "empty" : function(c){
5465 var r = [], ri = -1;
5466 for(var i = 0, ci; ci = c[i]; i++){
5467 var cns = ci.childNodes, j = 0, cn, empty = true;
5470 if(cn.nodeType == 1 || cn.nodeType == 3){
5482 "contains" : function(c, v){
5483 var r = [], ri = -1;
5484 for(var i = 0, ci; ci = c[i]; i++){
5485 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5492 "nodeValue" : function(c, v){
5493 var r = [], ri = -1;
5494 for(var i = 0, ci; ci = c[i]; i++){
5495 if(ci.firstChild && ci.firstChild.nodeValue == v){
5502 "checked" : function(c){
5503 var r = [], ri = -1;
5504 for(var i = 0, ci; ci = c[i]; i++){
5505 if(ci.checked == true){
5512 "not" : function(c, ss){
5513 return Roo.DomQuery.filter(c, ss, true);
5516 "odd" : function(c){
5517 return this["nth-child"](c, "odd");
5520 "even" : function(c){
5521 return this["nth-child"](c, "even");
5524 "nth" : function(c, a){
5525 return c[a-1] || [];
5528 "first" : function(c){
5532 "last" : function(c){
5533 return c[c.length-1] || [];
5536 "has" : function(c, ss){
5537 var s = Roo.DomQuery.select;
5538 var r = [], ri = -1;
5539 for(var i = 0, ci; ci = c[i]; i++){
5540 if(s(ss, ci).length > 0){
5547 "next" : function(c, ss){
5548 var is = Roo.DomQuery.is;
5549 var r = [], ri = -1;
5550 for(var i = 0, ci; ci = c[i]; i++){
5559 "prev" : function(c, ss){
5560 var is = Roo.DomQuery.is;
5561 var r = [], ri = -1;
5562 for(var i = 0, ci; ci = c[i]; i++){
5575 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5576 * @param {String} path The selector/xpath query
5577 * @param {Node} root (optional) The start of the query (defaults to document).
5582 Roo.query = Roo.DomQuery.select;
5585 * Ext JS Library 1.1.1
5586 * Copyright(c) 2006-2007, Ext JS, LLC.
5588 * Originally Released Under LGPL - original licence link has changed is not relivant.
5591 * <script type="text/javascript">
5595 * @class Roo.util.Observable
5596 * Base class that provides a common interface for publishing events. Subclasses are expected to
5597 * to have a property "events" with all the events defined.<br>
5600 Employee = function(name){
5607 Roo.extend(Employee, Roo.util.Observable);
5609 * @param {Object} config properties to use (incuding events / listeners)
5612 Roo.util.Observable = function(cfg){
5615 this.addEvents(cfg.events || {});
5617 delete cfg.events; // make sure
5620 Roo.apply(this, cfg);
5623 this.on(this.listeners);
5624 delete this.listeners;
5627 Roo.util.Observable.prototype = {
5629 * @cfg {Object} listeners list of events and functions to call for this object,
5633 'click' : function(e) {
5643 * Fires the specified event with the passed parameters (minus the event name).
5644 * @param {String} eventName
5645 * @param {Object...} args Variable number of parameters are passed to handlers
5646 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5648 fireEvent : function(){
5649 var ce = this.events[arguments[0].toLowerCase()];
5650 if(typeof ce == "object"){
5651 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5658 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5661 * Appends an event handler to this component
5662 * @param {String} eventName The type of event to listen for
5663 * @param {Function} handler The method the event invokes
5664 * @param {Object} scope (optional) The scope in which to execute the handler
5665 * function. The handler function's "this" context.
5666 * @param {Object} options (optional) An object containing handler configuration
5667 * properties. This may contain any of the following properties:<ul>
5668 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5669 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5670 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5671 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5672 * by the specified number of milliseconds. If the event fires again within that time, the original
5673 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5676 * <b>Combining Options</b><br>
5677 * Using the options argument, it is possible to combine different types of listeners:<br>
5679 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5681 el.on('click', this.onClick, this, {
5688 * <b>Attaching multiple handlers in 1 call</b><br>
5689 * The method also allows for a single argument to be passed which is a config object containing properties
5690 * which specify multiple handlers.
5699 fn: this.onMouseOver,
5703 fn: this.onMouseOut,
5709 * Or a shorthand syntax which passes the same scope object to all handlers:
5712 'click': this.onClick,
5713 'mouseover': this.onMouseOver,
5714 'mouseout': this.onMouseOut,
5719 addListener : function(eventName, fn, scope, o){
5720 if(typeof eventName == "object"){
5723 if(this.filterOptRe.test(e)){
5726 if(typeof o[e] == "function"){
5728 this.addListener(e, o[e], o.scope, o);
5730 // individual options
5731 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5736 o = (!o || typeof o == "boolean") ? {} : o;
5737 eventName = eventName.toLowerCase();
5738 var ce = this.events[eventName] || true;
5739 if(typeof ce == "boolean"){
5740 ce = new Roo.util.Event(this, eventName);
5741 this.events[eventName] = ce;
5743 ce.addListener(fn, scope, o);
5747 * Removes a listener
5748 * @param {String} eventName The type of event to listen for
5749 * @param {Function} handler The handler to remove
5750 * @param {Object} scope (optional) The scope (this object) for the handler
5752 removeListener : function(eventName, fn, scope){
5753 var ce = this.events[eventName.toLowerCase()];
5754 if(typeof ce == "object"){
5755 ce.removeListener(fn, scope);
5760 * Removes all listeners for this object
5762 purgeListeners : function(){
5763 for(var evt in this.events){
5764 if(typeof this.events[evt] == "object"){
5765 this.events[evt].clearListeners();
5770 relayEvents : function(o, events){
5771 var createHandler = function(ename){
5773 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5776 for(var i = 0, len = events.length; i < len; i++){
5777 var ename = events[i];
5778 if(!this.events[ename]){ this.events[ename] = true; };
5779 o.on(ename, createHandler(ename), this);
5784 * Used to define events on this Observable
5785 * @param {Object} object The object with the events defined
5787 addEvents : function(o){
5791 Roo.applyIf(this.events, o);
5795 * Checks to see if this object has any listeners for a specified event
5796 * @param {String} eventName The name of the event to check for
5797 * @return {Boolean} True if the event is being listened for, else false
5799 hasListener : function(eventName){
5800 var e = this.events[eventName];
5801 return typeof e == "object" && e.listeners.length > 0;
5805 * Appends an event handler to this element (shorthand for addListener)
5806 * @param {String} eventName The type of event to listen for
5807 * @param {Function} handler The method the event invokes
5808 * @param {Object} scope (optional) The scope in which to execute the handler
5809 * function. The handler function's "this" context.
5810 * @param {Object} options (optional)
5813 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5815 * Removes a listener (shorthand for removeListener)
5816 * @param {String} eventName The type of event to listen for
5817 * @param {Function} handler The handler to remove
5818 * @param {Object} scope (optional) The scope (this object) for the handler
5821 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5824 * Starts capture on the specified Observable. All events will be passed
5825 * to the supplied function with the event name + standard signature of the event
5826 * <b>before</b> the event is fired. If the supplied function returns false,
5827 * the event will not fire.
5828 * @param {Observable} o The Observable to capture
5829 * @param {Function} fn The function to call
5830 * @param {Object} scope (optional) The scope (this object) for the fn
5833 Roo.util.Observable.capture = function(o, fn, scope){
5834 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5838 * Removes <b>all</b> added captures from the Observable.
5839 * @param {Observable} o The Observable to release
5842 Roo.util.Observable.releaseCapture = function(o){
5843 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5848 var createBuffered = function(h, o, scope){
5849 var task = new Roo.util.DelayedTask();
5851 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5855 var createSingle = function(h, e, fn, scope){
5857 e.removeListener(fn, scope);
5858 return h.apply(scope, arguments);
5862 var createDelayed = function(h, o, scope){
5864 var args = Array.prototype.slice.call(arguments, 0);
5865 setTimeout(function(){
5866 h.apply(scope, args);
5871 Roo.util.Event = function(obj, name){
5874 this.listeners = [];
5877 Roo.util.Event.prototype = {
5878 addListener : function(fn, scope, options){
5879 var o = options || {};
5880 scope = scope || this.obj;
5881 if(!this.isListening(fn, scope)){
5882 var l = {fn: fn, scope: scope, options: o};
5885 h = createDelayed(h, o, scope);
5888 h = createSingle(h, this, fn, scope);
5891 h = createBuffered(h, o, scope);
5894 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5895 this.listeners.push(l);
5897 this.listeners = this.listeners.slice(0);
5898 this.listeners.push(l);
5903 findListener : function(fn, scope){
5904 scope = scope || this.obj;
5905 var ls = this.listeners;
5906 for(var i = 0, len = ls.length; i < len; i++){
5908 if(l.fn == fn && l.scope == scope){
5915 isListening : function(fn, scope){
5916 return this.findListener(fn, scope) != -1;
5919 removeListener : function(fn, scope){
5921 if((index = this.findListener(fn, scope)) != -1){
5923 this.listeners.splice(index, 1);
5925 this.listeners = this.listeners.slice(0);
5926 this.listeners.splice(index, 1);
5933 clearListeners : function(){
5934 this.listeners = [];
5938 var ls = this.listeners, scope, len = ls.length;
5941 var args = Array.prototype.slice.call(arguments, 0);
5942 for(var i = 0; i < len; i++){
5944 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5945 this.firing = false;
5949 this.firing = false;
5956 * Ext JS Library 1.1.1
5957 * Copyright(c) 2006-2007, Ext JS, LLC.
5959 * Originally Released Under LGPL - original licence link has changed is not relivant.
5962 * <script type="text/javascript">
5966 * @class Roo.EventManager
5967 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5968 * several useful events directly.
5969 * See {@link Roo.EventObject} for more details on normalized event objects.
5972 Roo.EventManager = function(){
5973 var docReadyEvent, docReadyProcId, docReadyState = false;
5974 var resizeEvent, resizeTask, textEvent, textSize;
5975 var E = Roo.lib.Event;
5976 var D = Roo.lib.Dom;
5979 var fireDocReady = function(){
5981 docReadyState = true;
5984 clearInterval(docReadyProcId);
5986 if(Roo.isGecko || Roo.isOpera) {
5987 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5990 var defer = document.getElementById("ie-deferred-loader");
5992 defer.onreadystatechange = null;
5993 defer.parentNode.removeChild(defer);
5997 docReadyEvent.fire();
5998 docReadyEvent.clearListeners();
6003 var initDocReady = function(){
6004 docReadyEvent = new Roo.util.Event();
6005 if(Roo.isGecko || Roo.isOpera) {
6006 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6008 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6009 var defer = document.getElementById("ie-deferred-loader");
6010 defer.onreadystatechange = function(){
6011 if(this.readyState == "complete"){
6015 }else if(Roo.isSafari){
6016 docReadyProcId = setInterval(function(){
6017 var rs = document.readyState;
6018 if(rs == "complete") {
6023 // no matter what, make sure it fires on load
6024 E.on(window, "load", fireDocReady);
6027 var createBuffered = function(h, o){
6028 var task = new Roo.util.DelayedTask(h);
6030 // create new event object impl so new events don't wipe out properties
6031 e = new Roo.EventObjectImpl(e);
6032 task.delay(o.buffer, h, null, [e]);
6036 var createSingle = function(h, el, ename, fn){
6038 Roo.EventManager.removeListener(el, ename, fn);
6043 var createDelayed = function(h, o){
6045 // create new event object impl so new events don't wipe out properties
6046 e = new Roo.EventObjectImpl(e);
6047 setTimeout(function(){
6053 var listen = function(element, ename, opt, fn, scope){
6054 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6055 fn = fn || o.fn; scope = scope || o.scope;
6056 var el = Roo.getDom(element);
6058 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6060 var h = function(e){
6061 e = Roo.EventObject.setEvent(e);
6064 t = e.getTarget(o.delegate, el);
6071 if(o.stopEvent === true){
6074 if(o.preventDefault === true){
6077 if(o.stopPropagation === true){
6078 e.stopPropagation();
6081 if(o.normalized === false){
6085 fn.call(scope || el, e, t, o);
6088 h = createDelayed(h, o);
6091 h = createSingle(h, el, ename, fn);
6094 h = createBuffered(h, o);
6096 fn._handlers = fn._handlers || [];
6097 fn._handlers.push([Roo.id(el), ename, h]);
6100 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6101 el.addEventListener("DOMMouseScroll", h, false);
6102 E.on(window, 'unload', function(){
6103 el.removeEventListener("DOMMouseScroll", h, false);
6106 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6107 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6112 var stopListening = function(el, ename, fn){
6113 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6115 for(var i = 0, len = hds.length; i < len; i++){
6117 if(h[0] == id && h[1] == ename){
6124 E.un(el, ename, hd);
6125 el = Roo.getDom(el);
6126 if(ename == "mousewheel" && el.addEventListener){
6127 el.removeEventListener("DOMMouseScroll", hd, false);
6129 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6130 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6134 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6141 * @scope Roo.EventManager
6146 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6147 * object with a Roo.EventObject
6148 * @param {Function} fn The method the event invokes
6149 * @param {Object} scope An object that becomes the scope of the handler
6150 * @param {boolean} override If true, the obj passed in becomes
6151 * the execution scope of the listener
6152 * @return {Function} The wrapped function
6155 wrap : function(fn, scope, override){
6157 Roo.EventObject.setEvent(e);
6158 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6163 * Appends an event handler to an element (shorthand for addListener)
6164 * @param {String/HTMLElement} element The html element or id to assign the
6165 * @param {String} eventName The type of event to listen for
6166 * @param {Function} handler The method the event invokes
6167 * @param {Object} scope (optional) The scope in which to execute the handler
6168 * function. The handler function's "this" context.
6169 * @param {Object} options (optional) An object containing handler configuration
6170 * properties. This may contain any of the following properties:<ul>
6171 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6172 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6173 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6174 * <li>preventDefault {Boolean} True to prevent the default action</li>
6175 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6176 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6177 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6178 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6179 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6180 * by the specified number of milliseconds. If the event fires again within that time, the original
6181 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6184 * <b>Combining Options</b><br>
6185 * Using the options argument, it is possible to combine different types of listeners:<br>
6187 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6189 el.on('click', this.onClick, this, {
6196 * <b>Attaching multiple handlers in 1 call</b><br>
6197 * The method also allows for a single argument to be passed which is a config object containing properties
6198 * which specify multiple handlers.
6208 fn: this.onMouseOver
6217 * Or a shorthand syntax:<br>
6220 'click' : this.onClick,
6221 'mouseover' : this.onMouseOver,
6222 'mouseout' : this.onMouseOut
6226 addListener : function(element, eventName, fn, scope, options){
6227 if(typeof eventName == "object"){
6233 if(typeof o[e] == "function"){
6235 listen(element, e, o, o[e], o.scope);
6237 // individual options
6238 listen(element, e, o[e]);
6243 return listen(element, eventName, options, fn, scope);
6247 * Removes an event handler
6249 * @param {String/HTMLElement} element The id or html element to remove the
6251 * @param {String} eventName The type of event
6252 * @param {Function} fn
6253 * @return {Boolean} True if a listener was actually removed
6255 removeListener : function(element, eventName, fn){
6256 return stopListening(element, eventName, fn);
6260 * Fires when the document is ready (before onload and before images are loaded). Can be
6261 * accessed shorthanded Roo.onReady().
6262 * @param {Function} fn The method the event invokes
6263 * @param {Object} scope An object that becomes the scope of the handler
6264 * @param {boolean} options
6266 onDocumentReady : function(fn, scope, options){
6267 if(docReadyState){ // if it already fired
6268 docReadyEvent.addListener(fn, scope, options);
6269 docReadyEvent.fire();
6270 docReadyEvent.clearListeners();
6276 docReadyEvent.addListener(fn, scope, options);
6280 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6281 * @param {Function} fn The method the event invokes
6282 * @param {Object} scope An object that becomes the scope of the handler
6283 * @param {boolean} options
6285 onWindowResize : function(fn, scope, options){
6287 resizeEvent = new Roo.util.Event();
6288 resizeTask = new Roo.util.DelayedTask(function(){
6289 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6291 E.on(window, "resize", function(){
6293 resizeTask.delay(50);
6295 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6299 resizeEvent.addListener(fn, scope, options);
6303 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6304 * @param {Function} fn The method the event invokes
6305 * @param {Object} scope An object that becomes the scope of the handler
6306 * @param {boolean} options
6308 onTextResize : function(fn, scope, options){
6310 textEvent = new Roo.util.Event();
6311 var textEl = new Roo.Element(document.createElement('div'));
6312 textEl.dom.className = 'x-text-resize';
6313 textEl.dom.innerHTML = 'X';
6314 textEl.appendTo(document.body);
6315 textSize = textEl.dom.offsetHeight;
6316 setInterval(function(){
6317 if(textEl.dom.offsetHeight != textSize){
6318 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6320 }, this.textResizeInterval);
6322 textEvent.addListener(fn, scope, options);
6326 * Removes the passed window resize listener.
6327 * @param {Function} fn The method the event invokes
6328 * @param {Object} scope The scope of handler
6330 removeResizeListener : function(fn, scope){
6332 resizeEvent.removeListener(fn, scope);
6337 fireResize : function(){
6339 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6343 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6347 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6349 textResizeInterval : 50
6354 * @scopeAlias pub=Roo.EventManager
6358 * Appends an event handler to an element (shorthand for addListener)
6359 * @param {String/HTMLElement} element The html element or id to assign the
6360 * @param {String} eventName The type of event to listen for
6361 * @param {Function} handler The method the event invokes
6362 * @param {Object} scope (optional) The scope in which to execute the handler
6363 * function. The handler function's "this" context.
6364 * @param {Object} options (optional) An object containing handler configuration
6365 * properties. This may contain any of the following properties:<ul>
6366 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6367 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6368 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6369 * <li>preventDefault {Boolean} True to prevent the default action</li>
6370 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6371 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6372 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6373 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6374 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6375 * by the specified number of milliseconds. If the event fires again within that time, the original
6376 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6379 * <b>Combining Options</b><br>
6380 * Using the options argument, it is possible to combine different types of listeners:<br>
6382 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6384 el.on('click', this.onClick, this, {
6391 * <b>Attaching multiple handlers in 1 call</b><br>
6392 * The method also allows for a single argument to be passed which is a config object containing properties
6393 * which specify multiple handlers.
6403 fn: this.onMouseOver
6412 * Or a shorthand syntax:<br>
6415 'click' : this.onClick,
6416 'mouseover' : this.onMouseOver,
6417 'mouseout' : this.onMouseOut
6421 pub.on = pub.addListener;
6422 pub.un = pub.removeListener;
6424 pub.stoppedMouseDownEvent = new Roo.util.Event();
6428 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6429 * @param {Function} fn The method the event invokes
6430 * @param {Object} scope An object that becomes the scope of the handler
6431 * @param {boolean} override If true, the obj passed in becomes
6432 * the execution scope of the listener
6436 Roo.onReady = Roo.EventManager.onDocumentReady;
6438 Roo.onReady(function(){
6439 var bd = Roo.get(document.body);
6444 : Roo.isGecko ? "roo-gecko"
6445 : Roo.isOpera ? "roo-opera"
6446 : Roo.isSafari ? "roo-safari" : ""];
6449 cls.push("roo-mac");
6452 cls.push("roo-linux");
6454 if(Roo.isBorderBox){
6455 cls.push('roo-border-box');
6457 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6458 var p = bd.dom.parentNode;
6460 p.className += ' roo-strict';
6463 bd.addClass(cls.join(' '));
6467 * @class Roo.EventObject
6468 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6469 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6472 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6474 var target = e.getTarget();
6477 var myDiv = Roo.get("myDiv");
6478 myDiv.on("click", handleClick);
6480 Roo.EventManager.on("myDiv", 'click', handleClick);
6481 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6485 Roo.EventObject = function(){
6487 var E = Roo.lib.Event;
6489 // safari keypress events for special keys return bad keycodes
6492 63235 : 39, // right
6495 63276 : 33, // page up
6496 63277 : 34, // page down
6497 63272 : 46, // delete
6502 // normalize button clicks
6503 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6504 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6506 Roo.EventObjectImpl = function(e){
6508 this.setEvent(e.browserEvent || e);
6511 Roo.EventObjectImpl.prototype = {
6513 * Used to fix doc tools.
6514 * @scope Roo.EventObject.prototype
6520 /** The normal browser event */
6521 browserEvent : null,
6522 /** The button pressed in a mouse event */
6524 /** True if the shift key was down during the event */
6526 /** True if the control key was down during the event */
6528 /** True if the alt key was down during the event */
6587 setEvent : function(e){
6588 if(e == this || (e && e.browserEvent)){ // already wrapped
6591 this.browserEvent = e;
6593 // normalize buttons
6594 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6595 if(e.type == 'click' && this.button == -1){
6599 this.shiftKey = e.shiftKey;
6600 // mac metaKey behaves like ctrlKey
6601 this.ctrlKey = e.ctrlKey || e.metaKey;
6602 this.altKey = e.altKey;
6603 // in getKey these will be normalized for the mac
6604 this.keyCode = e.keyCode;
6605 // keyup warnings on firefox.
6606 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6607 // cache the target for the delayed and or buffered events
6608 this.target = E.getTarget(e);
6610 this.xy = E.getXY(e);
6613 this.shiftKey = false;
6614 this.ctrlKey = false;
6615 this.altKey = false;
6625 * Stop the event (preventDefault and stopPropagation)
6627 stopEvent : function(){
6628 if(this.browserEvent){
6629 if(this.browserEvent.type == 'mousedown'){
6630 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6632 E.stopEvent(this.browserEvent);
6637 * Prevents the browsers default handling of the event.
6639 preventDefault : function(){
6640 if(this.browserEvent){
6641 E.preventDefault(this.browserEvent);
6646 isNavKeyPress : function(){
6647 var k = this.keyCode;
6648 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6649 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6652 isSpecialKey : function(){
6653 var k = this.keyCode;
6654 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6655 (k == 16) || (k == 17) ||
6656 (k >= 18 && k <= 20) ||
6657 (k >= 33 && k <= 35) ||
6658 (k >= 36 && k <= 39) ||
6659 (k >= 44 && k <= 45);
6662 * Cancels bubbling of the event.
6664 stopPropagation : function(){
6665 if(this.browserEvent){
6666 if(this.type == 'mousedown'){
6667 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6669 E.stopPropagation(this.browserEvent);
6674 * Gets the key code for the event.
6677 getCharCode : function(){
6678 return this.charCode || this.keyCode;
6682 * Returns a normalized keyCode for the event.
6683 * @return {Number} The key code
6685 getKey : function(){
6686 var k = this.keyCode || this.charCode;
6687 return Roo.isSafari ? (safariKeys[k] || k) : k;
6691 * Gets the x coordinate of the event.
6694 getPageX : function(){
6699 * Gets the y coordinate of the event.
6702 getPageY : function(){
6707 * Gets the time of the event.
6710 getTime : function(){
6711 if(this.browserEvent){
6712 return E.getTime(this.browserEvent);
6718 * Gets the page coordinates of the event.
6719 * @return {Array} The xy values like [x, y]
6726 * Gets the target for the event.
6727 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6728 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6729 search as a number or element (defaults to 10 || document.body)
6730 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6731 * @return {HTMLelement}
6733 getTarget : function(selector, maxDepth, returnEl){
6734 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6737 * Gets the related target.
6738 * @return {HTMLElement}
6740 getRelatedTarget : function(){
6741 if(this.browserEvent){
6742 return E.getRelatedTarget(this.browserEvent);
6748 * Normalizes mouse wheel delta across browsers
6749 * @return {Number} The delta
6751 getWheelDelta : function(){
6752 var e = this.browserEvent;
6754 if(e.wheelDelta){ /* IE/Opera. */
6755 delta = e.wheelDelta/120;
6756 }else if(e.detail){ /* Mozilla case. */
6757 delta = -e.detail/3;
6763 * Returns true if the control, meta, shift or alt key was pressed during this event.
6766 hasModifier : function(){
6767 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6771 * Returns true if the target of this event equals el or is a child of el
6772 * @param {String/HTMLElement/Element} el
6773 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6776 within : function(el, related){
6777 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6778 return t && Roo.fly(el).contains(t);
6781 getPoint : function(){
6782 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6786 return new Roo.EventObjectImpl();
6791 * Ext JS Library 1.1.1
6792 * Copyright(c) 2006-2007, Ext JS, LLC.
6794 * Originally Released Under LGPL - original licence link has changed is not relivant.
6797 * <script type="text/javascript">
6801 // was in Composite Element!??!?!
6804 var D = Roo.lib.Dom;
6805 var E = Roo.lib.Event;
6806 var A = Roo.lib.Anim;
6808 // local style camelizing for speed
6810 var camelRe = /(-[a-z])/gi;
6811 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6812 var view = document.defaultView;
6815 * @class Roo.Element
6816 * Represents an Element in the DOM.<br><br>
6819 var el = Roo.get("my-div");
6822 var el = getEl("my-div");
6824 // or with a DOM element
6825 var el = Roo.get(myDivElement);
6827 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6828 * each call instead of constructing a new one.<br><br>
6829 * <b>Animations</b><br />
6830 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6831 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6833 Option Default Description
6834 --------- -------- ---------------------------------------------
6835 duration .35 The duration of the animation in seconds
6836 easing easeOut The YUI easing method
6837 callback none A function to execute when the anim completes
6838 scope this The scope (this) of the callback function
6840 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6841 * manipulate the animation. Here's an example:
6843 var el = Roo.get("my-div");
6848 // default animation
6849 el.setWidth(100, true);
6851 // animation with some options set
6858 // using the "anim" property to get the Anim object
6864 el.setWidth(100, opt);
6866 if(opt.anim.isAnimated()){
6870 * <b> Composite (Collections of) Elements</b><br />
6871 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6872 * @constructor Create a new Element directly.
6873 * @param {String/HTMLElement} element
6874 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6876 Roo.Element = function(element, forceNew){
6877 var dom = typeof element == "string" ?
6878 document.getElementById(element) : element;
6879 if(!dom){ // invalid id/element
6883 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6884 return Roo.Element.cache[id];
6894 * The DOM element ID
6897 this.id = id || Roo.id(dom);
6900 var El = Roo.Element;
6904 * The element's default display mode (defaults to "")
6907 originalDisplay : "",
6911 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6916 * Sets the element's visibility mode. When setVisible() is called it
6917 * will use this to determine whether to set the visibility or the display property.
6918 * @param visMode Element.VISIBILITY or Element.DISPLAY
6919 * @return {Roo.Element} this
6921 setVisibilityMode : function(visMode){
6922 this.visibilityMode = visMode;
6926 * Convenience method for setVisibilityMode(Element.DISPLAY)
6927 * @param {String} display (optional) What to set display to when visible
6928 * @return {Roo.Element} this
6930 enableDisplayMode : function(display){
6931 this.setVisibilityMode(El.DISPLAY);
6932 if(typeof display != "undefined") this.originalDisplay = display;
6937 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6938 * @param {String} selector The simple selector to test
6939 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6940 search as a number or element (defaults to 10 || document.body)
6941 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6942 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6944 findParent : function(simpleSelector, maxDepth, returnEl){
6945 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6946 maxDepth = maxDepth || 50;
6947 if(typeof maxDepth != "number"){
6948 stopEl = Roo.getDom(maxDepth);
6951 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6952 if(dq.is(p, simpleSelector)){
6953 return returnEl ? Roo.get(p) : p;
6963 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6964 * @param {String} selector The simple selector to test
6965 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6966 search as a number or element (defaults to 10 || document.body)
6967 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6968 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6970 findParentNode : function(simpleSelector, maxDepth, returnEl){
6971 var p = Roo.fly(this.dom.parentNode, '_internal');
6972 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6976 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6977 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6978 * @param {String} selector The simple selector to test
6979 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6980 search as a number or element (defaults to 10 || document.body)
6981 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6983 up : function(simpleSelector, maxDepth){
6984 return this.findParentNode(simpleSelector, maxDepth, true);
6990 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6991 * @param {String} selector The simple selector to test
6992 * @return {Boolean} True if this element matches the selector, else false
6994 is : function(simpleSelector){
6995 return Roo.DomQuery.is(this.dom, simpleSelector);
6999 * Perform animation on this element.
7000 * @param {Object} args The YUI animation control args
7001 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7002 * @param {Function} onComplete (optional) Function to call when animation completes
7003 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7004 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7005 * @return {Roo.Element} this
7007 animate : function(args, duration, onComplete, easing, animType){
7008 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7013 * @private Internal animation call
7015 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7016 animType = animType || 'run';
7018 var anim = Roo.lib.Anim[animType](
7020 (opt.duration || defaultDur) || .35,
7021 (opt.easing || defaultEase) || 'easeOut',
7023 Roo.callback(cb, this);
7024 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7032 // private legacy anim prep
7033 preanim : function(a, i){
7034 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7038 * Removes worthless text nodes
7039 * @param {Boolean} forceReclean (optional) By default the element
7040 * keeps track if it has been cleaned already so
7041 * you can call this over and over. However, if you update the element and
7042 * need to force a reclean, you can pass true.
7044 clean : function(forceReclean){
7045 if(this.isCleaned && forceReclean !== true){
7049 var d = this.dom, n = d.firstChild, ni = -1;
7051 var nx = n.nextSibling;
7052 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7059 this.isCleaned = true;
7064 calcOffsetsTo : function(el){
7067 var restorePos = false;
7068 if(el.getStyle('position') == 'static'){
7069 el.position('relative');
7074 while(op && op != d && op.tagName != 'HTML'){
7077 op = op.offsetParent;
7080 el.position('static');
7086 * Scrolls this element into view within the passed container.
7087 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7088 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7089 * @return {Roo.Element} this
7091 scrollIntoView : function(container, hscroll){
7092 var c = Roo.getDom(container) || document.body;
7095 var o = this.calcOffsetsTo(c),
7098 b = t+el.offsetHeight,
7099 r = l+el.offsetWidth;
7101 var ch = c.clientHeight;
7102 var ct = parseInt(c.scrollTop, 10);
7103 var cl = parseInt(c.scrollLeft, 10);
7105 var cr = cl + c.clientWidth;
7113 if(hscroll !== false){
7117 c.scrollLeft = r-c.clientWidth;
7124 scrollChildIntoView : function(child, hscroll){
7125 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7129 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7130 * the new height may not be available immediately.
7131 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7132 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7133 * @param {Function} onComplete (optional) Function to call when animation completes
7134 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7135 * @return {Roo.Element} this
7137 autoHeight : function(animate, duration, onComplete, easing){
7138 var oldHeight = this.getHeight();
7140 this.setHeight(1); // force clipping
7141 setTimeout(function(){
7142 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7144 this.setHeight(height);
7146 if(typeof onComplete == "function"){
7150 this.setHeight(oldHeight); // restore original height
7151 this.setHeight(height, animate, duration, function(){
7153 if(typeof onComplete == "function") onComplete();
7154 }.createDelegate(this), easing);
7156 }.createDelegate(this), 0);
7161 * Returns true if this element is an ancestor of the passed element
7162 * @param {HTMLElement/String} el The element to check
7163 * @return {Boolean} True if this element is an ancestor of el, else false
7165 contains : function(el){
7166 if(!el){return false;}
7167 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7171 * Checks whether the element is currently visible using both visibility and display properties.
7172 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7173 * @return {Boolean} True if the element is currently visible, else false
7175 isVisible : function(deep) {
7176 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7177 if(deep !== true || !vis){
7180 var p = this.dom.parentNode;
7181 while(p && p.tagName.toLowerCase() != "body"){
7182 if(!Roo.fly(p, '_isVisible').isVisible()){
7191 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7192 * @param {String} selector The CSS selector
7193 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7194 * @return {CompositeElement/CompositeElementLite} The composite element
7196 select : function(selector, unique){
7197 return El.select(selector, unique, this.dom);
7201 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7202 * @param {String} selector The CSS selector
7203 * @return {Array} An array of the matched nodes
7205 query : function(selector, unique){
7206 return Roo.DomQuery.select(selector, this.dom);
7210 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7211 * @param {String} selector The CSS selector
7212 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7213 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7215 child : function(selector, returnDom){
7216 var n = Roo.DomQuery.selectNode(selector, this.dom);
7217 return returnDom ? n : Roo.get(n);
7221 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7222 * @param {String} selector The CSS selector
7223 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7224 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7226 down : function(selector, returnDom){
7227 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7228 return returnDom ? n : Roo.get(n);
7232 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7233 * @param {String} group The group the DD object is member of
7234 * @param {Object} config The DD config object
7235 * @param {Object} overrides An object containing methods to override/implement on the DD object
7236 * @return {Roo.dd.DD} The DD object
7238 initDD : function(group, config, overrides){
7239 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7240 return Roo.apply(dd, overrides);
7244 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7245 * @param {String} group The group the DDProxy object is member of
7246 * @param {Object} config The DDProxy config object
7247 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7248 * @return {Roo.dd.DDProxy} The DDProxy object
7250 initDDProxy : function(group, config, overrides){
7251 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7252 return Roo.apply(dd, overrides);
7256 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7257 * @param {String} group The group the DDTarget object is member of
7258 * @param {Object} config The DDTarget config object
7259 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7260 * @return {Roo.dd.DDTarget} The DDTarget object
7262 initDDTarget : function(group, config, overrides){
7263 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7264 return Roo.apply(dd, overrides);
7268 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7269 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7270 * @param {Boolean} visible Whether the element is visible
7271 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7272 * @return {Roo.Element} this
7274 setVisible : function(visible, animate){
7276 if(this.visibilityMode == El.DISPLAY){
7277 this.setDisplayed(visible);
7280 this.dom.style.visibility = visible ? "visible" : "hidden";
7283 // closure for composites
7285 var visMode = this.visibilityMode;
7287 this.setOpacity(.01);
7288 this.setVisible(true);
7290 this.anim({opacity: { to: (visible?1:0) }},
7291 this.preanim(arguments, 1),
7292 null, .35, 'easeIn', function(){
7294 if(visMode == El.DISPLAY){
7295 dom.style.display = "none";
7297 dom.style.visibility = "hidden";
7299 Roo.get(dom).setOpacity(1);
7307 * Returns true if display is not "none"
7310 isDisplayed : function() {
7311 return this.getStyle("display") != "none";
7315 * Toggles the element's visibility or display, depending on visibility mode.
7316 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7317 * @return {Roo.Element} this
7319 toggle : function(animate){
7320 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7325 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7326 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7327 * @return {Roo.Element} this
7329 setDisplayed : function(value) {
7330 if(typeof value == "boolean"){
7331 value = value ? this.originalDisplay : "none";
7333 this.setStyle("display", value);
7338 * Tries to focus the element. Any exceptions are caught and ignored.
7339 * @return {Roo.Element} this
7341 focus : function() {
7349 * Tries to blur the element. Any exceptions are caught and ignored.
7350 * @return {Roo.Element} this
7360 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7361 * @param {String/Array} className The CSS class to add, or an array of classes
7362 * @return {Roo.Element} this
7364 addClass : function(className){
7365 if(className instanceof Array){
7366 for(var i = 0, len = className.length; i < len; i++) {
7367 this.addClass(className[i]);
7370 if(className && !this.hasClass(className)){
7371 this.dom.className = this.dom.className + " " + className;
7378 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7379 * @param {String/Array} className The CSS class to add, or an array of classes
7380 * @return {Roo.Element} this
7382 radioClass : function(className){
7383 var siblings = this.dom.parentNode.childNodes;
7384 for(var i = 0; i < siblings.length; i++) {
7385 var s = siblings[i];
7386 if(s.nodeType == 1){
7387 Roo.get(s).removeClass(className);
7390 this.addClass(className);
7395 * Removes one or more CSS classes from the element.
7396 * @param {String/Array} className The CSS class to remove, or an array of classes
7397 * @return {Roo.Element} this
7399 removeClass : function(className){
7400 if(!className || !this.dom.className){
7403 if(className instanceof Array){
7404 for(var i = 0, len = className.length; i < len; i++) {
7405 this.removeClass(className[i]);
7408 if(this.hasClass(className)){
7409 var re = this.classReCache[className];
7411 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7412 this.classReCache[className] = re;
7414 this.dom.className =
7415 this.dom.className.replace(re, " ");
7425 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7426 * @param {String} className The CSS class to toggle
7427 * @return {Roo.Element} this
7429 toggleClass : function(className){
7430 if(this.hasClass(className)){
7431 this.removeClass(className);
7433 this.addClass(className);
7439 * Checks if the specified CSS class exists on this element's DOM node.
7440 * @param {String} className The CSS class to check for
7441 * @return {Boolean} True if the class exists, else false
7443 hasClass : function(className){
7444 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7448 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7449 * @param {String} oldClassName The CSS class to replace
7450 * @param {String} newClassName The replacement CSS class
7451 * @return {Roo.Element} this
7453 replaceClass : function(oldClassName, newClassName){
7454 this.removeClass(oldClassName);
7455 this.addClass(newClassName);
7460 * Returns an object with properties matching the styles requested.
7461 * For example, el.getStyles('color', 'font-size', 'width') might return
7462 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7463 * @param {String} style1 A style name
7464 * @param {String} style2 A style name
7465 * @param {String} etc.
7466 * @return {Object} The style object
7468 getStyles : function(){
7469 var a = arguments, len = a.length, r = {};
7470 for(var i = 0; i < len; i++){
7471 r[a[i]] = this.getStyle(a[i]);
7477 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7478 * @param {String} property The style property whose value is returned.
7479 * @return {String} The current value of the style property for this element.
7481 getStyle : function(){
7482 return view && view.getComputedStyle ?
7484 var el = this.dom, v, cs, camel;
7485 if(prop == 'float'){
7488 if(el.style && (v = el.style[prop])){
7491 if(cs = view.getComputedStyle(el, "")){
7492 if(!(camel = propCache[prop])){
7493 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7500 var el = this.dom, v, cs, camel;
7501 if(prop == 'opacity'){
7502 if(typeof el.style.filter == 'string'){
7503 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7505 var fv = parseFloat(m[1]);
7507 return fv ? fv / 100 : 0;
7512 }else if(prop == 'float'){
7513 prop = "styleFloat";
7515 if(!(camel = propCache[prop])){
7516 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7518 if(v = el.style[camel]){
7521 if(cs = el.currentStyle){
7529 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7530 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7531 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7532 * @return {Roo.Element} this
7534 setStyle : function(prop, value){
7535 if(typeof prop == "string"){
7537 if (prop == 'float') {
7538 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7543 if(!(camel = propCache[prop])){
7544 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7547 if(camel == 'opacity') {
7548 this.setOpacity(value);
7550 this.dom.style[camel] = value;
7553 for(var style in prop){
7554 if(typeof prop[style] != "function"){
7555 this.setStyle(style, prop[style]);
7563 * More flexible version of {@link #setStyle} for setting style properties.
7564 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7565 * a function which returns such a specification.
7566 * @return {Roo.Element} this
7568 applyStyles : function(style){
7569 Roo.DomHelper.applyStyles(this.dom, style);
7574 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7575 * @return {Number} The X position of the element
7578 return D.getX(this.dom);
7582 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7583 * @return {Number} The Y position of the element
7586 return D.getY(this.dom);
7590 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7591 * @return {Array} The XY position of the element
7594 return D.getXY(this.dom);
7598 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7599 * @param {Number} The X position of the element
7600 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7601 * @return {Roo.Element} this
7603 setX : function(x, animate){
7605 D.setX(this.dom, x);
7607 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7613 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7614 * @param {Number} The Y position of the element
7615 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7616 * @return {Roo.Element} this
7618 setY : function(y, animate){
7620 D.setY(this.dom, y);
7622 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7628 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7629 * @param {String} left The left CSS property value
7630 * @return {Roo.Element} this
7632 setLeft : function(left){
7633 this.setStyle("left", this.addUnits(left));
7638 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7639 * @param {String} top The top CSS property value
7640 * @return {Roo.Element} this
7642 setTop : function(top){
7643 this.setStyle("top", this.addUnits(top));
7648 * Sets the element's CSS right style.
7649 * @param {String} right The right CSS property value
7650 * @return {Roo.Element} this
7652 setRight : function(right){
7653 this.setStyle("right", this.addUnits(right));
7658 * Sets the element's CSS bottom style.
7659 * @param {String} bottom The bottom CSS property value
7660 * @return {Roo.Element} this
7662 setBottom : function(bottom){
7663 this.setStyle("bottom", this.addUnits(bottom));
7668 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7669 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7670 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7671 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7672 * @return {Roo.Element} this
7674 setXY : function(pos, animate){
7676 D.setXY(this.dom, pos);
7678 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7684 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7685 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7686 * @param {Number} x X value for new position (coordinates are page-based)
7687 * @param {Number} y Y value for new position (coordinates are page-based)
7688 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7689 * @return {Roo.Element} this
7691 setLocation : function(x, y, animate){
7692 this.setXY([x, y], this.preanim(arguments, 2));
7697 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7698 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7699 * @param {Number} x X value for new position (coordinates are page-based)
7700 * @param {Number} y Y value for new position (coordinates are page-based)
7701 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7702 * @return {Roo.Element} this
7704 moveTo : function(x, y, animate){
7705 this.setXY([x, y], this.preanim(arguments, 2));
7710 * Returns the region of the given element.
7711 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7712 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7714 getRegion : function(){
7715 return D.getRegion(this.dom);
7719 * Returns the offset height of the element
7720 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7721 * @return {Number} The element's height
7723 getHeight : function(contentHeight){
7724 var h = this.dom.offsetHeight || 0;
7725 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7729 * Returns the offset width of the element
7730 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7731 * @return {Number} The element's width
7733 getWidth : function(contentWidth){
7734 var w = this.dom.offsetWidth || 0;
7735 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7739 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7740 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7741 * if a height has not been set using CSS.
7744 getComputedHeight : function(){
7745 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7747 h = parseInt(this.getStyle('height'), 10) || 0;
7748 if(!this.isBorderBox()){
7749 h += this.getFrameWidth('tb');
7756 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7757 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7758 * if a width has not been set using CSS.
7761 getComputedWidth : function(){
7762 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7764 w = parseInt(this.getStyle('width'), 10) || 0;
7765 if(!this.isBorderBox()){
7766 w += this.getFrameWidth('lr');
7773 * Returns the size of the element.
7774 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7775 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7777 getSize : function(contentSize){
7778 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7782 * Returns the width and height of the viewport.
7783 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7785 getViewSize : function(){
7786 var d = this.dom, doc = document, aw = 0, ah = 0;
7787 if(d == doc || d == doc.body){
7788 return {width : D.getViewWidth(), height: D.getViewHeight()};
7791 width : d.clientWidth,
7792 height: d.clientHeight
7798 * Returns the value of the "value" attribute
7799 * @param {Boolean} asNumber true to parse the value as a number
7800 * @return {String/Number}
7802 getValue : function(asNumber){
7803 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7807 adjustWidth : function(width){
7808 if(typeof width == "number"){
7809 if(this.autoBoxAdjust && !this.isBorderBox()){
7810 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7820 adjustHeight : function(height){
7821 if(typeof height == "number"){
7822 if(this.autoBoxAdjust && !this.isBorderBox()){
7823 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7833 * Set the width of the element
7834 * @param {Number} width The new width
7835 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7836 * @return {Roo.Element} this
7838 setWidth : function(width, animate){
7839 width = this.adjustWidth(width);
7841 this.dom.style.width = this.addUnits(width);
7843 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7849 * Set the height of the element
7850 * @param {Number} height The new height
7851 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7852 * @return {Roo.Element} this
7854 setHeight : function(height, animate){
7855 height = this.adjustHeight(height);
7857 this.dom.style.height = this.addUnits(height);
7859 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7865 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7866 * @param {Number} width The new width
7867 * @param {Number} height The new height
7868 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7869 * @return {Roo.Element} this
7871 setSize : function(width, height, animate){
7872 if(typeof width == "object"){ // in case of object from getSize()
7873 height = width.height; width = width.width;
7875 width = this.adjustWidth(width); height = this.adjustHeight(height);
7877 this.dom.style.width = this.addUnits(width);
7878 this.dom.style.height = this.addUnits(height);
7880 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7886 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7887 * @param {Number} x X value for new position (coordinates are page-based)
7888 * @param {Number} y Y value for new position (coordinates are page-based)
7889 * @param {Number} width The new width
7890 * @param {Number} height The new height
7891 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7892 * @return {Roo.Element} this
7894 setBounds : function(x, y, width, height, animate){
7896 this.setSize(width, height);
7897 this.setLocation(x, y);
7899 width = this.adjustWidth(width); height = this.adjustHeight(height);
7900 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7901 this.preanim(arguments, 4), 'motion');
7907 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
7908 * @param {Roo.lib.Region} region The region to fill
7909 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7910 * @return {Roo.Element} this
7912 setRegion : function(region, animate){
7913 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7918 * Appends an event handler
7920 * @param {String} eventName The type of event to append
7921 * @param {Function} fn The method the event invokes
7922 * @param {Object} scope (optional) The scope (this object) of the fn
7923 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7925 addListener : function(eventName, fn, scope, options){
7927 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7932 * Removes an event handler from this element
7933 * @param {String} eventName the type of event to remove
7934 * @param {Function} fn the method the event invokes
7935 * @return {Roo.Element} this
7937 removeListener : function(eventName, fn){
7938 Roo.EventManager.removeListener(this.dom, eventName, fn);
7943 * Removes all previous added listeners from this element
7944 * @return {Roo.Element} this
7946 removeAllListeners : function(){
7947 E.purgeElement(this.dom);
7951 relayEvent : function(eventName, observable){
7952 this.on(eventName, function(e){
7953 observable.fireEvent(eventName, e);
7958 * Set the opacity of the element
7959 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7960 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7961 * @return {Roo.Element} this
7963 setOpacity : function(opacity, animate){
7965 var s = this.dom.style;
7968 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7969 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7971 s.opacity = opacity;
7974 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7980 * Gets the left X coordinate
7981 * @param {Boolean} local True to get the local css position instead of page coordinate
7984 getLeft : function(local){
7988 return parseInt(this.getStyle("left"), 10) || 0;
7993 * Gets the right X coordinate of the element (element X position + element width)
7994 * @param {Boolean} local True to get the local css position instead of page coordinate
7997 getRight : function(local){
7999 return this.getX() + this.getWidth();
8001 return (this.getLeft(true) + this.getWidth()) || 0;
8006 * Gets the top Y coordinate
8007 * @param {Boolean} local True to get the local css position instead of page coordinate
8010 getTop : function(local) {
8014 return parseInt(this.getStyle("top"), 10) || 0;
8019 * Gets the bottom Y coordinate of the element (element Y position + element height)
8020 * @param {Boolean} local True to get the local css position instead of page coordinate
8023 getBottom : function(local){
8025 return this.getY() + this.getHeight();
8027 return (this.getTop(true) + this.getHeight()) || 0;
8032 * Initializes positioning on this element. If a desired position is not passed, it will make the
8033 * the element positioned relative IF it is not already positioned.
8034 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8035 * @param {Number} zIndex (optional) The zIndex to apply
8036 * @param {Number} x (optional) Set the page X position
8037 * @param {Number} y (optional) Set the page Y position
8039 position : function(pos, zIndex, x, y){
8041 if(this.getStyle('position') == 'static'){
8042 this.setStyle('position', 'relative');
8045 this.setStyle("position", pos);
8048 this.setStyle("z-index", zIndex);
8050 if(x !== undefined && y !== undefined){
8052 }else if(x !== undefined){
8054 }else if(y !== undefined){
8060 * Clear positioning back to the default when the document was loaded
8061 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8062 * @return {Roo.Element} this
8064 clearPositioning : function(value){
8072 "position" : "static"
8078 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8079 * snapshot before performing an update and then restoring the element.
8082 getPositioning : function(){
8083 var l = this.getStyle("left");
8084 var t = this.getStyle("top");
8086 "position" : this.getStyle("position"),
8088 "right" : l ? "" : this.getStyle("right"),
8090 "bottom" : t ? "" : this.getStyle("bottom"),
8091 "z-index" : this.getStyle("z-index")
8096 * Gets the width of the border(s) for the specified side(s)
8097 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8098 * passing lr would get the border (l)eft width + the border (r)ight width.
8099 * @return {Number} The width of the sides passed added together
8101 getBorderWidth : function(side){
8102 return this.addStyles(side, El.borders);
8106 * Gets the width of the padding(s) for the specified side(s)
8107 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8108 * passing lr would get the padding (l)eft + the padding (r)ight.
8109 * @return {Number} The padding of the sides passed added together
8111 getPadding : function(side){
8112 return this.addStyles(side, El.paddings);
8116 * Set positioning with an object returned by getPositioning().
8117 * @param {Object} posCfg
8118 * @return {Roo.Element} this
8120 setPositioning : function(pc){
8121 this.applyStyles(pc);
8122 if(pc.right == "auto"){
8123 this.dom.style.right = "";
8125 if(pc.bottom == "auto"){
8126 this.dom.style.bottom = "";
8132 fixDisplay : function(){
8133 if(this.getStyle("display") == "none"){
8134 this.setStyle("visibility", "hidden");
8135 this.setStyle("display", this.originalDisplay); // first try reverting to default
8136 if(this.getStyle("display") == "none"){ // if that fails, default to block
8137 this.setStyle("display", "block");
8143 * Quick set left and top adding default units
8144 * @param {String} left The left CSS property value
8145 * @param {String} top The top CSS property value
8146 * @return {Roo.Element} this
8148 setLeftTop : function(left, top){
8149 this.dom.style.left = this.addUnits(left);
8150 this.dom.style.top = this.addUnits(top);
8155 * Move this element relative to its current position.
8156 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8157 * @param {Number} distance How far to move the element in pixels
8158 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8159 * @return {Roo.Element} this
8161 move : function(direction, distance, animate){
8162 var xy = this.getXY();
8163 direction = direction.toLowerCase();
8167 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8171 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8176 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8181 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8188 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8189 * @return {Roo.Element} this
8192 if(!this.isClipped){
8193 this.isClipped = true;
8194 this.originalClip = {
8195 "o": this.getStyle("overflow"),
8196 "x": this.getStyle("overflow-x"),
8197 "y": this.getStyle("overflow-y")
8199 this.setStyle("overflow", "hidden");
8200 this.setStyle("overflow-x", "hidden");
8201 this.setStyle("overflow-y", "hidden");
8207 * Return clipping (overflow) to original clipping before clip() was called
8208 * @return {Roo.Element} this
8210 unclip : function(){
8212 this.isClipped = false;
8213 var o = this.originalClip;
8214 if(o.o){this.setStyle("overflow", o.o);}
8215 if(o.x){this.setStyle("overflow-x", o.x);}
8216 if(o.y){this.setStyle("overflow-y", o.y);}
8223 * Gets the x,y coordinates specified by the anchor position on the element.
8224 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8225 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8226 * {width: (target width), height: (target height)} (defaults to the element's current size)
8227 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8228 * @return {Array} [x, y] An array containing the element's x and y coordinates
8230 getAnchorXY : function(anchor, local, s){
8231 //Passing a different size is useful for pre-calculating anchors,
8232 //especially for anchored animations that change the el size.
8234 var w, h, vp = false;
8237 if(d == document.body || d == document){
8239 w = D.getViewWidth(); h = D.getViewHeight();
8241 w = this.getWidth(); h = this.getHeight();
8244 w = s.width; h = s.height;
8246 var x = 0, y = 0, r = Math.round;
8247 switch((anchor || "tl").toLowerCase()){
8289 var sc = this.getScroll();
8290 return [x + sc.left, y + sc.top];
8292 //Add the element's offset xy
8293 var o = this.getXY();
8294 return [x+o[0], y+o[1]];
8298 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8299 * supported position values.
8300 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8301 * @param {String} position The position to align to.
8302 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8303 * @return {Array} [x, y]
8305 getAlignToXY : function(el, p, o){
8309 throw "Element.alignTo with an element that doesn't exist";
8311 var c = false; //constrain to viewport
8312 var p1 = "", p2 = "";
8319 }else if(p.indexOf("-") == -1){
8322 p = p.toLowerCase();
8323 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8325 throw "Element.alignTo with an invalid alignment " + p;
8327 p1 = m[1]; p2 = m[2]; c = !!m[3];
8329 //Subtract the aligned el's internal xy from the target's offset xy
8330 //plus custom offset to get the aligned el's new offset xy
8331 var a1 = this.getAnchorXY(p1, true);
8332 var a2 = el.getAnchorXY(p2, false);
8333 var x = a2[0] - a1[0] + o[0];
8334 var y = a2[1] - a1[1] + o[1];
8336 //constrain the aligned el to viewport if necessary
8337 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8338 // 5px of margin for ie
8339 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8341 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8342 //perpendicular to the vp border, allow the aligned el to slide on that border,
8343 //otherwise swap the aligned el to the opposite border of the target.
8344 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8345 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8346 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8347 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8350 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8351 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8353 if((x+w) > dw + scrollX){
8354 x = swapX ? r.left-w : dw+scrollX-w;
8357 x = swapX ? r.right : scrollX;
8359 if((y+h) > dh + scrollY){
8360 y = swapY ? r.top-h : dh+scrollY-h;
8363 y = swapY ? r.bottom : scrollY;
8370 getConstrainToXY : function(){
8371 var os = {top:0, left:0, bottom:0, right: 0};
8373 return function(el, local, offsets, proposedXY){
8375 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8377 var vw, vh, vx = 0, vy = 0;
8378 if(el.dom == document.body || el.dom == document){
8379 vw = Roo.lib.Dom.getViewWidth();
8380 vh = Roo.lib.Dom.getViewHeight();
8382 vw = el.dom.clientWidth;
8383 vh = el.dom.clientHeight;
8385 var vxy = el.getXY();
8391 var s = el.getScroll();
8393 vx += offsets.left + s.left;
8394 vy += offsets.top + s.top;
8396 vw -= offsets.right;
8397 vh -= offsets.bottom;
8402 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8403 var x = xy[0], y = xy[1];
8404 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8406 // only move it if it needs it
8409 // first validate right/bottom
8418 // then make sure top/left isn't negative
8427 return moved ? [x, y] : false;
8432 adjustForConstraints : function(xy, parent, offsets){
8433 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8437 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8438 * document it aligns it to the viewport.
8439 * The position parameter is optional, and can be specified in any one of the following formats:
8441 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8442 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8443 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8444 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8445 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8446 * element's anchor point, and the second value is used as the target's anchor point.</li>
8448 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8449 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8450 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8451 * that specified in order to enforce the viewport constraints.
8452 * Following are all of the supported anchor positions:
8455 ----- -----------------------------
8456 tl The top left corner (default)
8457 t The center of the top edge
8458 tr The top right corner
8459 l The center of the left edge
8460 c In the center of the element
8461 r The center of the right edge
8462 bl The bottom left corner
8463 b The center of the bottom edge
8464 br The bottom right corner
8468 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8469 el.alignTo("other-el");
8471 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8472 el.alignTo("other-el", "tr?");
8474 // align the bottom right corner of el with the center left edge of other-el
8475 el.alignTo("other-el", "br-l?");
8477 // align the center of el with the bottom left corner of other-el and
8478 // adjust the x position by -6 pixels (and the y position by 0)
8479 el.alignTo("other-el", "c-bl", [-6, 0]);
8481 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8482 * @param {String} position The position to align to.
8483 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8484 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8485 * @return {Roo.Element} this
8487 alignTo : function(element, position, offsets, animate){
8488 var xy = this.getAlignToXY(element, position, offsets);
8489 this.setXY(xy, this.preanim(arguments, 3));
8494 * Anchors an element to another element and realigns it when the window is resized.
8495 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8496 * @param {String} position The position to align to.
8497 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8498 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8499 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8500 * is a number, it is used as the buffer delay (defaults to 50ms).
8501 * @param {Function} callback The function to call after the animation finishes
8502 * @return {Roo.Element} this
8504 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8505 var action = function(){
8506 this.alignTo(el, alignment, offsets, animate);
8507 Roo.callback(callback, this);
8509 Roo.EventManager.onWindowResize(action, this);
8510 var tm = typeof monitorScroll;
8511 if(tm != 'undefined'){
8512 Roo.EventManager.on(window, 'scroll', action, this,
8513 {buffer: tm == 'number' ? monitorScroll : 50});
8515 action.call(this); // align immediately
8519 * Clears any opacity settings from this element. Required in some cases for IE.
8520 * @return {Roo.Element} this
8522 clearOpacity : function(){
8523 if (window.ActiveXObject) {
8524 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8525 this.dom.style.filter = "";
8528 this.dom.style.opacity = "";
8529 this.dom.style["-moz-opacity"] = "";
8530 this.dom.style["-khtml-opacity"] = "";
8536 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8537 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8538 * @return {Roo.Element} this
8540 hide : function(animate){
8541 this.setVisible(false, this.preanim(arguments, 0));
8546 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8547 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8548 * @return {Roo.Element} this
8550 show : function(animate){
8551 this.setVisible(true, this.preanim(arguments, 0));
8556 * @private Test if size has a unit, otherwise appends the default
8558 addUnits : function(size){
8559 return Roo.Element.addUnits(size, this.defaultUnit);
8563 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8564 * @return {Roo.Element} this
8566 beginMeasure : function(){
8568 if(el.offsetWidth || el.offsetHeight){
8569 return this; // offsets work already
8572 var p = this.dom, b = document.body; // start with this element
8573 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8574 var pe = Roo.get(p);
8575 if(pe.getStyle('display') == 'none'){
8576 changed.push({el: p, visibility: pe.getStyle("visibility")});
8577 p.style.visibility = "hidden";
8578 p.style.display = "block";
8582 this._measureChanged = changed;
8588 * Restores displays to before beginMeasure was called
8589 * @return {Roo.Element} this
8591 endMeasure : function(){
8592 var changed = this._measureChanged;
8594 for(var i = 0, len = changed.length; i < len; i++) {
8596 r.el.style.visibility = r.visibility;
8597 r.el.style.display = "none";
8599 this._measureChanged = null;
8605 * Update the innerHTML of this element, optionally searching for and processing scripts
8606 * @param {String} html The new HTML
8607 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8608 * @param {Function} callback For async script loading you can be noticed when the update completes
8609 * @return {Roo.Element} this
8611 update : function(html, loadScripts, callback){
8612 if(typeof html == "undefined"){
8615 if(loadScripts !== true){
8616 this.dom.innerHTML = html;
8617 if(typeof callback == "function"){
8625 html += '<span id="' + id + '"></span>';
8627 E.onAvailable(id, function(){
8628 var hd = document.getElementsByTagName("head")[0];
8629 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8630 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8631 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8634 while(match = re.exec(html)){
8635 var attrs = match[1];
8636 var srcMatch = attrs ? attrs.match(srcRe) : false;
8637 if(srcMatch && srcMatch[2]){
8638 var s = document.createElement("script");
8639 s.src = srcMatch[2];
8640 var typeMatch = attrs.match(typeRe);
8641 if(typeMatch && typeMatch[2]){
8642 s.type = typeMatch[2];
8645 }else if(match[2] && match[2].length > 0){
8646 if(window.execScript) {
8647 window.execScript(match[2]);
8655 window.eval(match[2]);
8659 var el = document.getElementById(id);
8660 if(el){el.parentNode.removeChild(el);}
8661 if(typeof callback == "function"){
8665 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8670 * Direct access to the UpdateManager update() method (takes the same parameters).
8671 * @param {String/Function} url The url for this request or a function to call to get the url
8672 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8673 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8674 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8675 * @return {Roo.Element} this
8678 var um = this.getUpdateManager();
8679 um.update.apply(um, arguments);
8684 * Gets this element's UpdateManager
8685 * @return {Roo.UpdateManager} The UpdateManager
8687 getUpdateManager : function(){
8688 if(!this.updateManager){
8689 this.updateManager = new Roo.UpdateManager(this);
8691 return this.updateManager;
8695 * Disables text selection for this element (normalized across browsers)
8696 * @return {Roo.Element} this
8698 unselectable : function(){
8699 this.dom.unselectable = "on";
8700 this.swallowEvent("selectstart", true);
8701 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8702 this.addClass("x-unselectable");
8707 * Calculates the x, y to center this element on the screen
8708 * @return {Array} The x, y values [x, y]
8710 getCenterXY : function(){
8711 return this.getAlignToXY(document, 'c-c');
8715 * Centers the Element in either the viewport, or another Element.
8716 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8718 center : function(centerIn){
8719 this.alignTo(centerIn || document, 'c-c');
8724 * Tests various css rules/browsers to determine if this element uses a border box
8727 isBorderBox : function(){
8728 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8732 * Return a box {x, y, width, height} that can be used to set another elements
8733 * size/location to match this element.
8734 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8735 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8736 * @return {Object} box An object in the format {x, y, width, height}
8738 getBox : function(contentBox, local){
8743 var left = parseInt(this.getStyle("left"), 10) || 0;
8744 var top = parseInt(this.getStyle("top"), 10) || 0;
8747 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8749 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8751 var l = this.getBorderWidth("l")+this.getPadding("l");
8752 var r = this.getBorderWidth("r")+this.getPadding("r");
8753 var t = this.getBorderWidth("t")+this.getPadding("t");
8754 var b = this.getBorderWidth("b")+this.getPadding("b");
8755 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8757 bx.right = bx.x + bx.width;
8758 bx.bottom = bx.y + bx.height;
8763 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8764 for more information about the sides.
8765 * @param {String} sides
8768 getFrameWidth : function(sides, onlyContentBox){
8769 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8773 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8774 * @param {Object} box The box to fill {x, y, width, height}
8775 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8776 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8777 * @return {Roo.Element} this
8779 setBox : function(box, adjust, animate){
8780 var w = box.width, h = box.height;
8781 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8782 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8783 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8785 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8790 * Forces the browser to repaint this element
8791 * @return {Roo.Element} this
8793 repaint : function(){
8795 this.addClass("x-repaint");
8796 setTimeout(function(){
8797 Roo.get(dom).removeClass("x-repaint");
8803 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8804 * then it returns the calculated width of the sides (see getPadding)
8805 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8806 * @return {Object/Number}
8808 getMargins : function(side){
8811 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8812 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8813 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8814 right: parseInt(this.getStyle("margin-right"), 10) || 0
8817 return this.addStyles(side, El.margins);
8822 addStyles : function(sides, styles){
8824 for(var i = 0, len = sides.length; i < len; i++){
8825 v = this.getStyle(styles[sides.charAt(i)]);
8827 w = parseInt(v, 10);
8835 * Creates a proxy element of this element
8836 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8837 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8838 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8839 * @return {Roo.Element} The new proxy element
8841 createProxy : function(config, renderTo, matchBox){
8843 renderTo = Roo.getDom(renderTo);
8845 renderTo = document.body;
8847 config = typeof config == "object" ?
8848 config : {tag : "div", cls: config};
8849 var proxy = Roo.DomHelper.append(renderTo, config, true);
8851 proxy.setBox(this.getBox());
8857 * Puts a mask over this element to disable user interaction. Requires core.css.
8858 * This method can only be applied to elements which accept child nodes.
8859 * @param {String} msg (optional) A message to display in the mask
8860 * @param {String} msgCls (optional) A css class to apply to the msg element
8861 * @return {Element} The mask element
8863 mask : function(msg, msgCls)
8865 if(this.getStyle("position") == "static"){
8866 this.setStyle("position", "relative");
8869 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8871 this.addClass("x-masked");
8872 this._mask.setDisplayed(true);
8877 while (dom && dom.style) {
8878 if (!isNaN(parseInt(dom.style.zIndex))) {
8879 z = Math.max(z, parseInt(dom.style.zIndex));
8881 dom = dom.parentNode;
8883 // if we are masking the body - then it hides everything..
8884 if (this.dom == document.body) {
8888 if(typeof msg == 'string'){
8890 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8892 var mm = this._maskMsg;
8893 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8894 mm.dom.firstChild.innerHTML = msg;
8895 mm.setDisplayed(true);
8897 mm.setStyle('z-index', z + 102);
8899 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8900 this._mask.setHeight(this.getHeight());
8902 this._mask.setStyle('z-index', z + 100);
8908 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8909 * it is cached for reuse.
8911 unmask : function(removeEl){
8913 if(removeEl === true){
8914 this._mask.remove();
8917 this._maskMsg.remove();
8918 delete this._maskMsg;
8921 this._mask.setDisplayed(false);
8923 this._maskMsg.setDisplayed(false);
8927 this.removeClass("x-masked");
8931 * Returns true if this element is masked
8934 isMasked : function(){
8935 return this._mask && this._mask.isVisible();
8939 * Creates an iframe shim for this element to keep selects and other windowed objects from
8941 * @return {Roo.Element} The new shim element
8943 createShim : function(){
8944 var el = document.createElement('iframe');
8945 el.frameBorder = 'no';
8946 el.className = 'roo-shim';
8947 if(Roo.isIE && Roo.isSecure){
8948 el.src = Roo.SSL_SECURE_URL;
8950 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8951 shim.autoBoxAdjust = false;
8956 * Removes this element from the DOM and deletes it from the cache
8958 remove : function(){
8959 if(this.dom.parentNode){
8960 this.dom.parentNode.removeChild(this.dom);
8962 delete El.cache[this.dom.id];
8966 * Sets up event handlers to add and remove a css class when the mouse is over this element
8967 * @param {String} className
8968 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8969 * mouseout events for children elements
8970 * @return {Roo.Element} this
8972 addClassOnOver : function(className, preventFlicker){
8973 this.on("mouseover", function(){
8974 Roo.fly(this, '_internal').addClass(className);
8976 var removeFn = function(e){
8977 if(preventFlicker !== true || !e.within(this, true)){
8978 Roo.fly(this, '_internal').removeClass(className);
8981 this.on("mouseout", removeFn, this.dom);
8986 * Sets up event handlers to add and remove a css class when this element has the focus
8987 * @param {String} className
8988 * @return {Roo.Element} this
8990 addClassOnFocus : function(className){
8991 this.on("focus", function(){
8992 Roo.fly(this, '_internal').addClass(className);
8994 this.on("blur", function(){
8995 Roo.fly(this, '_internal').removeClass(className);
9000 * 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)
9001 * @param {String} className
9002 * @return {Roo.Element} this
9004 addClassOnClick : function(className){
9006 this.on("mousedown", function(){
9007 Roo.fly(dom, '_internal').addClass(className);
9008 var d = Roo.get(document);
9009 var fn = function(){
9010 Roo.fly(dom, '_internal').removeClass(className);
9011 d.removeListener("mouseup", fn);
9013 d.on("mouseup", fn);
9019 * Stops the specified event from bubbling and optionally prevents the default action
9020 * @param {String} eventName
9021 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9022 * @return {Roo.Element} this
9024 swallowEvent : function(eventName, preventDefault){
9025 var fn = function(e){
9026 e.stopPropagation();
9031 if(eventName instanceof Array){
9032 for(var i = 0, len = eventName.length; i < len; i++){
9033 this.on(eventName[i], fn);
9037 this.on(eventName, fn);
9044 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9047 * Sizes this element to its parent element's dimensions performing
9048 * neccessary box adjustments.
9049 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9050 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9051 * @return {Roo.Element} this
9053 fitToParent : function(monitorResize, targetParent) {
9054 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9055 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9056 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9059 var p = Roo.get(targetParent || this.dom.parentNode);
9060 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9061 if (monitorResize === true) {
9062 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9063 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9069 * Gets the next sibling, skipping text nodes
9070 * @return {HTMLElement} The next sibling or null
9072 getNextSibling : function(){
9073 var n = this.dom.nextSibling;
9074 while(n && n.nodeType != 1){
9081 * Gets the previous sibling, skipping text nodes
9082 * @return {HTMLElement} The previous sibling or null
9084 getPrevSibling : function(){
9085 var n = this.dom.previousSibling;
9086 while(n && n.nodeType != 1){
9087 n = n.previousSibling;
9094 * Appends the passed element(s) to this element
9095 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9096 * @return {Roo.Element} this
9098 appendChild: function(el){
9105 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9106 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9107 * automatically generated with the specified attributes.
9108 * @param {HTMLElement} insertBefore (optional) a child element of this element
9109 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9110 * @return {Roo.Element} The new child element
9112 createChild: function(config, insertBefore, returnDom){
9113 config = config || {tag:'div'};
9115 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9117 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9121 * Appends this element to the passed element
9122 * @param {String/HTMLElement/Element} el The new parent element
9123 * @return {Roo.Element} this
9125 appendTo: function(el){
9126 el = Roo.getDom(el);
9127 el.appendChild(this.dom);
9132 * Inserts this element before the passed element in the DOM
9133 * @param {String/HTMLElement/Element} el The element to insert before
9134 * @return {Roo.Element} this
9136 insertBefore: function(el){
9137 el = Roo.getDom(el);
9138 el.parentNode.insertBefore(this.dom, el);
9143 * Inserts this element after the passed element in the DOM
9144 * @param {String/HTMLElement/Element} el The element to insert after
9145 * @return {Roo.Element} this
9147 insertAfter: function(el){
9148 el = Roo.getDom(el);
9149 el.parentNode.insertBefore(this.dom, el.nextSibling);
9154 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9155 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9156 * @return {Roo.Element} The new child
9158 insertFirst: function(el, returnDom){
9160 if(typeof el == 'object' && !el.nodeType){ // dh config
9161 return this.createChild(el, this.dom.firstChild, returnDom);
9163 el = Roo.getDom(el);
9164 this.dom.insertBefore(el, this.dom.firstChild);
9165 return !returnDom ? Roo.get(el) : el;
9170 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9171 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9172 * @param {String} where (optional) 'before' or 'after' defaults to before
9173 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9174 * @return {Roo.Element} the inserted Element
9176 insertSibling: function(el, where, returnDom){
9177 where = where ? where.toLowerCase() : 'before';
9179 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9181 if(typeof el == 'object' && !el.nodeType){ // dh config
9182 if(where == 'after' && !this.dom.nextSibling){
9183 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9185 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9189 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9190 where == 'before' ? this.dom : this.dom.nextSibling);
9199 * Creates and wraps this element with another element
9200 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9201 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9202 * @return {HTMLElement/Element} The newly created wrapper element
9204 wrap: function(config, returnDom){
9206 config = {tag: "div"};
9208 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9209 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9214 * Replaces the passed element with this element
9215 * @param {String/HTMLElement/Element} el The element to replace
9216 * @return {Roo.Element} this
9218 replace: function(el){
9220 this.insertBefore(el);
9226 * Inserts an html fragment into this element
9227 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9228 * @param {String} html The HTML fragment
9229 * @param {Boolean} returnEl True to return an Roo.Element
9230 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9232 insertHtml : function(where, html, returnEl){
9233 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9234 return returnEl ? Roo.get(el) : el;
9238 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9239 * @param {Object} o The object with the attributes
9240 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9241 * @return {Roo.Element} this
9243 set : function(o, useSet){
9245 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9247 if(attr == "style" || typeof o[attr] == "function") continue;
9249 el.className = o["cls"];
9251 if(useSet) el.setAttribute(attr, o[attr]);
9252 else el[attr] = o[attr];
9256 Roo.DomHelper.applyStyles(el, o.style);
9262 * Convenience method for constructing a KeyMap
9263 * @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:
9264 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9265 * @param {Function} fn The function to call
9266 * @param {Object} scope (optional) The scope of the function
9267 * @return {Roo.KeyMap} The KeyMap created
9269 addKeyListener : function(key, fn, scope){
9271 if(typeof key != "object" || key instanceof Array){
9287 return new Roo.KeyMap(this, config);
9291 * Creates a KeyMap for this element
9292 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9293 * @return {Roo.KeyMap} The KeyMap created
9295 addKeyMap : function(config){
9296 return new Roo.KeyMap(this, config);
9300 * Returns true if this element is scrollable.
9303 isScrollable : function(){
9305 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9309 * 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().
9310 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9311 * @param {Number} value The new scroll value
9312 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9313 * @return {Element} this
9316 scrollTo : function(side, value, animate){
9317 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9319 this.dom[prop] = value;
9321 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9322 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9328 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9329 * within this element's scrollable range.
9330 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9331 * @param {Number} distance How far to scroll the element in pixels
9332 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9333 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9334 * was scrolled as far as it could go.
9336 scroll : function(direction, distance, animate){
9337 if(!this.isScrollable()){
9341 var l = el.scrollLeft, t = el.scrollTop;
9342 var w = el.scrollWidth, h = el.scrollHeight;
9343 var cw = el.clientWidth, ch = el.clientHeight;
9344 direction = direction.toLowerCase();
9345 var scrolled = false;
9346 var a = this.preanim(arguments, 2);
9351 var v = Math.min(l + distance, w-cw);
9352 this.scrollTo("left", v, a);
9359 var v = Math.max(l - distance, 0);
9360 this.scrollTo("left", v, a);
9368 var v = Math.max(t - distance, 0);
9369 this.scrollTo("top", v, a);
9377 var v = Math.min(t + distance, h-ch);
9378 this.scrollTo("top", v, a);
9387 * Translates the passed page coordinates into left/top css values for this element
9388 * @param {Number/Array} x The page x or an array containing [x, y]
9389 * @param {Number} y The page y
9390 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9392 translatePoints : function(x, y){
9393 if(typeof x == 'object' || x instanceof Array){
9396 var p = this.getStyle('position');
9397 var o = this.getXY();
9399 var l = parseInt(this.getStyle('left'), 10);
9400 var t = parseInt(this.getStyle('top'), 10);
9403 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9406 t = (p == "relative") ? 0 : this.dom.offsetTop;
9409 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9413 * Returns the current scroll position of the element.
9414 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9416 getScroll : function(){
9417 var d = this.dom, doc = document;
9418 if(d == doc || d == doc.body){
9419 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9420 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9421 return {left: l, top: t};
9423 return {left: d.scrollLeft, top: d.scrollTop};
9428 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9429 * are convert to standard 6 digit hex color.
9430 * @param {String} attr The css attribute
9431 * @param {String} defaultValue The default value to use when a valid color isn't found
9432 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9435 getColor : function(attr, defaultValue, prefix){
9436 var v = this.getStyle(attr);
9437 if(!v || v == "transparent" || v == "inherit") {
9438 return defaultValue;
9440 var color = typeof prefix == "undefined" ? "#" : prefix;
9441 if(v.substr(0, 4) == "rgb("){
9442 var rvs = v.slice(4, v.length -1).split(",");
9443 for(var i = 0; i < 3; i++){
9444 var h = parseInt(rvs[i]).toString(16);
9451 if(v.substr(0, 1) == "#"){
9453 for(var i = 1; i < 4; i++){
9454 var c = v.charAt(i);
9457 }else if(v.length == 7){
9458 color += v.substr(1);
9462 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9466 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9467 * gradient background, rounded corners and a 4-way shadow.
9468 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9469 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9470 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9471 * @return {Roo.Element} this
9473 boxWrap : function(cls){
9474 cls = cls || 'x-box';
9475 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9476 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9481 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9482 * @param {String} namespace The namespace in which to look for the attribute
9483 * @param {String} name The attribute name
9484 * @return {String} The attribute value
9486 getAttributeNS : Roo.isIE ? function(ns, name){
9488 var type = typeof d[ns+":"+name];
9489 if(type != 'undefined' && type != 'unknown'){
9490 return d[ns+":"+name];
9493 } : function(ns, name){
9495 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9499 var ep = El.prototype;
9502 * Appends an event handler (Shorthand for addListener)
9503 * @param {String} eventName The type of event to append
9504 * @param {Function} fn The method the event invokes
9505 * @param {Object} scope (optional) The scope (this object) of the fn
9506 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9509 ep.on = ep.addListener;
9511 ep.mon = ep.addListener;
9514 * Removes an event handler from this element (shorthand for removeListener)
9515 * @param {String} eventName the type of event to remove
9516 * @param {Function} fn the method the event invokes
9517 * @return {Roo.Element} this
9520 ep.un = ep.removeListener;
9523 * true to automatically adjust width and height settings for box-model issues (default to true)
9525 ep.autoBoxAdjust = true;
9528 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9531 El.addUnits = function(v, defaultUnit){
9532 if(v === "" || v == "auto"){
9535 if(v === undefined){
9538 if(typeof v == "number" || !El.unitPattern.test(v)){
9539 return v + (defaultUnit || 'px');
9544 // special markup used throughout Roo when box wrapping elements
9545 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>';
9547 * Visibility mode constant - Use visibility to hide element
9553 * Visibility mode constant - Use display to hide element
9559 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9560 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9561 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9573 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9574 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9575 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9576 * @return {Element} The Element object
9579 El.get = function(el){
9581 if(!el){ return null; }
9582 if(typeof el == "string"){ // element id
9583 if(!(elm = document.getElementById(el))){
9586 if(ex = El.cache[el]){
9589 ex = El.cache[el] = new El(elm);
9592 }else if(el.tagName){ // dom element
9596 if(ex = El.cache[id]){
9599 ex = El.cache[id] = new El(el);
9602 }else if(el instanceof El){
9604 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9605 // catch case where it hasn't been appended
9606 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9609 }else if(el.isComposite){
9611 }else if(el instanceof Array){
9612 return El.select(el);
9613 }else if(el == document){
9614 // create a bogus element object representing the document object
9616 var f = function(){};
9617 f.prototype = El.prototype;
9619 docEl.dom = document;
9627 El.uncache = function(el){
9628 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9630 delete El.cache[a[i].id || a[i]];
9636 // Garbage collection - uncache elements/purge listeners on orphaned elements
9637 // so we don't hold a reference and cause the browser to retain them
9638 El.garbageCollect = function(){
9639 if(!Roo.enableGarbageCollector){
9640 clearInterval(El.collectorThread);
9643 for(var eid in El.cache){
9644 var el = El.cache[eid], d = el.dom;
9645 // -------------------------------------------------------
9646 // Determining what is garbage:
9647 // -------------------------------------------------------
9649 // dom node is null, definitely garbage
9650 // -------------------------------------------------------
9652 // no parentNode == direct orphan, definitely garbage
9653 // -------------------------------------------------------
9654 // !d.offsetParent && !document.getElementById(eid)
9655 // display none elements have no offsetParent so we will
9656 // also try to look it up by it's id. However, check
9657 // offsetParent first so we don't do unneeded lookups.
9658 // This enables collection of elements that are not orphans
9659 // directly, but somewhere up the line they have an orphan
9661 // -------------------------------------------------------
9662 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9663 delete El.cache[eid];
9664 if(d && Roo.enableListenerCollection){
9670 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9674 El.Flyweight = function(dom){
9677 El.Flyweight.prototype = El.prototype;
9679 El._flyweights = {};
9681 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9682 * the dom node can be overwritten by other code.
9683 * @param {String/HTMLElement} el The dom node or id
9684 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9685 * prevent conflicts (e.g. internally Roo uses "_internal")
9687 * @return {Element} The shared Element object
9689 El.fly = function(el, named){
9690 named = named || '_global';
9691 el = Roo.getDom(el);
9695 if(!El._flyweights[named]){
9696 El._flyweights[named] = new El.Flyweight();
9698 El._flyweights[named].dom = el;
9699 return El._flyweights[named];
9703 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9704 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9705 * Shorthand of {@link Roo.Element#get}
9706 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9707 * @return {Element} The Element object
9713 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9714 * the dom node can be overwritten by other code.
9715 * Shorthand of {@link Roo.Element#fly}
9716 * @param {String/HTMLElement} el The dom node or id
9717 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9718 * prevent conflicts (e.g. internally Roo uses "_internal")
9720 * @return {Element} The shared Element object
9726 // speedy lookup for elements never to box adjust
9727 var noBoxAdjust = Roo.isStrict ? {
9730 input:1, select:1, textarea:1
9732 if(Roo.isIE || Roo.isGecko){
9733 noBoxAdjust['button'] = 1;
9737 Roo.EventManager.on(window, 'unload', function(){
9739 delete El._flyweights;
9747 Roo.Element.selectorFunction = Roo.DomQuery.select;
9750 Roo.Element.select = function(selector, unique, root){
9752 if(typeof selector == "string"){
9753 els = Roo.Element.selectorFunction(selector, root);
9754 }else if(selector.length !== undefined){
9757 throw "Invalid selector";
9759 if(unique === true){
9760 return new Roo.CompositeElement(els);
9762 return new Roo.CompositeElementLite(els);
9766 * Selects elements based on the passed CSS selector to enable working on them as 1.
9767 * @param {String/Array} selector The CSS selector or an array of elements
9768 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9769 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9770 * @return {CompositeElementLite/CompositeElement}
9774 Roo.select = Roo.Element.select;
9791 * Ext JS Library 1.1.1
9792 * Copyright(c) 2006-2007, Ext JS, LLC.
9794 * Originally Released Under LGPL - original licence link has changed is not relivant.
9797 * <script type="text/javascript">
9802 //Notifies Element that fx methods are available
9803 Roo.enableFx = true;
9807 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9808 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9809 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9810 * Element effects to work.</p><br/>
9812 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9813 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9814 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9815 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9816 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9817 * expected results and should be done with care.</p><br/>
9819 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9820 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9823 ----- -----------------------------
9824 tl The top left corner
9825 t The center of the top edge
9826 tr The top right corner
9827 l The center of the left edge
9828 r The center of the right edge
9829 bl The bottom left corner
9830 b The center of the bottom edge
9831 br The bottom right corner
9833 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9834 * below are common options that can be passed to any Fx method.</b>
9835 * @cfg {Function} callback A function called when the effect is finished
9836 * @cfg {Object} scope The scope of the effect function
9837 * @cfg {String} easing A valid Easing value for the effect
9838 * @cfg {String} afterCls A css class to apply after the effect
9839 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9840 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9841 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9842 * effects that end with the element being visually hidden, ignored otherwise)
9843 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9844 * a function which returns such a specification that will be applied to the Element after the effect finishes
9845 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9846 * @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
9847 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9851 * Slides the element into view. An anchor point can be optionally passed to set the point of
9852 * origin for the slide effect. This function automatically handles wrapping the element with
9853 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9856 // default: slide the element in from the top
9859 // custom: slide the element in from the right with a 2-second duration
9860 el.slideIn('r', { duration: 2 });
9862 // common config options shown with default values
9868 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9869 * @param {Object} options (optional) Object literal with any of the Fx config options
9870 * @return {Roo.Element} The Element
9872 slideIn : function(anchor, o){
9873 var el = this.getFxEl();
9876 el.queueFx(o, function(){
9878 anchor = anchor || "t";
9880 // fix display to visibility
9883 // restore values after effect
9884 var r = this.getFxRestore();
9885 var b = this.getBox();
9886 // fixed size for slide
9890 var wrap = this.fxWrap(r.pos, o, "hidden");
9892 var st = this.dom.style;
9893 st.visibility = "visible";
9894 st.position = "absolute";
9896 // clear out temp styles after slide and unwrap
9897 var after = function(){
9898 el.fxUnwrap(wrap, r.pos, o);
9900 st.height = r.height;
9903 // time to calc the positions
9904 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9906 switch(anchor.toLowerCase()){
9908 wrap.setSize(b.width, 0);
9909 st.left = st.bottom = "0";
9913 wrap.setSize(0, b.height);
9914 st.right = st.top = "0";
9918 wrap.setSize(0, b.height);
9920 st.left = st.top = "0";
9921 a = {width: bw, points: pt};
9924 wrap.setSize(b.width, 0);
9925 wrap.setY(b.bottom);
9926 st.left = st.top = "0";
9927 a = {height: bh, points: pt};
9931 st.right = st.bottom = "0";
9932 a = {width: bw, height: bh};
9936 wrap.setY(b.y+b.height);
9937 st.right = st.top = "0";
9938 a = {width: bw, height: bh, points: pt};
9942 wrap.setXY([b.right, b.bottom]);
9943 st.left = st.top = "0";
9944 a = {width: bw, height: bh, points: pt};
9948 wrap.setX(b.x+b.width);
9949 st.left = st.bottom = "0";
9950 a = {width: bw, height: bh, points: pt};
9953 this.dom.style.visibility = "visible";
9956 arguments.callee.anim = wrap.fxanim(a,
9966 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9967 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9968 * 'hidden') but block elements will still take up space in the document. The element must be removed
9969 * from the DOM using the 'remove' config option if desired. This function automatically handles
9970 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9973 // default: slide the element out to the top
9976 // custom: slide the element out to the right with a 2-second duration
9977 el.slideOut('r', { duration: 2 });
9979 // common config options shown with default values
9987 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9988 * @param {Object} options (optional) Object literal with any of the Fx config options
9989 * @return {Roo.Element} The Element
9991 slideOut : function(anchor, o){
9992 var el = this.getFxEl();
9995 el.queueFx(o, function(){
9997 anchor = anchor || "t";
9999 // restore values after effect
10000 var r = this.getFxRestore();
10002 var b = this.getBox();
10003 // fixed size for slide
10007 var wrap = this.fxWrap(r.pos, o, "visible");
10009 var st = this.dom.style;
10010 st.visibility = "visible";
10011 st.position = "absolute";
10015 var after = function(){
10017 el.setDisplayed(false);
10022 el.fxUnwrap(wrap, r.pos, o);
10024 st.width = r.width;
10025 st.height = r.height;
10030 var a, zero = {to: 0};
10031 switch(anchor.toLowerCase()){
10033 st.left = st.bottom = "0";
10034 a = {height: zero};
10037 st.right = st.top = "0";
10041 st.left = st.top = "0";
10042 a = {width: zero, points: {to:[b.right, b.y]}};
10045 st.left = st.top = "0";
10046 a = {height: zero, points: {to:[b.x, b.bottom]}};
10049 st.right = st.bottom = "0";
10050 a = {width: zero, height: zero};
10053 st.right = st.top = "0";
10054 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10057 st.left = st.top = "0";
10058 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10061 st.left = st.bottom = "0";
10062 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10066 arguments.callee.anim = wrap.fxanim(a,
10076 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10077 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10078 * The element must be removed from the DOM using the 'remove' config option if desired.
10084 // common config options shown with default values
10092 * @param {Object} options (optional) Object literal with any of the Fx config options
10093 * @return {Roo.Element} The Element
10095 puff : function(o){
10096 var el = this.getFxEl();
10099 el.queueFx(o, function(){
10100 this.clearOpacity();
10103 // restore values after effect
10104 var r = this.getFxRestore();
10105 var st = this.dom.style;
10107 var after = function(){
10109 el.setDisplayed(false);
10116 el.setPositioning(r.pos);
10117 st.width = r.width;
10118 st.height = r.height;
10123 var width = this.getWidth();
10124 var height = this.getHeight();
10126 arguments.callee.anim = this.fxanim({
10127 width : {to: this.adjustWidth(width * 2)},
10128 height : {to: this.adjustHeight(height * 2)},
10129 points : {by: [-(width * .5), -(height * .5)]},
10131 fontSize: {to:200, unit: "%"}
10142 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10143 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10144 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10150 // all config options shown with default values
10158 * @param {Object} options (optional) Object literal with any of the Fx config options
10159 * @return {Roo.Element} The Element
10161 switchOff : function(o){
10162 var el = this.getFxEl();
10165 el.queueFx(o, function(){
10166 this.clearOpacity();
10169 // restore values after effect
10170 var r = this.getFxRestore();
10171 var st = this.dom.style;
10173 var after = function(){
10175 el.setDisplayed(false);
10181 el.setPositioning(r.pos);
10182 st.width = r.width;
10183 st.height = r.height;
10188 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10189 this.clearOpacity();
10193 points:{by:[0, this.getHeight() * .5]}
10194 }, o, 'motion', 0.3, 'easeIn', after);
10195 }).defer(100, this);
10202 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10203 * changed using the "attr" config option) and then fading back to the original color. If no original
10204 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10207 // default: highlight background to yellow
10210 // custom: highlight foreground text to blue for 2 seconds
10211 el.highlight("0000ff", { attr: 'color', duration: 2 });
10213 // common config options shown with default values
10214 el.highlight("ffff9c", {
10215 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10216 endColor: (current color) or "ffffff",
10221 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10222 * @param {Object} options (optional) Object literal with any of the Fx config options
10223 * @return {Roo.Element} The Element
10225 highlight : function(color, o){
10226 var el = this.getFxEl();
10229 el.queueFx(o, function(){
10230 color = color || "ffff9c";
10231 attr = o.attr || "backgroundColor";
10233 this.clearOpacity();
10236 var origColor = this.getColor(attr);
10237 var restoreColor = this.dom.style[attr];
10238 endColor = (o.endColor || origColor) || "ffffff";
10240 var after = function(){
10241 el.dom.style[attr] = restoreColor;
10246 a[attr] = {from: color, to: endColor};
10247 arguments.callee.anim = this.fxanim(a,
10257 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10260 // default: a single light blue ripple
10263 // custom: 3 red ripples lasting 3 seconds total
10264 el.frame("ff0000", 3, { duration: 3 });
10266 // common config options shown with default values
10267 el.frame("C3DAF9", 1, {
10268 duration: 1 //duration of entire animation (not each individual ripple)
10269 // Note: Easing is not configurable and will be ignored if included
10272 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10273 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10274 * @param {Object} options (optional) Object literal with any of the Fx config options
10275 * @return {Roo.Element} The Element
10277 frame : function(color, count, o){
10278 var el = this.getFxEl();
10281 el.queueFx(o, function(){
10282 color = color || "#C3DAF9";
10283 if(color.length == 6){
10284 color = "#" + color;
10286 count = count || 1;
10287 duration = o.duration || 1;
10290 var b = this.getBox();
10291 var animFn = function(){
10292 var proxy = this.createProxy({
10295 visbility:"hidden",
10296 position:"absolute",
10297 "z-index":"35000", // yee haw
10298 border:"0px solid " + color
10301 var scale = Roo.isBorderBox ? 2 : 1;
10303 top:{from:b.y, to:b.y - 20},
10304 left:{from:b.x, to:b.x - 20},
10305 borderWidth:{from:0, to:10},
10306 opacity:{from:1, to:0},
10307 height:{from:b.height, to:(b.height + (20*scale))},
10308 width:{from:b.width, to:(b.width + (20*scale))}
10309 }, duration, function(){
10313 animFn.defer((duration/2)*1000, this);
10324 * Creates a pause before any subsequent queued effects begin. If there are
10325 * no effects queued after the pause it will have no effect.
10330 * @param {Number} seconds The length of time to pause (in seconds)
10331 * @return {Roo.Element} The Element
10333 pause : function(seconds){
10334 var el = this.getFxEl();
10337 el.queueFx(o, function(){
10338 setTimeout(function(){
10340 }, seconds * 1000);
10346 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10347 * using the "endOpacity" config option.
10350 // default: fade in from opacity 0 to 100%
10353 // custom: fade in from opacity 0 to 75% over 2 seconds
10354 el.fadeIn({ endOpacity: .75, duration: 2});
10356 // common config options shown with default values
10358 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10363 * @param {Object} options (optional) Object literal with any of the Fx config options
10364 * @return {Roo.Element} The Element
10366 fadeIn : function(o){
10367 var el = this.getFxEl();
10369 el.queueFx(o, function(){
10370 this.setOpacity(0);
10372 this.dom.style.visibility = 'visible';
10373 var to = o.endOpacity || 1;
10374 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10375 o, null, .5, "easeOut", function(){
10377 this.clearOpacity();
10386 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10387 * using the "endOpacity" config option.
10390 // default: fade out from the element's current opacity to 0
10393 // custom: fade out from the element's current opacity to 25% over 2 seconds
10394 el.fadeOut({ endOpacity: .25, duration: 2});
10396 // common config options shown with default values
10398 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10405 * @param {Object} options (optional) Object literal with any of the Fx config options
10406 * @return {Roo.Element} The Element
10408 fadeOut : function(o){
10409 var el = this.getFxEl();
10411 el.queueFx(o, function(){
10412 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10413 o, null, .5, "easeOut", function(){
10414 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10415 this.dom.style.display = "none";
10417 this.dom.style.visibility = "hidden";
10419 this.clearOpacity();
10427 * Animates the transition of an element's dimensions from a starting height/width
10428 * to an ending height/width.
10431 // change height and width to 100x100 pixels
10432 el.scale(100, 100);
10434 // common config options shown with default values. The height and width will default to
10435 // the element's existing values if passed as null.
10438 [element's height], {
10443 * @param {Number} width The new width (pass undefined to keep the original width)
10444 * @param {Number} height The new height (pass undefined to keep the original height)
10445 * @param {Object} options (optional) Object literal with any of the Fx config options
10446 * @return {Roo.Element} The Element
10448 scale : function(w, h, o){
10449 this.shift(Roo.apply({}, o, {
10457 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10458 * Any of these properties not specified in the config object will not be changed. This effect
10459 * requires that at least one new dimension, position or opacity setting must be passed in on
10460 * the config object in order for the function to have any effect.
10463 // slide the element horizontally to x position 200 while changing the height and opacity
10464 el.shift({ x: 200, height: 50, opacity: .8 });
10466 // common config options shown with default values.
10468 width: [element's width],
10469 height: [element's height],
10470 x: [element's x position],
10471 y: [element's y position],
10472 opacity: [element's opacity],
10477 * @param {Object} options Object literal with any of the Fx config options
10478 * @return {Roo.Element} The Element
10480 shift : function(o){
10481 var el = this.getFxEl();
10483 el.queueFx(o, function(){
10484 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10485 if(w !== undefined){
10486 a.width = {to: this.adjustWidth(w)};
10488 if(h !== undefined){
10489 a.height = {to: this.adjustHeight(h)};
10491 if(x !== undefined || y !== undefined){
10493 x !== undefined ? x : this.getX(),
10494 y !== undefined ? y : this.getY()
10497 if(op !== undefined){
10498 a.opacity = {to: op};
10500 if(o.xy !== undefined){
10501 a.points = {to: o.xy};
10503 arguments.callee.anim = this.fxanim(a,
10504 o, 'motion', .35, "easeOut", function(){
10512 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10513 * ending point of the effect.
10516 // default: slide the element downward while fading out
10519 // custom: slide the element out to the right with a 2-second duration
10520 el.ghost('r', { duration: 2 });
10522 // common config options shown with default values
10530 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10531 * @param {Object} options (optional) Object literal with any of the Fx config options
10532 * @return {Roo.Element} The Element
10534 ghost : function(anchor, o){
10535 var el = this.getFxEl();
10538 el.queueFx(o, function(){
10539 anchor = anchor || "b";
10541 // restore values after effect
10542 var r = this.getFxRestore();
10543 var w = this.getWidth(),
10544 h = this.getHeight();
10546 var st = this.dom.style;
10548 var after = function(){
10550 el.setDisplayed(false);
10556 el.setPositioning(r.pos);
10557 st.width = r.width;
10558 st.height = r.height;
10563 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10564 switch(anchor.toLowerCase()){
10591 arguments.callee.anim = this.fxanim(a,
10601 * Ensures that all effects queued after syncFx is called on the element are
10602 * run concurrently. This is the opposite of {@link #sequenceFx}.
10603 * @return {Roo.Element} The Element
10605 syncFx : function(){
10606 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10615 * Ensures that all effects queued after sequenceFx is called on the element are
10616 * run in sequence. This is the opposite of {@link #syncFx}.
10617 * @return {Roo.Element} The Element
10619 sequenceFx : function(){
10620 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10622 concurrent : false,
10629 nextFx : function(){
10630 var ef = this.fxQueue[0];
10637 * Returns true if the element has any effects actively running or queued, else returns false.
10638 * @return {Boolean} True if element has active effects, else false
10640 hasActiveFx : function(){
10641 return this.fxQueue && this.fxQueue[0];
10645 * Stops any running effects and clears the element's internal effects queue if it contains
10646 * any additional effects that haven't started yet.
10647 * @return {Roo.Element} The Element
10649 stopFx : function(){
10650 if(this.hasActiveFx()){
10651 var cur = this.fxQueue[0];
10652 if(cur && cur.anim && cur.anim.isAnimated()){
10653 this.fxQueue = [cur]; // clear out others
10654 cur.anim.stop(true);
10661 beforeFx : function(o){
10662 if(this.hasActiveFx() && !o.concurrent){
10673 * Returns true if the element is currently blocking so that no other effect can be queued
10674 * until this effect is finished, else returns false if blocking is not set. This is commonly
10675 * used to ensure that an effect initiated by a user action runs to completion prior to the
10676 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10677 * @return {Boolean} True if blocking, else false
10679 hasFxBlock : function(){
10680 var q = this.fxQueue;
10681 return q && q[0] && q[0].block;
10685 queueFx : function(o, fn){
10689 if(!this.hasFxBlock()){
10690 Roo.applyIf(o, this.fxDefaults);
10692 var run = this.beforeFx(o);
10693 fn.block = o.block;
10694 this.fxQueue.push(fn);
10706 fxWrap : function(pos, o, vis){
10708 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10711 wrapXY = this.getXY();
10713 var div = document.createElement("div");
10714 div.style.visibility = vis;
10715 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10716 wrap.setPositioning(pos);
10717 if(wrap.getStyle("position") == "static"){
10718 wrap.position("relative");
10720 this.clearPositioning('auto');
10722 wrap.dom.appendChild(this.dom);
10724 wrap.setXY(wrapXY);
10731 fxUnwrap : function(wrap, pos, o){
10732 this.clearPositioning();
10733 this.setPositioning(pos);
10735 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10741 getFxRestore : function(){
10742 var st = this.dom.style;
10743 return {pos: this.getPositioning(), width: st.width, height : st.height};
10747 afterFx : function(o){
10749 this.applyStyles(o.afterStyle);
10752 this.addClass(o.afterCls);
10754 if(o.remove === true){
10757 Roo.callback(o.callback, o.scope, [this]);
10759 this.fxQueue.shift();
10765 getFxEl : function(){ // support for composite element fx
10766 return Roo.get(this.dom);
10770 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10771 animType = animType || 'run';
10773 var anim = Roo.lib.Anim[animType](
10775 (opt.duration || defaultDur) || .35,
10776 (opt.easing || defaultEase) || 'easeOut',
10778 Roo.callback(cb, this);
10787 // backwords compat
10788 Roo.Fx.resize = Roo.Fx.scale;
10790 //When included, Roo.Fx is automatically applied to Element so that all basic
10791 //effects are available directly via the Element API
10792 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10794 * Ext JS Library 1.1.1
10795 * Copyright(c) 2006-2007, Ext JS, LLC.
10797 * Originally Released Under LGPL - original licence link has changed is not relivant.
10800 * <script type="text/javascript">
10805 * @class Roo.CompositeElement
10806 * Standard composite class. Creates a Roo.Element for every element in the collection.
10808 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10809 * actions will be performed on all the elements in this collection.</b>
10811 * All methods return <i>this</i> and can be chained.
10813 var els = Roo.select("#some-el div.some-class", true);
10814 // or select directly from an existing element
10815 var el = Roo.get('some-el');
10816 el.select('div.some-class', true);
10818 els.setWidth(100); // all elements become 100 width
10819 els.hide(true); // all elements fade out and hide
10821 els.setWidth(100).hide(true);
10824 Roo.CompositeElement = function(els){
10825 this.elements = [];
10826 this.addElements(els);
10828 Roo.CompositeElement.prototype = {
10830 addElements : function(els){
10831 if(!els) return this;
10832 if(typeof els == "string"){
10833 els = Roo.Element.selectorFunction(els);
10835 var yels = this.elements;
10836 var index = yels.length-1;
10837 for(var i = 0, len = els.length; i < len; i++) {
10838 yels[++index] = Roo.get(els[i]);
10844 * Clears this composite and adds the elements returned by the passed selector.
10845 * @param {String/Array} els A string CSS selector, an array of elements or an element
10846 * @return {CompositeElement} this
10848 fill : function(els){
10849 this.elements = [];
10855 * Filters this composite to only elements that match the passed selector.
10856 * @param {String} selector A string CSS selector
10857 * @return {CompositeElement} this
10859 filter : function(selector){
10861 this.each(function(el){
10862 if(el.is(selector)){
10863 els[els.length] = el.dom;
10870 invoke : function(fn, args){
10871 var els = this.elements;
10872 for(var i = 0, len = els.length; i < len; i++) {
10873 Roo.Element.prototype[fn].apply(els[i], args);
10878 * Adds elements to this composite.
10879 * @param {String/Array} els A string CSS selector, an array of elements or an element
10880 * @return {CompositeElement} this
10882 add : function(els){
10883 if(typeof els == "string"){
10884 this.addElements(Roo.Element.selectorFunction(els));
10885 }else if(els.length !== undefined){
10886 this.addElements(els);
10888 this.addElements([els]);
10893 * Calls the passed function passing (el, this, index) for each element in this composite.
10894 * @param {Function} fn The function to call
10895 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10896 * @return {CompositeElement} this
10898 each : function(fn, scope){
10899 var els = this.elements;
10900 for(var i = 0, len = els.length; i < len; i++){
10901 if(fn.call(scope || els[i], els[i], this, i) === false) {
10909 * Returns the Element object at the specified index
10910 * @param {Number} index
10911 * @return {Roo.Element}
10913 item : function(index){
10914 return this.elements[index] || null;
10918 * Returns the first Element
10919 * @return {Roo.Element}
10921 first : function(){
10922 return this.item(0);
10926 * Returns the last Element
10927 * @return {Roo.Element}
10930 return this.item(this.elements.length-1);
10934 * Returns the number of elements in this composite
10937 getCount : function(){
10938 return this.elements.length;
10942 * Returns true if this composite contains the passed element
10945 contains : function(el){
10946 return this.indexOf(el) !== -1;
10950 * Returns true if this composite contains the passed element
10953 indexOf : function(el){
10954 return this.elements.indexOf(Roo.get(el));
10959 * Removes the specified element(s).
10960 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10961 * or an array of any of those.
10962 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10963 * @return {CompositeElement} this
10965 removeElement : function(el, removeDom){
10966 if(el instanceof Array){
10967 for(var i = 0, len = el.length; i < len; i++){
10968 this.removeElement(el[i]);
10972 var index = typeof el == 'number' ? el : this.indexOf(el);
10975 var d = this.elements[index];
10979 d.parentNode.removeChild(d);
10982 this.elements.splice(index, 1);
10988 * Replaces the specified element with the passed element.
10989 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10991 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10992 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10993 * @return {CompositeElement} this
10995 replaceElement : function(el, replacement, domReplace){
10996 var index = typeof el == 'number' ? el : this.indexOf(el);
10999 this.elements[index].replaceWith(replacement);
11001 this.elements.splice(index, 1, Roo.get(replacement))
11008 * Removes all elements.
11010 clear : function(){
11011 this.elements = [];
11015 Roo.CompositeElement.createCall = function(proto, fnName){
11016 if(!proto[fnName]){
11017 proto[fnName] = function(){
11018 return this.invoke(fnName, arguments);
11022 for(var fnName in Roo.Element.prototype){
11023 if(typeof Roo.Element.prototype[fnName] == "function"){
11024 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11030 * Ext JS Library 1.1.1
11031 * Copyright(c) 2006-2007, Ext JS, LLC.
11033 * Originally Released Under LGPL - original licence link has changed is not relivant.
11036 * <script type="text/javascript">
11040 * @class Roo.CompositeElementLite
11041 * @extends Roo.CompositeElement
11042 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11044 var els = Roo.select("#some-el div.some-class");
11045 // or select directly from an existing element
11046 var el = Roo.get('some-el');
11047 el.select('div.some-class');
11049 els.setWidth(100); // all elements become 100 width
11050 els.hide(true); // all elements fade out and hide
11052 els.setWidth(100).hide(true);
11053 </code></pre><br><br>
11054 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11055 * actions will be performed on all the elements in this collection.</b>
11057 Roo.CompositeElementLite = function(els){
11058 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11059 this.el = new Roo.Element.Flyweight();
11061 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11062 addElements : function(els){
11064 if(els instanceof Array){
11065 this.elements = this.elements.concat(els);
11067 var yels = this.elements;
11068 var index = yels.length-1;
11069 for(var i = 0, len = els.length; i < len; i++) {
11070 yels[++index] = els[i];
11076 invoke : function(fn, args){
11077 var els = this.elements;
11079 for(var i = 0, len = els.length; i < len; i++) {
11081 Roo.Element.prototype[fn].apply(el, args);
11086 * Returns a flyweight Element of the dom element object at the specified index
11087 * @param {Number} index
11088 * @return {Roo.Element}
11090 item : function(index){
11091 if(!this.elements[index]){
11094 this.el.dom = this.elements[index];
11098 // fixes scope with flyweight
11099 addListener : function(eventName, handler, scope, opt){
11100 var els = this.elements;
11101 for(var i = 0, len = els.length; i < len; i++) {
11102 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11108 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11109 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11110 * a reference to the dom node, use el.dom.</b>
11111 * @param {Function} fn The function to call
11112 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11113 * @return {CompositeElement} this
11115 each : function(fn, scope){
11116 var els = this.elements;
11118 for(var i = 0, len = els.length; i < len; i++){
11120 if(fn.call(scope || el, el, this, i) === false){
11127 indexOf : function(el){
11128 return this.elements.indexOf(Roo.getDom(el));
11131 replaceElement : function(el, replacement, domReplace){
11132 var index = typeof el == 'number' ? el : this.indexOf(el);
11134 replacement = Roo.getDom(replacement);
11136 var d = this.elements[index];
11137 d.parentNode.insertBefore(replacement, d);
11138 d.parentNode.removeChild(d);
11140 this.elements.splice(index, 1, replacement);
11145 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11149 * Ext JS Library 1.1.1
11150 * Copyright(c) 2006-2007, Ext JS, LLC.
11152 * Originally Released Under LGPL - original licence link has changed is not relivant.
11155 * <script type="text/javascript">
11161 * @class Roo.data.Connection
11162 * @extends Roo.util.Observable
11163 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11164 * either to a configured URL, or to a URL specified at request time.<br><br>
11166 * Requests made by this class are asynchronous, and will return immediately. No data from
11167 * the server will be available to the statement immediately following the {@link #request} call.
11168 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11170 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11171 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11172 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11173 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11174 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11175 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11176 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11177 * standard DOM methods.
11179 * @param {Object} config a configuration object.
11181 Roo.data.Connection = function(config){
11182 Roo.apply(this, config);
11185 * @event beforerequest
11186 * Fires before a network request is made to retrieve a data object.
11187 * @param {Connection} conn This Connection object.
11188 * @param {Object} options The options config object passed to the {@link #request} method.
11190 "beforerequest" : true,
11192 * @event requestcomplete
11193 * Fires if the request was successfully completed.
11194 * @param {Connection} conn This Connection object.
11195 * @param {Object} response The XHR object containing the response data.
11196 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11197 * @param {Object} options The options config object passed to the {@link #request} method.
11199 "requestcomplete" : true,
11201 * @event requestexception
11202 * Fires if an error HTTP status was returned from the server.
11203 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11204 * @param {Connection} conn This Connection object.
11205 * @param {Object} response The XHR object containing the response data.
11206 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11207 * @param {Object} options The options config object passed to the {@link #request} method.
11209 "requestexception" : true
11211 Roo.data.Connection.superclass.constructor.call(this);
11214 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11216 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11219 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11220 * extra parameters to each request made by this object. (defaults to undefined)
11223 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11224 * to each request made by this object. (defaults to undefined)
11227 * @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)
11230 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11234 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11240 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11243 disableCaching: true,
11246 * Sends an HTTP request to a remote server.
11247 * @param {Object} options An object which may contain the following properties:<ul>
11248 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11249 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11250 * request, a url encoded string or a function to call to get either.</li>
11251 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11252 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11253 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11254 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11255 * <li>options {Object} The parameter to the request call.</li>
11256 * <li>success {Boolean} True if the request succeeded.</li>
11257 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11259 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11260 * The callback is passed the following parameters:<ul>
11261 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11262 * <li>options {Object} The parameter to the request call.</li>
11264 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11265 * The callback is passed the following parameters:<ul>
11266 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11267 * <li>options {Object} The parameter to the request call.</li>
11269 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11270 * for the callback function. Defaults to the browser window.</li>
11271 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11272 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11273 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11274 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11275 * params for the post data. Any params will be appended to the URL.</li>
11276 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11278 * @return {Number} transactionId
11280 request : function(o){
11281 if(this.fireEvent("beforerequest", this, o) !== false){
11284 if(typeof p == "function"){
11285 p = p.call(o.scope||window, o);
11287 if(typeof p == "object"){
11288 p = Roo.urlEncode(o.params);
11290 if(this.extraParams){
11291 var extras = Roo.urlEncode(this.extraParams);
11292 p = p ? (p + '&' + extras) : extras;
11295 var url = o.url || this.url;
11296 if(typeof url == 'function'){
11297 url = url.call(o.scope||window, o);
11301 var form = Roo.getDom(o.form);
11302 url = url || form.action;
11304 var enctype = form.getAttribute("enctype");
11305 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11306 return this.doFormUpload(o, p, url);
11308 var f = Roo.lib.Ajax.serializeForm(form);
11309 p = p ? (p + '&' + f) : f;
11312 var hs = o.headers;
11313 if(this.defaultHeaders){
11314 hs = Roo.apply(hs || {}, this.defaultHeaders);
11321 success: this.handleResponse,
11322 failure: this.handleFailure,
11324 argument: {options: o},
11325 timeout : this.timeout
11328 var method = o.method||this.method||(p ? "POST" : "GET");
11330 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11331 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11334 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11338 }else if(this.autoAbort !== false){
11342 if((method == 'GET' && p) || o.xmlData){
11343 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11346 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11347 return this.transId;
11349 Roo.callback(o.callback, o.scope, [o, null, null]);
11355 * Determine whether this object has a request outstanding.
11356 * @param {Number} transactionId (Optional) defaults to the last transaction
11357 * @return {Boolean} True if there is an outstanding request.
11359 isLoading : function(transId){
11361 return Roo.lib.Ajax.isCallInProgress(transId);
11363 return this.transId ? true : false;
11368 * Aborts any outstanding request.
11369 * @param {Number} transactionId (Optional) defaults to the last transaction
11371 abort : function(transId){
11372 if(transId || this.isLoading()){
11373 Roo.lib.Ajax.abort(transId || this.transId);
11378 handleResponse : function(response){
11379 this.transId = false;
11380 var options = response.argument.options;
11381 response.argument = options ? options.argument : null;
11382 this.fireEvent("requestcomplete", this, response, options);
11383 Roo.callback(options.success, options.scope, [response, options]);
11384 Roo.callback(options.callback, options.scope, [options, true, response]);
11388 handleFailure : function(response, e){
11389 this.transId = false;
11390 var options = response.argument.options;
11391 response.argument = options ? options.argument : null;
11392 this.fireEvent("requestexception", this, response, options, e);
11393 Roo.callback(options.failure, options.scope, [response, options]);
11394 Roo.callback(options.callback, options.scope, [options, false, response]);
11398 doFormUpload : function(o, ps, url){
11400 var frame = document.createElement('iframe');
11403 frame.className = 'x-hidden';
11405 frame.src = Roo.SSL_SECURE_URL;
11407 document.body.appendChild(frame);
11410 document.frames[id].name = id;
11413 var form = Roo.getDom(o.form);
11415 form.method = 'POST';
11416 form.enctype = form.encoding = 'multipart/form-data';
11422 if(ps){ // add dynamic params
11424 ps = Roo.urlDecode(ps, false);
11426 if(ps.hasOwnProperty(k)){
11427 hd = document.createElement('input');
11428 hd.type = 'hidden';
11431 form.appendChild(hd);
11438 var r = { // bogus response object
11443 r.argument = o ? o.argument : null;
11448 doc = frame.contentWindow.document;
11450 doc = (frame.contentDocument || window.frames[id].document);
11452 if(doc && doc.body){
11453 r.responseText = doc.body.innerHTML;
11455 if(doc && doc.XMLDocument){
11456 r.responseXML = doc.XMLDocument;
11458 r.responseXML = doc;
11465 Roo.EventManager.removeListener(frame, 'load', cb, this);
11467 this.fireEvent("requestcomplete", this, r, o);
11468 Roo.callback(o.success, o.scope, [r, o]);
11469 Roo.callback(o.callback, o.scope, [o, true, r]);
11471 setTimeout(function(){document.body.removeChild(frame);}, 100);
11474 Roo.EventManager.on(frame, 'load', cb, this);
11477 if(hiddens){ // remove dynamic params
11478 for(var i = 0, len = hiddens.length; i < len; i++){
11479 form.removeChild(hiddens[i]);
11487 * @extends Roo.data.Connection
11488 * Global Ajax request class.
11492 Roo.Ajax = new Roo.data.Connection({
11495 * @cfg {String} url @hide
11498 * @cfg {Object} extraParams @hide
11501 * @cfg {Object} defaultHeaders @hide
11504 * @cfg {String} method (Optional) @hide
11507 * @cfg {Number} timeout (Optional) @hide
11510 * @cfg {Boolean} autoAbort (Optional) @hide
11514 * @cfg {Boolean} disableCaching (Optional) @hide
11518 * @property disableCaching
11519 * True to add a unique cache-buster param to GET requests. (defaults to true)
11524 * The default URL to be used for requests to the server. (defaults to undefined)
11528 * @property extraParams
11529 * An object containing properties which are used as
11530 * extra parameters to each request made by this object. (defaults to undefined)
11534 * @property defaultHeaders
11535 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11540 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11544 * @property timeout
11545 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11550 * @property autoAbort
11551 * Whether a new request should abort any pending requests. (defaults to false)
11557 * Serialize the passed form into a url encoded string
11558 * @param {String/HTMLElement} form
11561 serializeForm : function(form){
11562 return Roo.lib.Ajax.serializeForm(form);
11566 * Ext JS Library 1.1.1
11567 * Copyright(c) 2006-2007, Ext JS, LLC.
11569 * Originally Released Under LGPL - original licence link has changed is not relivant.
11572 * <script type="text/javascript">
11576 * Global Ajax request class.
11579 * @extends Roo.data.Connection
11582 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11583 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11584 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11585 * @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)
11586 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11587 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11588 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11590 Roo.Ajax = new Roo.data.Connection({
11599 * Serialize the passed form into a url encoded string
11601 * @param {String/HTMLElement} form
11604 serializeForm : function(form){
11605 return Roo.lib.Ajax.serializeForm(form);
11609 * Ext JS Library 1.1.1
11610 * Copyright(c) 2006-2007, Ext JS, LLC.
11612 * Originally Released Under LGPL - original licence link has changed is not relivant.
11615 * <script type="text/javascript">
11620 * @class Roo.UpdateManager
11621 * @extends Roo.util.Observable
11622 * Provides AJAX-style update for Element object.<br><br>
11625 * // Get it from a Roo.Element object
11626 * var el = Roo.get("foo");
11627 * var mgr = el.getUpdateManager();
11628 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11630 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11632 * // or directly (returns the same UpdateManager instance)
11633 * var mgr = new Roo.UpdateManager("myElementId");
11634 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11635 * mgr.on("update", myFcnNeedsToKnow);
11637 // short handed call directly from the element object
11638 Roo.get("foo").load({
11642 text: "Loading Foo..."
11646 * Create new UpdateManager directly.
11647 * @param {String/HTMLElement/Roo.Element} el The element to update
11648 * @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).
11650 Roo.UpdateManager = function(el, forceNew){
11652 if(!forceNew && el.updateManager){
11653 return el.updateManager;
11656 * The Element object
11657 * @type Roo.Element
11661 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11664 this.defaultUrl = null;
11668 * @event beforeupdate
11669 * Fired before an update is made, return false from your handler and the update is cancelled.
11670 * @param {Roo.Element} el
11671 * @param {String/Object/Function} url
11672 * @param {String/Object} params
11674 "beforeupdate": true,
11677 * Fired after successful update is made.
11678 * @param {Roo.Element} el
11679 * @param {Object} oResponseObject The response Object
11684 * Fired on update failure.
11685 * @param {Roo.Element} el
11686 * @param {Object} oResponseObject The response Object
11690 var d = Roo.UpdateManager.defaults;
11692 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11695 this.sslBlankUrl = d.sslBlankUrl;
11697 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11700 this.disableCaching = d.disableCaching;
11702 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11705 this.indicatorText = d.indicatorText;
11707 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11710 this.showLoadIndicator = d.showLoadIndicator;
11712 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11715 this.timeout = d.timeout;
11718 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11721 this.loadScripts = d.loadScripts;
11724 * Transaction object of current executing transaction
11726 this.transaction = null;
11731 this.autoRefreshProcId = null;
11733 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11736 this.refreshDelegate = this.refresh.createDelegate(this);
11738 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11741 this.updateDelegate = this.update.createDelegate(this);
11743 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11746 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11750 this.successDelegate = this.processSuccess.createDelegate(this);
11754 this.failureDelegate = this.processFailure.createDelegate(this);
11756 if(!this.renderer){
11758 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11760 this.renderer = new Roo.UpdateManager.BasicRenderer();
11763 Roo.UpdateManager.superclass.constructor.call(this);
11766 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11768 * Get the Element this UpdateManager is bound to
11769 * @return {Roo.Element} The element
11771 getEl : function(){
11775 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11776 * @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:
11779 url: "your-url.php",<br/>
11780 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11781 callback: yourFunction,<br/>
11782 scope: yourObject, //(optional scope) <br/>
11783 discardUrl: false, <br/>
11784 nocache: false,<br/>
11785 text: "Loading...",<br/>
11787 scripts: false<br/>
11790 * The only required property is url. The optional properties nocache, text and scripts
11791 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11792 * @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}
11793 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11794 * @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.
11796 update : function(url, params, callback, discardUrl){
11797 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11798 var method = this.method, cfg;
11799 if(typeof url == "object"){ // must be config object
11802 params = params || cfg.params;
11803 callback = callback || cfg.callback;
11804 discardUrl = discardUrl || cfg.discardUrl;
11805 if(callback && cfg.scope){
11806 callback = callback.createDelegate(cfg.scope);
11808 if(typeof cfg.method != "undefined"){method = cfg.method;};
11809 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11810 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11811 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11812 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11814 this.showLoading();
11816 this.defaultUrl = url;
11818 if(typeof url == "function"){
11819 url = url.call(this);
11822 method = method || (params ? "POST" : "GET");
11823 if(method == "GET"){
11824 url = this.prepareUrl(url);
11827 var o = Roo.apply(cfg ||{}, {
11830 success: this.successDelegate,
11831 failure: this.failureDelegate,
11832 callback: undefined,
11833 timeout: (this.timeout*1000),
11834 argument: {"url": url, "form": null, "callback": callback, "params": params}
11837 this.transaction = Roo.Ajax.request(o);
11842 * 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.
11843 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11844 * @param {String/HTMLElement} form The form Id or form element
11845 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11846 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11847 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11849 formUpdate : function(form, url, reset, callback){
11850 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11851 if(typeof url == "function"){
11852 url = url.call(this);
11854 form = Roo.getDom(form);
11855 this.transaction = Roo.Ajax.request({
11858 success: this.successDelegate,
11859 failure: this.failureDelegate,
11860 timeout: (this.timeout*1000),
11861 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11863 this.showLoading.defer(1, this);
11868 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11869 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11871 refresh : function(callback){
11872 if(this.defaultUrl == null){
11875 this.update(this.defaultUrl, null, callback, true);
11879 * Set this element to auto refresh.
11880 * @param {Number} interval How often to update (in seconds).
11881 * @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)
11882 * @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}
11883 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11884 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11886 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11888 this.update(url || this.defaultUrl, params, callback, true);
11890 if(this.autoRefreshProcId){
11891 clearInterval(this.autoRefreshProcId);
11893 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11897 * Stop auto refresh on this element.
11899 stopAutoRefresh : function(){
11900 if(this.autoRefreshProcId){
11901 clearInterval(this.autoRefreshProcId);
11902 delete this.autoRefreshProcId;
11906 isAutoRefreshing : function(){
11907 return this.autoRefreshProcId ? true : false;
11910 * Called to update the element to "Loading" state. Override to perform custom action.
11912 showLoading : function(){
11913 if(this.showLoadIndicator){
11914 this.el.update(this.indicatorText);
11919 * Adds unique parameter to query string if disableCaching = true
11922 prepareUrl : function(url){
11923 if(this.disableCaching){
11924 var append = "_dc=" + (new Date().getTime());
11925 if(url.indexOf("?") !== -1){
11926 url += "&" + append;
11928 url += "?" + append;
11937 processSuccess : function(response){
11938 this.transaction = null;
11939 if(response.argument.form && response.argument.reset){
11940 try{ // put in try/catch since some older FF releases had problems with this
11941 response.argument.form.reset();
11944 if(this.loadScripts){
11945 this.renderer.render(this.el, response, this,
11946 this.updateComplete.createDelegate(this, [response]));
11948 this.renderer.render(this.el, response, this);
11949 this.updateComplete(response);
11953 updateComplete : function(response){
11954 this.fireEvent("update", this.el, response);
11955 if(typeof response.argument.callback == "function"){
11956 response.argument.callback(this.el, true, response);
11963 processFailure : function(response){
11964 this.transaction = null;
11965 this.fireEvent("failure", this.el, response);
11966 if(typeof response.argument.callback == "function"){
11967 response.argument.callback(this.el, false, response);
11972 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11973 * @param {Object} renderer The object implementing the render() method
11975 setRenderer : function(renderer){
11976 this.renderer = renderer;
11979 getRenderer : function(){
11980 return this.renderer;
11984 * Set the defaultUrl used for updates
11985 * @param {String/Function} defaultUrl The url or a function to call to get the url
11987 setDefaultUrl : function(defaultUrl){
11988 this.defaultUrl = defaultUrl;
11992 * Aborts the executing transaction
11994 abort : function(){
11995 if(this.transaction){
11996 Roo.Ajax.abort(this.transaction);
12001 * Returns true if an update is in progress
12002 * @return {Boolean}
12004 isUpdating : function(){
12005 if(this.transaction){
12006 return Roo.Ajax.isLoading(this.transaction);
12013 * @class Roo.UpdateManager.defaults
12014 * @static (not really - but it helps the doc tool)
12015 * The defaults collection enables customizing the default properties of UpdateManager
12017 Roo.UpdateManager.defaults = {
12019 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12025 * True to process scripts by default (Defaults to false).
12028 loadScripts : false,
12031 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12034 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12036 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12039 disableCaching : false,
12041 * Whether to show indicatorText when loading (Defaults to true).
12044 showLoadIndicator : true,
12046 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12049 indicatorText : '<div class="loading-indicator">Loading...</div>'
12053 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12055 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12056 * @param {String/HTMLElement/Roo.Element} el The element to update
12057 * @param {String} url The url
12058 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12059 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12062 * @member Roo.UpdateManager
12064 Roo.UpdateManager.updateElement = function(el, url, params, options){
12065 var um = Roo.get(el, true).getUpdateManager();
12066 Roo.apply(um, options);
12067 um.update(url, params, options ? options.callback : null);
12069 // alias for backwards compat
12070 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12072 * @class Roo.UpdateManager.BasicRenderer
12073 * Default Content renderer. Updates the elements innerHTML with the responseText.
12075 Roo.UpdateManager.BasicRenderer = function(){};
12077 Roo.UpdateManager.BasicRenderer.prototype = {
12079 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12080 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12081 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12082 * @param {Roo.Element} el The element being rendered
12083 * @param {Object} response The YUI Connect response object
12084 * @param {UpdateManager} updateManager The calling update manager
12085 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12087 render : function(el, response, updateManager, callback){
12088 el.update(response.responseText, updateManager.loadScripts, callback);
12093 * Ext JS Library 1.1.1
12094 * Copyright(c) 2006-2007, Ext JS, LLC.
12096 * Originally Released Under LGPL - original licence link has changed is not relivant.
12099 * <script type="text/javascript">
12103 * @class Roo.util.DelayedTask
12104 * Provides a convenient method of performing setTimeout where a new
12105 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12106 * You can use this class to buffer
12107 * the keypress events for a certain number of milliseconds, and perform only if they stop
12108 * for that amount of time.
12109 * @constructor The parameters to this constructor serve as defaults and are not required.
12110 * @param {Function} fn (optional) The default function to timeout
12111 * @param {Object} scope (optional) The default scope of that timeout
12112 * @param {Array} args (optional) The default Array of arguments
12114 Roo.util.DelayedTask = function(fn, scope, args){
12115 var id = null, d, t;
12117 var call = function(){
12118 var now = new Date().getTime();
12122 fn.apply(scope, args || []);
12126 * Cancels any pending timeout and queues a new one
12127 * @param {Number} delay The milliseconds to delay
12128 * @param {Function} newFn (optional) Overrides function passed to constructor
12129 * @param {Object} newScope (optional) Overrides scope passed to constructor
12130 * @param {Array} newArgs (optional) Overrides args passed to constructor
12132 this.delay = function(delay, newFn, newScope, newArgs){
12133 if(id && delay != d){
12137 t = new Date().getTime();
12139 scope = newScope || scope;
12140 args = newArgs || args;
12142 id = setInterval(call, d);
12147 * Cancel the last queued timeout
12149 this.cancel = function(){
12157 * Ext JS Library 1.1.1
12158 * Copyright(c) 2006-2007, Ext JS, LLC.
12160 * Originally Released Under LGPL - original licence link has changed is not relivant.
12163 * <script type="text/javascript">
12167 Roo.util.TaskRunner = function(interval){
12168 interval = interval || 10;
12169 var tasks = [], removeQueue = [];
12171 var running = false;
12173 var stopThread = function(){
12179 var startThread = function(){
12182 id = setInterval(runTasks, interval);
12186 var removeTask = function(task){
12187 removeQueue.push(task);
12193 var runTasks = function(){
12194 if(removeQueue.length > 0){
12195 for(var i = 0, len = removeQueue.length; i < len; i++){
12196 tasks.remove(removeQueue[i]);
12199 if(tasks.length < 1){
12204 var now = new Date().getTime();
12205 for(var i = 0, len = tasks.length; i < len; ++i){
12207 var itime = now - t.taskRunTime;
12208 if(t.interval <= itime){
12209 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12210 t.taskRunTime = now;
12211 if(rt === false || t.taskRunCount === t.repeat){
12216 if(t.duration && t.duration <= (now - t.taskStartTime)){
12223 * Queues a new task.
12224 * @param {Object} task
12226 this.start = function(task){
12228 task.taskStartTime = new Date().getTime();
12229 task.taskRunTime = 0;
12230 task.taskRunCount = 0;
12235 this.stop = function(task){
12240 this.stopAll = function(){
12242 for(var i = 0, len = tasks.length; i < len; i++){
12243 if(tasks[i].onStop){
12252 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12254 * Ext JS Library 1.1.1
12255 * Copyright(c) 2006-2007, Ext JS, LLC.
12257 * Originally Released Under LGPL - original licence link has changed is not relivant.
12260 * <script type="text/javascript">
12265 * @class Roo.util.MixedCollection
12266 * @extends Roo.util.Observable
12267 * A Collection class that maintains both numeric indexes and keys and exposes events.
12269 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12270 * collection (defaults to false)
12271 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12272 * and return the key value for that item. This is used when available to look up the key on items that
12273 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12274 * equivalent to providing an implementation for the {@link #getKey} method.
12276 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12284 * Fires when the collection is cleared.
12289 * Fires when an item is added to the collection.
12290 * @param {Number} index The index at which the item was added.
12291 * @param {Object} o The item added.
12292 * @param {String} key The key associated with the added item.
12297 * Fires when an item is replaced in the collection.
12298 * @param {String} key he key associated with the new added.
12299 * @param {Object} old The item being replaced.
12300 * @param {Object} new The new item.
12305 * Fires when an item is removed from the collection.
12306 * @param {Object} o The item being removed.
12307 * @param {String} key (optional) The key associated with the removed item.
12312 this.allowFunctions = allowFunctions === true;
12314 this.getKey = keyFn;
12316 Roo.util.MixedCollection.superclass.constructor.call(this);
12319 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12320 allowFunctions : false,
12323 * Adds an item to the collection.
12324 * @param {String} key The key to associate with the item
12325 * @param {Object} o The item to add.
12326 * @return {Object} The item added.
12328 add : function(key, o){
12329 if(arguments.length == 1){
12331 key = this.getKey(o);
12333 if(typeof key == "undefined" || key === null){
12335 this.items.push(o);
12336 this.keys.push(null);
12338 var old = this.map[key];
12340 return this.replace(key, o);
12343 this.items.push(o);
12345 this.keys.push(key);
12347 this.fireEvent("add", this.length-1, o, key);
12352 * MixedCollection has a generic way to fetch keys if you implement getKey.
12355 var mc = new Roo.util.MixedCollection();
12356 mc.add(someEl.dom.id, someEl);
12357 mc.add(otherEl.dom.id, otherEl);
12361 var mc = new Roo.util.MixedCollection();
12362 mc.getKey = function(el){
12368 // or via the constructor
12369 var mc = new Roo.util.MixedCollection(false, function(el){
12375 * @param o {Object} The item for which to find the key.
12376 * @return {Object} The key for the passed item.
12378 getKey : function(o){
12383 * Replaces an item in the collection.
12384 * @param {String} key The key associated with the item to replace, or the item to replace.
12385 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12386 * @return {Object} The new item.
12388 replace : function(key, o){
12389 if(arguments.length == 1){
12391 key = this.getKey(o);
12393 var old = this.item(key);
12394 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12395 return this.add(key, o);
12397 var index = this.indexOfKey(key);
12398 this.items[index] = o;
12400 this.fireEvent("replace", key, old, o);
12405 * Adds all elements of an Array or an Object to the collection.
12406 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12407 * an Array of values, each of which are added to the collection.
12409 addAll : function(objs){
12410 if(arguments.length > 1 || objs instanceof Array){
12411 var args = arguments.length > 1 ? arguments : objs;
12412 for(var i = 0, len = args.length; i < len; i++){
12416 for(var key in objs){
12417 if(this.allowFunctions || typeof objs[key] != "function"){
12418 this.add(key, objs[key]);
12425 * Executes the specified function once for every item in the collection, passing each
12426 * item as the first and only parameter. returning false from the function will stop the iteration.
12427 * @param {Function} fn The function to execute for each item.
12428 * @param {Object} scope (optional) The scope in which to execute the function.
12430 each : function(fn, scope){
12431 var items = [].concat(this.items); // each safe for removal
12432 for(var i = 0, len = items.length; i < len; i++){
12433 if(fn.call(scope || items[i], items[i], i, len) === false){
12440 * Executes the specified function once for every key in the collection, passing each
12441 * key, and its associated item as the first two parameters.
12442 * @param {Function} fn The function to execute for each item.
12443 * @param {Object} scope (optional) The scope in which to execute the function.
12445 eachKey : function(fn, scope){
12446 for(var i = 0, len = this.keys.length; i < len; i++){
12447 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12452 * Returns the first item in the collection which elicits a true return value from the
12453 * passed selection function.
12454 * @param {Function} fn The selection function to execute for each item.
12455 * @param {Object} scope (optional) The scope in which to execute the function.
12456 * @return {Object} The first item in the collection which returned true from the selection function.
12458 find : function(fn, scope){
12459 for(var i = 0, len = this.items.length; i < len; i++){
12460 if(fn.call(scope || window, this.items[i], this.keys[i])){
12461 return this.items[i];
12468 * Inserts an item at the specified index in the collection.
12469 * @param {Number} index The index to insert the item at.
12470 * @param {String} key The key to associate with the new item, or the item itself.
12471 * @param {Object} o (optional) If the second parameter was a key, the new item.
12472 * @return {Object} The item inserted.
12474 insert : function(index, key, o){
12475 if(arguments.length == 2){
12477 key = this.getKey(o);
12479 if(index >= this.length){
12480 return this.add(key, o);
12483 this.items.splice(index, 0, o);
12484 if(typeof key != "undefined" && key != null){
12487 this.keys.splice(index, 0, key);
12488 this.fireEvent("add", index, o, key);
12493 * Removed an item from the collection.
12494 * @param {Object} o The item to remove.
12495 * @return {Object} The item removed.
12497 remove : function(o){
12498 return this.removeAt(this.indexOf(o));
12502 * Remove an item from a specified index in the collection.
12503 * @param {Number} index The index within the collection of the item to remove.
12505 removeAt : function(index){
12506 if(index < this.length && index >= 0){
12508 var o = this.items[index];
12509 this.items.splice(index, 1);
12510 var key = this.keys[index];
12511 if(typeof key != "undefined"){
12512 delete this.map[key];
12514 this.keys.splice(index, 1);
12515 this.fireEvent("remove", o, key);
12520 * Removed an item associated with the passed key fom the collection.
12521 * @param {String} key The key of the item to remove.
12523 removeKey : function(key){
12524 return this.removeAt(this.indexOfKey(key));
12528 * Returns the number of items in the collection.
12529 * @return {Number} the number of items in the collection.
12531 getCount : function(){
12532 return this.length;
12536 * Returns index within the collection of the passed Object.
12537 * @param {Object} o The item to find the index of.
12538 * @return {Number} index of the item.
12540 indexOf : function(o){
12541 if(!this.items.indexOf){
12542 for(var i = 0, len = this.items.length; i < len; i++){
12543 if(this.items[i] == o) return i;
12547 return this.items.indexOf(o);
12552 * Returns index within the collection of the passed key.
12553 * @param {String} key The key to find the index of.
12554 * @return {Number} index of the key.
12556 indexOfKey : function(key){
12557 if(!this.keys.indexOf){
12558 for(var i = 0, len = this.keys.length; i < len; i++){
12559 if(this.keys[i] == key) return i;
12563 return this.keys.indexOf(key);
12568 * Returns the item associated with the passed key OR index. Key has priority over index.
12569 * @param {String/Number} key The key or index of the item.
12570 * @return {Object} The item associated with the passed key.
12572 item : function(key){
12573 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12574 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12578 * Returns the item at the specified index.
12579 * @param {Number} index The index of the item.
12582 itemAt : function(index){
12583 return this.items[index];
12587 * Returns the item associated with the passed key.
12588 * @param {String/Number} key The key of the item.
12589 * @return {Object} The item associated with the passed key.
12591 key : function(key){
12592 return this.map[key];
12596 * Returns true if the collection contains the passed Object as an item.
12597 * @param {Object} o The Object to look for in the collection.
12598 * @return {Boolean} True if the collection contains the Object as an item.
12600 contains : function(o){
12601 return this.indexOf(o) != -1;
12605 * Returns true if the collection contains the passed Object as a key.
12606 * @param {String} key The key to look for in the collection.
12607 * @return {Boolean} True if the collection contains the Object as a key.
12609 containsKey : function(key){
12610 return typeof this.map[key] != "undefined";
12614 * Removes all items from the collection.
12616 clear : function(){
12621 this.fireEvent("clear");
12625 * Returns the first item in the collection.
12626 * @return {Object} the first item in the collection..
12628 first : function(){
12629 return this.items[0];
12633 * Returns the last item in the collection.
12634 * @return {Object} the last item in the collection..
12637 return this.items[this.length-1];
12640 _sort : function(property, dir, fn){
12641 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12642 fn = fn || function(a, b){
12645 var c = [], k = this.keys, items = this.items;
12646 for(var i = 0, len = items.length; i < len; i++){
12647 c[c.length] = {key: k[i], value: items[i], index: i};
12649 c.sort(function(a, b){
12650 var v = fn(a[property], b[property]) * dsc;
12652 v = (a.index < b.index ? -1 : 1);
12656 for(var i = 0, len = c.length; i < len; i++){
12657 items[i] = c[i].value;
12660 this.fireEvent("sort", this);
12664 * Sorts this collection with the passed comparison function
12665 * @param {String} direction (optional) "ASC" or "DESC"
12666 * @param {Function} fn (optional) comparison function
12668 sort : function(dir, fn){
12669 this._sort("value", dir, fn);
12673 * Sorts this collection by keys
12674 * @param {String} direction (optional) "ASC" or "DESC"
12675 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12677 keySort : function(dir, fn){
12678 this._sort("key", dir, fn || function(a, b){
12679 return String(a).toUpperCase()-String(b).toUpperCase();
12684 * Returns a range of items in this collection
12685 * @param {Number} startIndex (optional) defaults to 0
12686 * @param {Number} endIndex (optional) default to the last item
12687 * @return {Array} An array of items
12689 getRange : function(start, end){
12690 var items = this.items;
12691 if(items.length < 1){
12694 start = start || 0;
12695 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12698 for(var i = start; i <= end; i++) {
12699 r[r.length] = items[i];
12702 for(var i = start; i >= end; i--) {
12703 r[r.length] = items[i];
12710 * Filter the <i>objects</i> in this collection by a specific property.
12711 * Returns a new collection that has been filtered.
12712 * @param {String} property A property on your objects
12713 * @param {String/RegExp} value Either string that the property values
12714 * should start with or a RegExp to test against the property
12715 * @return {MixedCollection} The new filtered collection
12717 filter : function(property, value){
12718 if(!value.exec){ // not a regex
12719 value = String(value);
12720 if(value.length == 0){
12721 return this.clone();
12723 value = new RegExp("^" + Roo.escapeRe(value), "i");
12725 return this.filterBy(function(o){
12726 return o && value.test(o[property]);
12731 * Filter by a function. * Returns a new collection that has been filtered.
12732 * The passed function will be called with each
12733 * object in the collection. If the function returns true, the value is included
12734 * otherwise it is filtered.
12735 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12736 * @param {Object} scope (optional) The scope of the function (defaults to this)
12737 * @return {MixedCollection} The new filtered collection
12739 filterBy : function(fn, scope){
12740 var r = new Roo.util.MixedCollection();
12741 r.getKey = this.getKey;
12742 var k = this.keys, it = this.items;
12743 for(var i = 0, len = it.length; i < len; i++){
12744 if(fn.call(scope||this, it[i], k[i])){
12745 r.add(k[i], it[i]);
12752 * Creates a duplicate of this collection
12753 * @return {MixedCollection}
12755 clone : function(){
12756 var r = new Roo.util.MixedCollection();
12757 var k = this.keys, it = this.items;
12758 for(var i = 0, len = it.length; i < len; i++){
12759 r.add(k[i], it[i]);
12761 r.getKey = this.getKey;
12766 * Returns the item associated with the passed key or index.
12768 * @param {String/Number} key The key or index of the item.
12769 * @return {Object} The item associated with the passed key.
12771 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12773 * Ext JS Library 1.1.1
12774 * Copyright(c) 2006-2007, Ext JS, LLC.
12776 * Originally Released Under LGPL - original licence link has changed is not relivant.
12779 * <script type="text/javascript">
12782 * @class Roo.util.JSON
12783 * Modified version of Douglas Crockford"s json.js that doesn"t
12784 * mess with the Object prototype
12785 * http://www.json.org/js.html
12788 Roo.util.JSON = new (function(){
12789 var useHasOwn = {}.hasOwnProperty ? true : false;
12791 // crashes Safari in some instances
12792 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12794 var pad = function(n) {
12795 return n < 10 ? "0" + n : n;
12808 var encodeString = function(s){
12809 if (/["\\\x00-\x1f]/.test(s)) {
12810 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12815 c = b.charCodeAt();
12817 Math.floor(c / 16).toString(16) +
12818 (c % 16).toString(16);
12821 return '"' + s + '"';
12824 var encodeArray = function(o){
12825 var a = ["["], b, i, l = o.length, v;
12826 for (i = 0; i < l; i += 1) {
12828 switch (typeof v) {
12837 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12845 var encodeDate = function(o){
12846 return '"' + o.getFullYear() + "-" +
12847 pad(o.getMonth() + 1) + "-" +
12848 pad(o.getDate()) + "T" +
12849 pad(o.getHours()) + ":" +
12850 pad(o.getMinutes()) + ":" +
12851 pad(o.getSeconds()) + '"';
12855 * Encodes an Object, Array or other value
12856 * @param {Mixed} o The variable to encode
12857 * @return {String} The JSON string
12859 this.encode = function(o)
12861 // should this be extended to fully wrap stringify..
12863 if(typeof o == "undefined" || o === null){
12865 }else if(o instanceof Array){
12866 return encodeArray(o);
12867 }else if(o instanceof Date){
12868 return encodeDate(o);
12869 }else if(typeof o == "string"){
12870 return encodeString(o);
12871 }else if(typeof o == "number"){
12872 return isFinite(o) ? String(o) : "null";
12873 }else if(typeof o == "boolean"){
12876 var a = ["{"], b, i, v;
12878 if(!useHasOwn || o.hasOwnProperty(i)) {
12880 switch (typeof v) {
12889 a.push(this.encode(i), ":",
12890 v === null ? "null" : this.encode(v));
12901 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12902 * @param {String} json The JSON string
12903 * @return {Object} The resulting object
12905 this.decode = function(json){
12907 return /** eval:var:json */ eval("(" + json + ')');
12911 * Shorthand for {@link Roo.util.JSON#encode}
12912 * @member Roo encode
12914 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12916 * Shorthand for {@link Roo.util.JSON#decode}
12917 * @member Roo decode
12919 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12922 * Ext JS Library 1.1.1
12923 * Copyright(c) 2006-2007, Ext JS, LLC.
12925 * Originally Released Under LGPL - original licence link has changed is not relivant.
12928 * <script type="text/javascript">
12932 * @class Roo.util.Format
12933 * Reusable data formatting functions
12936 Roo.util.Format = function(){
12937 var trimRe = /^\s+|\s+$/g;
12940 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12941 * @param {String} value The string to truncate
12942 * @param {Number} length The maximum length to allow before truncating
12943 * @return {String} The converted text
12945 ellipsis : function(value, len){
12946 if(value && value.length > len){
12947 return value.substr(0, len-3)+"...";
12953 * Checks a reference and converts it to empty string if it is undefined
12954 * @param {Mixed} value Reference to check
12955 * @return {Mixed} Empty string if converted, otherwise the original value
12957 undef : function(value){
12958 return typeof value != "undefined" ? value : "";
12962 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12963 * @param {String} value The string to encode
12964 * @return {String} The encoded text
12966 htmlEncode : function(value){
12967 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12971 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12972 * @param {String} value The string to decode
12973 * @return {String} The decoded text
12975 htmlDecode : function(value){
12976 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12980 * Trims any whitespace from either side of a string
12981 * @param {String} value The text to trim
12982 * @return {String} The trimmed text
12984 trim : function(value){
12985 return String(value).replace(trimRe, "");
12989 * Returns a substring from within an original string
12990 * @param {String} value The original text
12991 * @param {Number} start The start index of the substring
12992 * @param {Number} length The length of the substring
12993 * @return {String} The substring
12995 substr : function(value, start, length){
12996 return String(value).substr(start, length);
13000 * Converts a string to all lower case letters
13001 * @param {String} value The text to convert
13002 * @return {String} The converted text
13004 lowercase : function(value){
13005 return String(value).toLowerCase();
13009 * Converts a string to all upper case letters
13010 * @param {String} value The text to convert
13011 * @return {String} The converted text
13013 uppercase : function(value){
13014 return String(value).toUpperCase();
13018 * Converts the first character only of a string to upper case
13019 * @param {String} value The text to convert
13020 * @return {String} The converted text
13022 capitalize : function(value){
13023 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13027 call : function(value, fn){
13028 if(arguments.length > 2){
13029 var args = Array.prototype.slice.call(arguments, 2);
13030 args.unshift(value);
13032 return /** eval:var:value */ eval(fn).apply(window, args);
13034 /** eval:var:value */
13035 return /** eval:var:value */ eval(fn).call(window, value);
13041 * safer version of Math.toFixed..??/
13042 * @param {Number/String} value The numeric value to format
13043 * @param {Number/String} value Decimal places
13044 * @return {String} The formatted currency string
13046 toFixed : function(v, n)
13048 // why not use to fixed - precision is buggered???
13050 return Math.round(v-0);
13052 var fact = Math.pow(10,n+1);
13053 v = (Math.round((v-0)*fact))/fact;
13054 var z = (''+fact).substring(2);
13055 if (v == Math.floor(v)) {
13056 return Math.floor(v) + '.' + z;
13059 // now just padd decimals..
13060 var ps = String(v).split('.');
13061 var fd = (ps[1] + z);
13062 var r = fd.substring(0,n);
13063 var rm = fd.substring(n);
13065 return ps[0] + '.' + r;
13067 r*=1; // turn it into a number;
13069 if (String(r).length != n) {
13072 r = String(r).substring(1); // chop the end off.
13075 return ps[0] + '.' + r;
13080 * Format a number as US currency
13081 * @param {Number/String} value The numeric value to format
13082 * @return {String} The formatted currency string
13084 usMoney : function(v){
13085 v = (Math.round((v-0)*100))/100;
13086 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13088 var ps = v.split('.');
13090 var sub = ps[1] ? '.'+ ps[1] : '.00';
13091 var r = /(\d+)(\d{3})/;
13092 while (r.test(whole)) {
13093 whole = whole.replace(r, '$1' + ',' + '$2');
13095 return "$" + whole + sub ;
13099 * Parse a value into a formatted date using the specified format pattern.
13100 * @param {Mixed} value The value to format
13101 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13102 * @return {String} The formatted date string
13104 date : function(v, format){
13108 if(!(v instanceof Date)){
13109 v = new Date(Date.parse(v));
13111 return v.dateFormat(format || "m/d/Y");
13115 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13116 * @param {String} format Any valid date format string
13117 * @return {Function} The date formatting function
13119 dateRenderer : function(format){
13120 return function(v){
13121 return Roo.util.Format.date(v, format);
13126 stripTagsRE : /<\/?[^>]+>/gi,
13129 * Strips all HTML tags
13130 * @param {Mixed} value The text from which to strip tags
13131 * @return {String} The stripped text
13133 stripTags : function(v){
13134 return !v ? v : String(v).replace(this.stripTagsRE, "");
13139 * Ext JS Library 1.1.1
13140 * Copyright(c) 2006-2007, Ext JS, LLC.
13142 * Originally Released Under LGPL - original licence link has changed is not relivant.
13145 * <script type="text/javascript">
13152 * @class Roo.MasterTemplate
13153 * @extends Roo.Template
13154 * Provides a template that can have child templates. The syntax is:
13156 var t = new Roo.MasterTemplate(
13157 '<select name="{name}">',
13158 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13161 t.add('options', {value: 'foo', text: 'bar'});
13162 // or you can add multiple child elements in one shot
13163 t.addAll('options', [
13164 {value: 'foo', text: 'bar'},
13165 {value: 'foo2', text: 'bar2'},
13166 {value: 'foo3', text: 'bar3'}
13168 // then append, applying the master template values
13169 t.append('my-form', {name: 'my-select'});
13171 * A name attribute for the child template is not required if you have only one child
13172 * template or you want to refer to them by index.
13174 Roo.MasterTemplate = function(){
13175 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13176 this.originalHtml = this.html;
13178 var m, re = this.subTemplateRe;
13181 while(m = re.exec(this.html)){
13182 var name = m[1], content = m[2];
13187 tpl : new Roo.Template(content)
13190 st[name] = st[subIndex];
13192 st[subIndex].tpl.compile();
13193 st[subIndex].tpl.call = this.call.createDelegate(this);
13196 this.subCount = subIndex;
13199 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13201 * The regular expression used to match sub templates
13205 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13208 * Applies the passed values to a child template.
13209 * @param {String/Number} name (optional) The name or index of the child template
13210 * @param {Array/Object} values The values to be applied to the template
13211 * @return {MasterTemplate} this
13213 add : function(name, values){
13214 if(arguments.length == 1){
13215 values = arguments[0];
13218 var s = this.subs[name];
13219 s.buffer[s.buffer.length] = s.tpl.apply(values);
13224 * Applies all the passed values to a child template.
13225 * @param {String/Number} name (optional) The name or index of the child template
13226 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13227 * @param {Boolean} reset (optional) True to reset the template first
13228 * @return {MasterTemplate} this
13230 fill : function(name, values, reset){
13232 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13240 for(var i = 0, len = values.length; i < len; i++){
13241 this.add(name, values[i]);
13247 * Resets the template for reuse
13248 * @return {MasterTemplate} this
13250 reset : function(){
13252 for(var i = 0; i < this.subCount; i++){
13258 applyTemplate : function(values){
13260 var replaceIndex = -1;
13261 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13262 return s[++replaceIndex].buffer.join("");
13264 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13267 apply : function(){
13268 return this.applyTemplate.apply(this, arguments);
13271 compile : function(){return this;}
13275 * Alias for fill().
13278 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13280 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13281 * var tpl = Roo.MasterTemplate.from('element-id');
13282 * @param {String/HTMLElement} el
13283 * @param {Object} config
13286 Roo.MasterTemplate.from = function(el, config){
13287 el = Roo.getDom(el);
13288 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13291 * Ext JS Library 1.1.1
13292 * Copyright(c) 2006-2007, Ext JS, LLC.
13294 * Originally Released Under LGPL - original licence link has changed is not relivant.
13297 * <script type="text/javascript">
13302 * @class Roo.util.CSS
13303 * Utility class for manipulating CSS rules
13306 Roo.util.CSS = function(){
13308 var doc = document;
13310 var camelRe = /(-[a-z])/gi;
13311 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13315 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13316 * tag and appended to the HEAD of the document.
13317 * @param {String|Object} cssText The text containing the css rules
13318 * @param {String} id An id to add to the stylesheet for later removal
13319 * @return {StyleSheet}
13321 createStyleSheet : function(cssText, id){
13323 var head = doc.getElementsByTagName("head")[0];
13324 var nrules = doc.createElement("style");
13325 nrules.setAttribute("type", "text/css");
13327 nrules.setAttribute("id", id);
13329 if (typeof(cssText) != 'string') {
13330 // support object maps..
13331 // not sure if this a good idea..
13332 // perhaps it should be merged with the general css handling
13333 // and handle js style props.
13334 var cssTextNew = [];
13335 for(var n in cssText) {
13337 for(var k in cssText[n]) {
13338 citems.push( k + ' : ' +cssText[n][k] + ';' );
13340 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13343 cssText = cssTextNew.join("\n");
13349 head.appendChild(nrules);
13350 ss = nrules.styleSheet;
13351 ss.cssText = cssText;
13354 nrules.appendChild(doc.createTextNode(cssText));
13356 nrules.cssText = cssText;
13358 head.appendChild(nrules);
13359 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13361 this.cacheStyleSheet(ss);
13366 * Removes a style or link tag by id
13367 * @param {String} id The id of the tag
13369 removeStyleSheet : function(id){
13370 var existing = doc.getElementById(id);
13372 existing.parentNode.removeChild(existing);
13377 * Dynamically swaps an existing stylesheet reference for a new one
13378 * @param {String} id The id of an existing link tag to remove
13379 * @param {String} url The href of the new stylesheet to include
13381 swapStyleSheet : function(id, url){
13382 this.removeStyleSheet(id);
13383 var ss = doc.createElement("link");
13384 ss.setAttribute("rel", "stylesheet");
13385 ss.setAttribute("type", "text/css");
13386 ss.setAttribute("id", id);
13387 ss.setAttribute("href", url);
13388 doc.getElementsByTagName("head")[0].appendChild(ss);
13392 * Refresh the rule cache if you have dynamically added stylesheets
13393 * @return {Object} An object (hash) of rules indexed by selector
13395 refreshCache : function(){
13396 return this.getRules(true);
13400 cacheStyleSheet : function(stylesheet){
13404 try{// try catch for cross domain access issue
13405 var ssRules = stylesheet.cssRules || stylesheet.rules;
13406 for(var j = ssRules.length-1; j >= 0; --j){
13407 rules[ssRules[j].selectorText] = ssRules[j];
13413 * Gets all css rules for the document
13414 * @param {Boolean} refreshCache true to refresh the internal cache
13415 * @return {Object} An object (hash) of rules indexed by selector
13417 getRules : function(refreshCache){
13418 if(rules == null || refreshCache){
13420 var ds = doc.styleSheets;
13421 for(var i =0, len = ds.length; i < len; i++){
13423 this.cacheStyleSheet(ds[i]);
13431 * Gets an an individual CSS rule by selector(s)
13432 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13433 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13434 * @return {CSSRule} The CSS rule or null if one is not found
13436 getRule : function(selector, refreshCache){
13437 var rs = this.getRules(refreshCache);
13438 if(!(selector instanceof Array)){
13439 return rs[selector];
13441 for(var i = 0; i < selector.length; i++){
13442 if(rs[selector[i]]){
13443 return rs[selector[i]];
13451 * Updates a rule property
13452 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13453 * @param {String} property The css property
13454 * @param {String} value The new value for the property
13455 * @return {Boolean} true If a rule was found and updated
13457 updateRule : function(selector, property, value){
13458 if(!(selector instanceof Array)){
13459 var rule = this.getRule(selector);
13461 rule.style[property.replace(camelRe, camelFn)] = value;
13465 for(var i = 0; i < selector.length; i++){
13466 if(this.updateRule(selector[i], property, value)){
13476 * Ext JS Library 1.1.1
13477 * Copyright(c) 2006-2007, Ext JS, LLC.
13479 * Originally Released Under LGPL - original licence link has changed is not relivant.
13482 * <script type="text/javascript">
13488 * @class Roo.util.ClickRepeater
13489 * @extends Roo.util.Observable
13491 * A wrapper class which can be applied to any element. Fires a "click" event while the
13492 * mouse is pressed. The interval between firings may be specified in the config but
13493 * defaults to 10 milliseconds.
13495 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13497 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13498 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13499 * Similar to an autorepeat key delay.
13500 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13501 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13502 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13503 * "interval" and "delay" are ignored. "immediate" is honored.
13504 * @cfg {Boolean} preventDefault True to prevent the default click event
13505 * @cfg {Boolean} stopDefault True to stop the default click event
13508 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13509 * 2007-02-02 jvs Renamed to ClickRepeater
13510 * 2007-02-03 jvs Modifications for FF Mac and Safari
13513 * @param {String/HTMLElement/Element} el The element to listen on
13514 * @param {Object} config
13516 Roo.util.ClickRepeater = function(el, config)
13518 this.el = Roo.get(el);
13519 this.el.unselectable();
13521 Roo.apply(this, config);
13526 * Fires when the mouse button is depressed.
13527 * @param {Roo.util.ClickRepeater} this
13529 "mousedown" : true,
13532 * Fires on a specified interval during the time the element is pressed.
13533 * @param {Roo.util.ClickRepeater} this
13538 * Fires when the mouse key is released.
13539 * @param {Roo.util.ClickRepeater} this
13544 this.el.on("mousedown", this.handleMouseDown, this);
13545 if(this.preventDefault || this.stopDefault){
13546 this.el.on("click", function(e){
13547 if(this.preventDefault){
13548 e.preventDefault();
13550 if(this.stopDefault){
13556 // allow inline handler
13558 this.on("click", this.handler, this.scope || this);
13561 Roo.util.ClickRepeater.superclass.constructor.call(this);
13564 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13567 preventDefault : true,
13568 stopDefault : false,
13572 handleMouseDown : function(){
13573 clearTimeout(this.timer);
13575 if(this.pressClass){
13576 this.el.addClass(this.pressClass);
13578 this.mousedownTime = new Date();
13580 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13581 this.el.on("mouseout", this.handleMouseOut, this);
13583 this.fireEvent("mousedown", this);
13584 this.fireEvent("click", this);
13586 this.timer = this.click.defer(this.delay || this.interval, this);
13590 click : function(){
13591 this.fireEvent("click", this);
13592 this.timer = this.click.defer(this.getInterval(), this);
13596 getInterval: function(){
13597 if(!this.accelerate){
13598 return this.interval;
13600 var pressTime = this.mousedownTime.getElapsed();
13601 if(pressTime < 500){
13603 }else if(pressTime < 1700){
13605 }else if(pressTime < 2600){
13607 }else if(pressTime < 3500){
13609 }else if(pressTime < 4400){
13611 }else if(pressTime < 5300){
13613 }else if(pressTime < 6200){
13621 handleMouseOut : function(){
13622 clearTimeout(this.timer);
13623 if(this.pressClass){
13624 this.el.removeClass(this.pressClass);
13626 this.el.on("mouseover", this.handleMouseReturn, this);
13630 handleMouseReturn : function(){
13631 this.el.un("mouseover", this.handleMouseReturn);
13632 if(this.pressClass){
13633 this.el.addClass(this.pressClass);
13639 handleMouseUp : function(){
13640 clearTimeout(this.timer);
13641 this.el.un("mouseover", this.handleMouseReturn);
13642 this.el.un("mouseout", this.handleMouseOut);
13643 Roo.get(document).un("mouseup", this.handleMouseUp);
13644 this.el.removeClass(this.pressClass);
13645 this.fireEvent("mouseup", this);
13649 * Ext JS Library 1.1.1
13650 * Copyright(c) 2006-2007, Ext JS, LLC.
13652 * Originally Released Under LGPL - original licence link has changed is not relivant.
13655 * <script type="text/javascript">
13660 * @class Roo.KeyNav
13661 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13662 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13663 * way to implement custom navigation schemes for any UI component.</p>
13664 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13665 * pageUp, pageDown, del, home, end. Usage:</p>
13667 var nav = new Roo.KeyNav("my-element", {
13668 "left" : function(e){
13669 this.moveLeft(e.ctrlKey);
13671 "right" : function(e){
13672 this.moveRight(e.ctrlKey);
13674 "enter" : function(e){
13681 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13682 * @param {Object} config The config
13684 Roo.KeyNav = function(el, config){
13685 this.el = Roo.get(el);
13686 Roo.apply(this, config);
13687 if(!this.disabled){
13688 this.disabled = true;
13693 Roo.KeyNav.prototype = {
13695 * @cfg {Boolean} disabled
13696 * True to disable this KeyNav instance (defaults to false)
13700 * @cfg {String} defaultEventAction
13701 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13702 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13703 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13705 defaultEventAction: "stopEvent",
13707 * @cfg {Boolean} forceKeyDown
13708 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13709 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13710 * handle keydown instead of keypress.
13712 forceKeyDown : false,
13715 prepareEvent : function(e){
13716 var k = e.getKey();
13717 var h = this.keyToHandler[k];
13718 //if(h && this[h]){
13719 // e.stopPropagation();
13721 if(Roo.isSafari && h && k >= 37 && k <= 40){
13727 relay : function(e){
13728 var k = e.getKey();
13729 var h = this.keyToHandler[k];
13731 if(this.doRelay(e, this[h], h) !== true){
13732 e[this.defaultEventAction]();
13738 doRelay : function(e, h, hname){
13739 return h.call(this.scope || this, e);
13742 // possible handlers
13756 // quick lookup hash
13773 * Enable this KeyNav
13775 enable: function(){
13777 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13778 // the EventObject will normalize Safari automatically
13779 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13780 this.el.on("keydown", this.relay, this);
13782 this.el.on("keydown", this.prepareEvent, this);
13783 this.el.on("keypress", this.relay, this);
13785 this.disabled = false;
13790 * Disable this KeyNav
13792 disable: function(){
13793 if(!this.disabled){
13794 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13795 this.el.un("keydown", this.relay);
13797 this.el.un("keydown", this.prepareEvent);
13798 this.el.un("keypress", this.relay);
13800 this.disabled = true;
13805 * Ext JS Library 1.1.1
13806 * Copyright(c) 2006-2007, Ext JS, LLC.
13808 * Originally Released Under LGPL - original licence link has changed is not relivant.
13811 * <script type="text/javascript">
13816 * @class Roo.KeyMap
13817 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13818 * The constructor accepts the same config object as defined by {@link #addBinding}.
13819 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13820 * combination it will call the function with this signature (if the match is a multi-key
13821 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13822 * A KeyMap can also handle a string representation of keys.<br />
13825 // map one key by key code
13826 var map = new Roo.KeyMap("my-element", {
13827 key: 13, // or Roo.EventObject.ENTER
13832 // map multiple keys to one action by string
13833 var map = new Roo.KeyMap("my-element", {
13839 // map multiple keys to multiple actions by strings and array of codes
13840 var map = new Roo.KeyMap("my-element", [
13843 fn: function(){ alert("Return was pressed"); }
13846 fn: function(){ alert('a, b or c was pressed'); }
13851 fn: function(){ alert('Control + shift + tab was pressed.'); }
13855 * <b>Note: A KeyMap starts enabled</b>
13857 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13858 * @param {Object} config The config (see {@link #addBinding})
13859 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13861 Roo.KeyMap = function(el, config, eventName){
13862 this.el = Roo.get(el);
13863 this.eventName = eventName || "keydown";
13864 this.bindings = [];
13866 this.addBinding(config);
13871 Roo.KeyMap.prototype = {
13873 * True to stop the event from bubbling and prevent the default browser action if the
13874 * key was handled by the KeyMap (defaults to false)
13880 * Add a new binding to this KeyMap. The following config object properties are supported:
13882 Property Type Description
13883 ---------- --------------- ----------------------------------------------------------------------
13884 key String/Array A single keycode or an array of keycodes to handle
13885 shift Boolean True to handle key only when shift is pressed (defaults to false)
13886 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13887 alt Boolean True to handle key only when alt is pressed (defaults to false)
13888 fn Function The function to call when KeyMap finds the expected key combination
13889 scope Object The scope of the callback function
13895 var map = new Roo.KeyMap(document, {
13896 key: Roo.EventObject.ENTER,
13901 //Add a new binding to the existing KeyMap later
13909 * @param {Object/Array} config A single KeyMap config or an array of configs
13911 addBinding : function(config){
13912 if(config instanceof Array){
13913 for(var i = 0, len = config.length; i < len; i++){
13914 this.addBinding(config[i]);
13918 var keyCode = config.key,
13919 shift = config.shift,
13920 ctrl = config.ctrl,
13923 scope = config.scope;
13924 if(typeof keyCode == "string"){
13926 var keyString = keyCode.toUpperCase();
13927 for(var j = 0, len = keyString.length; j < len; j++){
13928 ks.push(keyString.charCodeAt(j));
13932 var keyArray = keyCode instanceof Array;
13933 var handler = function(e){
13934 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13935 var k = e.getKey();
13937 for(var i = 0, len = keyCode.length; i < len; i++){
13938 if(keyCode[i] == k){
13939 if(this.stopEvent){
13942 fn.call(scope || window, k, e);
13948 if(this.stopEvent){
13951 fn.call(scope || window, k, e);
13956 this.bindings.push(handler);
13960 * Shorthand for adding a single key listener
13961 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13962 * following options:
13963 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13964 * @param {Function} fn The function to call
13965 * @param {Object} scope (optional) The scope of the function
13967 on : function(key, fn, scope){
13968 var keyCode, shift, ctrl, alt;
13969 if(typeof key == "object" && !(key instanceof Array)){
13988 handleKeyDown : function(e){
13989 if(this.enabled){ //just in case
13990 var b = this.bindings;
13991 for(var i = 0, len = b.length; i < len; i++){
13992 b[i].call(this, e);
13998 * Returns true if this KeyMap is enabled
13999 * @return {Boolean}
14001 isEnabled : function(){
14002 return this.enabled;
14006 * Enables this KeyMap
14008 enable: function(){
14010 this.el.on(this.eventName, this.handleKeyDown, this);
14011 this.enabled = true;
14016 * Disable this KeyMap
14018 disable: function(){
14020 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14021 this.enabled = false;
14026 * Ext JS Library 1.1.1
14027 * Copyright(c) 2006-2007, Ext JS, LLC.
14029 * Originally Released Under LGPL - original licence link has changed is not relivant.
14032 * <script type="text/javascript">
14037 * @class Roo.util.TextMetrics
14038 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14039 * wide, in pixels, a given block of text will be.
14042 Roo.util.TextMetrics = function(){
14046 * Measures the size of the specified text
14047 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14048 * that can affect the size of the rendered text
14049 * @param {String} text The text to measure
14050 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14051 * in order to accurately measure the text height
14052 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14054 measure : function(el, text, fixedWidth){
14056 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14059 shared.setFixedWidth(fixedWidth || 'auto');
14060 return shared.getSize(text);
14064 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14065 * the overhead of multiple calls to initialize the style properties on each measurement.
14066 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14067 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14068 * in order to accurately measure the text height
14069 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14071 createInstance : function(el, fixedWidth){
14072 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14079 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14080 var ml = new Roo.Element(document.createElement('div'));
14081 document.body.appendChild(ml.dom);
14082 ml.position('absolute');
14083 ml.setLeftTop(-1000, -1000);
14087 ml.setWidth(fixedWidth);
14092 * Returns the size of the specified text based on the internal element's style and width properties
14093 * @memberOf Roo.util.TextMetrics.Instance#
14094 * @param {String} text The text to measure
14095 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14097 getSize : function(text){
14099 var s = ml.getSize();
14105 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14106 * that can affect the size of the rendered text
14107 * @memberOf Roo.util.TextMetrics.Instance#
14108 * @param {String/HTMLElement} el The element, dom node or id
14110 bind : function(el){
14112 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14117 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14118 * to set a fixed width in order to accurately measure the text height.
14119 * @memberOf Roo.util.TextMetrics.Instance#
14120 * @param {Number} width The width to set on the element
14122 setFixedWidth : function(width){
14123 ml.setWidth(width);
14127 * Returns the measured width of the specified text
14128 * @memberOf Roo.util.TextMetrics.Instance#
14129 * @param {String} text The text to measure
14130 * @return {Number} width The width in pixels
14132 getWidth : function(text){
14133 ml.dom.style.width = 'auto';
14134 return this.getSize(text).width;
14138 * Returns the measured height of the specified text. For multiline text, be sure to call
14139 * {@link #setFixedWidth} if necessary.
14140 * @memberOf Roo.util.TextMetrics.Instance#
14141 * @param {String} text The text to measure
14142 * @return {Number} height The height in pixels
14144 getHeight : function(text){
14145 return this.getSize(text).height;
14149 instance.bind(bindTo);
14154 // backwards compat
14155 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14157 * Ext JS Library 1.1.1
14158 * Copyright(c) 2006-2007, Ext JS, LLC.
14160 * Originally Released Under LGPL - original licence link has changed is not relivant.
14163 * <script type="text/javascript">
14167 * @class Roo.state.Provider
14168 * Abstract base class for state provider implementations. This class provides methods
14169 * for encoding and decoding <b>typed</b> variables including dates and defines the
14170 * Provider interface.
14172 Roo.state.Provider = function(){
14174 * @event statechange
14175 * Fires when a state change occurs.
14176 * @param {Provider} this This state provider
14177 * @param {String} key The state key which was changed
14178 * @param {String} value The encoded value for the state
14181 "statechange": true
14184 Roo.state.Provider.superclass.constructor.call(this);
14186 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14188 * Returns the current value for a key
14189 * @param {String} name The key name
14190 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14191 * @return {Mixed} The state data
14193 get : function(name, defaultValue){
14194 return typeof this.state[name] == "undefined" ?
14195 defaultValue : this.state[name];
14199 * Clears a value from the state
14200 * @param {String} name The key name
14202 clear : function(name){
14203 delete this.state[name];
14204 this.fireEvent("statechange", this, name, null);
14208 * Sets the value for a key
14209 * @param {String} name The key name
14210 * @param {Mixed} value The value to set
14212 set : function(name, value){
14213 this.state[name] = value;
14214 this.fireEvent("statechange", this, name, value);
14218 * Decodes a string previously encoded with {@link #encodeValue}.
14219 * @param {String} value The value to decode
14220 * @return {Mixed} The decoded value
14222 decodeValue : function(cookie){
14223 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14224 var matches = re.exec(unescape(cookie));
14225 if(!matches || !matches[1]) return; // non state cookie
14226 var type = matches[1];
14227 var v = matches[2];
14230 return parseFloat(v);
14232 return new Date(Date.parse(v));
14237 var values = v.split("^");
14238 for(var i = 0, len = values.length; i < len; i++){
14239 all.push(this.decodeValue(values[i]));
14244 var values = v.split("^");
14245 for(var i = 0, len = values.length; i < len; i++){
14246 var kv = values[i].split("=");
14247 all[kv[0]] = this.decodeValue(kv[1]);
14256 * Encodes a value including type information. Decode with {@link #decodeValue}.
14257 * @param {Mixed} value The value to encode
14258 * @return {String} The encoded value
14260 encodeValue : function(v){
14262 if(typeof v == "number"){
14264 }else if(typeof v == "boolean"){
14265 enc = "b:" + (v ? "1" : "0");
14266 }else if(v instanceof Date){
14267 enc = "d:" + v.toGMTString();
14268 }else if(v instanceof Array){
14270 for(var i = 0, len = v.length; i < len; i++){
14271 flat += this.encodeValue(v[i]);
14272 if(i != len-1) flat += "^";
14275 }else if(typeof v == "object"){
14278 if(typeof v[key] != "function"){
14279 flat += key + "=" + this.encodeValue(v[key]) + "^";
14282 enc = "o:" + flat.substring(0, flat.length-1);
14286 return escape(enc);
14292 * Ext JS Library 1.1.1
14293 * Copyright(c) 2006-2007, Ext JS, LLC.
14295 * Originally Released Under LGPL - original licence link has changed is not relivant.
14298 * <script type="text/javascript">
14301 * @class Roo.state.Manager
14302 * This is the global state manager. By default all components that are "state aware" check this class
14303 * for state information if you don't pass them a custom state provider. In order for this class
14304 * to be useful, it must be initialized with a provider when your application initializes.
14306 // in your initialization function
14308 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14310 // supposed you have a {@link Roo.BorderLayout}
14311 var layout = new Roo.BorderLayout(...);
14312 layout.restoreState();
14313 // or a {Roo.BasicDialog}
14314 var dialog = new Roo.BasicDialog(...);
14315 dialog.restoreState();
14319 Roo.state.Manager = function(){
14320 var provider = new Roo.state.Provider();
14324 * Configures the default state provider for your application
14325 * @param {Provider} stateProvider The state provider to set
14327 setProvider : function(stateProvider){
14328 provider = stateProvider;
14332 * Returns the current value for a key
14333 * @param {String} name The key name
14334 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14335 * @return {Mixed} The state data
14337 get : function(key, defaultValue){
14338 return provider.get(key, defaultValue);
14342 * Sets the value for a key
14343 * @param {String} name The key name
14344 * @param {Mixed} value The state data
14346 set : function(key, value){
14347 provider.set(key, value);
14351 * Clears a value from the state
14352 * @param {String} name The key name
14354 clear : function(key){
14355 provider.clear(key);
14359 * Gets the currently configured state provider
14360 * @return {Provider} The state provider
14362 getProvider : function(){
14369 * Ext JS Library 1.1.1
14370 * Copyright(c) 2006-2007, Ext JS, LLC.
14372 * Originally Released Under LGPL - original licence link has changed is not relivant.
14375 * <script type="text/javascript">
14378 * @class Roo.state.CookieProvider
14379 * @extends Roo.state.Provider
14380 * The default Provider implementation which saves state via cookies.
14383 var cp = new Roo.state.CookieProvider({
14385 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14386 domain: "roojs.com"
14388 Roo.state.Manager.setProvider(cp);
14390 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14391 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14392 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14393 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14394 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14395 * domain the page is running on including the 'www' like 'www.roojs.com')
14396 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14398 * Create a new CookieProvider
14399 * @param {Object} config The configuration object
14401 Roo.state.CookieProvider = function(config){
14402 Roo.state.CookieProvider.superclass.constructor.call(this);
14404 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14405 this.domain = null;
14406 this.secure = false;
14407 Roo.apply(this, config);
14408 this.state = this.readCookies();
14411 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14413 set : function(name, value){
14414 if(typeof value == "undefined" || value === null){
14418 this.setCookie(name, value);
14419 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14423 clear : function(name){
14424 this.clearCookie(name);
14425 Roo.state.CookieProvider.superclass.clear.call(this, name);
14429 readCookies : function(){
14431 var c = document.cookie + ";";
14432 var re = /\s?(.*?)=(.*?);/g;
14434 while((matches = re.exec(c)) != null){
14435 var name = matches[1];
14436 var value = matches[2];
14437 if(name && name.substring(0,3) == "ys-"){
14438 cookies[name.substr(3)] = this.decodeValue(value);
14445 setCookie : function(name, value){
14446 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14447 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14448 ((this.path == null) ? "" : ("; path=" + this.path)) +
14449 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14450 ((this.secure == true) ? "; secure" : "");
14454 clearCookie : function(name){
14455 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14456 ((this.path == null) ? "" : ("; path=" + this.path)) +
14457 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14458 ((this.secure == true) ? "; secure" : "");
14462 * Ext JS Library 1.1.1
14463 * Copyright(c) 2006-2007, Ext JS, LLC.
14465 * Originally Released Under LGPL - original licence link has changed is not relivant.
14468 * <script type="text/javascript">
14474 * These classes are derivatives of the similarly named classes in the YUI Library.
14475 * The original license:
14476 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14477 * Code licensed under the BSD License:
14478 * http://developer.yahoo.net/yui/license.txt
14483 var Event=Roo.EventManager;
14484 var Dom=Roo.lib.Dom;
14487 * @class Roo.dd.DragDrop
14488 * @extends Roo.util.Observable
14489 * Defines the interface and base operation of items that that can be
14490 * dragged or can be drop targets. It was designed to be extended, overriding
14491 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14492 * Up to three html elements can be associated with a DragDrop instance:
14494 * <li>linked element: the element that is passed into the constructor.
14495 * This is the element which defines the boundaries for interaction with
14496 * other DragDrop objects.</li>
14497 * <li>handle element(s): The drag operation only occurs if the element that
14498 * was clicked matches a handle element. By default this is the linked
14499 * element, but there are times that you will want only a portion of the
14500 * linked element to initiate the drag operation, and the setHandleElId()
14501 * method provides a way to define this.</li>
14502 * <li>drag element: this represents the element that would be moved along
14503 * with the cursor during a drag operation. By default, this is the linked
14504 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14505 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14508 * This class should not be instantiated until the onload event to ensure that
14509 * the associated elements are available.
14510 * The following would define a DragDrop obj that would interact with any
14511 * other DragDrop obj in the "group1" group:
14513 * dd = new Roo.dd.DragDrop("div1", "group1");
14515 * Since none of the event handlers have been implemented, nothing would
14516 * actually happen if you were to run the code above. Normally you would
14517 * override this class or one of the default implementations, but you can
14518 * also override the methods you want on an instance of the class...
14520 * dd.onDragDrop = function(e, id) {
14521 * alert("dd was dropped on " + id);
14525 * @param {String} id of the element that is linked to this instance
14526 * @param {String} sGroup the group of related DragDrop objects
14527 * @param {object} config an object containing configurable attributes
14528 * Valid properties for DragDrop:
14529 * padding, isTarget, maintainOffset, primaryButtonOnly
14531 Roo.dd.DragDrop = function(id, sGroup, config) {
14533 this.init(id, sGroup, config);
14538 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
14541 * The id of the element associated with this object. This is what we
14542 * refer to as the "linked element" because the size and position of
14543 * this element is used to determine when the drag and drop objects have
14551 * Configuration attributes passed into the constructor
14558 * The id of the element that will be dragged. By default this is same
14559 * as the linked element , but could be changed to another element. Ex:
14561 * @property dragElId
14568 * the id of the element that initiates the drag operation. By default
14569 * this is the linked element, but could be changed to be a child of this
14570 * element. This lets us do things like only starting the drag when the
14571 * header element within the linked html element is clicked.
14572 * @property handleElId
14579 * An associative array of HTML tags that will be ignored if clicked.
14580 * @property invalidHandleTypes
14581 * @type {string: string}
14583 invalidHandleTypes: null,
14586 * An associative array of ids for elements that will be ignored if clicked
14587 * @property invalidHandleIds
14588 * @type {string: string}
14590 invalidHandleIds: null,
14593 * An indexted array of css class names for elements that will be ignored
14595 * @property invalidHandleClasses
14598 invalidHandleClasses: null,
14601 * The linked element's absolute X position at the time the drag was
14603 * @property startPageX
14610 * The linked element's absolute X position at the time the drag was
14612 * @property startPageY
14619 * The group defines a logical collection of DragDrop objects that are
14620 * related. Instances only get events when interacting with other
14621 * DragDrop object in the same group. This lets us define multiple
14622 * groups using a single DragDrop subclass if we want.
14624 * @type {string: string}
14629 * Individual drag/drop instances can be locked. This will prevent
14630 * onmousedown start drag.
14638 * Lock this instance
14641 lock: function() { this.locked = true; },
14644 * Unlock this instace
14647 unlock: function() { this.locked = false; },
14650 * By default, all insances can be a drop target. This can be disabled by
14651 * setting isTarget to false.
14658 * The padding configured for this drag and drop object for calculating
14659 * the drop zone intersection with this object.
14666 * Cached reference to the linked element
14667 * @property _domRef
14673 * Internal typeof flag
14674 * @property __ygDragDrop
14677 __ygDragDrop: true,
14680 * Set to true when horizontal contraints are applied
14681 * @property constrainX
14688 * Set to true when vertical contraints are applied
14689 * @property constrainY
14696 * The left constraint
14704 * The right constraint
14712 * The up constraint
14721 * The down constraint
14729 * Maintain offsets when we resetconstraints. Set to true when you want
14730 * the position of the element relative to its parent to stay the same
14731 * when the page changes
14733 * @property maintainOffset
14736 maintainOffset: false,
14739 * Array of pixel locations the element will snap to if we specified a
14740 * horizontal graduation/interval. This array is generated automatically
14741 * when you define a tick interval.
14748 * Array of pixel locations the element will snap to if we specified a
14749 * vertical graduation/interval. This array is generated automatically
14750 * when you define a tick interval.
14757 * By default the drag and drop instance will only respond to the primary
14758 * button click (left button for a right-handed mouse). Set to true to
14759 * allow drag and drop to start with any mouse click that is propogated
14761 * @property primaryButtonOnly
14764 primaryButtonOnly: true,
14767 * The availabe property is false until the linked dom element is accessible.
14768 * @property available
14774 * By default, drags can only be initiated if the mousedown occurs in the
14775 * region the linked element is. This is done in part to work around a
14776 * bug in some browsers that mis-report the mousedown if the previous
14777 * mouseup happened outside of the window. This property is set to true
14778 * if outer handles are defined.
14780 * @property hasOuterHandles
14784 hasOuterHandles: false,
14787 * Code that executes immediately before the startDrag event
14788 * @method b4StartDrag
14791 b4StartDrag: function(x, y) { },
14794 * Abstract method called after a drag/drop object is clicked
14795 * and the drag or mousedown time thresholds have beeen met.
14796 * @method startDrag
14797 * @param {int} X click location
14798 * @param {int} Y click location
14800 startDrag: function(x, y) { /* override this */ },
14803 * Code that executes immediately before the onDrag event
14807 b4Drag: function(e) { },
14810 * Abstract method called during the onMouseMove event while dragging an
14813 * @param {Event} e the mousemove event
14815 onDrag: function(e) { /* override this */ },
14818 * Abstract method called when this element fist begins hovering over
14819 * another DragDrop obj
14820 * @method onDragEnter
14821 * @param {Event} e the mousemove event
14822 * @param {String|DragDrop[]} id In POINT mode, the element
14823 * id this is hovering over. In INTERSECT mode, an array of one or more
14824 * dragdrop items being hovered over.
14826 onDragEnter: function(e, id) { /* override this */ },
14829 * Code that executes immediately before the onDragOver event
14830 * @method b4DragOver
14833 b4DragOver: function(e) { },
14836 * Abstract method called when this element is hovering over another
14838 * @method onDragOver
14839 * @param {Event} e the mousemove event
14840 * @param {String|DragDrop[]} id In POINT mode, the element
14841 * id this is hovering over. In INTERSECT mode, an array of dd items
14842 * being hovered over.
14844 onDragOver: function(e, id) { /* override this */ },
14847 * Code that executes immediately before the onDragOut event
14848 * @method b4DragOut
14851 b4DragOut: function(e) { },
14854 * Abstract method called when we are no longer hovering over an element
14855 * @method onDragOut
14856 * @param {Event} e the mousemove event
14857 * @param {String|DragDrop[]} id In POINT mode, the element
14858 * id this was hovering over. In INTERSECT mode, an array of dd items
14859 * that the mouse is no longer over.
14861 onDragOut: function(e, id) { /* override this */ },
14864 * Code that executes immediately before the onDragDrop event
14865 * @method b4DragDrop
14868 b4DragDrop: function(e) { },
14871 * Abstract method called when this item is dropped on another DragDrop
14873 * @method onDragDrop
14874 * @param {Event} e the mouseup event
14875 * @param {String|DragDrop[]} id In POINT mode, the element
14876 * id this was dropped on. In INTERSECT mode, an array of dd items this
14879 onDragDrop: function(e, id) { /* override this */ },
14882 * Abstract method called when this item is dropped on an area with no
14884 * @method onInvalidDrop
14885 * @param {Event} e the mouseup event
14887 onInvalidDrop: function(e) { /* override this */ },
14890 * Code that executes immediately before the endDrag event
14891 * @method b4EndDrag
14894 b4EndDrag: function(e) { },
14897 * Fired when we are done dragging the object
14899 * @param {Event} e the mouseup event
14901 endDrag: function(e) { /* override this */ },
14904 * Code executed immediately before the onMouseDown event
14905 * @method b4MouseDown
14906 * @param {Event} e the mousedown event
14909 b4MouseDown: function(e) { },
14912 * Event handler that fires when a drag/drop obj gets a mousedown
14913 * @method onMouseDown
14914 * @param {Event} e the mousedown event
14916 onMouseDown: function(e) { /* override this */ },
14919 * Event handler that fires when a drag/drop obj gets a mouseup
14920 * @method onMouseUp
14921 * @param {Event} e the mouseup event
14923 onMouseUp: function(e) { /* override this */ },
14926 * Override the onAvailable method to do what is needed after the initial
14927 * position was determined.
14928 * @method onAvailable
14930 onAvailable: function () {
14934 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14937 defaultPadding : {left:0, right:0, top:0, bottom:0},
14940 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14944 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14945 { dragElId: "existingProxyDiv" });
14946 dd.startDrag = function(){
14947 this.constrainTo("parent-id");
14950 * Or you can initalize it using the {@link Roo.Element} object:
14952 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14953 startDrag : function(){
14954 this.constrainTo("parent-id");
14958 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14959 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14960 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14961 * an object containing the sides to pad. For example: {right:10, bottom:10}
14962 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14964 constrainTo : function(constrainTo, pad, inContent){
14965 if(typeof pad == "number"){
14966 pad = {left: pad, right:pad, top:pad, bottom:pad};
14968 pad = pad || this.defaultPadding;
14969 var b = Roo.get(this.getEl()).getBox();
14970 var ce = Roo.get(constrainTo);
14971 var s = ce.getScroll();
14972 var c, cd = ce.dom;
14973 if(cd == document.body){
14974 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14977 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14981 var topSpace = b.y - c.y;
14982 var leftSpace = b.x - c.x;
14984 this.resetConstraints();
14985 this.setXConstraint(leftSpace - (pad.left||0), // left
14986 c.width - leftSpace - b.width - (pad.right||0) //right
14988 this.setYConstraint(topSpace - (pad.top||0), //top
14989 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14994 * Returns a reference to the linked element
14996 * @return {HTMLElement} the html element
14998 getEl: function() {
14999 if (!this._domRef) {
15000 this._domRef = Roo.getDom(this.id);
15003 return this._domRef;
15007 * Returns a reference to the actual element to drag. By default this is
15008 * the same as the html element, but it can be assigned to another
15009 * element. An example of this can be found in Roo.dd.DDProxy
15010 * @method getDragEl
15011 * @return {HTMLElement} the html element
15013 getDragEl: function() {
15014 return Roo.getDom(this.dragElId);
15018 * Sets up the DragDrop object. Must be called in the constructor of any
15019 * Roo.dd.DragDrop subclass
15021 * @param id the id of the linked element
15022 * @param {String} sGroup the group of related items
15023 * @param {object} config configuration attributes
15025 init: function(id, sGroup, config) {
15026 this.initTarget(id, sGroup, config);
15027 Event.on(this.id, "mousedown", this.handleMouseDown, this);
15028 // Event.on(this.id, "selectstart", Event.preventDefault);
15032 * Initializes Targeting functionality only... the object does not
15033 * get a mousedown handler.
15034 * @method initTarget
15035 * @param id the id of the linked element
15036 * @param {String} sGroup the group of related items
15037 * @param {object} config configuration attributes
15039 initTarget: function(id, sGroup, config) {
15041 // configuration attributes
15042 this.config = config || {};
15044 // create a local reference to the drag and drop manager
15045 this.DDM = Roo.dd.DDM;
15046 // initialize the groups array
15049 // assume that we have an element reference instead of an id if the
15050 // parameter is not a string
15051 if (typeof id !== "string") {
15058 // add to an interaction group
15059 this.addToGroup((sGroup) ? sGroup : "default");
15061 // We don't want to register this as the handle with the manager
15062 // so we just set the id rather than calling the setter.
15063 this.handleElId = id;
15065 // the linked element is the element that gets dragged by default
15066 this.setDragElId(id);
15068 // by default, clicked anchors will not start drag operations.
15069 this.invalidHandleTypes = { A: "A" };
15070 this.invalidHandleIds = {};
15071 this.invalidHandleClasses = [];
15073 this.applyConfig();
15075 this.handleOnAvailable();
15079 * Applies the configuration parameters that were passed into the constructor.
15080 * This is supposed to happen at each level through the inheritance chain. So
15081 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15082 * DragDrop in order to get all of the parameters that are available in
15084 * @method applyConfig
15086 applyConfig: function() {
15088 // configurable properties:
15089 // padding, isTarget, maintainOffset, primaryButtonOnly
15090 this.padding = this.config.padding || [0, 0, 0, 0];
15091 this.isTarget = (this.config.isTarget !== false);
15092 this.maintainOffset = (this.config.maintainOffset);
15093 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15098 * Executed when the linked element is available
15099 * @method handleOnAvailable
15102 handleOnAvailable: function() {
15103 this.available = true;
15104 this.resetConstraints();
15105 this.onAvailable();
15109 * Configures the padding for the target zone in px. Effectively expands
15110 * (or reduces) the virtual object size for targeting calculations.
15111 * Supports css-style shorthand; if only one parameter is passed, all sides
15112 * will have that padding, and if only two are passed, the top and bottom
15113 * will have the first param, the left and right the second.
15114 * @method setPadding
15115 * @param {int} iTop Top pad
15116 * @param {int} iRight Right pad
15117 * @param {int} iBot Bot pad
15118 * @param {int} iLeft Left pad
15120 setPadding: function(iTop, iRight, iBot, iLeft) {
15121 // this.padding = [iLeft, iRight, iTop, iBot];
15122 if (!iRight && 0 !== iRight) {
15123 this.padding = [iTop, iTop, iTop, iTop];
15124 } else if (!iBot && 0 !== iBot) {
15125 this.padding = [iTop, iRight, iTop, iRight];
15127 this.padding = [iTop, iRight, iBot, iLeft];
15132 * Stores the initial placement of the linked element.
15133 * @method setInitialPosition
15134 * @param {int} diffX the X offset, default 0
15135 * @param {int} diffY the Y offset, default 0
15137 setInitPosition: function(diffX, diffY) {
15138 var el = this.getEl();
15140 if (!this.DDM.verifyEl(el)) {
15144 var dx = diffX || 0;
15145 var dy = diffY || 0;
15147 var p = Dom.getXY( el );
15149 this.initPageX = p[0] - dx;
15150 this.initPageY = p[1] - dy;
15152 this.lastPageX = p[0];
15153 this.lastPageY = p[1];
15156 this.setStartPosition(p);
15160 * Sets the start position of the element. This is set when the obj
15161 * is initialized, the reset when a drag is started.
15162 * @method setStartPosition
15163 * @param pos current position (from previous lookup)
15166 setStartPosition: function(pos) {
15167 var p = pos || Dom.getXY( this.getEl() );
15168 this.deltaSetXY = null;
15170 this.startPageX = p[0];
15171 this.startPageY = p[1];
15175 * Add this instance to a group of related drag/drop objects. All
15176 * instances belong to at least one group, and can belong to as many
15177 * groups as needed.
15178 * @method addToGroup
15179 * @param sGroup {string} the name of the group
15181 addToGroup: function(sGroup) {
15182 this.groups[sGroup] = true;
15183 this.DDM.regDragDrop(this, sGroup);
15187 * Remove's this instance from the supplied interaction group
15188 * @method removeFromGroup
15189 * @param {string} sGroup The group to drop
15191 removeFromGroup: function(sGroup) {
15192 if (this.groups[sGroup]) {
15193 delete this.groups[sGroup];
15196 this.DDM.removeDDFromGroup(this, sGroup);
15200 * Allows you to specify that an element other than the linked element
15201 * will be moved with the cursor during a drag
15202 * @method setDragElId
15203 * @param id {string} the id of the element that will be used to initiate the drag
15205 setDragElId: function(id) {
15206 this.dragElId = id;
15210 * Allows you to specify a child of the linked element that should be
15211 * used to initiate the drag operation. An example of this would be if
15212 * you have a content div with text and links. Clicking anywhere in the
15213 * content area would normally start the drag operation. Use this method
15214 * to specify that an element inside of the content div is the element
15215 * that starts the drag operation.
15216 * @method setHandleElId
15217 * @param id {string} the id of the element that will be used to
15218 * initiate the drag.
15220 setHandleElId: function(id) {
15221 if (typeof id !== "string") {
15224 this.handleElId = id;
15225 this.DDM.regHandle(this.id, id);
15229 * Allows you to set an element outside of the linked element as a drag
15231 * @method setOuterHandleElId
15232 * @param id the id of the element that will be used to initiate the drag
15234 setOuterHandleElId: function(id) {
15235 if (typeof id !== "string") {
15238 Event.on(id, "mousedown",
15239 this.handleMouseDown, this);
15240 this.setHandleElId(id);
15242 this.hasOuterHandles = true;
15246 * Remove all drag and drop hooks for this element
15249 unreg: function() {
15250 Event.un(this.id, "mousedown",
15251 this.handleMouseDown);
15252 this._domRef = null;
15253 this.DDM._remove(this);
15256 destroy : function(){
15261 * Returns true if this instance is locked, or the drag drop mgr is locked
15262 * (meaning that all drag/drop is disabled on the page.)
15264 * @return {boolean} true if this obj or all drag/drop is locked, else
15267 isLocked: function() {
15268 return (this.DDM.isLocked() || this.locked);
15272 * Fired when this object is clicked
15273 * @method handleMouseDown
15275 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15278 handleMouseDown: function(e, oDD){
15279 if (this.primaryButtonOnly && e.button != 0) {
15283 if (this.isLocked()) {
15287 this.DDM.refreshCache(this.groups);
15289 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15290 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15292 if (this.clickValidator(e)) {
15294 // set the initial element position
15295 this.setStartPosition();
15298 this.b4MouseDown(e);
15299 this.onMouseDown(e);
15301 this.DDM.handleMouseDown(e, this);
15303 this.DDM.stopEvent(e);
15311 clickValidator: function(e) {
15312 var target = e.getTarget();
15313 return ( this.isValidHandleChild(target) &&
15314 (this.id == this.handleElId ||
15315 this.DDM.handleWasClicked(target, this.id)) );
15319 * Allows you to specify a tag name that should not start a drag operation
15320 * when clicked. This is designed to facilitate embedding links within a
15321 * drag handle that do something other than start the drag.
15322 * @method addInvalidHandleType
15323 * @param {string} tagName the type of element to exclude
15325 addInvalidHandleType: function(tagName) {
15326 var type = tagName.toUpperCase();
15327 this.invalidHandleTypes[type] = type;
15331 * Lets you to specify an element id for a child of a drag handle
15332 * that should not initiate a drag
15333 * @method addInvalidHandleId
15334 * @param {string} id the element id of the element you wish to ignore
15336 addInvalidHandleId: function(id) {
15337 if (typeof id !== "string") {
15340 this.invalidHandleIds[id] = id;
15344 * Lets you specify a css class of elements that will not initiate a drag
15345 * @method addInvalidHandleClass
15346 * @param {string} cssClass the class of the elements you wish to ignore
15348 addInvalidHandleClass: function(cssClass) {
15349 this.invalidHandleClasses.push(cssClass);
15353 * Unsets an excluded tag name set by addInvalidHandleType
15354 * @method removeInvalidHandleType
15355 * @param {string} tagName the type of element to unexclude
15357 removeInvalidHandleType: function(tagName) {
15358 var type = tagName.toUpperCase();
15359 // this.invalidHandleTypes[type] = null;
15360 delete this.invalidHandleTypes[type];
15364 * Unsets an invalid handle id
15365 * @method removeInvalidHandleId
15366 * @param {string} id the id of the element to re-enable
15368 removeInvalidHandleId: function(id) {
15369 if (typeof id !== "string") {
15372 delete this.invalidHandleIds[id];
15376 * Unsets an invalid css class
15377 * @method removeInvalidHandleClass
15378 * @param {string} cssClass the class of the element(s) you wish to
15381 removeInvalidHandleClass: function(cssClass) {
15382 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15383 if (this.invalidHandleClasses[i] == cssClass) {
15384 delete this.invalidHandleClasses[i];
15390 * Checks the tag exclusion list to see if this click should be ignored
15391 * @method isValidHandleChild
15392 * @param {HTMLElement} node the HTMLElement to evaluate
15393 * @return {boolean} true if this is a valid tag type, false if not
15395 isValidHandleChild: function(node) {
15398 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15401 nodeName = node.nodeName.toUpperCase();
15403 nodeName = node.nodeName;
15405 valid = valid && !this.invalidHandleTypes[nodeName];
15406 valid = valid && !this.invalidHandleIds[node.id];
15408 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15409 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15418 * Create the array of horizontal tick marks if an interval was specified
15419 * in setXConstraint().
15420 * @method setXTicks
15423 setXTicks: function(iStartX, iTickSize) {
15425 this.xTickSize = iTickSize;
15429 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15431 this.xTicks[this.xTicks.length] = i;
15436 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15438 this.xTicks[this.xTicks.length] = i;
15443 this.xTicks.sort(this.DDM.numericSort) ;
15447 * Create the array of vertical tick marks if an interval was specified in
15448 * setYConstraint().
15449 * @method setYTicks
15452 setYTicks: function(iStartY, iTickSize) {
15454 this.yTickSize = iTickSize;
15458 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15460 this.yTicks[this.yTicks.length] = i;
15465 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15467 this.yTicks[this.yTicks.length] = i;
15472 this.yTicks.sort(this.DDM.numericSort) ;
15476 * By default, the element can be dragged any place on the screen. Use
15477 * this method to limit the horizontal travel of the element. Pass in
15478 * 0,0 for the parameters if you want to lock the drag to the y axis.
15479 * @method setXConstraint
15480 * @param {int} iLeft the number of pixels the element can move to the left
15481 * @param {int} iRight the number of pixels the element can move to the
15483 * @param {int} iTickSize optional parameter for specifying that the
15485 * should move iTickSize pixels at a time.
15487 setXConstraint: function(iLeft, iRight, iTickSize) {
15488 this.leftConstraint = iLeft;
15489 this.rightConstraint = iRight;
15491 this.minX = this.initPageX - iLeft;
15492 this.maxX = this.initPageX + iRight;
15493 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15495 this.constrainX = true;
15499 * Clears any constraints applied to this instance. Also clears ticks
15500 * since they can't exist independent of a constraint at this time.
15501 * @method clearConstraints
15503 clearConstraints: function() {
15504 this.constrainX = false;
15505 this.constrainY = false;
15510 * Clears any tick interval defined for this instance
15511 * @method clearTicks
15513 clearTicks: function() {
15514 this.xTicks = null;
15515 this.yTicks = null;
15516 this.xTickSize = 0;
15517 this.yTickSize = 0;
15521 * By default, the element can be dragged any place on the screen. Set
15522 * this to limit the vertical travel of the element. Pass in 0,0 for the
15523 * parameters if you want to lock the drag to the x axis.
15524 * @method setYConstraint
15525 * @param {int} iUp the number of pixels the element can move up
15526 * @param {int} iDown the number of pixels the element can move down
15527 * @param {int} iTickSize optional parameter for specifying that the
15528 * element should move iTickSize pixels at a time.
15530 setYConstraint: function(iUp, iDown, iTickSize) {
15531 this.topConstraint = iUp;
15532 this.bottomConstraint = iDown;
15534 this.minY = this.initPageY - iUp;
15535 this.maxY = this.initPageY + iDown;
15536 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15538 this.constrainY = true;
15543 * resetConstraints must be called if you manually reposition a dd element.
15544 * @method resetConstraints
15545 * @param {boolean} maintainOffset
15547 resetConstraints: function() {
15550 // Maintain offsets if necessary
15551 if (this.initPageX || this.initPageX === 0) {
15552 // figure out how much this thing has moved
15553 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15554 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15556 this.setInitPosition(dx, dy);
15558 // This is the first time we have detected the element's position
15560 this.setInitPosition();
15563 if (this.constrainX) {
15564 this.setXConstraint( this.leftConstraint,
15565 this.rightConstraint,
15569 if (this.constrainY) {
15570 this.setYConstraint( this.topConstraint,
15571 this.bottomConstraint,
15577 * Normally the drag element is moved pixel by pixel, but we can specify
15578 * that it move a number of pixels at a time. This method resolves the
15579 * location when we have it set up like this.
15581 * @param {int} val where we want to place the object
15582 * @param {int[]} tickArray sorted array of valid points
15583 * @return {int} the closest tick
15586 getTick: function(val, tickArray) {
15589 // If tick interval is not defined, it is effectively 1 pixel,
15590 // so we return the value passed to us.
15592 } else if (tickArray[0] >= val) {
15593 // The value is lower than the first tick, so we return the first
15595 return tickArray[0];
15597 for (var i=0, len=tickArray.length; i<len; ++i) {
15599 if (tickArray[next] && tickArray[next] >= val) {
15600 var diff1 = val - tickArray[i];
15601 var diff2 = tickArray[next] - val;
15602 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15606 // The value is larger than the last tick, so we return the last
15608 return tickArray[tickArray.length - 1];
15615 * @return {string} string representation of the dd obj
15617 toString: function() {
15618 return ("DragDrop " + this.id);
15626 * Ext JS Library 1.1.1
15627 * Copyright(c) 2006-2007, Ext JS, LLC.
15629 * Originally Released Under LGPL - original licence link has changed is not relivant.
15632 * <script type="text/javascript">
15637 * The drag and drop utility provides a framework for building drag and drop
15638 * applications. In addition to enabling drag and drop for specific elements,
15639 * the drag and drop elements are tracked by the manager class, and the
15640 * interactions between the various elements are tracked during the drag and
15641 * the implementing code is notified about these important moments.
15644 // Only load the library once. Rewriting the manager class would orphan
15645 // existing drag and drop instances.
15646 if (!Roo.dd.DragDropMgr) {
15649 * @class Roo.dd.DragDropMgr
15650 * DragDropMgr is a singleton that tracks the element interaction for
15651 * all DragDrop items in the window. Generally, you will not call
15652 * this class directly, but it does have helper methods that could
15653 * be useful in your DragDrop implementations.
15656 Roo.dd.DragDropMgr = function() {
15658 var Event = Roo.EventManager;
15663 * Two dimensional Array of registered DragDrop objects. The first
15664 * dimension is the DragDrop item group, the second the DragDrop
15667 * @type {string: string}
15674 * Array of element ids defined as drag handles. Used to determine
15675 * if the element that generated the mousedown event is actually the
15676 * handle and not the html element itself.
15677 * @property handleIds
15678 * @type {string: string}
15685 * the DragDrop object that is currently being dragged
15686 * @property dragCurrent
15694 * the DragDrop object(s) that are being hovered over
15695 * @property dragOvers
15703 * the X distance between the cursor and the object being dragged
15712 * the Y distance between the cursor and the object being dragged
15721 * Flag to determine if we should prevent the default behavior of the
15722 * events we define. By default this is true, but this can be set to
15723 * false if you need the default behavior (not recommended)
15724 * @property preventDefault
15728 preventDefault: true,
15731 * Flag to determine if we should stop the propagation of the events
15732 * we generate. This is true by default but you may want to set it to
15733 * false if the html element contains other features that require the
15735 * @property stopPropagation
15739 stopPropagation: true,
15742 * Internal flag that is set to true when drag and drop has been
15744 * @property initialized
15751 * All drag and drop can be disabled.
15759 * Called the first time an element is registered.
15765 this.initialized = true;
15769 * In point mode, drag and drop interaction is defined by the
15770 * location of the cursor during the drag/drop
15778 * In intersect mode, drag and drop interactio nis defined by the
15779 * overlap of two or more drag and drop objects.
15780 * @property INTERSECT
15787 * The current drag and drop mode. Default: POINT
15795 * Runs method on all drag and drop objects
15796 * @method _execOnAll
15800 _execOnAll: function(sMethod, args) {
15801 for (var i in this.ids) {
15802 for (var j in this.ids[i]) {
15803 var oDD = this.ids[i][j];
15804 if (! this.isTypeOfDD(oDD)) {
15807 oDD[sMethod].apply(oDD, args);
15813 * Drag and drop initialization. Sets up the global event handlers
15818 _onLoad: function() {
15823 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15824 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15825 Event.on(window, "unload", this._onUnload, this, true);
15826 Event.on(window, "resize", this._onResize, this, true);
15827 // Event.on(window, "mouseout", this._test);
15832 * Reset constraints on all drag and drop objs
15833 * @method _onResize
15837 _onResize: function(e) {
15838 this._execOnAll("resetConstraints", []);
15842 * Lock all drag and drop functionality
15846 lock: function() { this.locked = true; },
15849 * Unlock all drag and drop functionality
15853 unlock: function() { this.locked = false; },
15856 * Is drag and drop locked?
15858 * @return {boolean} True if drag and drop is locked, false otherwise.
15861 isLocked: function() { return this.locked; },
15864 * Location cache that is set for all drag drop objects when a drag is
15865 * initiated, cleared when the drag is finished.
15866 * @property locationCache
15873 * Set useCache to false if you want to force object the lookup of each
15874 * drag and drop linked element constantly during a drag.
15875 * @property useCache
15882 * The number of pixels that the mouse needs to move after the
15883 * mousedown before the drag is initiated. Default=3;
15884 * @property clickPixelThresh
15888 clickPixelThresh: 3,
15891 * The number of milliseconds after the mousedown event to initiate the
15892 * drag if we don't get a mouseup event. Default=1000
15893 * @property clickTimeThresh
15897 clickTimeThresh: 350,
15900 * Flag that indicates that either the drag pixel threshold or the
15901 * mousdown time threshold has been met
15902 * @property dragThreshMet
15907 dragThreshMet: false,
15910 * Timeout used for the click time threshold
15911 * @property clickTimeout
15916 clickTimeout: null,
15919 * The X position of the mousedown event stored for later use when a
15920 * drag threshold is met.
15929 * The Y position of the mousedown event stored for later use when a
15930 * drag threshold is met.
15939 * Each DragDrop instance must be registered with the DragDropMgr.
15940 * This is executed in DragDrop.init()
15941 * @method regDragDrop
15942 * @param {DragDrop} oDD the DragDrop object to register
15943 * @param {String} sGroup the name of the group this element belongs to
15946 regDragDrop: function(oDD, sGroup) {
15947 if (!this.initialized) { this.init(); }
15949 if (!this.ids[sGroup]) {
15950 this.ids[sGroup] = {};
15952 this.ids[sGroup][oDD.id] = oDD;
15956 * Removes the supplied dd instance from the supplied group. Executed
15957 * by DragDrop.removeFromGroup, so don't call this function directly.
15958 * @method removeDDFromGroup
15962 removeDDFromGroup: function(oDD, sGroup) {
15963 if (!this.ids[sGroup]) {
15964 this.ids[sGroup] = {};
15967 var obj = this.ids[sGroup];
15968 if (obj && obj[oDD.id]) {
15969 delete obj[oDD.id];
15974 * Unregisters a drag and drop item. This is executed in
15975 * DragDrop.unreg, use that method instead of calling this directly.
15980 _remove: function(oDD) {
15981 for (var g in oDD.groups) {
15982 if (g && this.ids[g][oDD.id]) {
15983 delete this.ids[g][oDD.id];
15986 delete this.handleIds[oDD.id];
15990 * Each DragDrop handle element must be registered. This is done
15991 * automatically when executing DragDrop.setHandleElId()
15992 * @method regHandle
15993 * @param {String} sDDId the DragDrop id this element is a handle for
15994 * @param {String} sHandleId the id of the element that is the drag
15998 regHandle: function(sDDId, sHandleId) {
15999 if (!this.handleIds[sDDId]) {
16000 this.handleIds[sDDId] = {};
16002 this.handleIds[sDDId][sHandleId] = sHandleId;
16006 * Utility function to determine if a given element has been
16007 * registered as a drag drop item.
16008 * @method isDragDrop
16009 * @param {String} id the element id to check
16010 * @return {boolean} true if this element is a DragDrop item,
16014 isDragDrop: function(id) {
16015 return ( this.getDDById(id) ) ? true : false;
16019 * Returns the drag and drop instances that are in all groups the
16020 * passed in instance belongs to.
16021 * @method getRelated
16022 * @param {DragDrop} p_oDD the obj to get related data for
16023 * @param {boolean} bTargetsOnly if true, only return targetable objs
16024 * @return {DragDrop[]} the related instances
16027 getRelated: function(p_oDD, bTargetsOnly) {
16029 for (var i in p_oDD.groups) {
16030 for (j in this.ids[i]) {
16031 var dd = this.ids[i][j];
16032 if (! this.isTypeOfDD(dd)) {
16035 if (!bTargetsOnly || dd.isTarget) {
16036 oDDs[oDDs.length] = dd;
16045 * Returns true if the specified dd target is a legal target for
16046 * the specifice drag obj
16047 * @method isLegalTarget
16048 * @param {DragDrop} the drag obj
16049 * @param {DragDrop} the target
16050 * @return {boolean} true if the target is a legal target for the
16054 isLegalTarget: function (oDD, oTargetDD) {
16055 var targets = this.getRelated(oDD, true);
16056 for (var i=0, len=targets.length;i<len;++i) {
16057 if (targets[i].id == oTargetDD.id) {
16066 * My goal is to be able to transparently determine if an object is
16067 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16068 * returns "object", oDD.constructor.toString() always returns
16069 * "DragDrop" and not the name of the subclass. So for now it just
16070 * evaluates a well-known variable in DragDrop.
16071 * @method isTypeOfDD
16072 * @param {Object} the object to evaluate
16073 * @return {boolean} true if typeof oDD = DragDrop
16076 isTypeOfDD: function (oDD) {
16077 return (oDD && oDD.__ygDragDrop);
16081 * Utility function to determine if a given element has been
16082 * registered as a drag drop handle for the given Drag Drop object.
16084 * @param {String} id the element id to check
16085 * @return {boolean} true if this element is a DragDrop handle, false
16089 isHandle: function(sDDId, sHandleId) {
16090 return ( this.handleIds[sDDId] &&
16091 this.handleIds[sDDId][sHandleId] );
16095 * Returns the DragDrop instance for a given id
16096 * @method getDDById
16097 * @param {String} id the id of the DragDrop object
16098 * @return {DragDrop} the drag drop object, null if it is not found
16101 getDDById: function(id) {
16102 for (var i in this.ids) {
16103 if (this.ids[i][id]) {
16104 return this.ids[i][id];
16111 * Fired after a registered DragDrop object gets the mousedown event.
16112 * Sets up the events required to track the object being dragged
16113 * @method handleMouseDown
16114 * @param {Event} e the event
16115 * @param oDD the DragDrop object being dragged
16119 handleMouseDown: function(e, oDD) {
16121 Roo.QuickTips.disable();
16123 this.currentTarget = e.getTarget();
16125 this.dragCurrent = oDD;
16127 var el = oDD.getEl();
16129 // track start position
16130 this.startX = e.getPageX();
16131 this.startY = e.getPageY();
16133 this.deltaX = this.startX - el.offsetLeft;
16134 this.deltaY = this.startY - el.offsetTop;
16136 this.dragThreshMet = false;
16138 this.clickTimeout = setTimeout(
16140 var DDM = Roo.dd.DDM;
16141 DDM.startDrag(DDM.startX, DDM.startY);
16143 this.clickTimeThresh );
16147 * Fired when either the drag pixel threshol or the mousedown hold
16148 * time threshold has been met.
16149 * @method startDrag
16150 * @param x {int} the X position of the original mousedown
16151 * @param y {int} the Y position of the original mousedown
16154 startDrag: function(x, y) {
16155 clearTimeout(this.clickTimeout);
16156 if (this.dragCurrent) {
16157 this.dragCurrent.b4StartDrag(x, y);
16158 this.dragCurrent.startDrag(x, y);
16160 this.dragThreshMet = true;
16164 * Internal function to handle the mouseup event. Will be invoked
16165 * from the context of the document.
16166 * @method handleMouseUp
16167 * @param {Event} e the event
16171 handleMouseUp: function(e) {
16174 Roo.QuickTips.enable();
16176 if (! this.dragCurrent) {
16180 clearTimeout(this.clickTimeout);
16182 if (this.dragThreshMet) {
16183 this.fireEvents(e, true);
16193 * Utility to stop event propagation and event default, if these
16194 * features are turned on.
16195 * @method stopEvent
16196 * @param {Event} e the event as returned by this.getEvent()
16199 stopEvent: function(e){
16200 if(this.stopPropagation) {
16201 e.stopPropagation();
16204 if (this.preventDefault) {
16205 e.preventDefault();
16210 * Internal function to clean up event handlers after the drag
16211 * operation is complete
16213 * @param {Event} e the event
16217 stopDrag: function(e) {
16218 // Fire the drag end event for the item that was dragged
16219 if (this.dragCurrent) {
16220 if (this.dragThreshMet) {
16221 this.dragCurrent.b4EndDrag(e);
16222 this.dragCurrent.endDrag(e);
16225 this.dragCurrent.onMouseUp(e);
16228 this.dragCurrent = null;
16229 this.dragOvers = {};
16233 * Internal function to handle the mousemove event. Will be invoked
16234 * from the context of the html element.
16236 * @TODO figure out what we can do about mouse events lost when the
16237 * user drags objects beyond the window boundary. Currently we can
16238 * detect this in internet explorer by verifying that the mouse is
16239 * down during the mousemove event. Firefox doesn't give us the
16240 * button state on the mousemove event.
16241 * @method handleMouseMove
16242 * @param {Event} e the event
16246 handleMouseMove: function(e) {
16247 if (! this.dragCurrent) {
16251 // var button = e.which || e.button;
16253 // check for IE mouseup outside of page boundary
16254 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16256 return this.handleMouseUp(e);
16259 if (!this.dragThreshMet) {
16260 var diffX = Math.abs(this.startX - e.getPageX());
16261 var diffY = Math.abs(this.startY - e.getPageY());
16262 if (diffX > this.clickPixelThresh ||
16263 diffY > this.clickPixelThresh) {
16264 this.startDrag(this.startX, this.startY);
16268 if (this.dragThreshMet) {
16269 this.dragCurrent.b4Drag(e);
16270 this.dragCurrent.onDrag(e);
16271 if(!this.dragCurrent.moveOnly){
16272 this.fireEvents(e, false);
16282 * Iterates over all of the DragDrop elements to find ones we are
16283 * hovering over or dropping on
16284 * @method fireEvents
16285 * @param {Event} e the event
16286 * @param {boolean} isDrop is this a drop op or a mouseover op?
16290 fireEvents: function(e, isDrop) {
16291 var dc = this.dragCurrent;
16293 // If the user did the mouse up outside of the window, we could
16294 // get here even though we have ended the drag.
16295 if (!dc || dc.isLocked()) {
16299 var pt = e.getPoint();
16301 // cache the previous dragOver array
16307 var enterEvts = [];
16309 // Check to see if the object(s) we were hovering over is no longer
16310 // being hovered over so we can fire the onDragOut event
16311 for (var i in this.dragOvers) {
16313 var ddo = this.dragOvers[i];
16315 if (! this.isTypeOfDD(ddo)) {
16319 if (! this.isOverTarget(pt, ddo, this.mode)) {
16320 outEvts.push( ddo );
16323 oldOvers[i] = true;
16324 delete this.dragOvers[i];
16327 for (var sGroup in dc.groups) {
16329 if ("string" != typeof sGroup) {
16333 for (i in this.ids[sGroup]) {
16334 var oDD = this.ids[sGroup][i];
16335 if (! this.isTypeOfDD(oDD)) {
16339 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16340 if (this.isOverTarget(pt, oDD, this.mode)) {
16341 // look for drop interactions
16343 dropEvts.push( oDD );
16344 // look for drag enter and drag over interactions
16347 // initial drag over: dragEnter fires
16348 if (!oldOvers[oDD.id]) {
16349 enterEvts.push( oDD );
16350 // subsequent drag overs: dragOver fires
16352 overEvts.push( oDD );
16355 this.dragOvers[oDD.id] = oDD;
16363 if (outEvts.length) {
16364 dc.b4DragOut(e, outEvts);
16365 dc.onDragOut(e, outEvts);
16368 if (enterEvts.length) {
16369 dc.onDragEnter(e, enterEvts);
16372 if (overEvts.length) {
16373 dc.b4DragOver(e, overEvts);
16374 dc.onDragOver(e, overEvts);
16377 if (dropEvts.length) {
16378 dc.b4DragDrop(e, dropEvts);
16379 dc.onDragDrop(e, dropEvts);
16383 // fire dragout events
16385 for (i=0, len=outEvts.length; i<len; ++i) {
16386 dc.b4DragOut(e, outEvts[i].id);
16387 dc.onDragOut(e, outEvts[i].id);
16390 // fire enter events
16391 for (i=0,len=enterEvts.length; i<len; ++i) {
16392 // dc.b4DragEnter(e, oDD.id);
16393 dc.onDragEnter(e, enterEvts[i].id);
16396 // fire over events
16397 for (i=0,len=overEvts.length; i<len; ++i) {
16398 dc.b4DragOver(e, overEvts[i].id);
16399 dc.onDragOver(e, overEvts[i].id);
16402 // fire drop events
16403 for (i=0, len=dropEvts.length; i<len; ++i) {
16404 dc.b4DragDrop(e, dropEvts[i].id);
16405 dc.onDragDrop(e, dropEvts[i].id);
16410 // notify about a drop that did not find a target
16411 if (isDrop && !dropEvts.length) {
16412 dc.onInvalidDrop(e);
16418 * Helper function for getting the best match from the list of drag
16419 * and drop objects returned by the drag and drop events when we are
16420 * in INTERSECT mode. It returns either the first object that the
16421 * cursor is over, or the object that has the greatest overlap with
16422 * the dragged element.
16423 * @method getBestMatch
16424 * @param {DragDrop[]} dds The array of drag and drop objects
16426 * @return {DragDrop} The best single match
16429 getBestMatch: function(dds) {
16431 // Return null if the input is not what we expect
16432 //if (!dds || !dds.length || dds.length == 0) {
16434 // If there is only one item, it wins
16435 //} else if (dds.length == 1) {
16437 var len = dds.length;
16442 // Loop through the targeted items
16443 for (var i=0; i<len; ++i) {
16445 // If the cursor is over the object, it wins. If the
16446 // cursor is over multiple matches, the first one we come
16448 if (dd.cursorIsOver) {
16451 // Otherwise the object with the most overlap wins
16454 winner.overlap.getArea() < dd.overlap.getArea()) {
16465 * Refreshes the cache of the top-left and bottom-right points of the
16466 * drag and drop objects in the specified group(s). This is in the
16467 * format that is stored in the drag and drop instance, so typical
16470 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16474 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16476 * @TODO this really should be an indexed array. Alternatively this
16477 * method could accept both.
16478 * @method refreshCache
16479 * @param {Object} groups an associative array of groups to refresh
16482 refreshCache: function(groups) {
16483 for (var sGroup in groups) {
16484 if ("string" != typeof sGroup) {
16487 for (var i in this.ids[sGroup]) {
16488 var oDD = this.ids[sGroup][i];
16490 if (this.isTypeOfDD(oDD)) {
16491 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16492 var loc = this.getLocation(oDD);
16494 this.locationCache[oDD.id] = loc;
16496 delete this.locationCache[oDD.id];
16497 // this will unregister the drag and drop object if
16498 // the element is not in a usable state
16507 * This checks to make sure an element exists and is in the DOM. The
16508 * main purpose is to handle cases where innerHTML is used to remove
16509 * drag and drop objects from the DOM. IE provides an 'unspecified
16510 * error' when trying to access the offsetParent of such an element
16512 * @param {HTMLElement} el the element to check
16513 * @return {boolean} true if the element looks usable
16516 verifyEl: function(el) {
16521 parent = el.offsetParent;
16524 parent = el.offsetParent;
16535 * Returns a Region object containing the drag and drop element's position
16536 * and size, including the padding configured for it
16537 * @method getLocation
16538 * @param {DragDrop} oDD the drag and drop object to get the
16540 * @return {Roo.lib.Region} a Region object representing the total area
16541 * the element occupies, including any padding
16542 * the instance is configured for.
16545 getLocation: function(oDD) {
16546 if (! this.isTypeOfDD(oDD)) {
16550 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16553 pos= Roo.lib.Dom.getXY(el);
16561 x2 = x1 + el.offsetWidth;
16563 y2 = y1 + el.offsetHeight;
16565 t = y1 - oDD.padding[0];
16566 r = x2 + oDD.padding[1];
16567 b = y2 + oDD.padding[2];
16568 l = x1 - oDD.padding[3];
16570 return new Roo.lib.Region( t, r, b, l );
16574 * Checks the cursor location to see if it over the target
16575 * @method isOverTarget
16576 * @param {Roo.lib.Point} pt The point to evaluate
16577 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16578 * @return {boolean} true if the mouse is over the target
16582 isOverTarget: function(pt, oTarget, intersect) {
16583 // use cache if available
16584 var loc = this.locationCache[oTarget.id];
16585 if (!loc || !this.useCache) {
16586 loc = this.getLocation(oTarget);
16587 this.locationCache[oTarget.id] = loc;
16595 oTarget.cursorIsOver = loc.contains( pt );
16597 // DragDrop is using this as a sanity check for the initial mousedown
16598 // in this case we are done. In POINT mode, if the drag obj has no
16599 // contraints, we are also done. Otherwise we need to evaluate the
16600 // location of the target as related to the actual location of the
16601 // dragged element.
16602 var dc = this.dragCurrent;
16603 if (!dc || !dc.getTargetCoord ||
16604 (!intersect && !dc.constrainX && !dc.constrainY)) {
16605 return oTarget.cursorIsOver;
16608 oTarget.overlap = null;
16610 // Get the current location of the drag element, this is the
16611 // location of the mouse event less the delta that represents
16612 // where the original mousedown happened on the element. We
16613 // need to consider constraints and ticks as well.
16614 var pos = dc.getTargetCoord(pt.x, pt.y);
16616 var el = dc.getDragEl();
16617 var curRegion = new Roo.lib.Region( pos.y,
16618 pos.x + el.offsetWidth,
16619 pos.y + el.offsetHeight,
16622 var overlap = curRegion.intersect(loc);
16625 oTarget.overlap = overlap;
16626 return (intersect) ? true : oTarget.cursorIsOver;
16633 * unload event handler
16634 * @method _onUnload
16638 _onUnload: function(e, me) {
16639 Roo.dd.DragDropMgr.unregAll();
16643 * Cleans up the drag and drop events and objects.
16648 unregAll: function() {
16650 if (this.dragCurrent) {
16652 this.dragCurrent = null;
16655 this._execOnAll("unreg", []);
16657 for (i in this.elementCache) {
16658 delete this.elementCache[i];
16661 this.elementCache = {};
16666 * A cache of DOM elements
16667 * @property elementCache
16674 * Get the wrapper for the DOM element specified
16675 * @method getElWrapper
16676 * @param {String} id the id of the element to get
16677 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16679 * @deprecated This wrapper isn't that useful
16682 getElWrapper: function(id) {
16683 var oWrapper = this.elementCache[id];
16684 if (!oWrapper || !oWrapper.el) {
16685 oWrapper = this.elementCache[id] =
16686 new this.ElementWrapper(Roo.getDom(id));
16692 * Returns the actual DOM element
16693 * @method getElement
16694 * @param {String} id the id of the elment to get
16695 * @return {Object} The element
16696 * @deprecated use Roo.getDom instead
16699 getElement: function(id) {
16700 return Roo.getDom(id);
16704 * Returns the style property for the DOM element (i.e.,
16705 * document.getElById(id).style)
16707 * @param {String} id the id of the elment to get
16708 * @return {Object} The style property of the element
16709 * @deprecated use Roo.getDom instead
16712 getCss: function(id) {
16713 var el = Roo.getDom(id);
16714 return (el) ? el.style : null;
16718 * Inner class for cached elements
16719 * @class DragDropMgr.ElementWrapper
16724 ElementWrapper: function(el) {
16729 this.el = el || null;
16734 this.id = this.el && el.id;
16736 * A reference to the style property
16739 this.css = this.el && el.style;
16743 * Returns the X position of an html element
16745 * @param el the element for which to get the position
16746 * @return {int} the X coordinate
16748 * @deprecated use Roo.lib.Dom.getX instead
16751 getPosX: function(el) {
16752 return Roo.lib.Dom.getX(el);
16756 * Returns the Y position of an html element
16758 * @param el the element for which to get the position
16759 * @return {int} the Y coordinate
16760 * @deprecated use Roo.lib.Dom.getY instead
16763 getPosY: function(el) {
16764 return Roo.lib.Dom.getY(el);
16768 * Swap two nodes. In IE, we use the native method, for others we
16769 * emulate the IE behavior
16771 * @param n1 the first node to swap
16772 * @param n2 the other node to swap
16775 swapNode: function(n1, n2) {
16779 var p = n2.parentNode;
16780 var s = n2.nextSibling;
16783 p.insertBefore(n1, n2);
16784 } else if (n2 == n1.nextSibling) {
16785 p.insertBefore(n2, n1);
16787 n1.parentNode.replaceChild(n2, n1);
16788 p.insertBefore(n1, s);
16794 * Returns the current scroll position
16795 * @method getScroll
16799 getScroll: function () {
16800 var t, l, dde=document.documentElement, db=document.body;
16801 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16803 l = dde.scrollLeft;
16810 return { top: t, left: l };
16814 * Returns the specified element style property
16816 * @param {HTMLElement} el the element
16817 * @param {string} styleProp the style property
16818 * @return {string} The value of the style property
16819 * @deprecated use Roo.lib.Dom.getStyle
16822 getStyle: function(el, styleProp) {
16823 return Roo.fly(el).getStyle(styleProp);
16827 * Gets the scrollTop
16828 * @method getScrollTop
16829 * @return {int} the document's scrollTop
16832 getScrollTop: function () { return this.getScroll().top; },
16835 * Gets the scrollLeft
16836 * @method getScrollLeft
16837 * @return {int} the document's scrollTop
16840 getScrollLeft: function () { return this.getScroll().left; },
16843 * Sets the x/y position of an element to the location of the
16846 * @param {HTMLElement} moveEl The element to move
16847 * @param {HTMLElement} targetEl The position reference element
16850 moveToEl: function (moveEl, targetEl) {
16851 var aCoord = Roo.lib.Dom.getXY(targetEl);
16852 Roo.lib.Dom.setXY(moveEl, aCoord);
16856 * Numeric array sort function
16857 * @method numericSort
16860 numericSort: function(a, b) { return (a - b); },
16864 * @property _timeoutCount
16871 * Trying to make the load order less important. Without this we get
16872 * an error if this file is loaded before the Event Utility.
16873 * @method _addListeners
16877 _addListeners: function() {
16878 var DDM = Roo.dd.DDM;
16879 if ( Roo.lib.Event && document ) {
16882 if (DDM._timeoutCount > 2000) {
16884 setTimeout(DDM._addListeners, 10);
16885 if (document && document.body) {
16886 DDM._timeoutCount += 1;
16893 * Recursively searches the immediate parent and all child nodes for
16894 * the handle element in order to determine wheter or not it was
16896 * @method handleWasClicked
16897 * @param node the html element to inspect
16900 handleWasClicked: function(node, id) {
16901 if (this.isHandle(id, node.id)) {
16904 // check to see if this is a text node child of the one we want
16905 var p = node.parentNode;
16908 if (this.isHandle(id, p.id)) {
16923 // shorter alias, save a few bytes
16924 Roo.dd.DDM = Roo.dd.DragDropMgr;
16925 Roo.dd.DDM._addListeners();
16929 * Ext JS Library 1.1.1
16930 * Copyright(c) 2006-2007, Ext JS, LLC.
16932 * Originally Released Under LGPL - original licence link has changed is not relivant.
16935 * <script type="text/javascript">
16940 * A DragDrop implementation where the linked element follows the
16941 * mouse cursor during a drag.
16942 * @extends Roo.dd.DragDrop
16944 * @param {String} id the id of the linked element
16945 * @param {String} sGroup the group of related DragDrop items
16946 * @param {object} config an object containing configurable attributes
16947 * Valid properties for DD:
16950 Roo.dd.DD = function(id, sGroup, config) {
16952 this.init(id, sGroup, config);
16956 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16959 * When set to true, the utility automatically tries to scroll the browser
16960 * window wehn a drag and drop element is dragged near the viewport boundary.
16961 * Defaults to true.
16968 * Sets the pointer offset to the distance between the linked element's top
16969 * left corner and the location the element was clicked
16970 * @method autoOffset
16971 * @param {int} iPageX the X coordinate of the click
16972 * @param {int} iPageY the Y coordinate of the click
16974 autoOffset: function(iPageX, iPageY) {
16975 var x = iPageX - this.startPageX;
16976 var y = iPageY - this.startPageY;
16977 this.setDelta(x, y);
16981 * Sets the pointer offset. You can call this directly to force the
16982 * offset to be in a particular location (e.g., pass in 0,0 to set it
16983 * to the center of the object)
16985 * @param {int} iDeltaX the distance from the left
16986 * @param {int} iDeltaY the distance from the top
16988 setDelta: function(iDeltaX, iDeltaY) {
16989 this.deltaX = iDeltaX;
16990 this.deltaY = iDeltaY;
16994 * Sets the drag element to the location of the mousedown or click event,
16995 * maintaining the cursor location relative to the location on the element
16996 * that was clicked. Override this if you want to place the element in a
16997 * location other than where the cursor is.
16998 * @method setDragElPos
16999 * @param {int} iPageX the X coordinate of the mousedown or drag event
17000 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17002 setDragElPos: function(iPageX, iPageY) {
17003 // the first time we do this, we are going to check to make sure
17004 // the element has css positioning
17006 var el = this.getDragEl();
17007 this.alignElWithMouse(el, iPageX, iPageY);
17011 * Sets the element to the location of the mousedown or click event,
17012 * maintaining the cursor location relative to the location on the element
17013 * that was clicked. Override this if you want to place the element in a
17014 * location other than where the cursor is.
17015 * @method alignElWithMouse
17016 * @param {HTMLElement} el the element to move
17017 * @param {int} iPageX the X coordinate of the mousedown or drag event
17018 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17020 alignElWithMouse: function(el, iPageX, iPageY) {
17021 var oCoord = this.getTargetCoord(iPageX, iPageY);
17022 var fly = el.dom ? el : Roo.fly(el);
17023 if (!this.deltaSetXY) {
17024 var aCoord = [oCoord.x, oCoord.y];
17026 var newLeft = fly.getLeft(true);
17027 var newTop = fly.getTop(true);
17028 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
17030 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
17033 this.cachePosition(oCoord.x, oCoord.y);
17034 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
17039 * Saves the most recent position so that we can reset the constraints and
17040 * tick marks on-demand. We need to know this so that we can calculate the
17041 * number of pixels the element is offset from its original position.
17042 * @method cachePosition
17043 * @param iPageX the current x position (optional, this just makes it so we
17044 * don't have to look it up again)
17045 * @param iPageY the current y position (optional, this just makes it so we
17046 * don't have to look it up again)
17048 cachePosition: function(iPageX, iPageY) {
17050 this.lastPageX = iPageX;
17051 this.lastPageY = iPageY;
17053 var aCoord = Roo.lib.Dom.getXY(this.getEl());
17054 this.lastPageX = aCoord[0];
17055 this.lastPageY = aCoord[1];
17060 * Auto-scroll the window if the dragged object has been moved beyond the
17061 * visible window boundary.
17062 * @method autoScroll
17063 * @param {int} x the drag element's x position
17064 * @param {int} y the drag element's y position
17065 * @param {int} h the height of the drag element
17066 * @param {int} w the width of the drag element
17069 autoScroll: function(x, y, h, w) {
17072 // The client height
17073 var clientH = Roo.lib.Dom.getViewWidth();
17075 // The client width
17076 var clientW = Roo.lib.Dom.getViewHeight();
17078 // The amt scrolled down
17079 var st = this.DDM.getScrollTop();
17081 // The amt scrolled right
17082 var sl = this.DDM.getScrollLeft();
17084 // Location of the bottom of the element
17087 // Location of the right of the element
17090 // The distance from the cursor to the bottom of the visible area,
17091 // adjusted so that we don't scroll if the cursor is beyond the
17092 // element drag constraints
17093 var toBot = (clientH + st - y - this.deltaY);
17095 // The distance from the cursor to the right of the visible area
17096 var toRight = (clientW + sl - x - this.deltaX);
17099 // How close to the edge the cursor must be before we scroll
17100 // var thresh = (document.all) ? 100 : 40;
17103 // How many pixels to scroll per autoscroll op. This helps to reduce
17104 // clunky scrolling. IE is more sensitive about this ... it needs this
17105 // value to be higher.
17106 var scrAmt = (document.all) ? 80 : 30;
17108 // Scroll down if we are near the bottom of the visible page and the
17109 // obj extends below the crease
17110 if ( bot > clientH && toBot < thresh ) {
17111 window.scrollTo(sl, st + scrAmt);
17114 // Scroll up if the window is scrolled down and the top of the object
17115 // goes above the top border
17116 if ( y < st && st > 0 && y - st < thresh ) {
17117 window.scrollTo(sl, st - scrAmt);
17120 // Scroll right if the obj is beyond the right border and the cursor is
17121 // near the border.
17122 if ( right > clientW && toRight < thresh ) {
17123 window.scrollTo(sl + scrAmt, st);
17126 // Scroll left if the window has been scrolled to the right and the obj
17127 // extends past the left border
17128 if ( x < sl && sl > 0 && x - sl < thresh ) {
17129 window.scrollTo(sl - scrAmt, st);
17135 * Finds the location the element should be placed if we want to move
17136 * it to where the mouse location less the click offset would place us.
17137 * @method getTargetCoord
17138 * @param {int} iPageX the X coordinate of the click
17139 * @param {int} iPageY the Y coordinate of the click
17140 * @return an object that contains the coordinates (Object.x and Object.y)
17143 getTargetCoord: function(iPageX, iPageY) {
17146 var x = iPageX - this.deltaX;
17147 var y = iPageY - this.deltaY;
17149 if (this.constrainX) {
17150 if (x < this.minX) { x = this.minX; }
17151 if (x > this.maxX) { x = this.maxX; }
17154 if (this.constrainY) {
17155 if (y < this.minY) { y = this.minY; }
17156 if (y > this.maxY) { y = this.maxY; }
17159 x = this.getTick(x, this.xTicks);
17160 y = this.getTick(y, this.yTicks);
17167 * Sets up config options specific to this class. Overrides
17168 * Roo.dd.DragDrop, but all versions of this method through the
17169 * inheritance chain are called
17171 applyConfig: function() {
17172 Roo.dd.DD.superclass.applyConfig.call(this);
17173 this.scroll = (this.config.scroll !== false);
17177 * Event that fires prior to the onMouseDown event. Overrides
17180 b4MouseDown: function(e) {
17181 // this.resetConstraints();
17182 this.autoOffset(e.getPageX(),
17187 * Event that fires prior to the onDrag event. Overrides
17190 b4Drag: function(e) {
17191 this.setDragElPos(e.getPageX(),
17195 toString: function() {
17196 return ("DD " + this.id);
17199 //////////////////////////////////////////////////////////////////////////
17200 // Debugging ygDragDrop events that can be overridden
17201 //////////////////////////////////////////////////////////////////////////
17203 startDrag: function(x, y) {
17206 onDrag: function(e) {
17209 onDragEnter: function(e, id) {
17212 onDragOver: function(e, id) {
17215 onDragOut: function(e, id) {
17218 onDragDrop: function(e, id) {
17221 endDrag: function(e) {
17228 * Ext JS Library 1.1.1
17229 * Copyright(c) 2006-2007, Ext JS, LLC.
17231 * Originally Released Under LGPL - original licence link has changed is not relivant.
17234 * <script type="text/javascript">
17238 * @class Roo.dd.DDProxy
17239 * A DragDrop implementation that inserts an empty, bordered div into
17240 * the document that follows the cursor during drag operations. At the time of
17241 * the click, the frame div is resized to the dimensions of the linked html
17242 * element, and moved to the exact location of the linked element.
17244 * References to the "frame" element refer to the single proxy element that
17245 * was created to be dragged in place of all DDProxy elements on the
17248 * @extends Roo.dd.DD
17250 * @param {String} id the id of the linked html element
17251 * @param {String} sGroup the group of related DragDrop objects
17252 * @param {object} config an object containing configurable attributes
17253 * Valid properties for DDProxy in addition to those in DragDrop:
17254 * resizeFrame, centerFrame, dragElId
17256 Roo.dd.DDProxy = function(id, sGroup, config) {
17258 this.init(id, sGroup, config);
17264 * The default drag frame div id
17265 * @property Roo.dd.DDProxy.dragElId
17269 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17271 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17274 * By default we resize the drag frame to be the same size as the element
17275 * we want to drag (this is to get the frame effect). We can turn it off
17276 * if we want a different behavior.
17277 * @property resizeFrame
17283 * By default the frame is positioned exactly where the drag element is, so
17284 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17285 * you do not have constraints on the obj is to have the drag frame centered
17286 * around the cursor. Set centerFrame to true for this effect.
17287 * @property centerFrame
17290 centerFrame: false,
17293 * Creates the proxy element if it does not yet exist
17294 * @method createFrame
17296 createFrame: function() {
17298 var body = document.body;
17300 if (!body || !body.firstChild) {
17301 setTimeout( function() { self.createFrame(); }, 50 );
17305 var div = this.getDragEl();
17308 div = document.createElement("div");
17309 div.id = this.dragElId;
17312 s.position = "absolute";
17313 s.visibility = "hidden";
17315 s.border = "2px solid #aaa";
17318 // appendChild can blow up IE if invoked prior to the window load event
17319 // while rendering a table. It is possible there are other scenarios
17320 // that would cause this to happen as well.
17321 body.insertBefore(div, body.firstChild);
17326 * Initialization for the drag frame element. Must be called in the
17327 * constructor of all subclasses
17328 * @method initFrame
17330 initFrame: function() {
17331 this.createFrame();
17334 applyConfig: function() {
17335 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17337 this.resizeFrame = (this.config.resizeFrame !== false);
17338 this.centerFrame = (this.config.centerFrame);
17339 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17343 * Resizes the drag frame to the dimensions of the clicked object, positions
17344 * it over the object, and finally displays it
17345 * @method showFrame
17346 * @param {int} iPageX X click position
17347 * @param {int} iPageY Y click position
17350 showFrame: function(iPageX, iPageY) {
17351 var el = this.getEl();
17352 var dragEl = this.getDragEl();
17353 var s = dragEl.style;
17355 this._resizeProxy();
17357 if (this.centerFrame) {
17358 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17359 Math.round(parseInt(s.height, 10)/2) );
17362 this.setDragElPos(iPageX, iPageY);
17364 Roo.fly(dragEl).show();
17368 * The proxy is automatically resized to the dimensions of the linked
17369 * element when a drag is initiated, unless resizeFrame is set to false
17370 * @method _resizeProxy
17373 _resizeProxy: function() {
17374 if (this.resizeFrame) {
17375 var el = this.getEl();
17376 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17380 // overrides Roo.dd.DragDrop
17381 b4MouseDown: function(e) {
17382 var x = e.getPageX();
17383 var y = e.getPageY();
17384 this.autoOffset(x, y);
17385 this.setDragElPos(x, y);
17388 // overrides Roo.dd.DragDrop
17389 b4StartDrag: function(x, y) {
17390 // show the drag frame
17391 this.showFrame(x, y);
17394 // overrides Roo.dd.DragDrop
17395 b4EndDrag: function(e) {
17396 Roo.fly(this.getDragEl()).hide();
17399 // overrides Roo.dd.DragDrop
17400 // By default we try to move the element to the last location of the frame.
17401 // This is so that the default behavior mirrors that of Roo.dd.DD.
17402 endDrag: function(e) {
17404 var lel = this.getEl();
17405 var del = this.getDragEl();
17407 // Show the drag frame briefly so we can get its position
17408 del.style.visibility = "";
17411 // Hide the linked element before the move to get around a Safari
17413 lel.style.visibility = "hidden";
17414 Roo.dd.DDM.moveToEl(lel, del);
17415 del.style.visibility = "hidden";
17416 lel.style.visibility = "";
17421 beforeMove : function(){
17425 afterDrag : function(){
17429 toString: function() {
17430 return ("DDProxy " + this.id);
17436 * Ext JS Library 1.1.1
17437 * Copyright(c) 2006-2007, Ext JS, LLC.
17439 * Originally Released Under LGPL - original licence link has changed is not relivant.
17442 * <script type="text/javascript">
17446 * @class Roo.dd.DDTarget
17447 * A DragDrop implementation that does not move, but can be a drop
17448 * target. You would get the same result by simply omitting implementation
17449 * for the event callbacks, but this way we reduce the processing cost of the
17450 * event listener and the callbacks.
17451 * @extends Roo.dd.DragDrop
17453 * @param {String} id the id of the element that is a drop target
17454 * @param {String} sGroup the group of related DragDrop objects
17455 * @param {object} config an object containing configurable attributes
17456 * Valid properties for DDTarget in addition to those in
17460 Roo.dd.DDTarget = function(id, sGroup, config) {
17462 this.initTarget(id, sGroup, config);
17464 if (config.listeners || config.events) {
17465 Roo.dd.DragDrop.superclass.constructor.call(this, {
17466 listeners : config.listeners || {},
17467 events : config.events || {}
17472 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17473 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17474 toString: function() {
17475 return ("DDTarget " + this.id);
17480 * Ext JS Library 1.1.1
17481 * Copyright(c) 2006-2007, Ext JS, LLC.
17483 * Originally Released Under LGPL - original licence link has changed is not relivant.
17486 * <script type="text/javascript">
17491 * @class Roo.dd.ScrollManager
17492 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17493 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17496 Roo.dd.ScrollManager = function(){
17497 var ddm = Roo.dd.DragDropMgr;
17502 var onStop = function(e){
17507 var triggerRefresh = function(){
17508 if(ddm.dragCurrent){
17509 ddm.refreshCache(ddm.dragCurrent.groups);
17513 var doScroll = function(){
17514 if(ddm.dragCurrent){
17515 var dds = Roo.dd.ScrollManager;
17517 if(proc.el.scroll(proc.dir, dds.increment)){
17521 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17526 var clearProc = function(){
17528 clearInterval(proc.id);
17535 var startProc = function(el, dir){
17539 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17542 var onFire = function(e, isDrop){
17543 if(isDrop || !ddm.dragCurrent){ return; }
17544 var dds = Roo.dd.ScrollManager;
17545 if(!dragEl || dragEl != ddm.dragCurrent){
17546 dragEl = ddm.dragCurrent;
17547 // refresh regions on drag start
17548 dds.refreshCache();
17551 var xy = Roo.lib.Event.getXY(e);
17552 var pt = new Roo.lib.Point(xy[0], xy[1]);
17553 for(var id in els){
17554 var el = els[id], r = el._region;
17555 if(r && r.contains(pt) && el.isScrollable()){
17556 if(r.bottom - pt.y <= dds.thresh){
17558 startProc(el, "down");
17561 }else if(r.right - pt.x <= dds.thresh){
17563 startProc(el, "left");
17566 }else if(pt.y - r.top <= dds.thresh){
17568 startProc(el, "up");
17571 }else if(pt.x - r.left <= dds.thresh){
17573 startProc(el, "right");
17582 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17583 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17587 * Registers new overflow element(s) to auto scroll
17588 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17590 register : function(el){
17591 if(el instanceof Array){
17592 for(var i = 0, len = el.length; i < len; i++) {
17593 this.register(el[i]);
17602 * Unregisters overflow element(s) so they are no longer scrolled
17603 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17605 unregister : function(el){
17606 if(el instanceof Array){
17607 for(var i = 0, len = el.length; i < len; i++) {
17608 this.unregister(el[i]);
17617 * The number of pixels from the edge of a container the pointer needs to be to
17618 * trigger scrolling (defaults to 25)
17624 * The number of pixels to scroll in each scroll increment (defaults to 50)
17630 * The frequency of scrolls in milliseconds (defaults to 500)
17636 * True to animate the scroll (defaults to true)
17642 * The animation duration in seconds -
17643 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17649 * Manually trigger a cache refresh.
17651 refreshCache : function(){
17652 for(var id in els){
17653 if(typeof els[id] == 'object'){ // for people extending the object prototype
17654 els[id]._region = els[id].getRegion();
17661 * Ext JS Library 1.1.1
17662 * Copyright(c) 2006-2007, Ext JS, LLC.
17664 * Originally Released Under LGPL - original licence link has changed is not relivant.
17667 * <script type="text/javascript">
17672 * @class Roo.dd.Registry
17673 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17674 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17677 Roo.dd.Registry = function(){
17680 var autoIdSeed = 0;
17682 var getId = function(el, autogen){
17683 if(typeof el == "string"){
17687 if(!id && autogen !== false){
17688 id = "roodd-" + (++autoIdSeed);
17696 * Register a drag drop element
17697 * @param {String|HTMLElement} element The id or DOM node to register
17698 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17699 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17700 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17701 * populated in the data object (if applicable):
17703 Value Description<br />
17704 --------- ------------------------------------------<br />
17705 handles Array of DOM nodes that trigger dragging<br />
17706 for the element being registered<br />
17707 isHandle True if the element passed in triggers<br />
17708 dragging itself, else false
17711 register : function(el, data){
17713 if(typeof el == "string"){
17714 el = document.getElementById(el);
17717 elements[getId(el)] = data;
17718 if(data.isHandle !== false){
17719 handles[data.ddel.id] = data;
17722 var hs = data.handles;
17723 for(var i = 0, len = hs.length; i < len; i++){
17724 handles[getId(hs[i])] = data;
17730 * Unregister a drag drop element
17731 * @param {String|HTMLElement} element The id or DOM node to unregister
17733 unregister : function(el){
17734 var id = getId(el, false);
17735 var data = elements[id];
17737 delete elements[id];
17739 var hs = data.handles;
17740 for(var i = 0, len = hs.length; i < len; i++){
17741 delete handles[getId(hs[i], false)];
17748 * Returns the handle registered for a DOM Node by id
17749 * @param {String|HTMLElement} id The DOM node or id to look up
17750 * @return {Object} handle The custom handle data
17752 getHandle : function(id){
17753 if(typeof id != "string"){ // must be element?
17756 return handles[id];
17760 * Returns the handle that is registered for the DOM node that is the target of the event
17761 * @param {Event} e The event
17762 * @return {Object} handle The custom handle data
17764 getHandleFromEvent : function(e){
17765 var t = Roo.lib.Event.getTarget(e);
17766 return t ? handles[t.id] : null;
17770 * Returns a custom data object that is registered for a DOM node by id
17771 * @param {String|HTMLElement} id The DOM node or id to look up
17772 * @return {Object} data The custom data
17774 getTarget : function(id){
17775 if(typeof id != "string"){ // must be element?
17778 return elements[id];
17782 * Returns a custom data object that is registered for the DOM node that is the target of the event
17783 * @param {Event} e The event
17784 * @return {Object} data The custom data
17786 getTargetFromEvent : function(e){
17787 var t = Roo.lib.Event.getTarget(e);
17788 return t ? elements[t.id] || handles[t.id] : null;
17793 * Ext JS Library 1.1.1
17794 * Copyright(c) 2006-2007, Ext JS, LLC.
17796 * Originally Released Under LGPL - original licence link has changed is not relivant.
17799 * <script type="text/javascript">
17804 * @class Roo.dd.StatusProxy
17805 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17806 * default drag proxy used by all Roo.dd components.
17808 * @param {Object} config
17810 Roo.dd.StatusProxy = function(config){
17811 Roo.apply(this, config);
17812 this.id = this.id || Roo.id();
17813 this.el = new Roo.Layer({
17815 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17816 {tag: "div", cls: "x-dd-drop-icon"},
17817 {tag: "div", cls: "x-dd-drag-ghost"}
17820 shadow: !config || config.shadow !== false
17822 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17823 this.dropStatus = this.dropNotAllowed;
17826 Roo.dd.StatusProxy.prototype = {
17828 * @cfg {String} dropAllowed
17829 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17831 dropAllowed : "x-dd-drop-ok",
17833 * @cfg {String} dropNotAllowed
17834 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17836 dropNotAllowed : "x-dd-drop-nodrop",
17839 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17840 * over the current target element.
17841 * @param {String} cssClass The css class for the new drop status indicator image
17843 setStatus : function(cssClass){
17844 cssClass = cssClass || this.dropNotAllowed;
17845 if(this.dropStatus != cssClass){
17846 this.el.replaceClass(this.dropStatus, cssClass);
17847 this.dropStatus = cssClass;
17852 * Resets the status indicator to the default dropNotAllowed value
17853 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17855 reset : function(clearGhost){
17856 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17857 this.dropStatus = this.dropNotAllowed;
17859 this.ghost.update("");
17864 * Updates the contents of the ghost element
17865 * @param {String} html The html that will replace the current innerHTML of the ghost element
17867 update : function(html){
17868 if(typeof html == "string"){
17869 this.ghost.update(html);
17871 this.ghost.update("");
17872 html.style.margin = "0";
17873 this.ghost.dom.appendChild(html);
17875 // ensure float = none set?? cant remember why though.
17876 var el = this.ghost.dom.firstChild;
17878 Roo.fly(el).setStyle('float', 'none');
17883 * Returns the underlying proxy {@link Roo.Layer}
17884 * @return {Roo.Layer} el
17886 getEl : function(){
17891 * Returns the ghost element
17892 * @return {Roo.Element} el
17894 getGhost : function(){
17900 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17902 hide : function(clear){
17910 * Stops the repair animation if it's currently running
17913 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17919 * Displays this proxy
17926 * Force the Layer to sync its shadow and shim positions to the element
17933 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17934 * invalid drop operation by the item being dragged.
17935 * @param {Array} xy The XY position of the element ([x, y])
17936 * @param {Function} callback The function to call after the repair is complete
17937 * @param {Object} scope The scope in which to execute the callback
17939 repair : function(xy, callback, scope){
17940 this.callback = callback;
17941 this.scope = scope;
17942 if(xy && this.animRepair !== false){
17943 this.el.addClass("x-dd-drag-repair");
17944 this.el.hideUnders(true);
17945 this.anim = this.el.shift({
17946 duration: this.repairDuration || .5,
17950 callback: this.afterRepair,
17954 this.afterRepair();
17959 afterRepair : function(){
17961 if(typeof this.callback == "function"){
17962 this.callback.call(this.scope || this);
17964 this.callback = null;
17969 * Ext JS Library 1.1.1
17970 * Copyright(c) 2006-2007, Ext JS, LLC.
17972 * Originally Released Under LGPL - original licence link has changed is not relivant.
17975 * <script type="text/javascript">
17979 * @class Roo.dd.DragSource
17980 * @extends Roo.dd.DDProxy
17981 * A simple class that provides the basic implementation needed to make any element draggable.
17983 * @param {String/HTMLElement/Element} el The container element
17984 * @param {Object} config
17986 Roo.dd.DragSource = function(el, config){
17987 this.el = Roo.get(el);
17988 this.dragData = {};
17990 Roo.apply(this, config);
17993 this.proxy = new Roo.dd.StatusProxy();
17996 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
17997 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
17999 this.dragging = false;
18002 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
18004 * @cfg {String} dropAllowed
18005 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18007 dropAllowed : "x-dd-drop-ok",
18009 * @cfg {String} dropNotAllowed
18010 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18012 dropNotAllowed : "x-dd-drop-nodrop",
18015 * Returns the data object associated with this drag source
18016 * @return {Object} data An object containing arbitrary data
18018 getDragData : function(e){
18019 return this.dragData;
18023 onDragEnter : function(e, id){
18024 var target = Roo.dd.DragDropMgr.getDDById(id);
18025 this.cachedTarget = target;
18026 if(this.beforeDragEnter(target, e, id) !== false){
18027 if(target.isNotifyTarget){
18028 var status = target.notifyEnter(this, e, this.dragData);
18029 this.proxy.setStatus(status);
18031 this.proxy.setStatus(this.dropAllowed);
18034 if(this.afterDragEnter){
18036 * An empty function by default, but provided so that you can perform a custom action
18037 * when the dragged item enters the drop target by providing an implementation.
18038 * @param {Roo.dd.DragDrop} target The drop target
18039 * @param {Event} e The event object
18040 * @param {String} id The id of the dragged element
18041 * @method afterDragEnter
18043 this.afterDragEnter(target, e, id);
18049 * An empty function by default, but provided so that you can perform a custom action
18050 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
18051 * @param {Roo.dd.DragDrop} target The drop target
18052 * @param {Event} e The event object
18053 * @param {String} id The id of the dragged element
18054 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18056 beforeDragEnter : function(target, e, id){
18061 alignElWithMouse: function() {
18062 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18067 onDragOver : function(e, id){
18068 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18069 if(this.beforeDragOver(target, e, id) !== false){
18070 if(target.isNotifyTarget){
18071 var status = target.notifyOver(this, e, this.dragData);
18072 this.proxy.setStatus(status);
18075 if(this.afterDragOver){
18077 * An empty function by default, but provided so that you can perform a custom action
18078 * while the dragged item is over the drop target by providing an implementation.
18079 * @param {Roo.dd.DragDrop} target The drop target
18080 * @param {Event} e The event object
18081 * @param {String} id The id of the dragged element
18082 * @method afterDragOver
18084 this.afterDragOver(target, e, id);
18090 * An empty function by default, but provided so that you can perform a custom action
18091 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18092 * @param {Roo.dd.DragDrop} target The drop target
18093 * @param {Event} e The event object
18094 * @param {String} id The id of the dragged element
18095 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18097 beforeDragOver : function(target, e, id){
18102 onDragOut : function(e, id){
18103 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18104 if(this.beforeDragOut(target, e, id) !== false){
18105 if(target.isNotifyTarget){
18106 target.notifyOut(this, e, this.dragData);
18108 this.proxy.reset();
18109 if(this.afterDragOut){
18111 * An empty function by default, but provided so that you can perform a custom action
18112 * after the dragged item is dragged out of the target without dropping.
18113 * @param {Roo.dd.DragDrop} target The drop target
18114 * @param {Event} e The event object
18115 * @param {String} id The id of the dragged element
18116 * @method afterDragOut
18118 this.afterDragOut(target, e, id);
18121 this.cachedTarget = null;
18125 * An empty function by default, but provided so that you can perform a custom action before the dragged
18126 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18127 * @param {Roo.dd.DragDrop} target The drop target
18128 * @param {Event} e The event object
18129 * @param {String} id The id of the dragged element
18130 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18132 beforeDragOut : function(target, e, id){
18137 onDragDrop : function(e, id){
18138 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18139 if(this.beforeDragDrop(target, e, id) !== false){
18140 if(target.isNotifyTarget){
18141 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18142 this.onValidDrop(target, e, id);
18144 this.onInvalidDrop(target, e, id);
18147 this.onValidDrop(target, e, id);
18150 if(this.afterDragDrop){
18152 * An empty function by default, but provided so that you can perform a custom action
18153 * after a valid drag drop has occurred by providing an implementation.
18154 * @param {Roo.dd.DragDrop} target The drop target
18155 * @param {Event} e The event object
18156 * @param {String} id The id of the dropped element
18157 * @method afterDragDrop
18159 this.afterDragDrop(target, e, id);
18162 delete this.cachedTarget;
18166 * An empty function by default, but provided so that you can perform a custom action before the dragged
18167 * item is dropped onto the target and optionally cancel the onDragDrop.
18168 * @param {Roo.dd.DragDrop} target The drop target
18169 * @param {Event} e The event object
18170 * @param {String} id The id of the dragged element
18171 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18173 beforeDragDrop : function(target, e, id){
18178 onValidDrop : function(target, e, id){
18180 if(this.afterValidDrop){
18182 * An empty function by default, but provided so that you can perform a custom action
18183 * after a valid drop has occurred by providing an implementation.
18184 * @param {Object} target The target DD
18185 * @param {Event} e The event object
18186 * @param {String} id The id of the dropped element
18187 * @method afterInvalidDrop
18189 this.afterValidDrop(target, e, id);
18194 getRepairXY : function(e, data){
18195 return this.el.getXY();
18199 onInvalidDrop : function(target, e, id){
18200 this.beforeInvalidDrop(target, e, id);
18201 if(this.cachedTarget){
18202 if(this.cachedTarget.isNotifyTarget){
18203 this.cachedTarget.notifyOut(this, e, this.dragData);
18205 this.cacheTarget = null;
18207 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18209 if(this.afterInvalidDrop){
18211 * An empty function by default, but provided so that you can perform a custom action
18212 * after an invalid drop has occurred by providing an implementation.
18213 * @param {Event} e The event object
18214 * @param {String} id The id of the dropped element
18215 * @method afterInvalidDrop
18217 this.afterInvalidDrop(e, id);
18222 afterRepair : function(){
18224 this.el.highlight(this.hlColor || "c3daf9");
18226 this.dragging = false;
18230 * An empty function by default, but provided so that you can perform a custom action after an invalid
18231 * drop has occurred.
18232 * @param {Roo.dd.DragDrop} target The drop target
18233 * @param {Event} e The event object
18234 * @param {String} id The id of the dragged element
18235 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18237 beforeInvalidDrop : function(target, e, id){
18242 handleMouseDown : function(e){
18243 if(this.dragging) {
18246 var data = this.getDragData(e);
18247 if(data && this.onBeforeDrag(data, e) !== false){
18248 this.dragData = data;
18250 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18255 * An empty function by default, but provided so that you can perform a custom action before the initial
18256 * drag event begins and optionally cancel it.
18257 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18258 * @param {Event} e The event object
18259 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18261 onBeforeDrag : function(data, e){
18266 * An empty function by default, but provided so that you can perform a custom action once the initial
18267 * drag event has begun. The drag cannot be canceled from this function.
18268 * @param {Number} x The x position of the click on the dragged object
18269 * @param {Number} y The y position of the click on the dragged object
18271 onStartDrag : Roo.emptyFn,
18273 // private - YUI override
18274 startDrag : function(x, y){
18275 this.proxy.reset();
18276 this.dragging = true;
18277 this.proxy.update("");
18278 this.onInitDrag(x, y);
18283 onInitDrag : function(x, y){
18284 var clone = this.el.dom.cloneNode(true);
18285 clone.id = Roo.id(); // prevent duplicate ids
18286 this.proxy.update(clone);
18287 this.onStartDrag(x, y);
18292 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18293 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18295 getProxy : function(){
18300 * Hides the drag source's {@link Roo.dd.StatusProxy}
18302 hideProxy : function(){
18304 this.proxy.reset(true);
18305 this.dragging = false;
18309 triggerCacheRefresh : function(){
18310 Roo.dd.DDM.refreshCache(this.groups);
18313 // private - override to prevent hiding
18314 b4EndDrag: function(e) {
18317 // private - override to prevent moving
18318 endDrag : function(e){
18319 this.onEndDrag(this.dragData, e);
18323 onEndDrag : function(data, e){
18326 // private - pin to cursor
18327 autoOffset : function(x, y) {
18328 this.setDelta(-12, -20);
18332 * Ext JS Library 1.1.1
18333 * Copyright(c) 2006-2007, Ext JS, LLC.
18335 * Originally Released Under LGPL - original licence link has changed is not relivant.
18338 * <script type="text/javascript">
18343 * @class Roo.dd.DropTarget
18344 * @extends Roo.dd.DDTarget
18345 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18346 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18348 * @param {String/HTMLElement/Element} el The container element
18349 * @param {Object} config
18351 Roo.dd.DropTarget = function(el, config){
18352 this.el = Roo.get(el);
18354 var listeners = false; ;
18355 if (config && config.listeners) {
18356 listeners= config.listeners;
18357 delete config.listeners;
18359 Roo.apply(this, config);
18361 if(this.containerScroll){
18362 Roo.dd.ScrollManager.register(this.el);
18366 * @scope Roo.dd.DropTarget
18371 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18372 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18373 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18375 * IMPORTANT : it should set this.overClass and this.dropAllowed
18377 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18378 * @param {Event} e The event
18379 * @param {Object} data An object containing arbitrary data supplied by the drag source
18385 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18386 * This method will be called on every mouse movement while the drag source is over the drop target.
18387 * This default implementation simply returns the dropAllowed config value.
18389 * IMPORTANT : it should set this.dropAllowed
18391 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18392 * @param {Event} e The event
18393 * @param {Object} data An object containing arbitrary data supplied by the drag source
18399 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18400 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18401 * overClass (if any) from the drop element.
18402 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18403 * @param {Event} e The event
18404 * @param {Object} data An object containing arbitrary data supplied by the drag source
18410 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18411 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18412 * implementation that does something to process the drop event and returns true so that the drag source's
18413 * repair action does not run.
18415 * IMPORTANT : it should set this.success
18417 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18418 * @param {Event} e The event
18419 * @param {Object} data An object containing arbitrary data supplied by the drag source
18425 Roo.dd.DropTarget.superclass.constructor.call( this,
18427 this.ddGroup || this.group,
18430 listeners : listeners || {}
18438 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18440 * @cfg {String} overClass
18441 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18444 * @cfg {String} ddGroup
18445 * The drag drop group to handle drop events for
18449 * @cfg {String} dropAllowed
18450 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18452 dropAllowed : "x-dd-drop-ok",
18454 * @cfg {String} dropNotAllowed
18455 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18457 dropNotAllowed : "x-dd-drop-nodrop",
18459 * @cfg {boolean} success
18460 * set this after drop listener..
18464 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
18465 * if the drop point is valid for over/enter..
18472 isNotifyTarget : true,
18477 notifyEnter : function(dd, e, data)
18480 this.fireEvent('enter', dd, e, data);
18481 if(this.overClass){
18482 this.el.addClass(this.overClass);
18484 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18485 this.valid ? this.dropAllowed : this.dropNotAllowed
18492 notifyOver : function(dd, e, data)
18495 this.fireEvent('over', dd, e, data);
18496 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18497 this.valid ? this.dropAllowed : this.dropNotAllowed
18504 notifyOut : function(dd, e, data)
18506 this.fireEvent('out', dd, e, data);
18507 if(this.overClass){
18508 this.el.removeClass(this.overClass);
18515 notifyDrop : function(dd, e, data)
18517 this.success = false;
18518 this.fireEvent('drop', dd, e, data);
18519 return this.success;
18523 * Ext JS Library 1.1.1
18524 * Copyright(c) 2006-2007, Ext JS, LLC.
18526 * Originally Released Under LGPL - original licence link has changed is not relivant.
18529 * <script type="text/javascript">
18534 * @class Roo.dd.DragZone
18535 * @extends Roo.dd.DragSource
18536 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18537 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18539 * @param {String/HTMLElement/Element} el The container element
18540 * @param {Object} config
18542 Roo.dd.DragZone = function(el, config){
18543 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18544 if(this.containerScroll){
18545 Roo.dd.ScrollManager.register(this.el);
18549 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18551 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18552 * for auto scrolling during drag operations.
18555 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18556 * method after a failed drop (defaults to "c3daf9" - light blue)
18560 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18561 * for a valid target to drag based on the mouse down. Override this method
18562 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18563 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18564 * @param {EventObject} e The mouse down event
18565 * @return {Object} The dragData
18567 getDragData : function(e){
18568 return Roo.dd.Registry.getHandleFromEvent(e);
18572 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18573 * this.dragData.ddel
18574 * @param {Number} x The x position of the click on the dragged object
18575 * @param {Number} y The y position of the click on the dragged object
18576 * @return {Boolean} true to continue the drag, false to cancel
18578 onInitDrag : function(x, y){
18579 this.proxy.update(this.dragData.ddel.cloneNode(true));
18580 this.onStartDrag(x, y);
18585 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18587 afterRepair : function(){
18589 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18591 this.dragging = false;
18595 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18596 * the XY of this.dragData.ddel
18597 * @param {EventObject} e The mouse up event
18598 * @return {Array} The xy location (e.g. [100, 200])
18600 getRepairXY : function(e){
18601 return Roo.Element.fly(this.dragData.ddel).getXY();
18605 * Ext JS Library 1.1.1
18606 * Copyright(c) 2006-2007, Ext JS, LLC.
18608 * Originally Released Under LGPL - original licence link has changed is not relivant.
18611 * <script type="text/javascript">
18614 * @class Roo.dd.DropZone
18615 * @extends Roo.dd.DropTarget
18616 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18617 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18619 * @param {String/HTMLElement/Element} el The container element
18620 * @param {Object} config
18622 Roo.dd.DropZone = function(el, config){
18623 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18626 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18628 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18629 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18630 * provide your own custom lookup.
18631 * @param {Event} e The event
18632 * @return {Object} data The custom data
18634 getTargetFromEvent : function(e){
18635 return Roo.dd.Registry.getTargetFromEvent(e);
18639 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18640 * that it has registered. This method has no default implementation and should be overridden to provide
18641 * node-specific processing if necessary.
18642 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18643 * {@link #getTargetFromEvent} for this node)
18644 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18645 * @param {Event} e The event
18646 * @param {Object} data An object containing arbitrary data supplied by the drag source
18648 onNodeEnter : function(n, dd, e, data){
18653 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18654 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18655 * overridden to provide the proper feedback.
18656 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18657 * {@link #getTargetFromEvent} for this node)
18658 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18659 * @param {Event} e The event
18660 * @param {Object} data An object containing arbitrary data supplied by the drag source
18661 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18662 * underlying {@link Roo.dd.StatusProxy} can be updated
18664 onNodeOver : function(n, dd, e, data){
18665 return this.dropAllowed;
18669 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18670 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18671 * node-specific processing if necessary.
18672 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18673 * {@link #getTargetFromEvent} for this node)
18674 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18675 * @param {Event} e The event
18676 * @param {Object} data An object containing arbitrary data supplied by the drag source
18678 onNodeOut : function(n, dd, e, data){
18683 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18684 * the drop node. The default implementation returns false, so it should be overridden to provide the
18685 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18686 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18687 * {@link #getTargetFromEvent} for this node)
18688 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18689 * @param {Event} e The event
18690 * @param {Object} data An object containing arbitrary data supplied by the drag source
18691 * @return {Boolean} True if the drop was valid, else false
18693 onNodeDrop : function(n, dd, e, data){
18698 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18699 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18700 * it should be overridden to provide the proper feedback if necessary.
18701 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18702 * @param {Event} e The event
18703 * @param {Object} data An object containing arbitrary data supplied by the drag source
18704 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18705 * underlying {@link Roo.dd.StatusProxy} can be updated
18707 onContainerOver : function(dd, e, data){
18708 return this.dropNotAllowed;
18712 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18713 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18714 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18715 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18716 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18717 * @param {Event} e The event
18718 * @param {Object} data An object containing arbitrary data supplied by the drag source
18719 * @return {Boolean} True if the drop was valid, else false
18721 onContainerDrop : function(dd, e, data){
18726 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18727 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18728 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18729 * you should override this method and provide a custom implementation.
18730 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18731 * @param {Event} e The event
18732 * @param {Object} data An object containing arbitrary data supplied by the drag source
18733 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18734 * underlying {@link Roo.dd.StatusProxy} can be updated
18736 notifyEnter : function(dd, e, data){
18737 return this.dropNotAllowed;
18741 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18742 * This method will be called on every mouse movement while the drag source is over the drop zone.
18743 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18744 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18745 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18746 * registered node, it will call {@link #onContainerOver}.
18747 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18748 * @param {Event} e The event
18749 * @param {Object} data An object containing arbitrary data supplied by the drag source
18750 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18751 * underlying {@link Roo.dd.StatusProxy} can be updated
18753 notifyOver : function(dd, e, data){
18754 var n = this.getTargetFromEvent(e);
18755 if(!n){ // not over valid drop target
18756 if(this.lastOverNode){
18757 this.onNodeOut(this.lastOverNode, dd, e, data);
18758 this.lastOverNode = null;
18760 return this.onContainerOver(dd, e, data);
18762 if(this.lastOverNode != n){
18763 if(this.lastOverNode){
18764 this.onNodeOut(this.lastOverNode, dd, e, data);
18766 this.onNodeEnter(n, dd, e, data);
18767 this.lastOverNode = n;
18769 return this.onNodeOver(n, dd, e, data);
18773 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18774 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18775 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18776 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18777 * @param {Event} e The event
18778 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18780 notifyOut : function(dd, e, data){
18781 if(this.lastOverNode){
18782 this.onNodeOut(this.lastOverNode, dd, e, data);
18783 this.lastOverNode = null;
18788 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18789 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18790 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18791 * otherwise it will call {@link #onContainerDrop}.
18792 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18793 * @param {Event} e The event
18794 * @param {Object} data An object containing arbitrary data supplied by the drag source
18795 * @return {Boolean} True if the drop was valid, else false
18797 notifyDrop : function(dd, e, data){
18798 if(this.lastOverNode){
18799 this.onNodeOut(this.lastOverNode, dd, e, data);
18800 this.lastOverNode = null;
18802 var n = this.getTargetFromEvent(e);
18804 this.onNodeDrop(n, dd, e, data) :
18805 this.onContainerDrop(dd, e, data);
18809 triggerCacheRefresh : function(){
18810 Roo.dd.DDM.refreshCache(this.groups);
18814 * Ext JS Library 1.1.1
18815 * Copyright(c) 2006-2007, Ext JS, LLC.
18817 * Originally Released Under LGPL - original licence link has changed is not relivant.
18820 * <script type="text/javascript">
18825 * @class Roo.data.SortTypes
18827 * Defines the default sorting (casting?) comparison functions used when sorting data.
18829 Roo.data.SortTypes = {
18831 * Default sort that does nothing
18832 * @param {Mixed} s The value being converted
18833 * @return {Mixed} The comparison value
18835 none : function(s){
18840 * The regular expression used to strip tags
18844 stripTagsRE : /<\/?[^>]+>/gi,
18847 * Strips all HTML tags to sort on text only
18848 * @param {Mixed} s The value being converted
18849 * @return {String} The comparison value
18851 asText : function(s){
18852 return String(s).replace(this.stripTagsRE, "");
18856 * Strips all HTML tags to sort on text only - Case insensitive
18857 * @param {Mixed} s The value being converted
18858 * @return {String} The comparison value
18860 asUCText : function(s){
18861 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18865 * Case insensitive string
18866 * @param {Mixed} s The value being converted
18867 * @return {String} The comparison value
18869 asUCString : function(s) {
18870 return String(s).toUpperCase();
18875 * @param {Mixed} s The value being converted
18876 * @return {Number} The comparison value
18878 asDate : function(s) {
18882 if(s instanceof Date){
18883 return s.getTime();
18885 return Date.parse(String(s));
18890 * @param {Mixed} s The value being converted
18891 * @return {Float} The comparison value
18893 asFloat : function(s) {
18894 var val = parseFloat(String(s).replace(/,/g, ""));
18895 if(isNaN(val)) val = 0;
18901 * @param {Mixed} s The value being converted
18902 * @return {Number} The comparison value
18904 asInt : function(s) {
18905 var val = parseInt(String(s).replace(/,/g, ""));
18906 if(isNaN(val)) val = 0;
18911 * Ext JS Library 1.1.1
18912 * Copyright(c) 2006-2007, Ext JS, LLC.
18914 * Originally Released Under LGPL - original licence link has changed is not relivant.
18917 * <script type="text/javascript">
18921 * @class Roo.data.Record
18922 * Instances of this class encapsulate both record <em>definition</em> information, and record
18923 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18924 * to access Records cached in an {@link Roo.data.Store} object.<br>
18926 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18927 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18930 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18932 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18933 * {@link #create}. The parameters are the same.
18934 * @param {Array} data An associative Array of data values keyed by the field name.
18935 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18936 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18937 * not specified an integer id is generated.
18939 Roo.data.Record = function(data, id){
18940 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18945 * Generate a constructor for a specific record layout.
18946 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18947 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18948 * Each field definition object may contain the following properties: <ul>
18949 * <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,
18950 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18951 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18952 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18953 * is being used, then this is a string containing the javascript expression to reference the data relative to
18954 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18955 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18956 * this may be omitted.</p></li>
18957 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18958 * <ul><li>auto (Default, implies no conversion)</li>
18963 * <li>date</li></ul></p></li>
18964 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18965 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18966 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18967 * by the Reader into an object that will be stored in the Record. It is passed the
18968 * following parameters:<ul>
18969 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18971 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18973 * <br>usage:<br><pre><code>
18974 var TopicRecord = Roo.data.Record.create(
18975 {name: 'title', mapping: 'topic_title'},
18976 {name: 'author', mapping: 'username'},
18977 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18978 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18979 {name: 'lastPoster', mapping: 'user2'},
18980 {name: 'excerpt', mapping: 'post_text'}
18983 var myNewRecord = new TopicRecord({
18984 title: 'Do my job please',
18987 lastPost: new Date(),
18988 lastPoster: 'Animal',
18989 excerpt: 'No way dude!'
18991 myStore.add(myNewRecord);
18996 Roo.data.Record.create = function(o){
18997 var f = function(){
18998 f.superclass.constructor.apply(this, arguments);
19000 Roo.extend(f, Roo.data.Record);
19001 var p = f.prototype;
19002 p.fields = new Roo.util.MixedCollection(false, function(field){
19005 for(var i = 0, len = o.length; i < len; i++){
19006 p.fields.add(new Roo.data.Field(o[i]));
19008 f.getField = function(name){
19009 return p.fields.get(name);
19014 Roo.data.Record.AUTO_ID = 1000;
19015 Roo.data.Record.EDIT = 'edit';
19016 Roo.data.Record.REJECT = 'reject';
19017 Roo.data.Record.COMMIT = 'commit';
19019 Roo.data.Record.prototype = {
19021 * Readonly flag - true if this record has been modified.
19030 join : function(store){
19031 this.store = store;
19035 * Set the named field to the specified value.
19036 * @param {String} name The name of the field to set.
19037 * @param {Object} value The value to set the field to.
19039 set : function(name, value){
19040 if(this.data[name] == value){
19044 if(!this.modified){
19045 this.modified = {};
19047 if(typeof this.modified[name] == 'undefined'){
19048 this.modified[name] = this.data[name];
19050 this.data[name] = value;
19051 if(!this.editing && this.store){
19052 this.store.afterEdit(this);
19057 * Get the value of the named field.
19058 * @param {String} name The name of the field to get the value of.
19059 * @return {Object} The value of the field.
19061 get : function(name){
19062 return this.data[name];
19066 beginEdit : function(){
19067 this.editing = true;
19068 this.modified = {};
19072 cancelEdit : function(){
19073 this.editing = false;
19074 delete this.modified;
19078 endEdit : function(){
19079 this.editing = false;
19080 if(this.dirty && this.store){
19081 this.store.afterEdit(this);
19086 * Usually called by the {@link Roo.data.Store} which owns the Record.
19087 * Rejects all changes made to the Record since either creation, or the last commit operation.
19088 * Modified fields are reverted to their original values.
19090 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19091 * of reject operations.
19093 reject : function(){
19094 var m = this.modified;
19096 if(typeof m[n] != "function"){
19097 this.data[n] = m[n];
19100 this.dirty = false;
19101 delete this.modified;
19102 this.editing = false;
19104 this.store.afterReject(this);
19109 * Usually called by the {@link Roo.data.Store} which owns the Record.
19110 * Commits all changes made to the Record since either creation, or the last commit operation.
19112 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19113 * of commit operations.
19115 commit : function(){
19116 this.dirty = false;
19117 delete this.modified;
19118 this.editing = false;
19120 this.store.afterCommit(this);
19125 hasError : function(){
19126 return this.error != null;
19130 clearError : function(){
19135 * Creates a copy of this record.
19136 * @param {String} id (optional) A new record id if you don't want to use this record's id
19139 copy : function(newId) {
19140 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19144 * Ext JS Library 1.1.1
19145 * Copyright(c) 2006-2007, Ext JS, LLC.
19147 * Originally Released Under LGPL - original licence link has changed is not relivant.
19150 * <script type="text/javascript">
19156 * @class Roo.data.Store
19157 * @extends Roo.util.Observable
19158 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19159 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19161 * 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
19162 * has no knowledge of the format of the data returned by the Proxy.<br>
19164 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19165 * instances from the data object. These records are cached and made available through accessor functions.
19167 * Creates a new Store.
19168 * @param {Object} config A config object containing the objects needed for the Store to access data,
19169 * and read the data into Records.
19171 Roo.data.Store = function(config){
19172 this.data = new Roo.util.MixedCollection(false);
19173 this.data.getKey = function(o){
19176 this.baseParams = {};
19178 this.paramNames = {
19183 "multisort" : "_multisort"
19186 if(config && config.data){
19187 this.inlineData = config.data;
19188 delete config.data;
19191 Roo.apply(this, config);
19193 if(this.reader){ // reader passed
19194 this.reader = Roo.factory(this.reader, Roo.data);
19195 this.reader.xmodule = this.xmodule || false;
19196 if(!this.recordType){
19197 this.recordType = this.reader.recordType;
19199 if(this.reader.onMetaChange){
19200 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19204 if(this.recordType){
19205 this.fields = this.recordType.prototype.fields;
19207 this.modified = [];
19211 * @event datachanged
19212 * Fires when the data cache has changed, and a widget which is using this Store
19213 * as a Record cache should refresh its view.
19214 * @param {Store} this
19216 datachanged : true,
19218 * @event metachange
19219 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19220 * @param {Store} this
19221 * @param {Object} meta The JSON metadata
19226 * Fires when Records have been added to the Store
19227 * @param {Store} this
19228 * @param {Roo.data.Record[]} records The array of Records added
19229 * @param {Number} index The index at which the record(s) were added
19234 * Fires when a Record has been removed from the Store
19235 * @param {Store} this
19236 * @param {Roo.data.Record} record The Record that was removed
19237 * @param {Number} index The index at which the record was removed
19242 * Fires when a Record has been updated
19243 * @param {Store} this
19244 * @param {Roo.data.Record} record The Record that was updated
19245 * @param {String} operation The update operation being performed. Value may be one of:
19247 Roo.data.Record.EDIT
19248 Roo.data.Record.REJECT
19249 Roo.data.Record.COMMIT
19255 * Fires when the data cache has been cleared.
19256 * @param {Store} this
19260 * @event beforeload
19261 * Fires before a request is made for a new data object. If the beforeload handler returns false
19262 * the load action will be canceled.
19263 * @param {Store} this
19264 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19269 * Fires after a new set of Records has been loaded.
19270 * @param {Store} this
19271 * @param {Roo.data.Record[]} records The Records that were loaded
19272 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19276 * @event loadexception
19277 * Fires if an exception occurs in the Proxy during loading.
19278 * Called with the signature of the Proxy's "loadexception" event.
19279 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19282 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19283 * @param {Object} load options
19284 * @param {Object} jsonData from your request (normally this contains the Exception)
19286 loadexception : true
19290 this.proxy = Roo.factory(this.proxy, Roo.data);
19291 this.proxy.xmodule = this.xmodule || false;
19292 this.relayEvents(this.proxy, ["loadexception"]);
19294 this.sortToggle = {};
19295 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
19297 Roo.data.Store.superclass.constructor.call(this);
19299 if(this.inlineData){
19300 this.loadData(this.inlineData);
19301 delete this.inlineData;
19304 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19306 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19307 * without a remote query - used by combo/forms at present.
19311 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19314 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19317 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19318 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19321 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19322 * on any HTTP request
19325 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19328 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
19332 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19333 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19335 remoteSort : false,
19338 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19339 * loaded or when a record is removed. (defaults to false).
19341 pruneModifiedRecords : false,
19344 lastOptions : null,
19347 * Add Records to the Store and fires the add event.
19348 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19350 add : function(records){
19351 records = [].concat(records);
19352 for(var i = 0, len = records.length; i < len; i++){
19353 records[i].join(this);
19355 var index = this.data.length;
19356 this.data.addAll(records);
19357 this.fireEvent("add", this, records, index);
19361 * Remove a Record from the Store and fires the remove event.
19362 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19364 remove : function(record){
19365 var index = this.data.indexOf(record);
19366 this.data.removeAt(index);
19367 if(this.pruneModifiedRecords){
19368 this.modified.remove(record);
19370 this.fireEvent("remove", this, record, index);
19374 * Remove all Records from the Store and fires the clear event.
19376 removeAll : function(){
19378 if(this.pruneModifiedRecords){
19379 this.modified = [];
19381 this.fireEvent("clear", this);
19385 * Inserts Records to the Store at the given index and fires the add event.
19386 * @param {Number} index The start index at which to insert the passed Records.
19387 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19389 insert : function(index, records){
19390 records = [].concat(records);
19391 for(var i = 0, len = records.length; i < len; i++){
19392 this.data.insert(index, records[i]);
19393 records[i].join(this);
19395 this.fireEvent("add", this, records, index);
19399 * Get the index within the cache of the passed Record.
19400 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19401 * @return {Number} The index of the passed Record. Returns -1 if not found.
19403 indexOf : function(record){
19404 return this.data.indexOf(record);
19408 * Get the index within the cache of the Record with the passed id.
19409 * @param {String} id The id of the Record to find.
19410 * @return {Number} The index of the Record. Returns -1 if not found.
19412 indexOfId : function(id){
19413 return this.data.indexOfKey(id);
19417 * Get the Record with the specified id.
19418 * @param {String} id The id of the Record to find.
19419 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19421 getById : function(id){
19422 return this.data.key(id);
19426 * Get the Record at the specified index.
19427 * @param {Number} index The index of the Record to find.
19428 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19430 getAt : function(index){
19431 return this.data.itemAt(index);
19435 * Returns a range of Records between specified indices.
19436 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19437 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19438 * @return {Roo.data.Record[]} An array of Records
19440 getRange : function(start, end){
19441 return this.data.getRange(start, end);
19445 storeOptions : function(o){
19446 o = Roo.apply({}, o);
19449 this.lastOptions = o;
19453 * Loads the Record cache from the configured Proxy using the configured Reader.
19455 * If using remote paging, then the first load call must specify the <em>start</em>
19456 * and <em>limit</em> properties in the options.params property to establish the initial
19457 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19459 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19460 * and this call will return before the new data has been loaded. Perform any post-processing
19461 * in a callback function, or in a "load" event handler.</strong>
19463 * @param {Object} options An object containing properties which control loading options:<ul>
19464 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19465 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19466 * passed the following arguments:<ul>
19467 * <li>r : Roo.data.Record[]</li>
19468 * <li>options: Options object from the load call</li>
19469 * <li>success: Boolean success indicator</li></ul></li>
19470 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19471 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19474 load : function(options){
19475 options = options || {};
19476 if(this.fireEvent("beforeload", this, options) !== false){
19477 this.storeOptions(options);
19478 var p = Roo.apply(options.params || {}, this.baseParams);
19479 // if meta was not loaded from remote source.. try requesting it.
19480 if (!this.reader.metaFromRemote) {
19481 p._requestMeta = 1;
19483 if(this.sortInfo && this.remoteSort){
19484 var pn = this.paramNames;
19485 p[pn["sort"]] = this.sortInfo.field;
19486 p[pn["dir"]] = this.sortInfo.direction;
19488 if (this.multiSort) {
19489 var pn = this.paramNames;
19490 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
19493 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19498 * Reloads the Record cache from the configured Proxy using the configured Reader and
19499 * the options from the last load operation performed.
19500 * @param {Object} options (optional) An object containing properties which may override the options
19501 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19502 * the most recently used options are reused).
19504 reload : function(options){
19505 this.load(Roo.applyIf(options||{}, this.lastOptions));
19509 // Called as a callback by the Reader during a load operation.
19510 loadRecords : function(o, options, success){
19511 if(!o || success === false){
19512 if(success !== false){
19513 this.fireEvent("load", this, [], options);
19515 if(options.callback){
19516 options.callback.call(options.scope || this, [], options, false);
19520 // if data returned failure - throw an exception.
19521 if (o.success === false) {
19522 // show a message if no listener is registered.
19523 if (!this.hasListener('loadexception') && typeof(this.reader.jsonData.errorMsg) != 'undefined') {
19524 Roo.MessageBox.alert("Error loading",this.reader.jsonData.errorMsg);
19526 // loadmask wil be hooked into this..
19527 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19530 var r = o.records, t = o.totalRecords || r.length;
19531 if(!options || options.add !== true){
19532 if(this.pruneModifiedRecords){
19533 this.modified = [];
19535 for(var i = 0, len = r.length; i < len; i++){
19539 this.data = this.snapshot;
19540 delete this.snapshot;
19543 this.data.addAll(r);
19544 this.totalLength = t;
19546 this.fireEvent("datachanged", this);
19548 this.totalLength = Math.max(t, this.data.length+r.length);
19551 this.fireEvent("load", this, r, options);
19552 if(options.callback){
19553 options.callback.call(options.scope || this, r, options, true);
19559 * Loads data from a passed data block. A Reader which understands the format of the data
19560 * must have been configured in the constructor.
19561 * @param {Object} data The data block from which to read the Records. The format of the data expected
19562 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19563 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19565 loadData : function(o, append){
19566 var r = this.reader.readRecords(o);
19567 this.loadRecords(r, {add: append}, true);
19571 * Gets the number of cached records.
19573 * <em>If using paging, this may not be the total size of the dataset. If the data object
19574 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19575 * the data set size</em>
19577 getCount : function(){
19578 return this.data.length || 0;
19582 * Gets the total number of records in the dataset as returned by the server.
19584 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19585 * the dataset size</em>
19587 getTotalCount : function(){
19588 return this.totalLength || 0;
19592 * Returns the sort state of the Store as an object with two properties:
19594 field {String} The name of the field by which the Records are sorted
19595 direction {String} The sort order, "ASC" or "DESC"
19598 getSortState : function(){
19599 return this.sortInfo;
19603 applySort : function(){
19604 if(this.sortInfo && !this.remoteSort){
19605 var s = this.sortInfo, f = s.field;
19606 var st = this.fields.get(f).sortType;
19607 var fn = function(r1, r2){
19608 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19609 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19611 this.data.sort(s.direction, fn);
19612 if(this.snapshot && this.snapshot != this.data){
19613 this.snapshot.sort(s.direction, fn);
19619 * Sets the default sort column and order to be used by the next load operation.
19620 * @param {String} fieldName The name of the field to sort by.
19621 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19623 setDefaultSort : function(field, dir){
19624 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19628 * Sort the Records.
19629 * If remote sorting is used, the sort is performed on the server, and the cache is
19630 * reloaded. If local sorting is used, the cache is sorted internally.
19631 * @param {String} fieldName The name of the field to sort by.
19632 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19634 sort : function(fieldName, dir){
19635 var f = this.fields.get(fieldName);
19637 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
19639 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
19640 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19645 this.sortToggle[f.name] = dir;
19646 this.sortInfo = {field: f.name, direction: dir};
19647 if(!this.remoteSort){
19649 this.fireEvent("datachanged", this);
19651 this.load(this.lastOptions);
19656 * Calls the specified function for each of the Records in the cache.
19657 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19658 * Returning <em>false</em> aborts and exits the iteration.
19659 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19661 each : function(fn, scope){
19662 this.data.each(fn, scope);
19666 * Gets all records modified since the last commit. Modified records are persisted across load operations
19667 * (e.g., during paging).
19668 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19670 getModifiedRecords : function(){
19671 return this.modified;
19675 createFilterFn : function(property, value, anyMatch){
19676 if(!value.exec){ // not a regex
19677 value = String(value);
19678 if(value.length == 0){
19681 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19683 return function(r){
19684 return value.test(r.data[property]);
19689 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19690 * @param {String} property A field on your records
19691 * @param {Number} start The record index to start at (defaults to 0)
19692 * @param {Number} end The last record index to include (defaults to length - 1)
19693 * @return {Number} The sum
19695 sum : function(property, start, end){
19696 var rs = this.data.items, v = 0;
19697 start = start || 0;
19698 end = (end || end === 0) ? end : rs.length-1;
19700 for(var i = start; i <= end; i++){
19701 v += (rs[i].data[property] || 0);
19707 * Filter the records by a specified property.
19708 * @param {String} field A field on your records
19709 * @param {String/RegExp} value Either a string that the field
19710 * should start with or a RegExp to test against the field
19711 * @param {Boolean} anyMatch True to match any part not just the beginning
19713 filter : function(property, value, anyMatch){
19714 var fn = this.createFilterFn(property, value, anyMatch);
19715 return fn ? this.filterBy(fn) : this.clearFilter();
19719 * Filter by a function. The specified function will be called with each
19720 * record in this data source. If the function returns true the record is included,
19721 * otherwise it is filtered.
19722 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19723 * @param {Object} scope (optional) The scope of the function (defaults to this)
19725 filterBy : function(fn, scope){
19726 this.snapshot = this.snapshot || this.data;
19727 this.data = this.queryBy(fn, scope||this);
19728 this.fireEvent("datachanged", this);
19732 * Query the records by a specified property.
19733 * @param {String} field A field on your records
19734 * @param {String/RegExp} value Either a string that the field
19735 * should start with or a RegExp to test against the field
19736 * @param {Boolean} anyMatch True to match any part not just the beginning
19737 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19739 query : function(property, value, anyMatch){
19740 var fn = this.createFilterFn(property, value, anyMatch);
19741 return fn ? this.queryBy(fn) : this.data.clone();
19745 * Query by a function. The specified function will be called with each
19746 * record in this data source. If the function returns true the record is included
19748 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19749 * @param {Object} scope (optional) The scope of the function (defaults to this)
19750 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19752 queryBy : function(fn, scope){
19753 var data = this.snapshot || this.data;
19754 return data.filterBy(fn, scope||this);
19758 * Collects unique values for a particular dataIndex from this store.
19759 * @param {String} dataIndex The property to collect
19760 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19761 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19762 * @return {Array} An array of the unique values
19764 collect : function(dataIndex, allowNull, bypassFilter){
19765 var d = (bypassFilter === true && this.snapshot) ?
19766 this.snapshot.items : this.data.items;
19767 var v, sv, r = [], l = {};
19768 for(var i = 0, len = d.length; i < len; i++){
19769 v = d[i].data[dataIndex];
19771 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19780 * Revert to a view of the Record cache with no filtering applied.
19781 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19783 clearFilter : function(suppressEvent){
19784 if(this.snapshot && this.snapshot != this.data){
19785 this.data = this.snapshot;
19786 delete this.snapshot;
19787 if(suppressEvent !== true){
19788 this.fireEvent("datachanged", this);
19794 afterEdit : function(record){
19795 if(this.modified.indexOf(record) == -1){
19796 this.modified.push(record);
19798 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19802 afterReject : function(record){
19803 this.modified.remove(record);
19804 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19808 afterCommit : function(record){
19809 this.modified.remove(record);
19810 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19814 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19815 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19817 commitChanges : function(){
19818 var m = this.modified.slice(0);
19819 this.modified = [];
19820 for(var i = 0, len = m.length; i < len; i++){
19826 * Cancel outstanding changes on all changed records.
19828 rejectChanges : function(){
19829 var m = this.modified.slice(0);
19830 this.modified = [];
19831 for(var i = 0, len = m.length; i < len; i++){
19836 onMetaChange : function(meta, rtype, o){
19837 this.recordType = rtype;
19838 this.fields = rtype.prototype.fields;
19839 delete this.snapshot;
19840 this.sortInfo = meta.sortInfo || this.sortInfo;
19841 this.modified = [];
19842 this.fireEvent('metachange', this, this.reader.meta);
19846 * Ext JS Library 1.1.1
19847 * Copyright(c) 2006-2007, Ext JS, LLC.
19849 * Originally Released Under LGPL - original licence link has changed is not relivant.
19852 * <script type="text/javascript">
19856 * @class Roo.data.SimpleStore
19857 * @extends Roo.data.Store
19858 * Small helper class to make creating Stores from Array data easier.
19859 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19860 * @cfg {Array} fields An array of field definition objects, or field name strings.
19861 * @cfg {Array} data The multi-dimensional array of data
19863 * @param {Object} config
19865 Roo.data.SimpleStore = function(config){
19866 Roo.data.SimpleStore.superclass.constructor.call(this, {
19868 reader: new Roo.data.ArrayReader({
19871 Roo.data.Record.create(config.fields)
19873 proxy : new Roo.data.MemoryProxy(config.data)
19877 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
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">
19890 * @extends Roo.data.Store
19891 * @class Roo.data.JsonStore
19892 * Small helper class to make creating Stores for JSON data easier. <br/>
19894 var store = new Roo.data.JsonStore({
19895 url: 'get-images.php',
19897 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19900 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19901 * JsonReader and HttpProxy (unless inline data is provided).</b>
19902 * @cfg {Array} fields An array of field definition objects, or field name strings.
19904 * @param {Object} config
19906 Roo.data.JsonStore = function(c){
19907 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19908 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19909 reader: new Roo.data.JsonReader(c, c.fields)
19912 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19914 * Ext JS Library 1.1.1
19915 * Copyright(c) 2006-2007, Ext JS, LLC.
19917 * Originally Released Under LGPL - original licence link has changed is not relivant.
19920 * <script type="text/javascript">
19924 Roo.data.Field = function(config){
19925 if(typeof config == "string"){
19926 config = {name: config};
19928 Roo.apply(this, config);
19931 this.type = "auto";
19934 var st = Roo.data.SortTypes;
19935 // named sortTypes are supported, here we look them up
19936 if(typeof this.sortType == "string"){
19937 this.sortType = st[this.sortType];
19940 // set default sortType for strings and dates
19941 if(!this.sortType){
19944 this.sortType = st.asUCString;
19947 this.sortType = st.asDate;
19950 this.sortType = st.none;
19955 var stripRe = /[\$,%]/g;
19957 // prebuilt conversion function for this field, instead of
19958 // switching every time we're reading a value
19960 var cv, dateFormat = this.dateFormat;
19965 cv = function(v){ return v; };
19968 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19972 return v !== undefined && v !== null && v !== '' ?
19973 parseInt(String(v).replace(stripRe, ""), 10) : '';
19978 return v !== undefined && v !== null && v !== '' ?
19979 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19984 cv = function(v){ return v === true || v === "true" || v == 1; };
19991 if(v instanceof Date){
19995 if(dateFormat == "timestamp"){
19996 return new Date(v*1000);
19998 return Date.parseDate(v, dateFormat);
20000 var parsed = Date.parse(v);
20001 return parsed ? new Date(parsed) : null;
20010 Roo.data.Field.prototype = {
20018 * Ext JS Library 1.1.1
20019 * Copyright(c) 2006-2007, Ext JS, LLC.
20021 * Originally Released Under LGPL - original licence link has changed is not relivant.
20024 * <script type="text/javascript">
20027 // Base class for reading structured data from a data source. This class is intended to be
20028 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20031 * @class Roo.data.DataReader
20032 * Base class for reading structured data from a data source. This class is intended to be
20033 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20036 Roo.data.DataReader = function(meta, recordType){
20040 this.recordType = recordType instanceof Array ?
20041 Roo.data.Record.create(recordType) : recordType;
20044 Roo.data.DataReader.prototype = {
20046 * Create an empty record
20047 * @param {Object} data (optional) - overlay some values
20048 * @return {Roo.data.Record} record created.
20050 newRow : function(d) {
20052 this.recordType.prototype.fields.each(function(c) {
20054 case 'int' : da[c.name] = 0; break;
20055 case 'date' : da[c.name] = new Date(); break;
20056 case 'float' : da[c.name] = 0.0; break;
20057 case 'boolean' : da[c.name] = false; break;
20058 default : da[c.name] = ""; break;
20062 return new this.recordType(Roo.apply(da, d));
20067 * Ext JS Library 1.1.1
20068 * Copyright(c) 2006-2007, Ext JS, LLC.
20070 * Originally Released Under LGPL - original licence link has changed is not relivant.
20073 * <script type="text/javascript">
20077 * @class Roo.data.DataProxy
20078 * @extends Roo.data.Observable
20079 * This class is an abstract base class for implementations which provide retrieval of
20080 * unformatted data objects.<br>
20082 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20083 * (of the appropriate type which knows how to parse the data object) to provide a block of
20084 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20086 * Custom implementations must implement the load method as described in
20087 * {@link Roo.data.HttpProxy#load}.
20089 Roo.data.DataProxy = function(){
20092 * @event beforeload
20093 * Fires before a network request is made to retrieve a data object.
20094 * @param {Object} This DataProxy object.
20095 * @param {Object} params The params parameter to the load function.
20100 * Fires before the load method's callback is called.
20101 * @param {Object} This DataProxy object.
20102 * @param {Object} o The data object.
20103 * @param {Object} arg The callback argument object passed to the load function.
20107 * @event loadexception
20108 * Fires if an Exception occurs during data retrieval.
20109 * @param {Object} This DataProxy object.
20110 * @param {Object} o The data object.
20111 * @param {Object} arg The callback argument object passed to the load function.
20112 * @param {Object} e The Exception.
20114 loadexception : true
20116 Roo.data.DataProxy.superclass.constructor.call(this);
20119 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20122 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20126 * Ext JS Library 1.1.1
20127 * Copyright(c) 2006-2007, Ext JS, LLC.
20129 * Originally Released Under LGPL - original licence link has changed is not relivant.
20132 * <script type="text/javascript">
20135 * @class Roo.data.MemoryProxy
20136 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20137 * to the Reader when its load method is called.
20139 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20141 Roo.data.MemoryProxy = function(data){
20145 Roo.data.MemoryProxy.superclass.constructor.call(this);
20149 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20151 * Load data from the requested source (in this case an in-memory
20152 * data object passed to the constructor), read the data object into
20153 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20154 * process that block using the passed callback.
20155 * @param {Object} params This parameter is not used by the MemoryProxy class.
20156 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20157 * object into a block of Roo.data.Records.
20158 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20159 * The function must be passed <ul>
20160 * <li>The Record block object</li>
20161 * <li>The "arg" argument from the load function</li>
20162 * <li>A boolean success indicator</li>
20164 * @param {Object} scope The scope in which to call the callback
20165 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20167 load : function(params, reader, callback, scope, arg){
20168 params = params || {};
20171 result = reader.readRecords(this.data);
20173 this.fireEvent("loadexception", this, arg, null, e);
20174 callback.call(scope, null, arg, false);
20177 callback.call(scope, result, arg, true);
20181 update : function(params, records){
20186 * Ext JS Library 1.1.1
20187 * Copyright(c) 2006-2007, Ext JS, LLC.
20189 * Originally Released Under LGPL - original licence link has changed is not relivant.
20192 * <script type="text/javascript">
20195 * @class Roo.data.HttpProxy
20196 * @extends Roo.data.DataProxy
20197 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20198 * configured to reference a certain URL.<br><br>
20200 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20201 * from which the running page was served.<br><br>
20203 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20205 * Be aware that to enable the browser to parse an XML document, the server must set
20206 * the Content-Type header in the HTTP response to "text/xml".
20208 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20209 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20210 * will be used to make the request.
20212 Roo.data.HttpProxy = function(conn){
20213 Roo.data.HttpProxy.superclass.constructor.call(this);
20214 // is conn a conn config or a real conn?
20216 this.useAjax = !conn || !conn.events;
20220 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20221 // thse are take from connection...
20224 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20227 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20228 * extra parameters to each request made by this object. (defaults to undefined)
20231 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20232 * to each request made by this object. (defaults to undefined)
20235 * @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)
20238 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20241 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20247 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20251 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20252 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20253 * a finer-grained basis than the DataProxy events.
20255 getConnection : function(){
20256 return this.useAjax ? Roo.Ajax : this.conn;
20260 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20261 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20262 * process that block using the passed callback.
20263 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20264 * for the request to the remote server.
20265 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20266 * object into a block of Roo.data.Records.
20267 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20268 * The function must be passed <ul>
20269 * <li>The Record block object</li>
20270 * <li>The "arg" argument from the load function</li>
20271 * <li>A boolean success indicator</li>
20273 * @param {Object} scope The scope in which to call the callback
20274 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20276 load : function(params, reader, callback, scope, arg){
20277 if(this.fireEvent("beforeload", this, params) !== false){
20279 params : params || {},
20281 callback : callback,
20286 callback : this.loadResponse,
20290 Roo.applyIf(o, this.conn);
20291 if(this.activeRequest){
20292 Roo.Ajax.abort(this.activeRequest);
20294 this.activeRequest = Roo.Ajax.request(o);
20296 this.conn.request(o);
20299 callback.call(scope||this, null, arg, false);
20304 loadResponse : function(o, success, response){
20305 delete this.activeRequest;
20307 this.fireEvent("loadexception", this, o, response);
20308 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20313 result = o.reader.read(response);
20315 this.fireEvent("loadexception", this, o, response, e);
20316 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20320 this.fireEvent("load", this, o, o.request.arg);
20321 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20325 update : function(dataSet){
20330 updateResponse : function(dataSet){
20335 * Ext JS Library 1.1.1
20336 * Copyright(c) 2006-2007, Ext JS, LLC.
20338 * Originally Released Under LGPL - original licence link has changed is not relivant.
20341 * <script type="text/javascript">
20345 * @class Roo.data.ScriptTagProxy
20346 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20347 * other than the originating domain of the running page.<br><br>
20349 * <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
20350 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20352 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20353 * source code that is used as the source inside a <script> tag.<br><br>
20355 * In order for the browser to process the returned data, the server must wrap the data object
20356 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20357 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20358 * depending on whether the callback name was passed:
20361 boolean scriptTag = false;
20362 String cb = request.getParameter("callback");
20365 response.setContentType("text/javascript");
20367 response.setContentType("application/x-json");
20369 Writer out = response.getWriter();
20371 out.write(cb + "(");
20373 out.print(dataBlock.toJsonString());
20380 * @param {Object} config A configuration object.
20382 Roo.data.ScriptTagProxy = function(config){
20383 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20384 Roo.apply(this, config);
20385 this.head = document.getElementsByTagName("head")[0];
20388 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20390 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20392 * @cfg {String} url The URL from which to request the data object.
20395 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20399 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20400 * the server the name of the callback function set up by the load call to process the returned data object.
20401 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20402 * javascript output which calls this named function passing the data object as its only parameter.
20404 callbackParam : "callback",
20406 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20407 * name to the request.
20412 * Load data from the configured URL, read the data object into
20413 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20414 * process that block using the passed callback.
20415 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20416 * for the request to the remote server.
20417 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20418 * object into a block of Roo.data.Records.
20419 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20420 * The function must be passed <ul>
20421 * <li>The Record block object</li>
20422 * <li>The "arg" argument from the load function</li>
20423 * <li>A boolean success indicator</li>
20425 * @param {Object} scope The scope in which to call the callback
20426 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20428 load : function(params, reader, callback, scope, arg){
20429 if(this.fireEvent("beforeload", this, params) !== false){
20431 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20433 var url = this.url;
20434 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20436 url += "&_dc=" + (new Date().getTime());
20438 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20441 cb : "stcCallback"+transId,
20442 scriptId : "stcScript"+transId,
20446 callback : callback,
20452 window[trans.cb] = function(o){
20453 conn.handleResponse(o, trans);
20456 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20458 if(this.autoAbort !== false){
20462 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20464 var script = document.createElement("script");
20465 script.setAttribute("src", url);
20466 script.setAttribute("type", "text/javascript");
20467 script.setAttribute("id", trans.scriptId);
20468 this.head.appendChild(script);
20470 this.trans = trans;
20472 callback.call(scope||this, null, arg, false);
20477 isLoading : function(){
20478 return this.trans ? true : false;
20482 * Abort the current server request.
20484 abort : function(){
20485 if(this.isLoading()){
20486 this.destroyTrans(this.trans);
20491 destroyTrans : function(trans, isLoaded){
20492 this.head.removeChild(document.getElementById(trans.scriptId));
20493 clearTimeout(trans.timeoutId);
20495 window[trans.cb] = undefined;
20497 delete window[trans.cb];
20500 // if hasn't been loaded, wait for load to remove it to prevent script error
20501 window[trans.cb] = function(){
20502 window[trans.cb] = undefined;
20504 delete window[trans.cb];
20511 handleResponse : function(o, trans){
20512 this.trans = false;
20513 this.destroyTrans(trans, true);
20516 result = trans.reader.readRecords(o);
20518 this.fireEvent("loadexception", this, o, trans.arg, e);
20519 trans.callback.call(trans.scope||window, null, trans.arg, false);
20522 this.fireEvent("load", this, o, trans.arg);
20523 trans.callback.call(trans.scope||window, result, trans.arg, true);
20527 handleFailure : function(trans){
20528 this.trans = false;
20529 this.destroyTrans(trans, false);
20530 this.fireEvent("loadexception", this, null, trans.arg);
20531 trans.callback.call(trans.scope||window, null, trans.arg, false);
20535 * Ext JS Library 1.1.1
20536 * Copyright(c) 2006-2007, Ext JS, LLC.
20538 * Originally Released Under LGPL - original licence link has changed is not relivant.
20541 * <script type="text/javascript">
20545 * @class Roo.data.JsonReader
20546 * @extends Roo.data.DataReader
20547 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20548 * based on mappings in a provided Roo.data.Record constructor.
20550 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
20551 * in the reply previously.
20556 var RecordDef = Roo.data.Record.create([
20557 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20558 {name: 'occupation'} // This field will use "occupation" as the mapping.
20560 var myReader = new Roo.data.JsonReader({
20561 totalProperty: "results", // The property which contains the total dataset size (optional)
20562 root: "rows", // The property which contains an Array of row objects
20563 id: "id" // The property within each row object that provides an ID for the record (optional)
20567 * This would consume a JSON file like this:
20569 { 'results': 2, 'rows': [
20570 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20571 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20574 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20575 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20576 * paged from the remote server.
20577 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20578 * @cfg {String} root name of the property which contains the Array of row objects.
20579 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20581 * Create a new JsonReader
20582 * @param {Object} meta Metadata configuration options
20583 * @param {Object} recordType Either an Array of field definition objects,
20584 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20586 Roo.data.JsonReader = function(meta, recordType){
20589 // set some defaults:
20590 Roo.applyIf(meta, {
20591 totalProperty: 'total',
20592 successProperty : 'success',
20597 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20599 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20602 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
20603 * Used by Store query builder to append _requestMeta to params.
20606 metaFromRemote : false,
20608 * This method is only used by a DataProxy which has retrieved data from a remote server.
20609 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20610 * @return {Object} data A data block which is used by an Roo.data.Store object as
20611 * a cache of Roo.data.Records.
20613 read : function(response){
20614 var json = response.responseText;
20616 var o = /* eval:var:o */ eval("("+json+")");
20618 throw {message: "JsonReader.read: Json object not found"};
20624 this.metaFromRemote = true;
20625 this.meta = o.metaData;
20626 this.recordType = Roo.data.Record.create(o.metaData.fields);
20627 this.onMetaChange(this.meta, this.recordType, o);
20629 return this.readRecords(o);
20632 // private function a store will implement
20633 onMetaChange : function(meta, recordType, o){
20640 simpleAccess: function(obj, subsc) {
20647 getJsonAccessor: function(){
20649 return function(expr) {
20651 return(re.test(expr))
20652 ? new Function("obj", "return obj." + expr)
20657 return Roo.emptyFn;
20662 * Create a data block containing Roo.data.Records from an XML document.
20663 * @param {Object} o An object which contains an Array of row objects in the property specified
20664 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20665 * which contains the total size of the dataset.
20666 * @return {Object} data A data block which is used by an Roo.data.Store object as
20667 * a cache of Roo.data.Records.
20669 readRecords : function(o){
20671 * After any data loads, the raw JSON data is available for further custom processing.
20675 var s = this.meta, Record = this.recordType,
20676 f = Record.prototype.fields, fi = f.items, fl = f.length;
20678 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20680 if(s.totalProperty) {
20681 this.getTotal = this.getJsonAccessor(s.totalProperty);
20683 if(s.successProperty) {
20684 this.getSuccess = this.getJsonAccessor(s.successProperty);
20686 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20688 var g = this.getJsonAccessor(s.id);
20689 this.getId = function(rec) {
20691 return (r === undefined || r === "") ? null : r;
20694 this.getId = function(){return null;};
20697 for(var jj = 0; jj < fl; jj++){
20699 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20700 this.ef[jj] = this.getJsonAccessor(map);
20704 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20705 if(s.totalProperty){
20706 var vt = parseInt(this.getTotal(o), 10);
20711 if(s.successProperty){
20712 var vs = this.getSuccess(o);
20713 if(vs === false || vs === 'false'){
20718 for(var i = 0; i < c; i++){
20721 var id = this.getId(n);
20722 for(var j = 0; j < fl; j++){
20724 var v = this.ef[j](n);
20726 Roo.log('missing convert for ' + f.name);
20730 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20732 var record = new Record(values, id);
20734 records[i] = record;
20739 totalRecords : totalRecords
20744 * Ext JS Library 1.1.1
20745 * Copyright(c) 2006-2007, Ext JS, LLC.
20747 * Originally Released Under LGPL - original licence link has changed is not relivant.
20750 * <script type="text/javascript">
20754 * @class Roo.data.XmlReader
20755 * @extends Roo.data.DataReader
20756 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20757 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20759 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20760 * header in the HTTP response must be set to "text/xml".</em>
20764 var RecordDef = Roo.data.Record.create([
20765 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20766 {name: 'occupation'} // This field will use "occupation" as the mapping.
20768 var myReader = new Roo.data.XmlReader({
20769 totalRecords: "results", // The element which contains the total dataset size (optional)
20770 record: "row", // The repeated element which contains row information
20771 id: "id" // The element within the row that provides an ID for the record (optional)
20775 * This would consume an XML file like this:
20779 <results>2</results>
20782 <name>Bill</name>
20783 <occupation>Gardener</occupation>
20787 <name>Ben</name>
20788 <occupation>Horticulturalist</occupation>
20792 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20793 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20794 * paged from the remote server.
20795 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20796 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20797 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20798 * a record identifier value.
20800 * Create a new XmlReader
20801 * @param {Object} meta Metadata configuration options
20802 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20803 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20804 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20806 Roo.data.XmlReader = function(meta, recordType){
20808 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20810 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20812 * This method is only used by a DataProxy which has retrieved data from a remote server.
20813 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20814 * to contain a method called 'responseXML' that returns an XML document object.
20815 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20816 * a cache of Roo.data.Records.
20818 read : function(response){
20819 var doc = response.responseXML;
20821 throw {message: "XmlReader.read: XML Document not available"};
20823 return this.readRecords(doc);
20827 * Create a data block containing Roo.data.Records from an XML document.
20828 * @param {Object} doc A parsed XML document.
20829 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20830 * a cache of Roo.data.Records.
20832 readRecords : function(doc){
20834 * After any data loads/reads, the raw XML Document is available for further custom processing.
20835 * @type XMLDocument
20837 this.xmlData = doc;
20838 var root = doc.documentElement || doc;
20839 var q = Roo.DomQuery;
20840 var recordType = this.recordType, fields = recordType.prototype.fields;
20841 var sid = this.meta.id;
20842 var totalRecords = 0, success = true;
20843 if(this.meta.totalRecords){
20844 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20847 if(this.meta.success){
20848 var sv = q.selectValue(this.meta.success, root, true);
20849 success = sv !== false && sv !== 'false';
20852 var ns = q.select(this.meta.record, root);
20853 for(var i = 0, len = ns.length; i < len; i++) {
20856 var id = sid ? q.selectValue(sid, n) : undefined;
20857 for(var j = 0, jlen = fields.length; j < jlen; j++){
20858 var f = fields.items[j];
20859 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20861 values[f.name] = v;
20863 var record = new recordType(values, id);
20865 records[records.length] = record;
20871 totalRecords : totalRecords || records.length
20876 * Ext JS Library 1.1.1
20877 * Copyright(c) 2006-2007, Ext JS, LLC.
20879 * Originally Released Under LGPL - original licence link has changed is not relivant.
20882 * <script type="text/javascript">
20886 * @class Roo.data.ArrayReader
20887 * @extends Roo.data.DataReader
20888 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20889 * Each element of that Array represents a row of data fields. The
20890 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20891 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20895 var RecordDef = Roo.data.Record.create([
20896 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20897 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20899 var myReader = new Roo.data.ArrayReader({
20900 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20904 * This would consume an Array like this:
20906 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20908 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20910 * Create a new JsonReader
20911 * @param {Object} meta Metadata configuration options.
20912 * @param {Object} recordType Either an Array of field definition objects
20913 * as specified to {@link Roo.data.Record#create},
20914 * or an {@link Roo.data.Record} object
20915 * created using {@link Roo.data.Record#create}.
20917 Roo.data.ArrayReader = function(meta, recordType){
20918 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20921 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20923 * Create a data block containing Roo.data.Records from an XML document.
20924 * @param {Object} o An Array of row objects which represents the dataset.
20925 * @return {Object} data A data block which is used by an Roo.data.Store object as
20926 * a cache of Roo.data.Records.
20928 readRecords : function(o){
20929 var sid = this.meta ? this.meta.id : null;
20930 var recordType = this.recordType, fields = recordType.prototype.fields;
20933 for(var i = 0; i < root.length; i++){
20936 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20937 for(var j = 0, jlen = fields.length; j < jlen; j++){
20938 var f = fields.items[j];
20939 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20940 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20942 values[f.name] = v;
20944 var record = new recordType(values, id);
20946 records[records.length] = record;
20950 totalRecords : records.length
20955 * Ext JS Library 1.1.1
20956 * Copyright(c) 2006-2007, Ext JS, LLC.
20958 * Originally Released Under LGPL - original licence link has changed is not relivant.
20961 * <script type="text/javascript">
20966 * @class Roo.data.Tree
20967 * @extends Roo.util.Observable
20968 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20969 * in the tree have most standard DOM functionality.
20971 * @param {Node} root (optional) The root node
20973 Roo.data.Tree = function(root){
20974 this.nodeHash = {};
20976 * The root node for this tree
20981 this.setRootNode(root);
20986 * Fires when a new child node is appended to a node in this tree.
20987 * @param {Tree} tree The owner tree
20988 * @param {Node} parent The parent node
20989 * @param {Node} node The newly appended node
20990 * @param {Number} index The index of the newly appended node
20995 * Fires when a child node is removed from a node in this tree.
20996 * @param {Tree} tree The owner tree
20997 * @param {Node} parent The parent node
20998 * @param {Node} node The child node removed
21003 * Fires when a node is moved to a new location in the tree
21004 * @param {Tree} tree The owner tree
21005 * @param {Node} node The node moved
21006 * @param {Node} oldParent The old parent of this node
21007 * @param {Node} newParent The new parent of this node
21008 * @param {Number} index The index it was moved to
21013 * Fires when a new child node is inserted in a node in this tree.
21014 * @param {Tree} tree The owner tree
21015 * @param {Node} parent The parent node
21016 * @param {Node} node The child node inserted
21017 * @param {Node} refNode The child node the node was inserted before
21021 * @event beforeappend
21022 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21023 * @param {Tree} tree The owner tree
21024 * @param {Node} parent The parent node
21025 * @param {Node} node The child node to be appended
21027 "beforeappend" : true,
21029 * @event beforeremove
21030 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21031 * @param {Tree} tree The owner tree
21032 * @param {Node} parent The parent node
21033 * @param {Node} node The child node to be removed
21035 "beforeremove" : true,
21037 * @event beforemove
21038 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21039 * @param {Tree} tree The owner tree
21040 * @param {Node} node The node being moved
21041 * @param {Node} oldParent The parent of the node
21042 * @param {Node} newParent The new parent the node is moving to
21043 * @param {Number} index The index it is being moved to
21045 "beforemove" : true,
21047 * @event beforeinsert
21048 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21049 * @param {Tree} tree The owner tree
21050 * @param {Node} parent The parent node
21051 * @param {Node} node The child node to be inserted
21052 * @param {Node} refNode The child node the node is being inserted before
21054 "beforeinsert" : true
21057 Roo.data.Tree.superclass.constructor.call(this);
21060 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21061 pathSeparator: "/",
21063 proxyNodeEvent : function(){
21064 return this.fireEvent.apply(this, arguments);
21068 * Returns the root node for this tree.
21071 getRootNode : function(){
21076 * Sets the root node for this tree.
21077 * @param {Node} node
21080 setRootNode : function(node){
21082 node.ownerTree = this;
21083 node.isRoot = true;
21084 this.registerNode(node);
21089 * Gets a node in this tree by its id.
21090 * @param {String} id
21093 getNodeById : function(id){
21094 return this.nodeHash[id];
21097 registerNode : function(node){
21098 this.nodeHash[node.id] = node;
21101 unregisterNode : function(node){
21102 delete this.nodeHash[node.id];
21105 toString : function(){
21106 return "[Tree"+(this.id?" "+this.id:"")+"]";
21111 * @class Roo.data.Node
21112 * @extends Roo.util.Observable
21113 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21114 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21116 * @param {Object} attributes The attributes/config for the node
21118 Roo.data.Node = function(attributes){
21120 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21123 this.attributes = attributes || {};
21124 this.leaf = this.attributes.leaf;
21126 * The node id. @type String
21128 this.id = this.attributes.id;
21130 this.id = Roo.id(null, "ynode-");
21131 this.attributes.id = this.id;
21134 * All child nodes of this node. @type Array
21136 this.childNodes = [];
21137 if(!this.childNodes.indexOf){ // indexOf is a must
21138 this.childNodes.indexOf = function(o){
21139 for(var i = 0, len = this.length; i < len; i++){
21148 * The parent node for this node. @type Node
21150 this.parentNode = null;
21152 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21154 this.firstChild = null;
21156 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21158 this.lastChild = null;
21160 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21162 this.previousSibling = null;
21164 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21166 this.nextSibling = null;
21171 * Fires when a new child node is appended
21172 * @param {Tree} tree The owner tree
21173 * @param {Node} this This node
21174 * @param {Node} node The newly appended node
21175 * @param {Number} index The index of the newly appended node
21180 * Fires when a child node is removed
21181 * @param {Tree} tree The owner tree
21182 * @param {Node} this This node
21183 * @param {Node} node The removed node
21188 * Fires when this node is moved to a new location in the tree
21189 * @param {Tree} tree The owner tree
21190 * @param {Node} this This node
21191 * @param {Node} oldParent The old parent of this node
21192 * @param {Node} newParent The new parent of this node
21193 * @param {Number} index The index it was moved to
21198 * Fires when a new child node is inserted.
21199 * @param {Tree} tree The owner tree
21200 * @param {Node} this This node
21201 * @param {Node} node The child node inserted
21202 * @param {Node} refNode The child node the node was inserted before
21206 * @event beforeappend
21207 * Fires before a new child is appended, return false to cancel the append.
21208 * @param {Tree} tree The owner tree
21209 * @param {Node} this This node
21210 * @param {Node} node The child node to be appended
21212 "beforeappend" : true,
21214 * @event beforeremove
21215 * Fires before a child is removed, return false to cancel the remove.
21216 * @param {Tree} tree The owner tree
21217 * @param {Node} this This node
21218 * @param {Node} node The child node to be removed
21220 "beforeremove" : true,
21222 * @event beforemove
21223 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21224 * @param {Tree} tree The owner tree
21225 * @param {Node} this This node
21226 * @param {Node} oldParent The parent of this node
21227 * @param {Node} newParent The new parent this node is moving to
21228 * @param {Number} index The index it is being moved to
21230 "beforemove" : true,
21232 * @event beforeinsert
21233 * Fires before a new child is inserted, return false to cancel the insert.
21234 * @param {Tree} tree The owner tree
21235 * @param {Node} this This node
21236 * @param {Node} node The child node to be inserted
21237 * @param {Node} refNode The child node the node is being inserted before
21239 "beforeinsert" : true
21241 this.listeners = this.attributes.listeners;
21242 Roo.data.Node.superclass.constructor.call(this);
21245 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21246 fireEvent : function(evtName){
21247 // first do standard event for this node
21248 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21251 // then bubble it up to the tree if the event wasn't cancelled
21252 var ot = this.getOwnerTree();
21254 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21262 * Returns true if this node is a leaf
21263 * @return {Boolean}
21265 isLeaf : function(){
21266 return this.leaf === true;
21270 setFirstChild : function(node){
21271 this.firstChild = node;
21275 setLastChild : function(node){
21276 this.lastChild = node;
21281 * Returns true if this node is the last child of its parent
21282 * @return {Boolean}
21284 isLast : function(){
21285 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21289 * Returns true if this node is the first child of its parent
21290 * @return {Boolean}
21292 isFirst : function(){
21293 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21296 hasChildNodes : function(){
21297 return !this.isLeaf() && this.childNodes.length > 0;
21301 * Insert node(s) as the last child node of this node.
21302 * @param {Node/Array} node The node or Array of nodes to append
21303 * @return {Node} The appended node if single append, or null if an array was passed
21305 appendChild : function(node){
21307 if(node instanceof Array){
21309 }else if(arguments.length > 1){
21312 // if passed an array or multiple args do them one by one
21314 for(var i = 0, len = multi.length; i < len; i++) {
21315 this.appendChild(multi[i]);
21318 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21321 var index = this.childNodes.length;
21322 var oldParent = node.parentNode;
21323 // it's a move, make sure we move it cleanly
21325 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21328 oldParent.removeChild(node);
21330 index = this.childNodes.length;
21332 this.setFirstChild(node);
21334 this.childNodes.push(node);
21335 node.parentNode = this;
21336 var ps = this.childNodes[index-1];
21338 node.previousSibling = ps;
21339 ps.nextSibling = node;
21341 node.previousSibling = null;
21343 node.nextSibling = null;
21344 this.setLastChild(node);
21345 node.setOwnerTree(this.getOwnerTree());
21346 this.fireEvent("append", this.ownerTree, this, node, index);
21348 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21355 * Removes a child node from this node.
21356 * @param {Node} node The node to remove
21357 * @return {Node} The removed node
21359 removeChild : function(node){
21360 var index = this.childNodes.indexOf(node);
21364 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21368 // remove it from childNodes collection
21369 this.childNodes.splice(index, 1);
21372 if(node.previousSibling){
21373 node.previousSibling.nextSibling = node.nextSibling;
21375 if(node.nextSibling){
21376 node.nextSibling.previousSibling = node.previousSibling;
21379 // update child refs
21380 if(this.firstChild == node){
21381 this.setFirstChild(node.nextSibling);
21383 if(this.lastChild == node){
21384 this.setLastChild(node.previousSibling);
21387 node.setOwnerTree(null);
21388 // clear any references from the node
21389 node.parentNode = null;
21390 node.previousSibling = null;
21391 node.nextSibling = null;
21392 this.fireEvent("remove", this.ownerTree, this, node);
21397 * Inserts the first node before the second node in this nodes childNodes collection.
21398 * @param {Node} node The node to insert
21399 * @param {Node} refNode The node to insert before (if null the node is appended)
21400 * @return {Node} The inserted node
21402 insertBefore : function(node, refNode){
21403 if(!refNode){ // like standard Dom, refNode can be null for append
21404 return this.appendChild(node);
21407 if(node == refNode){
21411 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21414 var index = this.childNodes.indexOf(refNode);
21415 var oldParent = node.parentNode;
21416 var refIndex = index;
21418 // when moving internally, indexes will change after remove
21419 if(oldParent == this && this.childNodes.indexOf(node) < index){
21423 // it's a move, make sure we move it cleanly
21425 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21428 oldParent.removeChild(node);
21431 this.setFirstChild(node);
21433 this.childNodes.splice(refIndex, 0, node);
21434 node.parentNode = this;
21435 var ps = this.childNodes[refIndex-1];
21437 node.previousSibling = ps;
21438 ps.nextSibling = node;
21440 node.previousSibling = null;
21442 node.nextSibling = refNode;
21443 refNode.previousSibling = node;
21444 node.setOwnerTree(this.getOwnerTree());
21445 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21447 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21453 * Returns the child node at the specified index.
21454 * @param {Number} index
21457 item : function(index){
21458 return this.childNodes[index];
21462 * Replaces one child node in this node with another.
21463 * @param {Node} newChild The replacement node
21464 * @param {Node} oldChild The node to replace
21465 * @return {Node} The replaced node
21467 replaceChild : function(newChild, oldChild){
21468 this.insertBefore(newChild, oldChild);
21469 this.removeChild(oldChild);
21474 * Returns the index of a child node
21475 * @param {Node} node
21476 * @return {Number} The index of the node or -1 if it was not found
21478 indexOf : function(child){
21479 return this.childNodes.indexOf(child);
21483 * Returns the tree this node is in.
21486 getOwnerTree : function(){
21487 // if it doesn't have one, look for one
21488 if(!this.ownerTree){
21492 this.ownerTree = p.ownerTree;
21498 return this.ownerTree;
21502 * Returns depth of this node (the root node has a depth of 0)
21505 getDepth : function(){
21508 while(p.parentNode){
21516 setOwnerTree : function(tree){
21517 // if it's move, we need to update everyone
21518 if(tree != this.ownerTree){
21519 if(this.ownerTree){
21520 this.ownerTree.unregisterNode(this);
21522 this.ownerTree = tree;
21523 var cs = this.childNodes;
21524 for(var i = 0, len = cs.length; i < len; i++) {
21525 cs[i].setOwnerTree(tree);
21528 tree.registerNode(this);
21534 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21535 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21536 * @return {String} The path
21538 getPath : function(attr){
21539 attr = attr || "id";
21540 var p = this.parentNode;
21541 var b = [this.attributes[attr]];
21543 b.unshift(p.attributes[attr]);
21546 var sep = this.getOwnerTree().pathSeparator;
21547 return sep + b.join(sep);
21551 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21552 * function call will be the scope provided or the current node. The arguments to the function
21553 * will be the args provided or the current node. If the function returns false at any point,
21554 * the bubble is stopped.
21555 * @param {Function} fn The function to call
21556 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21557 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21559 bubble : function(fn, scope, args){
21562 if(fn.call(scope || p, args || p) === false){
21570 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21571 * function call will be the scope provided or the current node. The arguments to the function
21572 * will be the args provided or the current node. If the function returns false at any point,
21573 * the cascade is stopped on that branch.
21574 * @param {Function} fn The function to call
21575 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21576 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21578 cascade : function(fn, scope, args){
21579 if(fn.call(scope || this, args || this) !== false){
21580 var cs = this.childNodes;
21581 for(var i = 0, len = cs.length; i < len; i++) {
21582 cs[i].cascade(fn, scope, args);
21588 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21589 * function call will be the scope provided or the current node. The arguments to the function
21590 * will be the args provided or the current node. If the function returns false at any point,
21591 * the iteration stops.
21592 * @param {Function} fn The function to call
21593 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21594 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21596 eachChild : function(fn, scope, args){
21597 var cs = this.childNodes;
21598 for(var i = 0, len = cs.length; i < len; i++) {
21599 if(fn.call(scope || this, args || cs[i]) === false){
21606 * Finds the first child that has the attribute with the specified value.
21607 * @param {String} attribute The attribute name
21608 * @param {Mixed} value The value to search for
21609 * @return {Node} The found child or null if none was found
21611 findChild : function(attribute, value){
21612 var cs = this.childNodes;
21613 for(var i = 0, len = cs.length; i < len; i++) {
21614 if(cs[i].attributes[attribute] == value){
21622 * Finds the first child by a custom function. The child matches if the function passed
21624 * @param {Function} fn
21625 * @param {Object} scope (optional)
21626 * @return {Node} The found child or null if none was found
21628 findChildBy : function(fn, scope){
21629 var cs = this.childNodes;
21630 for(var i = 0, len = cs.length; i < len; i++) {
21631 if(fn.call(scope||cs[i], cs[i]) === true){
21639 * Sorts this nodes children using the supplied sort function
21640 * @param {Function} fn
21641 * @param {Object} scope (optional)
21643 sort : function(fn, scope){
21644 var cs = this.childNodes;
21645 var len = cs.length;
21647 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21649 for(var i = 0; i < len; i++){
21651 n.previousSibling = cs[i-1];
21652 n.nextSibling = cs[i+1];
21654 this.setFirstChild(n);
21657 this.setLastChild(n);
21664 * Returns true if this node is an ancestor (at any point) of the passed node.
21665 * @param {Node} node
21666 * @return {Boolean}
21668 contains : function(node){
21669 return node.isAncestor(this);
21673 * Returns true if the passed node is an ancestor (at any point) of this node.
21674 * @param {Node} node
21675 * @return {Boolean}
21677 isAncestor : function(node){
21678 var p = this.parentNode;
21688 toString : function(){
21689 return "[Node"+(this.id?" "+this.id:"")+"]";
21693 * Ext JS Library 1.1.1
21694 * Copyright(c) 2006-2007, Ext JS, LLC.
21696 * Originally Released Under LGPL - original licence link has changed is not relivant.
21699 * <script type="text/javascript">
21704 * @class Roo.ComponentMgr
21705 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21708 Roo.ComponentMgr = function(){
21709 var all = new Roo.util.MixedCollection();
21713 * Registers a component.
21714 * @param {Roo.Component} c The component
21716 register : function(c){
21721 * Unregisters a component.
21722 * @param {Roo.Component} c The component
21724 unregister : function(c){
21729 * Returns a component by id
21730 * @param {String} id The component id
21732 get : function(id){
21733 return all.get(id);
21737 * Registers a function that will be called when a specified component is added to ComponentMgr
21738 * @param {String} id The component id
21739 * @param {Funtction} fn The callback function
21740 * @param {Object} scope The scope of the callback
21742 onAvailable : function(id, fn, scope){
21743 all.on("add", function(index, o){
21745 fn.call(scope || o, o);
21746 all.un("add", fn, scope);
21753 * Ext JS Library 1.1.1
21754 * Copyright(c) 2006-2007, Ext JS, LLC.
21756 * Originally Released Under LGPL - original licence link has changed is not relivant.
21759 * <script type="text/javascript">
21763 * @class Roo.Component
21764 * @extends Roo.util.Observable
21765 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21766 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21767 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21768 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21769 * All visual components (widgets) that require rendering into a layout should subclass Component.
21771 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21772 * 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
21773 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21775 Roo.Component = function(config){
21776 config = config || {};
21777 if(config.tagName || config.dom || typeof config == "string"){ // element object
21778 config = {el: config, id: config.id || config};
21780 this.initialConfig = config;
21782 Roo.apply(this, config);
21786 * Fires after the component is disabled.
21787 * @param {Roo.Component} this
21792 * Fires after the component is enabled.
21793 * @param {Roo.Component} this
21797 * @event beforeshow
21798 * Fires before the component is shown. Return false to stop the show.
21799 * @param {Roo.Component} this
21804 * Fires after the component is shown.
21805 * @param {Roo.Component} this
21809 * @event beforehide
21810 * Fires before the component is hidden. Return false to stop the hide.
21811 * @param {Roo.Component} this
21816 * Fires after the component is hidden.
21817 * @param {Roo.Component} this
21821 * @event beforerender
21822 * Fires before the component is rendered. Return false to stop the render.
21823 * @param {Roo.Component} this
21825 beforerender : true,
21828 * Fires after the component is rendered.
21829 * @param {Roo.Component} this
21833 * @event beforedestroy
21834 * Fires before the component is destroyed. Return false to stop the destroy.
21835 * @param {Roo.Component} this
21837 beforedestroy : true,
21840 * Fires after the component is destroyed.
21841 * @param {Roo.Component} this
21846 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21848 Roo.ComponentMgr.register(this);
21849 Roo.Component.superclass.constructor.call(this);
21850 this.initComponent();
21851 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21852 this.render(this.renderTo);
21853 delete this.renderTo;
21858 Roo.Component.AUTO_ID = 1000;
21860 Roo.extend(Roo.Component, Roo.util.Observable, {
21862 * @scope Roo.Component.prototype
21864 * true if this component is hidden. Read-only.
21869 * true if this component is disabled. Read-only.
21874 * true if this component has been rendered. Read-only.
21878 /** @cfg {String} disableClass
21879 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21881 disabledClass : "x-item-disabled",
21882 /** @cfg {Boolean} allowDomMove
21883 * Whether the component can move the Dom node when rendering (defaults to true).
21885 allowDomMove : true,
21886 /** @cfg {String} hideMode
21887 * How this component should hidden. Supported values are
21888 * "visibility" (css visibility), "offsets" (negative offset position) and
21889 * "display" (css display) - defaults to "display".
21891 hideMode: 'display',
21894 ctype : "Roo.Component",
21897 * @cfg {String} actionMode
21898 * which property holds the element that used for hide() / show() / disable() / enable()
21904 getActionEl : function(){
21905 return this[this.actionMode];
21908 initComponent : Roo.emptyFn,
21910 * If this is a lazy rendering component, render it to its container element.
21911 * @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.
21913 render : function(container, position){
21914 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21915 if(!container && this.el){
21916 this.el = Roo.get(this.el);
21917 container = this.el.dom.parentNode;
21918 this.allowDomMove = false;
21920 this.container = Roo.get(container);
21921 this.rendered = true;
21922 if(position !== undefined){
21923 if(typeof position == 'number'){
21924 position = this.container.dom.childNodes[position];
21926 position = Roo.getDom(position);
21929 this.onRender(this.container, position || null);
21931 this.el.addClass(this.cls);
21935 this.el.applyStyles(this.style);
21938 this.fireEvent("render", this);
21939 this.afterRender(this.container);
21951 // default function is not really useful
21952 onRender : function(ct, position){
21954 this.el = Roo.get(this.el);
21955 if(this.allowDomMove !== false){
21956 ct.dom.insertBefore(this.el.dom, position);
21962 getAutoCreate : function(){
21963 var cfg = typeof this.autoCreate == "object" ?
21964 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21965 if(this.id && !cfg.id){
21972 afterRender : Roo.emptyFn,
21975 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21976 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21978 destroy : function(){
21979 if(this.fireEvent("beforedestroy", this) !== false){
21980 this.purgeListeners();
21981 this.beforeDestroy();
21983 this.el.removeAllListeners();
21985 if(this.actionMode == "container"){
21986 this.container.remove();
21990 Roo.ComponentMgr.unregister(this);
21991 this.fireEvent("destroy", this);
21996 beforeDestroy : function(){
22001 onDestroy : function(){
22006 * Returns the underlying {@link Roo.Element}.
22007 * @return {Roo.Element} The element
22009 getEl : function(){
22014 * Returns the id of this component.
22017 getId : function(){
22022 * Try to focus this component.
22023 * @param {Boolean} selectText True to also select the text in this component (if applicable)
22024 * @return {Roo.Component} this
22026 focus : function(selectText){
22029 if(selectText === true){
22030 this.el.dom.select();
22045 * Disable this component.
22046 * @return {Roo.Component} this
22048 disable : function(){
22052 this.disabled = true;
22053 this.fireEvent("disable", this);
22058 onDisable : function(){
22059 this.getActionEl().addClass(this.disabledClass);
22060 this.el.dom.disabled = true;
22064 * Enable this component.
22065 * @return {Roo.Component} this
22067 enable : function(){
22071 this.disabled = false;
22072 this.fireEvent("enable", this);
22077 onEnable : function(){
22078 this.getActionEl().removeClass(this.disabledClass);
22079 this.el.dom.disabled = false;
22083 * Convenience function for setting disabled/enabled by boolean.
22084 * @param {Boolean} disabled
22086 setDisabled : function(disabled){
22087 this[disabled ? "disable" : "enable"]();
22091 * Show this component.
22092 * @return {Roo.Component} this
22095 if(this.fireEvent("beforeshow", this) !== false){
22096 this.hidden = false;
22100 this.fireEvent("show", this);
22106 onShow : function(){
22107 var ae = this.getActionEl();
22108 if(this.hideMode == 'visibility'){
22109 ae.dom.style.visibility = "visible";
22110 }else if(this.hideMode == 'offsets'){
22111 ae.removeClass('x-hidden');
22113 ae.dom.style.display = "";
22118 * Hide this component.
22119 * @return {Roo.Component} this
22122 if(this.fireEvent("beforehide", this) !== false){
22123 this.hidden = true;
22127 this.fireEvent("hide", this);
22133 onHide : function(){
22134 var ae = this.getActionEl();
22135 if(this.hideMode == 'visibility'){
22136 ae.dom.style.visibility = "hidden";
22137 }else if(this.hideMode == 'offsets'){
22138 ae.addClass('x-hidden');
22140 ae.dom.style.display = "none";
22145 * Convenience function to hide or show this component by boolean.
22146 * @param {Boolean} visible True to show, false to hide
22147 * @return {Roo.Component} this
22149 setVisible: function(visible){
22159 * Returns true if this component is visible.
22161 isVisible : function(){
22162 return this.getActionEl().isVisible();
22165 cloneConfig : function(overrides){
22166 overrides = overrides || {};
22167 var id = overrides.id || Roo.id();
22168 var cfg = Roo.applyIf(overrides, this.initialConfig);
22169 cfg.id = id; // prevent dup id
22170 return new this.constructor(cfg);
22174 * Ext JS Library 1.1.1
22175 * Copyright(c) 2006-2007, Ext JS, LLC.
22177 * Originally Released Under LGPL - original licence link has changed is not relivant.
22180 * <script type="text/javascript">
22185 * @extends Roo.Element
22186 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22187 * automatic maintaining of shadow/shim positions.
22188 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22189 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22190 * you can pass a string with a CSS class name. False turns off the shadow.
22191 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22192 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22193 * @cfg {String} cls CSS class to add to the element
22194 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22195 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22197 * @param {Object} config An object with config options.
22198 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22201 Roo.Layer = function(config, existingEl){
22202 config = config || {};
22203 var dh = Roo.DomHelper;
22204 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22206 this.dom = Roo.getDom(existingEl);
22209 var o = config.dh || {tag: "div", cls: "x-layer"};
22210 this.dom = dh.append(pel, o);
22213 this.addClass(config.cls);
22215 this.constrain = config.constrain !== false;
22216 this.visibilityMode = Roo.Element.VISIBILITY;
22218 this.id = this.dom.id = config.id;
22220 this.id = Roo.id(this.dom);
22222 this.zindex = config.zindex || this.getZIndex();
22223 this.position("absolute", this.zindex);
22225 this.shadowOffset = config.shadowOffset || 4;
22226 this.shadow = new Roo.Shadow({
22227 offset : this.shadowOffset,
22228 mode : config.shadow
22231 this.shadowOffset = 0;
22233 this.useShim = config.shim !== false && Roo.useShims;
22234 this.useDisplay = config.useDisplay;
22238 var supr = Roo.Element.prototype;
22240 // shims are shared among layer to keep from having 100 iframes
22243 Roo.extend(Roo.Layer, Roo.Element, {
22245 getZIndex : function(){
22246 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22249 getShim : function(){
22256 var shim = shims.shift();
22258 shim = this.createShim();
22259 shim.enableDisplayMode('block');
22260 shim.dom.style.display = 'none';
22261 shim.dom.style.visibility = 'visible';
22263 var pn = this.dom.parentNode;
22264 if(shim.dom.parentNode != pn){
22265 pn.insertBefore(shim.dom, this.dom);
22267 shim.setStyle('z-index', this.getZIndex()-2);
22272 hideShim : function(){
22274 this.shim.setDisplayed(false);
22275 shims.push(this.shim);
22280 disableShadow : function(){
22282 this.shadowDisabled = true;
22283 this.shadow.hide();
22284 this.lastShadowOffset = this.shadowOffset;
22285 this.shadowOffset = 0;
22289 enableShadow : function(show){
22291 this.shadowDisabled = false;
22292 this.shadowOffset = this.lastShadowOffset;
22293 delete this.lastShadowOffset;
22301 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22302 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22303 sync : function(doShow){
22304 var sw = this.shadow;
22305 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22306 var sh = this.getShim();
22308 var w = this.getWidth(),
22309 h = this.getHeight();
22311 var l = this.getLeft(true),
22312 t = this.getTop(true);
22314 if(sw && !this.shadowDisabled){
22315 if(doShow && !sw.isVisible()){
22318 sw.realign(l, t, w, h);
22324 // fit the shim behind the shadow, so it is shimmed too
22325 var a = sw.adjusts, s = sh.dom.style;
22326 s.left = (Math.min(l, l+a.l))+"px";
22327 s.top = (Math.min(t, t+a.t))+"px";
22328 s.width = (w+a.w)+"px";
22329 s.height = (h+a.h)+"px";
22336 sh.setLeftTop(l, t);
22343 destroy : function(){
22346 this.shadow.hide();
22348 this.removeAllListeners();
22349 var pn = this.dom.parentNode;
22351 pn.removeChild(this.dom);
22353 Roo.Element.uncache(this.id);
22356 remove : function(){
22361 beginUpdate : function(){
22362 this.updating = true;
22366 endUpdate : function(){
22367 this.updating = false;
22372 hideUnders : function(negOffset){
22374 this.shadow.hide();
22380 constrainXY : function(){
22381 if(this.constrain){
22382 var vw = Roo.lib.Dom.getViewWidth(),
22383 vh = Roo.lib.Dom.getViewHeight();
22384 var s = Roo.get(document).getScroll();
22386 var xy = this.getXY();
22387 var x = xy[0], y = xy[1];
22388 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22389 // only move it if it needs it
22391 // first validate right/bottom
22392 if((x + w) > vw+s.left){
22393 x = vw - w - this.shadowOffset;
22396 if((y + h) > vh+s.top){
22397 y = vh - h - this.shadowOffset;
22400 // then make sure top/left isn't negative
22411 var ay = this.avoidY;
22412 if(y <= ay && (y+h) >= ay){
22418 supr.setXY.call(this, xy);
22424 isVisible : function(){
22425 return this.visible;
22429 showAction : function(){
22430 this.visible = true; // track visibility to prevent getStyle calls
22431 if(this.useDisplay === true){
22432 this.setDisplayed("");
22433 }else if(this.lastXY){
22434 supr.setXY.call(this, this.lastXY);
22435 }else if(this.lastLT){
22436 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22441 hideAction : function(){
22442 this.visible = false;
22443 if(this.useDisplay === true){
22444 this.setDisplayed(false);
22446 this.setLeftTop(-10000,-10000);
22450 // overridden Element method
22451 setVisible : function(v, a, d, c, e){
22456 var cb = function(){
22461 }.createDelegate(this);
22462 supr.setVisible.call(this, true, true, d, cb, e);
22465 this.hideUnders(true);
22474 }.createDelegate(this);
22476 supr.setVisible.call(this, v, a, d, cb, e);
22485 storeXY : function(xy){
22486 delete this.lastLT;
22490 storeLeftTop : function(left, top){
22491 delete this.lastXY;
22492 this.lastLT = [left, top];
22496 beforeFx : function(){
22497 this.beforeAction();
22498 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22502 afterFx : function(){
22503 Roo.Layer.superclass.afterFx.apply(this, arguments);
22504 this.sync(this.isVisible());
22508 beforeAction : function(){
22509 if(!this.updating && this.shadow){
22510 this.shadow.hide();
22514 // overridden Element method
22515 setLeft : function(left){
22516 this.storeLeftTop(left, this.getTop(true));
22517 supr.setLeft.apply(this, arguments);
22521 setTop : function(top){
22522 this.storeLeftTop(this.getLeft(true), top);
22523 supr.setTop.apply(this, arguments);
22527 setLeftTop : function(left, top){
22528 this.storeLeftTop(left, top);
22529 supr.setLeftTop.apply(this, arguments);
22533 setXY : function(xy, a, d, c, e){
22535 this.beforeAction();
22537 var cb = this.createCB(c);
22538 supr.setXY.call(this, xy, a, d, cb, e);
22545 createCB : function(c){
22556 // overridden Element method
22557 setX : function(x, a, d, c, e){
22558 this.setXY([x, this.getY()], a, d, c, e);
22561 // overridden Element method
22562 setY : function(y, a, d, c, e){
22563 this.setXY([this.getX(), y], a, d, c, e);
22566 // overridden Element method
22567 setSize : function(w, h, a, d, c, e){
22568 this.beforeAction();
22569 var cb = this.createCB(c);
22570 supr.setSize.call(this, w, h, a, d, cb, e);
22576 // overridden Element method
22577 setWidth : function(w, a, d, c, e){
22578 this.beforeAction();
22579 var cb = this.createCB(c);
22580 supr.setWidth.call(this, w, a, d, cb, e);
22586 // overridden Element method
22587 setHeight : function(h, a, d, c, e){
22588 this.beforeAction();
22589 var cb = this.createCB(c);
22590 supr.setHeight.call(this, h, a, d, cb, e);
22596 // overridden Element method
22597 setBounds : function(x, y, w, h, a, d, c, e){
22598 this.beforeAction();
22599 var cb = this.createCB(c);
22601 this.storeXY([x, y]);
22602 supr.setXY.call(this, [x, y]);
22603 supr.setSize.call(this, w, h, a, d, cb, e);
22606 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22612 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22613 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22614 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22615 * @param {Number} zindex The new z-index to set
22616 * @return {this} The Layer
22618 setZIndex : function(zindex){
22619 this.zindex = zindex;
22620 this.setStyle("z-index", zindex + 2);
22622 this.shadow.setZIndex(zindex + 1);
22625 this.shim.setStyle("z-index", zindex);
22631 * Ext JS Library 1.1.1
22632 * Copyright(c) 2006-2007, Ext JS, LLC.
22634 * Originally Released Under LGPL - original licence link has changed is not relivant.
22637 * <script type="text/javascript">
22642 * @class Roo.Shadow
22643 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22644 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22645 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22647 * Create a new Shadow
22648 * @param {Object} config The config object
22650 Roo.Shadow = function(config){
22651 Roo.apply(this, config);
22652 if(typeof this.mode != "string"){
22653 this.mode = this.defaultMode;
22655 var o = this.offset, a = {h: 0};
22656 var rad = Math.floor(this.offset/2);
22657 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22663 a.l -= this.offset + rad;
22664 a.t -= this.offset + rad;
22675 a.l -= (this.offset - rad);
22676 a.t -= this.offset + rad;
22678 a.w -= (this.offset - rad)*2;
22689 a.l -= (this.offset - rad);
22690 a.t -= (this.offset - rad);
22692 a.w -= (this.offset + rad + 1);
22693 a.h -= (this.offset + rad);
22702 Roo.Shadow.prototype = {
22704 * @cfg {String} mode
22705 * The shadow display mode. Supports the following options:<br />
22706 * sides: Shadow displays on both sides and bottom only<br />
22707 * frame: Shadow displays equally on all four sides<br />
22708 * drop: Traditional bottom-right drop shadow (default)
22711 * @cfg {String} offset
22712 * The number of pixels to offset the shadow from the element (defaults to 4)
22717 defaultMode: "drop",
22720 * Displays the shadow under the target element
22721 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22723 show : function(target){
22724 target = Roo.get(target);
22726 this.el = Roo.Shadow.Pool.pull();
22727 if(this.el.dom.nextSibling != target.dom){
22728 this.el.insertBefore(target);
22731 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22733 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22736 target.getLeft(true),
22737 target.getTop(true),
22741 this.el.dom.style.display = "block";
22745 * Returns true if the shadow is visible, else false
22747 isVisible : function(){
22748 return this.el ? true : false;
22752 * Direct alignment when values are already available. Show must be called at least once before
22753 * calling this method to ensure it is initialized.
22754 * @param {Number} left The target element left position
22755 * @param {Number} top The target element top position
22756 * @param {Number} width The target element width
22757 * @param {Number} height The target element height
22759 realign : function(l, t, w, h){
22763 var a = this.adjusts, d = this.el.dom, s = d.style;
22765 s.left = (l+a.l)+"px";
22766 s.top = (t+a.t)+"px";
22767 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22769 if(s.width != sws || s.height != shs){
22773 var cn = d.childNodes;
22774 var sww = Math.max(0, (sw-12))+"px";
22775 cn[0].childNodes[1].style.width = sww;
22776 cn[1].childNodes[1].style.width = sww;
22777 cn[2].childNodes[1].style.width = sww;
22778 cn[1].style.height = Math.max(0, (sh-12))+"px";
22784 * Hides this shadow
22788 this.el.dom.style.display = "none";
22789 Roo.Shadow.Pool.push(this.el);
22795 * Adjust the z-index of this shadow
22796 * @param {Number} zindex The new z-index
22798 setZIndex : function(z){
22801 this.el.setStyle("z-index", z);
22806 // Private utility class that manages the internal Shadow cache
22807 Roo.Shadow.Pool = function(){
22809 var markup = Roo.isIE ?
22810 '<div class="x-ie-shadow"></div>' :
22811 '<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>';
22814 var sh = p.shift();
22816 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22817 sh.autoBoxAdjust = false;
22822 push : function(sh){
22828 * Ext JS Library 1.1.1
22829 * Copyright(c) 2006-2007, Ext JS, LLC.
22831 * Originally Released Under LGPL - original licence link has changed is not relivant.
22834 * <script type="text/javascript">
22838 * @class Roo.BoxComponent
22839 * @extends Roo.Component
22840 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22841 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22842 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22843 * layout containers.
22845 * @param {Roo.Element/String/Object} config The configuration options.
22847 Roo.BoxComponent = function(config){
22848 Roo.Component.call(this, config);
22852 * Fires after the component is resized.
22853 * @param {Roo.Component} this
22854 * @param {Number} adjWidth The box-adjusted width that was set
22855 * @param {Number} adjHeight The box-adjusted height that was set
22856 * @param {Number} rawWidth The width that was originally specified
22857 * @param {Number} rawHeight The height that was originally specified
22862 * Fires after the component is moved.
22863 * @param {Roo.Component} this
22864 * @param {Number} x The new x position
22865 * @param {Number} y The new y position
22871 Roo.extend(Roo.BoxComponent, Roo.Component, {
22872 // private, set in afterRender to signify that the component has been rendered
22874 // private, used to defer height settings to subclasses
22875 deferHeight: false,
22876 /** @cfg {Number} width
22877 * width (optional) size of component
22879 /** @cfg {Number} height
22880 * height (optional) size of component
22884 * Sets the width and height of the component. This method fires the resize event. This method can accept
22885 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22886 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22887 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22888 * @return {Roo.BoxComponent} this
22890 setSize : function(w, h){
22891 // support for standard size objects
22892 if(typeof w == 'object'){
22897 if(!this.boxReady){
22903 // prevent recalcs when not needed
22904 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22907 this.lastSize = {width: w, height: h};
22909 var adj = this.adjustSize(w, h);
22910 var aw = adj.width, ah = adj.height;
22911 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22912 var rz = this.getResizeEl();
22913 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22914 rz.setSize(aw, ah);
22915 }else if(!this.deferHeight && ah !== undefined){
22917 }else if(aw !== undefined){
22920 this.onResize(aw, ah, w, h);
22921 this.fireEvent('resize', this, aw, ah, w, h);
22927 * Gets the current size of the component's underlying element.
22928 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22930 getSize : function(){
22931 return this.el.getSize();
22935 * Gets the current XY position of the component's underlying element.
22936 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22937 * @return {Array} The XY position of the element (e.g., [100, 200])
22939 getPosition : function(local){
22940 if(local === true){
22941 return [this.el.getLeft(true), this.el.getTop(true)];
22943 return this.xy || this.el.getXY();
22947 * Gets the current box measurements of the component's underlying element.
22948 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22949 * @returns {Object} box An object in the format {x, y, width, height}
22951 getBox : function(local){
22952 var s = this.el.getSize();
22954 s.x = this.el.getLeft(true);
22955 s.y = this.el.getTop(true);
22957 var xy = this.xy || this.el.getXY();
22965 * Sets the current box measurements of the component's underlying element.
22966 * @param {Object} box An object in the format {x, y, width, height}
22967 * @returns {Roo.BoxComponent} this
22969 updateBox : function(box){
22970 this.setSize(box.width, box.height);
22971 this.setPagePosition(box.x, box.y);
22976 getResizeEl : function(){
22977 return this.resizeEl || this.el;
22981 getPositionEl : function(){
22982 return this.positionEl || this.el;
22986 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22987 * This method fires the move event.
22988 * @param {Number} left The new left
22989 * @param {Number} top The new top
22990 * @returns {Roo.BoxComponent} this
22992 setPosition : function(x, y){
22995 if(!this.boxReady){
22998 var adj = this.adjustPosition(x, y);
22999 var ax = adj.x, ay = adj.y;
23001 var el = this.getPositionEl();
23002 if(ax !== undefined || ay !== undefined){
23003 if(ax !== undefined && ay !== undefined){
23004 el.setLeftTop(ax, ay);
23005 }else if(ax !== undefined){
23007 }else if(ay !== undefined){
23010 this.onPosition(ax, ay);
23011 this.fireEvent('move', this, ax, ay);
23017 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
23018 * This method fires the move event.
23019 * @param {Number} x The new x position
23020 * @param {Number} y The new y position
23021 * @returns {Roo.BoxComponent} this
23023 setPagePosition : function(x, y){
23026 if(!this.boxReady){
23029 if(x === undefined || y === undefined){ // cannot translate undefined points
23032 var p = this.el.translatePoints(x, y);
23033 this.setPosition(p.left, p.top);
23038 onRender : function(ct, position){
23039 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23041 this.resizeEl = Roo.get(this.resizeEl);
23043 if(this.positionEl){
23044 this.positionEl = Roo.get(this.positionEl);
23049 afterRender : function(){
23050 Roo.BoxComponent.superclass.afterRender.call(this);
23051 this.boxReady = true;
23052 this.setSize(this.width, this.height);
23053 if(this.x || this.y){
23054 this.setPosition(this.x, this.y);
23056 if(this.pageX || this.pageY){
23057 this.setPagePosition(this.pageX, this.pageY);
23062 * Force the component's size to recalculate based on the underlying element's current height and width.
23063 * @returns {Roo.BoxComponent} this
23065 syncSize : function(){
23066 delete this.lastSize;
23067 this.setSize(this.el.getWidth(), this.el.getHeight());
23072 * Called after the component is resized, this method is empty by default but can be implemented by any
23073 * subclass that needs to perform custom logic after a resize occurs.
23074 * @param {Number} adjWidth The box-adjusted width that was set
23075 * @param {Number} adjHeight The box-adjusted height that was set
23076 * @param {Number} rawWidth The width that was originally specified
23077 * @param {Number} rawHeight The height that was originally specified
23079 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23084 * Called after the component is moved, this method is empty by default but can be implemented by any
23085 * subclass that needs to perform custom logic after a move occurs.
23086 * @param {Number} x The new x position
23087 * @param {Number} y The new y position
23089 onPosition : function(x, y){
23094 adjustSize : function(w, h){
23095 if(this.autoWidth){
23098 if(this.autoHeight){
23101 return {width : w, height: h};
23105 adjustPosition : function(x, y){
23106 return {x : x, y: y};
23110 * Ext JS Library 1.1.1
23111 * Copyright(c) 2006-2007, Ext JS, LLC.
23113 * Originally Released Under LGPL - original licence link has changed is not relivant.
23116 * <script type="text/javascript">
23121 * @class Roo.SplitBar
23122 * @extends Roo.util.Observable
23123 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23127 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23128 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23129 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23130 split.minSize = 100;
23131 split.maxSize = 600;
23132 split.animate = true;
23133 split.on('moved', splitterMoved);
23136 * Create a new SplitBar
23137 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23138 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23139 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23140 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23141 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23142 position of the SplitBar).
23144 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23147 this.el = Roo.get(dragElement, true);
23148 this.el.dom.unselectable = "on";
23150 this.resizingEl = Roo.get(resizingElement, true);
23154 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23155 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23158 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23161 * The minimum size of the resizing element. (Defaults to 0)
23167 * The maximum size of the resizing element. (Defaults to 2000)
23170 this.maxSize = 2000;
23173 * Whether to animate the transition to the new size
23176 this.animate = false;
23179 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23182 this.useShim = false;
23187 if(!existingProxy){
23189 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23191 this.proxy = Roo.get(existingProxy).dom;
23194 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23197 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23200 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23203 this.dragSpecs = {};
23206 * @private The adapter to use to positon and resize elements
23208 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23209 this.adapter.init(this);
23211 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23213 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23214 this.el.addClass("x-splitbar-h");
23217 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23218 this.el.addClass("x-splitbar-v");
23224 * Fires when the splitter is moved (alias for {@link #event-moved})
23225 * @param {Roo.SplitBar} this
23226 * @param {Number} newSize the new width or height
23231 * Fires when the splitter is moved
23232 * @param {Roo.SplitBar} this
23233 * @param {Number} newSize the new width or height
23237 * @event beforeresize
23238 * Fires before the splitter is dragged
23239 * @param {Roo.SplitBar} this
23241 "beforeresize" : true,
23243 "beforeapply" : true
23246 Roo.util.Observable.call(this);
23249 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23250 onStartProxyDrag : function(x, y){
23251 this.fireEvent("beforeresize", this);
23253 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23255 o.enableDisplayMode("block");
23256 // all splitbars share the same overlay
23257 Roo.SplitBar.prototype.overlay = o;
23259 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23260 this.overlay.show();
23261 Roo.get(this.proxy).setDisplayed("block");
23262 var size = this.adapter.getElementSize(this);
23263 this.activeMinSize = this.getMinimumSize();;
23264 this.activeMaxSize = this.getMaximumSize();;
23265 var c1 = size - this.activeMinSize;
23266 var c2 = Math.max(this.activeMaxSize - size, 0);
23267 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23268 this.dd.resetConstraints();
23269 this.dd.setXConstraint(
23270 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23271 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23273 this.dd.setYConstraint(0, 0);
23275 this.dd.resetConstraints();
23276 this.dd.setXConstraint(0, 0);
23277 this.dd.setYConstraint(
23278 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23279 this.placement == Roo.SplitBar.TOP ? c2 : c1
23282 this.dragSpecs.startSize = size;
23283 this.dragSpecs.startPoint = [x, y];
23284 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23288 * @private Called after the drag operation by the DDProxy
23290 onEndProxyDrag : function(e){
23291 Roo.get(this.proxy).setDisplayed(false);
23292 var endPoint = Roo.lib.Event.getXY(e);
23294 this.overlay.hide();
23297 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23298 newSize = this.dragSpecs.startSize +
23299 (this.placement == Roo.SplitBar.LEFT ?
23300 endPoint[0] - this.dragSpecs.startPoint[0] :
23301 this.dragSpecs.startPoint[0] - endPoint[0]
23304 newSize = this.dragSpecs.startSize +
23305 (this.placement == Roo.SplitBar.TOP ?
23306 endPoint[1] - this.dragSpecs.startPoint[1] :
23307 this.dragSpecs.startPoint[1] - endPoint[1]
23310 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23311 if(newSize != this.dragSpecs.startSize){
23312 if(this.fireEvent('beforeapply', this, newSize) !== false){
23313 this.adapter.setElementSize(this, newSize);
23314 this.fireEvent("moved", this, newSize);
23315 this.fireEvent("resize", this, newSize);
23321 * Get the adapter this SplitBar uses
23322 * @return The adapter object
23324 getAdapter : function(){
23325 return this.adapter;
23329 * Set the adapter this SplitBar uses
23330 * @param {Object} adapter A SplitBar adapter object
23332 setAdapter : function(adapter){
23333 this.adapter = adapter;
23334 this.adapter.init(this);
23338 * Gets the minimum size for the resizing element
23339 * @return {Number} The minimum size
23341 getMinimumSize : function(){
23342 return this.minSize;
23346 * Sets the minimum size for the resizing element
23347 * @param {Number} minSize The minimum size
23349 setMinimumSize : function(minSize){
23350 this.minSize = minSize;
23354 * Gets the maximum size for the resizing element
23355 * @return {Number} The maximum size
23357 getMaximumSize : function(){
23358 return this.maxSize;
23362 * Sets the maximum size for the resizing element
23363 * @param {Number} maxSize The maximum size
23365 setMaximumSize : function(maxSize){
23366 this.maxSize = maxSize;
23370 * Sets the initialize size for the resizing element
23371 * @param {Number} size The initial size
23373 setCurrentSize : function(size){
23374 var oldAnimate = this.animate;
23375 this.animate = false;
23376 this.adapter.setElementSize(this, size);
23377 this.animate = oldAnimate;
23381 * Destroy this splitbar.
23382 * @param {Boolean} removeEl True to remove the element
23384 destroy : function(removeEl){
23386 this.shim.remove();
23389 this.proxy.parentNode.removeChild(this.proxy);
23397 * @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.
23399 Roo.SplitBar.createProxy = function(dir){
23400 var proxy = new Roo.Element(document.createElement("div"));
23401 proxy.unselectable();
23402 var cls = 'x-splitbar-proxy';
23403 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23404 document.body.appendChild(proxy.dom);
23409 * @class Roo.SplitBar.BasicLayoutAdapter
23410 * Default Adapter. It assumes the splitter and resizing element are not positioned
23411 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23413 Roo.SplitBar.BasicLayoutAdapter = function(){
23416 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23417 // do nothing for now
23418 init : function(s){
23422 * Called before drag operations to get the current size of the resizing element.
23423 * @param {Roo.SplitBar} s The SplitBar using this adapter
23425 getElementSize : function(s){
23426 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23427 return s.resizingEl.getWidth();
23429 return s.resizingEl.getHeight();
23434 * Called after drag operations to set the size of the resizing element.
23435 * @param {Roo.SplitBar} s The SplitBar using this adapter
23436 * @param {Number} newSize The new size to set
23437 * @param {Function} onComplete A function to be invoked when resizing is complete
23439 setElementSize : function(s, newSize, onComplete){
23440 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23442 s.resizingEl.setWidth(newSize);
23444 onComplete(s, newSize);
23447 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23452 s.resizingEl.setHeight(newSize);
23454 onComplete(s, newSize);
23457 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23464 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23465 * @extends Roo.SplitBar.BasicLayoutAdapter
23466 * Adapter that moves the splitter element to align with the resized sizing element.
23467 * Used with an absolute positioned SplitBar.
23468 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23469 * document.body, make sure you assign an id to the body element.
23471 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23472 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23473 this.container = Roo.get(container);
23476 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23477 init : function(s){
23478 this.basic.init(s);
23481 getElementSize : function(s){
23482 return this.basic.getElementSize(s);
23485 setElementSize : function(s, newSize, onComplete){
23486 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23489 moveSplitter : function(s){
23490 var yes = Roo.SplitBar;
23491 switch(s.placement){
23493 s.el.setX(s.resizingEl.getRight());
23496 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23499 s.el.setY(s.resizingEl.getBottom());
23502 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23509 * Orientation constant - Create a vertical SplitBar
23513 Roo.SplitBar.VERTICAL = 1;
23516 * Orientation constant - Create a horizontal SplitBar
23520 Roo.SplitBar.HORIZONTAL = 2;
23523 * Placement constant - The resizing element is to the left of the splitter element
23527 Roo.SplitBar.LEFT = 1;
23530 * Placement constant - The resizing element is to the right of the splitter element
23534 Roo.SplitBar.RIGHT = 2;
23537 * Placement constant - The resizing element is positioned above the splitter element
23541 Roo.SplitBar.TOP = 3;
23544 * Placement constant - The resizing element is positioned under splitter element
23548 Roo.SplitBar.BOTTOM = 4;
23551 * Ext JS Library 1.1.1
23552 * Copyright(c) 2006-2007, Ext JS, LLC.
23554 * Originally Released Under LGPL - original licence link has changed is not relivant.
23557 * <script type="text/javascript">
23562 * @extends Roo.util.Observable
23563 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23564 * This class also supports single and multi selection modes. <br>
23565 * Create a data model bound view:
23567 var store = new Roo.data.Store(...);
23569 var view = new Roo.View({
23571 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
23573 singleSelect: true,
23574 selectedClass: "ydataview-selected",
23578 // listen for node click?
23579 view.on("click", function(vw, index, node, e){
23580 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23584 dataModel.load("foobar.xml");
23586 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23588 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23589 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23591 * Note: old style constructor is still suported (container, template, config)
23594 * Create a new View
23595 * @param {Object} config The config object
23598 Roo.View = function(config, depreciated_tpl, depreciated_config){
23600 if (typeof(depreciated_tpl) == 'undefined') {
23601 // new way.. - universal constructor.
23602 Roo.apply(this, config);
23603 this.el = Roo.get(this.el);
23606 this.el = Roo.get(config);
23607 this.tpl = depreciated_tpl;
23608 Roo.apply(this, depreciated_config);
23612 if(typeof(this.tpl) == "string"){
23613 this.tpl = new Roo.Template(this.tpl);
23615 // support xtype ctors..
23616 this.tpl = new Roo.factory(this.tpl, Roo);
23620 this.tpl.compile();
23627 * @event beforeclick
23628 * Fires before a click is processed. Returns false to cancel the default action.
23629 * @param {Roo.View} this
23630 * @param {Number} index The index of the target node
23631 * @param {HTMLElement} node The target node
23632 * @param {Roo.EventObject} e The raw event object
23634 "beforeclick" : true,
23637 * Fires when a template node is clicked.
23638 * @param {Roo.View} this
23639 * @param {Number} index The index of the target node
23640 * @param {HTMLElement} node The target node
23641 * @param {Roo.EventObject} e The raw event object
23646 * Fires when a template node is double clicked.
23647 * @param {Roo.View} this
23648 * @param {Number} index The index of the target node
23649 * @param {HTMLElement} node The target node
23650 * @param {Roo.EventObject} e The raw event object
23654 * @event contextmenu
23655 * Fires when a template node is right clicked.
23656 * @param {Roo.View} this
23657 * @param {Number} index The index of the target node
23658 * @param {HTMLElement} node The target node
23659 * @param {Roo.EventObject} e The raw event object
23661 "contextmenu" : true,
23663 * @event selectionchange
23664 * Fires when the selected nodes change.
23665 * @param {Roo.View} this
23666 * @param {Array} selections Array of the selected nodes
23668 "selectionchange" : true,
23671 * @event beforeselect
23672 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23673 * @param {Roo.View} this
23674 * @param {HTMLElement} node The node to be selected
23675 * @param {Array} selections Array of currently selected nodes
23677 "beforeselect" : true,
23679 * @event preparedata
23680 * Fires on every row to render, to allow you to change the data.
23681 * @param {Roo.View} this
23682 * @param {Object} data to be rendered (change this)
23684 "preparedata" : true
23688 "click": this.onClick,
23689 "dblclick": this.onDblClick,
23690 "contextmenu": this.onContextMenu,
23694 this.selections = [];
23696 this.cmp = new Roo.CompositeElementLite([]);
23698 this.store = Roo.factory(this.store, Roo.data);
23699 this.setStore(this.store, true);
23701 Roo.View.superclass.constructor.call(this);
23704 Roo.extend(Roo.View, Roo.util.Observable, {
23707 * @cfg {Roo.data.Store} store Data store to load data from.
23712 * @cfg {String|Roo.Element} el The container element.
23717 * @cfg {String|Roo.Template} tpl The template used by this View
23722 * @cfg {String} selectedClass The css class to add to selected nodes
23724 selectedClass : "x-view-selected",
23726 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23730 * @cfg {Boolean} multiSelect Allow multiple selection
23732 multiSelect : false,
23734 * @cfg {Boolean} singleSelect Allow single selection
23736 singleSelect: false,
23739 * @cfg {Boolean} toggleSelect - selecting
23741 toggleSelect : false,
23744 * Returns the element this view is bound to.
23745 * @return {Roo.Element}
23747 getEl : function(){
23752 * Refreshes the view.
23754 refresh : function(){
23756 this.clearSelections();
23757 this.el.update("");
23759 var records = this.store.getRange();
23760 if(records.length < 1){
23761 this.el.update(this.emptyText);
23764 for(var i = 0, len = records.length; i < len; i++){
23765 var data = this.prepareData(records[i].data, i, records[i]);
23766 this.fireEvent("preparedata", this, data, i, records[i]);
23767 html[html.length] = t.apply(data);
23769 this.el.update(html.join(""));
23770 this.nodes = this.el.dom.childNodes;
23771 this.updateIndexes(0);
23775 * Function to override to reformat the data that is sent to
23776 * the template for each node.
23777 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23778 * a JSON object for an UpdateManager bound view).
23780 prepareData : function(data){
23784 onUpdate : function(ds, record){
23785 this.clearSelections();
23786 var index = this.store.indexOf(record);
23787 var n = this.nodes[index];
23788 this.tpl.insertBefore(n, this.prepareData(record.data));
23789 n.parentNode.removeChild(n);
23790 this.updateIndexes(index, index);
23793 onAdd : function(ds, records, index){
23794 this.clearSelections();
23795 if(this.nodes.length == 0){
23799 var n = this.nodes[index];
23800 for(var i = 0, len = records.length; i < len; i++){
23801 var d = this.prepareData(records[i].data);
23803 this.tpl.insertBefore(n, d);
23805 this.tpl.append(this.el, d);
23808 this.updateIndexes(index);
23811 onRemove : function(ds, record, index){
23812 this.clearSelections();
23813 this.el.dom.removeChild(this.nodes[index]);
23814 this.updateIndexes(index);
23818 * Refresh an individual node.
23819 * @param {Number} index
23821 refreshNode : function(index){
23822 this.onUpdate(this.store, this.store.getAt(index));
23825 updateIndexes : function(startIndex, endIndex){
23826 var ns = this.nodes;
23827 startIndex = startIndex || 0;
23828 endIndex = endIndex || ns.length - 1;
23829 for(var i = startIndex; i <= endIndex; i++){
23830 ns[i].nodeIndex = i;
23835 * Changes the data store this view uses and refresh the view.
23836 * @param {Store} store
23838 setStore : function(store, initial){
23839 if(!initial && this.store){
23840 this.store.un("datachanged", this.refresh);
23841 this.store.un("add", this.onAdd);
23842 this.store.un("remove", this.onRemove);
23843 this.store.un("update", this.onUpdate);
23844 this.store.un("clear", this.refresh);
23848 store.on("datachanged", this.refresh, this);
23849 store.on("add", this.onAdd, this);
23850 store.on("remove", this.onRemove, this);
23851 store.on("update", this.onUpdate, this);
23852 store.on("clear", this.refresh, this);
23861 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23862 * @param {HTMLElement} node
23863 * @return {HTMLElement} The template node
23865 findItemFromChild : function(node){
23866 var el = this.el.dom;
23867 if(!node || node.parentNode == el){
23870 var p = node.parentNode;
23871 while(p && p != el){
23872 if(p.parentNode == el){
23881 onClick : function(e){
23882 var item = this.findItemFromChild(e.getTarget());
23884 var index = this.indexOf(item);
23885 if(this.onItemClick(item, index, e) !== false){
23886 this.fireEvent("click", this, index, item, e);
23889 this.clearSelections();
23894 onContextMenu : function(e){
23895 var item = this.findItemFromChild(e.getTarget());
23897 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23902 onDblClick : function(e){
23903 var item = this.findItemFromChild(e.getTarget());
23905 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23909 onItemClick : function(item, index, e)
23911 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23914 if (this.toggleSelect) {
23915 var m = this.isSelected(item) ? 'unselect' : 'select';
23918 _t[m](item, true, false);
23921 if(this.multiSelect || this.singleSelect){
23922 if(this.multiSelect && e.shiftKey && this.lastSelection){
23923 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23925 this.select(item, this.multiSelect && e.ctrlKey);
23926 this.lastSelection = item;
23928 e.preventDefault();
23934 * Get the number of selected nodes.
23937 getSelectionCount : function(){
23938 return this.selections.length;
23942 * Get the currently selected nodes.
23943 * @return {Array} An array of HTMLElements
23945 getSelectedNodes : function(){
23946 return this.selections;
23950 * Get the indexes of the selected nodes.
23953 getSelectedIndexes : function(){
23954 var indexes = [], s = this.selections;
23955 for(var i = 0, len = s.length; i < len; i++){
23956 indexes.push(s[i].nodeIndex);
23962 * Clear all selections
23963 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23965 clearSelections : function(suppressEvent){
23966 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23967 this.cmp.elements = this.selections;
23968 this.cmp.removeClass(this.selectedClass);
23969 this.selections = [];
23970 if(!suppressEvent){
23971 this.fireEvent("selectionchange", this, this.selections);
23977 * Returns true if the passed node is selected
23978 * @param {HTMLElement/Number} node The node or node index
23979 * @return {Boolean}
23981 isSelected : function(node){
23982 var s = this.selections;
23986 node = this.getNode(node);
23987 return s.indexOf(node) !== -1;
23992 * @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
23993 * @param {Boolean} keepExisting (optional) true to keep existing selections
23994 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23996 select : function(nodeInfo, keepExisting, suppressEvent){
23997 if(nodeInfo instanceof Array){
23999 this.clearSelections(true);
24001 for(var i = 0, len = nodeInfo.length; i < len; i++){
24002 this.select(nodeInfo[i], true, true);
24006 var node = this.getNode(nodeInfo);
24007 if(!node || this.isSelected(node)){
24008 return; // already selected.
24011 this.clearSelections(true);
24013 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
24014 Roo.fly(node).addClass(this.selectedClass);
24015 this.selections.push(node);
24016 if(!suppressEvent){
24017 this.fireEvent("selectionchange", this, this.selections);
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 IGNORED (for campatibility with select)
24027 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24029 unselect : function(nodeInfo, keepExisting, suppressEvent)
24031 if(nodeInfo instanceof Array){
24032 Roo.each(this.selections, function(s) {
24033 this.unselect(s, nodeInfo);
24037 var node = this.getNode(nodeInfo);
24038 if(!node || !this.isSelected(node)){
24039 Roo.log("not selected");
24040 return; // not selected.
24044 Roo.each(this.selections, function(s) {
24046 Roo.fly(node).removeClass(this.selectedClass);
24053 this.selections= ns;
24054 this.fireEvent("selectionchange", this, this.selections);
24058 * Gets a template node.
24059 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24060 * @return {HTMLElement} The node or null if it wasn't found
24062 getNode : function(nodeInfo){
24063 if(typeof nodeInfo == "string"){
24064 return document.getElementById(nodeInfo);
24065 }else if(typeof nodeInfo == "number"){
24066 return this.nodes[nodeInfo];
24072 * Gets a range template nodes.
24073 * @param {Number} startIndex
24074 * @param {Number} endIndex
24075 * @return {Array} An array of nodes
24077 getNodes : function(start, end){
24078 var ns = this.nodes;
24079 start = start || 0;
24080 end = typeof end == "undefined" ? ns.length - 1 : end;
24083 for(var i = start; i <= end; i++){
24087 for(var i = start; i >= end; i--){
24095 * Finds the index of the passed node
24096 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24097 * @return {Number} The index of the node or -1
24099 indexOf : function(node){
24100 node = this.getNode(node);
24101 if(typeof node.nodeIndex == "number"){
24102 return node.nodeIndex;
24104 var ns = this.nodes;
24105 for(var i = 0, len = ns.length; i < len; i++){
24115 * Ext JS Library 1.1.1
24116 * Copyright(c) 2006-2007, Ext JS, LLC.
24118 * Originally Released Under LGPL - original licence link has changed is not relivant.
24121 * <script type="text/javascript">
24125 * @class Roo.JsonView
24126 * @extends Roo.View
24127 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24129 var view = new Roo.JsonView({
24130 container: "my-element",
24131 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24136 // listen for node click?
24137 view.on("click", function(vw, index, node, e){
24138 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24141 // direct load of JSON data
24142 view.load("foobar.php");
24144 // Example from my blog list
24145 var tpl = new Roo.Template(
24146 '<div class="entry">' +
24147 '<a class="entry-title" href="{link}">{title}</a>' +
24148 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24149 "</div><hr />"
24152 var moreView = new Roo.JsonView({
24153 container : "entry-list",
24157 moreView.on("beforerender", this.sortEntries, this);
24159 url: "/blog/get-posts.php",
24160 params: "allposts=true",
24161 text: "Loading Blog Entries..."
24165 * Note: old code is supported with arguments : (container, template, config)
24169 * Create a new JsonView
24171 * @param {Object} config The config object
24174 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24177 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24179 var um = this.el.getUpdateManager();
24180 um.setRenderer(this);
24181 um.on("update", this.onLoad, this);
24182 um.on("failure", this.onLoadException, this);
24185 * @event beforerender
24186 * Fires before rendering of the downloaded JSON data.
24187 * @param {Roo.JsonView} this
24188 * @param {Object} data The JSON data loaded
24192 * Fires when data is loaded.
24193 * @param {Roo.JsonView} this
24194 * @param {Object} data The JSON data loaded
24195 * @param {Object} response The raw Connect response object
24198 * @event loadexception
24199 * Fires when loading fails.
24200 * @param {Roo.JsonView} this
24201 * @param {Object} response The raw Connect response object
24204 'beforerender' : true,
24206 'loadexception' : true
24209 Roo.extend(Roo.JsonView, Roo.View, {
24211 * @type {String} The root property in the loaded JSON object that contains the data
24216 * Refreshes the view.
24218 refresh : function(){
24219 this.clearSelections();
24220 this.el.update("");
24222 var o = this.jsonData;
24223 if(o && o.length > 0){
24224 for(var i = 0, len = o.length; i < len; i++){
24225 var data = this.prepareData(o[i], i, o);
24226 html[html.length] = this.tpl.apply(data);
24229 html.push(this.emptyText);
24231 this.el.update(html.join(""));
24232 this.nodes = this.el.dom.childNodes;
24233 this.updateIndexes(0);
24237 * 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.
24238 * @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:
24241 url: "your-url.php",
24242 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24243 callback: yourFunction,
24244 scope: yourObject, //(optional scope)
24247 text: "Loading...",
24252 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24253 * 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.
24254 * @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}
24255 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24256 * @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.
24259 var um = this.el.getUpdateManager();
24260 um.update.apply(um, arguments);
24263 render : function(el, response){
24264 this.clearSelections();
24265 this.el.update("");
24268 o = Roo.util.JSON.decode(response.responseText);
24271 o = o[this.jsonRoot];
24276 * The current JSON data or null
24279 this.beforeRender();
24284 * Get the number of records in the current JSON dataset
24287 getCount : function(){
24288 return this.jsonData ? this.jsonData.length : 0;
24292 * Returns the JSON object for the specified node(s)
24293 * @param {HTMLElement/Array} node The node or an array of nodes
24294 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24295 * you get the JSON object for the node
24297 getNodeData : function(node){
24298 if(node instanceof Array){
24300 for(var i = 0, len = node.length; i < len; i++){
24301 data.push(this.getNodeData(node[i]));
24305 return this.jsonData[this.indexOf(node)] || null;
24308 beforeRender : function(){
24309 this.snapshot = this.jsonData;
24311 this.sort.apply(this, this.sortInfo);
24313 this.fireEvent("beforerender", this, this.jsonData);
24316 onLoad : function(el, o){
24317 this.fireEvent("load", this, this.jsonData, o);
24320 onLoadException : function(el, o){
24321 this.fireEvent("loadexception", this, o);
24325 * Filter the data by a specific property.
24326 * @param {String} property A property on your JSON objects
24327 * @param {String/RegExp} value Either string that the property values
24328 * should start with, or a RegExp to test against the property
24330 filter : function(property, value){
24333 var ss = this.snapshot;
24334 if(typeof value == "string"){
24335 var vlen = value.length;
24337 this.clearFilter();
24340 value = value.toLowerCase();
24341 for(var i = 0, len = ss.length; i < len; i++){
24343 if(o[property].substr(0, vlen).toLowerCase() == value){
24347 } else if(value.exec){ // regex?
24348 for(var i = 0, len = ss.length; i < len; i++){
24350 if(value.test(o[property])){
24357 this.jsonData = data;
24363 * Filter by a function. The passed function will be called with each
24364 * object in the current dataset. If the function returns true the value is kept,
24365 * otherwise it is filtered.
24366 * @param {Function} fn
24367 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24369 filterBy : function(fn, scope){
24372 var ss = this.snapshot;
24373 for(var i = 0, len = ss.length; i < len; i++){
24375 if(fn.call(scope || this, o)){
24379 this.jsonData = data;
24385 * Clears the current filter.
24387 clearFilter : function(){
24388 if(this.snapshot && this.jsonData != this.snapshot){
24389 this.jsonData = this.snapshot;
24396 * Sorts the data for this view and refreshes it.
24397 * @param {String} property A property on your JSON objects to sort on
24398 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24399 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24401 sort : function(property, dir, sortType){
24402 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24405 var dsc = dir && dir.toLowerCase() == "desc";
24406 var f = function(o1, o2){
24407 var v1 = sortType ? sortType(o1[p]) : o1[p];
24408 var v2 = sortType ? sortType(o2[p]) : o2[p];
24411 return dsc ? +1 : -1;
24412 } else if(v1 > v2){
24413 return dsc ? -1 : +1;
24418 this.jsonData.sort(f);
24420 if(this.jsonData != this.snapshot){
24421 this.snapshot.sort(f);
24427 * Ext JS Library 1.1.1
24428 * Copyright(c) 2006-2007, Ext JS, LLC.
24430 * Originally Released Under LGPL - original licence link has changed is not relivant.
24433 * <script type="text/javascript">
24438 * @class Roo.ColorPalette
24439 * @extends Roo.Component
24440 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24441 * Here's an example of typical usage:
24443 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24444 cp.render('my-div');
24446 cp.on('select', function(palette, selColor){
24447 // do something with selColor
24451 * Create a new ColorPalette
24452 * @param {Object} config The config object
24454 Roo.ColorPalette = function(config){
24455 Roo.ColorPalette.superclass.constructor.call(this, config);
24459 * Fires when a color is selected
24460 * @param {ColorPalette} this
24461 * @param {String} color The 6-digit color hex code (without the # symbol)
24467 this.on("select", this.handler, this.scope, true);
24470 Roo.extend(Roo.ColorPalette, Roo.Component, {
24472 * @cfg {String} itemCls
24473 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24475 itemCls : "x-color-palette",
24477 * @cfg {String} value
24478 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24479 * the hex codes are case-sensitive.
24482 clickEvent:'click',
24484 ctype: "Roo.ColorPalette",
24487 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24489 allowReselect : false,
24492 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24493 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24494 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24495 * of colors with the width setting until the box is symmetrical.</p>
24496 * <p>You can override individual colors if needed:</p>
24498 var cp = new Roo.ColorPalette();
24499 cp.colors[0] = "FF0000"; // change the first box to red
24502 Or you can provide a custom array of your own for complete control:
24504 var cp = new Roo.ColorPalette();
24505 cp.colors = ["000000", "993300", "333300"];
24510 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24511 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24512 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24513 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24514 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24518 onRender : function(container, position){
24519 var t = new Roo.MasterTemplate(
24520 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24522 var c = this.colors;
24523 for(var i = 0, len = c.length; i < len; i++){
24526 var el = document.createElement("div");
24527 el.className = this.itemCls;
24529 container.dom.insertBefore(el, position);
24530 this.el = Roo.get(el);
24531 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24532 if(this.clickEvent != 'click'){
24533 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24538 afterRender : function(){
24539 Roo.ColorPalette.superclass.afterRender.call(this);
24541 var s = this.value;
24548 handleClick : function(e, t){
24549 e.preventDefault();
24550 if(!this.disabled){
24551 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24552 this.select(c.toUpperCase());
24557 * Selects the specified color in the palette (fires the select event)
24558 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24560 select : function(color){
24561 color = color.replace("#", "");
24562 if(color != this.value || this.allowReselect){
24565 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24567 el.child("a.color-"+color).addClass("x-color-palette-sel");
24568 this.value = color;
24569 this.fireEvent("select", this, color);
24574 * Ext JS Library 1.1.1
24575 * Copyright(c) 2006-2007, Ext JS, LLC.
24577 * Originally Released Under LGPL - original licence link has changed is not relivant.
24580 * <script type="text/javascript">
24584 * @class Roo.DatePicker
24585 * @extends Roo.Component
24586 * Simple date picker class.
24588 * Create a new DatePicker
24589 * @param {Object} config The config object
24591 Roo.DatePicker = function(config){
24592 Roo.DatePicker.superclass.constructor.call(this, config);
24594 this.value = config && config.value ?
24595 config.value.clearTime() : new Date().clearTime();
24600 * Fires when a date is selected
24601 * @param {DatePicker} this
24602 * @param {Date} date The selected date
24606 * @event monthchange
24607 * Fires when the displayed month changes
24608 * @param {DatePicker} this
24609 * @param {Date} date The selected month
24611 'monthchange': true
24615 this.on("select", this.handler, this.scope || this);
24617 // build the disabledDatesRE
24618 if(!this.disabledDatesRE && this.disabledDates){
24619 var dd = this.disabledDates;
24621 for(var i = 0; i < dd.length; i++){
24623 if(i != dd.length-1) re += "|";
24625 this.disabledDatesRE = new RegExp(re + ")");
24629 Roo.extend(Roo.DatePicker, Roo.Component, {
24631 * @cfg {String} todayText
24632 * The text to display on the button that selects the current date (defaults to "Today")
24634 todayText : "Today",
24636 * @cfg {String} okText
24637 * The text to display on the ok button
24639 okText : " OK ", //   to give the user extra clicking room
24641 * @cfg {String} cancelText
24642 * The text to display on the cancel button
24644 cancelText : "Cancel",
24646 * @cfg {String} todayTip
24647 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24649 todayTip : "{0} (Spacebar)",
24651 * @cfg {Date} minDate
24652 * Minimum allowable date (JavaScript date object, defaults to null)
24656 * @cfg {Date} maxDate
24657 * Maximum allowable date (JavaScript date object, defaults to null)
24661 * @cfg {String} minText
24662 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24664 minText : "This date is before the minimum date",
24666 * @cfg {String} maxText
24667 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24669 maxText : "This date is after the maximum date",
24671 * @cfg {String} format
24672 * The default date format string which can be overriden for localization support. The format must be
24673 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24677 * @cfg {Array} disabledDays
24678 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24680 disabledDays : null,
24682 * @cfg {String} disabledDaysText
24683 * The tooltip to display when the date falls on a disabled day (defaults to "")
24685 disabledDaysText : "",
24687 * @cfg {RegExp} disabledDatesRE
24688 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24690 disabledDatesRE : null,
24692 * @cfg {String} disabledDatesText
24693 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24695 disabledDatesText : "",
24697 * @cfg {Boolean} constrainToViewport
24698 * True to constrain the date picker to the viewport (defaults to true)
24700 constrainToViewport : true,
24702 * @cfg {Array} monthNames
24703 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24705 monthNames : Date.monthNames,
24707 * @cfg {Array} dayNames
24708 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24710 dayNames : Date.dayNames,
24712 * @cfg {String} nextText
24713 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24715 nextText: 'Next Month (Control+Right)',
24717 * @cfg {String} prevText
24718 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24720 prevText: 'Previous Month (Control+Left)',
24722 * @cfg {String} monthYearText
24723 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24725 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24727 * @cfg {Number} startDay
24728 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24732 * @cfg {Bool} showClear
24733 * Show a clear button (usefull for date form elements that can be blank.)
24739 * Sets the value of the date field
24740 * @param {Date} value The date to set
24742 setValue : function(value){
24743 var old = this.value;
24744 this.value = value.clearTime(true);
24746 this.update(this.value);
24751 * Gets the current selected value of the date field
24752 * @return {Date} The selected date
24754 getValue : function(){
24759 focus : function(){
24761 this.update(this.activeDate);
24766 onRender : function(container, position){
24768 '<table cellspacing="0">',
24769 '<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>',
24770 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24771 var dn = this.dayNames;
24772 for(var i = 0; i < 7; i++){
24773 var d = this.startDay+i;
24777 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24779 m[m.length] = "</tr></thead><tbody><tr>";
24780 for(var i = 0; i < 42; i++) {
24781 if(i % 7 == 0 && i != 0){
24782 m[m.length] = "</tr><tr>";
24784 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24786 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24787 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24789 var el = document.createElement("div");
24790 el.className = "x-date-picker";
24791 el.innerHTML = m.join("");
24793 container.dom.insertBefore(el, position);
24795 this.el = Roo.get(el);
24796 this.eventEl = Roo.get(el.firstChild);
24798 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24799 handler: this.showPrevMonth,
24801 preventDefault:true,
24805 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24806 handler: this.showNextMonth,
24808 preventDefault:true,
24812 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24814 this.monthPicker = this.el.down('div.x-date-mp');
24815 this.monthPicker.enableDisplayMode('block');
24817 var kn = new Roo.KeyNav(this.eventEl, {
24818 "left" : function(e){
24820 this.showPrevMonth() :
24821 this.update(this.activeDate.add("d", -1));
24824 "right" : function(e){
24826 this.showNextMonth() :
24827 this.update(this.activeDate.add("d", 1));
24830 "up" : function(e){
24832 this.showNextYear() :
24833 this.update(this.activeDate.add("d", -7));
24836 "down" : function(e){
24838 this.showPrevYear() :
24839 this.update(this.activeDate.add("d", 7));
24842 "pageUp" : function(e){
24843 this.showNextMonth();
24846 "pageDown" : function(e){
24847 this.showPrevMonth();
24850 "enter" : function(e){
24851 e.stopPropagation();
24858 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24860 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24862 this.el.unselectable();
24864 this.cells = this.el.select("table.x-date-inner tbody td");
24865 this.textNodes = this.el.query("table.x-date-inner tbody span");
24867 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24869 tooltip: this.monthYearText
24872 this.mbtn.on('click', this.showMonthPicker, this);
24873 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24876 var today = (new Date()).dateFormat(this.format);
24878 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24879 if (this.showClear) {
24880 baseTb.add( new Roo.Toolbar.Fill());
24883 text: String.format(this.todayText, today),
24884 tooltip: String.format(this.todayTip, today),
24885 handler: this.selectToday,
24889 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24892 if (this.showClear) {
24894 baseTb.add( new Roo.Toolbar.Fill());
24897 cls: 'x-btn-icon x-btn-clear',
24898 handler: function() {
24900 this.fireEvent("select", this, '');
24910 this.update(this.value);
24913 createMonthPicker : function(){
24914 if(!this.monthPicker.dom.firstChild){
24915 var buf = ['<table border="0" cellspacing="0">'];
24916 for(var i = 0; i < 6; i++){
24918 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24919 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24921 '<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>' :
24922 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24926 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24928 '</button><button type="button" class="x-date-mp-cancel">',
24930 '</button></td></tr>',
24933 this.monthPicker.update(buf.join(''));
24934 this.monthPicker.on('click', this.onMonthClick, this);
24935 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24937 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24938 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24940 this.mpMonths.each(function(m, a, i){
24943 m.dom.xmonth = 5 + Math.round(i * .5);
24945 m.dom.xmonth = Math.round((i-1) * .5);
24951 showMonthPicker : function(){
24952 this.createMonthPicker();
24953 var size = this.el.getSize();
24954 this.monthPicker.setSize(size);
24955 this.monthPicker.child('table').setSize(size);
24957 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24958 this.updateMPMonth(this.mpSelMonth);
24959 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24960 this.updateMPYear(this.mpSelYear);
24962 this.monthPicker.slideIn('t', {duration:.2});
24965 updateMPYear : function(y){
24967 var ys = this.mpYears.elements;
24968 for(var i = 1; i <= 10; i++){
24969 var td = ys[i-1], y2;
24971 y2 = y + Math.round(i * .5);
24972 td.firstChild.innerHTML = y2;
24975 y2 = y - (5-Math.round(i * .5));
24976 td.firstChild.innerHTML = y2;
24979 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24983 updateMPMonth : function(sm){
24984 this.mpMonths.each(function(m, a, i){
24985 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24989 selectMPMonth: function(m){
24993 onMonthClick : function(e, t){
24995 var el = new Roo.Element(t), pn;
24996 if(el.is('button.x-date-mp-cancel')){
24997 this.hideMonthPicker();
24999 else if(el.is('button.x-date-mp-ok')){
25000 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25001 this.hideMonthPicker();
25003 else if(pn = el.up('td.x-date-mp-month', 2)){
25004 this.mpMonths.removeClass('x-date-mp-sel');
25005 pn.addClass('x-date-mp-sel');
25006 this.mpSelMonth = pn.dom.xmonth;
25008 else if(pn = el.up('td.x-date-mp-year', 2)){
25009 this.mpYears.removeClass('x-date-mp-sel');
25010 pn.addClass('x-date-mp-sel');
25011 this.mpSelYear = pn.dom.xyear;
25013 else if(el.is('a.x-date-mp-prev')){
25014 this.updateMPYear(this.mpyear-10);
25016 else if(el.is('a.x-date-mp-next')){
25017 this.updateMPYear(this.mpyear+10);
25021 onMonthDblClick : function(e, t){
25023 var el = new Roo.Element(t), pn;
25024 if(pn = el.up('td.x-date-mp-month', 2)){
25025 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
25026 this.hideMonthPicker();
25028 else if(pn = el.up('td.x-date-mp-year', 2)){
25029 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25030 this.hideMonthPicker();
25034 hideMonthPicker : function(disableAnim){
25035 if(this.monthPicker){
25036 if(disableAnim === true){
25037 this.monthPicker.hide();
25039 this.monthPicker.slideOut('t', {duration:.2});
25045 showPrevMonth : function(e){
25046 this.update(this.activeDate.add("mo", -1));
25050 showNextMonth : function(e){
25051 this.update(this.activeDate.add("mo", 1));
25055 showPrevYear : function(){
25056 this.update(this.activeDate.add("y", -1));
25060 showNextYear : function(){
25061 this.update(this.activeDate.add("y", 1));
25065 handleMouseWheel : function(e){
25066 var delta = e.getWheelDelta();
25068 this.showPrevMonth();
25070 } else if(delta < 0){
25071 this.showNextMonth();
25077 handleDateClick : function(e, t){
25079 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25080 this.setValue(new Date(t.dateValue));
25081 this.fireEvent("select", this, this.value);
25086 selectToday : function(){
25087 this.setValue(new Date().clearTime());
25088 this.fireEvent("select", this, this.value);
25092 update : function(date)
25094 var vd = this.activeDate;
25095 this.activeDate = date;
25097 var t = date.getTime();
25098 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25099 this.cells.removeClass("x-date-selected");
25100 this.cells.each(function(c){
25101 if(c.dom.firstChild.dateValue == t){
25102 c.addClass("x-date-selected");
25103 setTimeout(function(){
25104 try{c.dom.firstChild.focus();}catch(e){}
25113 var days = date.getDaysInMonth();
25114 var firstOfMonth = date.getFirstDateOfMonth();
25115 var startingPos = firstOfMonth.getDay()-this.startDay;
25117 if(startingPos <= this.startDay){
25121 var pm = date.add("mo", -1);
25122 var prevStart = pm.getDaysInMonth()-startingPos;
25124 var cells = this.cells.elements;
25125 var textEls = this.textNodes;
25126 days += startingPos;
25128 // convert everything to numbers so it's fast
25129 var day = 86400000;
25130 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25131 var today = new Date().clearTime().getTime();
25132 var sel = date.clearTime().getTime();
25133 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25134 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25135 var ddMatch = this.disabledDatesRE;
25136 var ddText = this.disabledDatesText;
25137 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25138 var ddaysText = this.disabledDaysText;
25139 var format = this.format;
25141 var setCellClass = function(cal, cell){
25143 var t = d.getTime();
25144 cell.firstChild.dateValue = t;
25146 cell.className += " x-date-today";
25147 cell.title = cal.todayText;
25150 cell.className += " x-date-selected";
25151 setTimeout(function(){
25152 try{cell.firstChild.focus();}catch(e){}
25157 cell.className = " x-date-disabled";
25158 cell.title = cal.minText;
25162 cell.className = " x-date-disabled";
25163 cell.title = cal.maxText;
25167 if(ddays.indexOf(d.getDay()) != -1){
25168 cell.title = ddaysText;
25169 cell.className = " x-date-disabled";
25172 if(ddMatch && format){
25173 var fvalue = d.dateFormat(format);
25174 if(ddMatch.test(fvalue)){
25175 cell.title = ddText.replace("%0", fvalue);
25176 cell.className = " x-date-disabled";
25182 for(; i < startingPos; i++) {
25183 textEls[i].innerHTML = (++prevStart);
25184 d.setDate(d.getDate()+1);
25185 cells[i].className = "x-date-prevday";
25186 setCellClass(this, cells[i]);
25188 for(; i < days; i++){
25189 intDay = i - startingPos + 1;
25190 textEls[i].innerHTML = (intDay);
25191 d.setDate(d.getDate()+1);
25192 cells[i].className = "x-date-active";
25193 setCellClass(this, cells[i]);
25196 for(; i < 42; i++) {
25197 textEls[i].innerHTML = (++extraDays);
25198 d.setDate(d.getDate()+1);
25199 cells[i].className = "x-date-nextday";
25200 setCellClass(this, cells[i]);
25203 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25204 this.fireEvent('monthchange', this, date);
25206 if(!this.internalRender){
25207 var main = this.el.dom.firstChild;
25208 var w = main.offsetWidth;
25209 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25210 Roo.fly(main).setWidth(w);
25211 this.internalRender = true;
25212 // opera does not respect the auto grow header center column
25213 // then, after it gets a width opera refuses to recalculate
25214 // without a second pass
25215 if(Roo.isOpera && !this.secondPass){
25216 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25217 this.secondPass = true;
25218 this.update.defer(10, this, [date]);
25226 * Ext JS Library 1.1.1
25227 * Copyright(c) 2006-2007, Ext JS, LLC.
25229 * Originally Released Under LGPL - original licence link has changed is not relivant.
25232 * <script type="text/javascript">
25235 * @class Roo.TabPanel
25236 * @extends Roo.util.Observable
25237 * A lightweight tab container.
25241 // basic tabs 1, built from existing content
25242 var tabs = new Roo.TabPanel("tabs1");
25243 tabs.addTab("script", "View Script");
25244 tabs.addTab("markup", "View Markup");
25245 tabs.activate("script");
25247 // more advanced tabs, built from javascript
25248 var jtabs = new Roo.TabPanel("jtabs");
25249 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25251 // set up the UpdateManager
25252 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25253 var updater = tab2.getUpdateManager();
25254 updater.setDefaultUrl("ajax1.htm");
25255 tab2.on('activate', updater.refresh, updater, true);
25257 // Use setUrl for Ajax loading
25258 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25259 tab3.setUrl("ajax2.htm", null, true);
25262 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25265 jtabs.activate("jtabs-1");
25268 * Create a new TabPanel.
25269 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25270 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25272 Roo.TabPanel = function(container, config){
25274 * The container element for this TabPanel.
25275 * @type Roo.Element
25277 this.el = Roo.get(container, true);
25279 if(typeof config == "boolean"){
25280 this.tabPosition = config ? "bottom" : "top";
25282 Roo.apply(this, config);
25285 if(this.tabPosition == "bottom"){
25286 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25287 this.el.addClass("x-tabs-bottom");
25289 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25290 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25291 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25293 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25295 if(this.tabPosition != "bottom"){
25296 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
25297 * @type Roo.Element
25299 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25300 this.el.addClass("x-tabs-top");
25304 this.bodyEl.setStyle("position", "relative");
25306 this.active = null;
25307 this.activateDelegate = this.activate.createDelegate(this);
25312 * Fires when the active tab changes
25313 * @param {Roo.TabPanel} this
25314 * @param {Roo.TabPanelItem} activePanel The new active tab
25318 * @event beforetabchange
25319 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25320 * @param {Roo.TabPanel} this
25321 * @param {Object} e Set cancel to true on this object to cancel the tab change
25322 * @param {Roo.TabPanelItem} tab The tab being changed to
25324 "beforetabchange" : true
25327 Roo.EventManager.onWindowResize(this.onResize, this);
25328 this.cpad = this.el.getPadding("lr");
25329 this.hiddenCount = 0;
25332 // toolbar on the tabbar support...
25333 if (this.toolbar) {
25334 var tcfg = this.toolbar;
25335 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
25336 this.toolbar = new Roo.Toolbar(tcfg);
25337 if (Roo.isSafari) {
25338 var tbl = tcfg.container.child('table', true);
25339 tbl.setAttribute('width', '100%');
25346 Roo.TabPanel.superclass.constructor.call(this);
25349 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25351 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25353 tabPosition : "top",
25355 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25357 currentTabWidth : 0,
25359 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25363 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25367 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25369 preferredTabWidth : 175,
25371 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25373 resizeTabs : false,
25375 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25377 monitorResize : true,
25379 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
25384 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25385 * @param {String} id The id of the div to use <b>or create</b>
25386 * @param {String} text The text for the tab
25387 * @param {String} content (optional) Content to put in the TabPanelItem body
25388 * @param {Boolean} closable (optional) True to create a close icon on the tab
25389 * @return {Roo.TabPanelItem} The created TabPanelItem
25391 addTab : function(id, text, content, closable){
25392 var item = new Roo.TabPanelItem(this, id, text, closable);
25393 this.addTabItem(item);
25395 item.setContent(content);
25401 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25402 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25403 * @return {Roo.TabPanelItem}
25405 getTab : function(id){
25406 return this.items[id];
25410 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25411 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25413 hideTab : function(id){
25414 var t = this.items[id];
25417 this.hiddenCount++;
25418 this.autoSizeTabs();
25423 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25424 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25426 unhideTab : function(id){
25427 var t = this.items[id];
25429 t.setHidden(false);
25430 this.hiddenCount--;
25431 this.autoSizeTabs();
25436 * Adds an existing {@link Roo.TabPanelItem}.
25437 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25439 addTabItem : function(item){
25440 this.items[item.id] = item;
25441 this.items.push(item);
25442 if(this.resizeTabs){
25443 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25444 this.autoSizeTabs();
25451 * Removes a {@link Roo.TabPanelItem}.
25452 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25454 removeTab : function(id){
25455 var items = this.items;
25456 var tab = items[id];
25457 if(!tab) { return; }
25458 var index = items.indexOf(tab);
25459 if(this.active == tab && items.length > 1){
25460 var newTab = this.getNextAvailable(index);
25465 this.stripEl.dom.removeChild(tab.pnode.dom);
25466 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25467 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25469 items.splice(index, 1);
25470 delete this.items[tab.id];
25471 tab.fireEvent("close", tab);
25472 tab.purgeListeners();
25473 this.autoSizeTabs();
25476 getNextAvailable : function(start){
25477 var items = this.items;
25479 // look for a next tab that will slide over to
25480 // replace the one being removed
25481 while(index < items.length){
25482 var item = items[++index];
25483 if(item && !item.isHidden()){
25487 // if one isn't found select the previous tab (on the left)
25490 var item = items[--index];
25491 if(item && !item.isHidden()){
25499 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25500 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25502 disableTab : function(id){
25503 var tab = this.items[id];
25504 if(tab && this.active != tab){
25510 * Enables a {@link Roo.TabPanelItem} that is disabled.
25511 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25513 enableTab : function(id){
25514 var tab = this.items[id];
25519 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25520 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25521 * @return {Roo.TabPanelItem} The TabPanelItem.
25523 activate : function(id){
25524 var tab = this.items[id];
25528 if(tab == this.active || tab.disabled){
25532 this.fireEvent("beforetabchange", this, e, tab);
25533 if(e.cancel !== true && !tab.disabled){
25535 this.active.hide();
25537 this.active = this.items[id];
25538 this.active.show();
25539 this.fireEvent("tabchange", this, this.active);
25545 * Gets the active {@link Roo.TabPanelItem}.
25546 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25548 getActiveTab : function(){
25549 return this.active;
25553 * Updates the tab body element to fit the height of the container element
25554 * for overflow scrolling
25555 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25557 syncHeight : function(targetHeight){
25558 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25559 var bm = this.bodyEl.getMargins();
25560 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25561 this.bodyEl.setHeight(newHeight);
25565 onResize : function(){
25566 if(this.monitorResize){
25567 this.autoSizeTabs();
25572 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25574 beginUpdate : function(){
25575 this.updating = true;
25579 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25581 endUpdate : function(){
25582 this.updating = false;
25583 this.autoSizeTabs();
25587 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25589 autoSizeTabs : function(){
25590 var count = this.items.length;
25591 var vcount = count - this.hiddenCount;
25592 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25593 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25594 var availWidth = Math.floor(w / vcount);
25595 var b = this.stripBody;
25596 if(b.getWidth() > w){
25597 var tabs = this.items;
25598 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25599 if(availWidth < this.minTabWidth){
25600 /*if(!this.sleft){ // incomplete scrolling code
25601 this.createScrollButtons();
25604 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25607 if(this.currentTabWidth < this.preferredTabWidth){
25608 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25614 * Returns the number of tabs in this TabPanel.
25617 getCount : function(){
25618 return this.items.length;
25622 * Resizes all the tabs to the passed width
25623 * @param {Number} The new width
25625 setTabWidth : function(width){
25626 this.currentTabWidth = width;
25627 for(var i = 0, len = this.items.length; i < len; i++) {
25628 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25633 * Destroys this TabPanel
25634 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25636 destroy : function(removeEl){
25637 Roo.EventManager.removeResizeListener(this.onResize, this);
25638 for(var i = 0, len = this.items.length; i < len; i++){
25639 this.items[i].purgeListeners();
25641 if(removeEl === true){
25642 this.el.update("");
25649 * @class Roo.TabPanelItem
25650 * @extends Roo.util.Observable
25651 * Represents an individual item (tab plus body) in a TabPanel.
25652 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25653 * @param {String} id The id of this TabPanelItem
25654 * @param {String} text The text for the tab of this TabPanelItem
25655 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25657 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25659 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25660 * @type Roo.TabPanel
25662 this.tabPanel = tabPanel;
25664 * The id for this TabPanelItem
25669 this.disabled = false;
25673 this.loaded = false;
25674 this.closable = closable;
25677 * The body element for this TabPanelItem.
25678 * @type Roo.Element
25680 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25681 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25682 this.bodyEl.setStyle("display", "block");
25683 this.bodyEl.setStyle("zoom", "1");
25686 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25688 this.el = Roo.get(els.el, true);
25689 this.inner = Roo.get(els.inner, true);
25690 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25691 this.pnode = Roo.get(els.el.parentNode, true);
25692 this.el.on("mousedown", this.onTabMouseDown, this);
25693 this.el.on("click", this.onTabClick, this);
25696 var c = Roo.get(els.close, true);
25697 c.dom.title = this.closeText;
25698 c.addClassOnOver("close-over");
25699 c.on("click", this.closeClick, this);
25705 * Fires when this tab becomes the active tab.
25706 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25707 * @param {Roo.TabPanelItem} this
25711 * @event beforeclose
25712 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25713 * @param {Roo.TabPanelItem} this
25714 * @param {Object} e Set cancel to true on this object to cancel the close.
25716 "beforeclose": true,
25719 * Fires when this tab is closed.
25720 * @param {Roo.TabPanelItem} this
25724 * @event deactivate
25725 * Fires when this tab is no longer the active tab.
25726 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25727 * @param {Roo.TabPanelItem} this
25729 "deactivate" : true
25731 this.hidden = false;
25733 Roo.TabPanelItem.superclass.constructor.call(this);
25736 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25737 purgeListeners : function(){
25738 Roo.util.Observable.prototype.purgeListeners.call(this);
25739 this.el.removeAllListeners();
25742 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25745 this.pnode.addClass("on");
25748 this.tabPanel.stripWrap.repaint();
25750 this.fireEvent("activate", this.tabPanel, this);
25754 * Returns true if this tab is the active tab.
25755 * @return {Boolean}
25757 isActive : function(){
25758 return this.tabPanel.getActiveTab() == this;
25762 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25765 this.pnode.removeClass("on");
25767 this.fireEvent("deactivate", this.tabPanel, this);
25770 hideAction : function(){
25771 this.bodyEl.hide();
25772 this.bodyEl.setStyle("position", "absolute");
25773 this.bodyEl.setLeft("-20000px");
25774 this.bodyEl.setTop("-20000px");
25777 showAction : function(){
25778 this.bodyEl.setStyle("position", "relative");
25779 this.bodyEl.setTop("");
25780 this.bodyEl.setLeft("");
25781 this.bodyEl.show();
25785 * Set the tooltip for the tab.
25786 * @param {String} tooltip The tab's tooltip
25788 setTooltip : function(text){
25789 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25790 this.textEl.dom.qtip = text;
25791 this.textEl.dom.removeAttribute('title');
25793 this.textEl.dom.title = text;
25797 onTabClick : function(e){
25798 e.preventDefault();
25799 this.tabPanel.activate(this.id);
25802 onTabMouseDown : function(e){
25803 e.preventDefault();
25804 this.tabPanel.activate(this.id);
25807 getWidth : function(){
25808 return this.inner.getWidth();
25811 setWidth : function(width){
25812 var iwidth = width - this.pnode.getPadding("lr");
25813 this.inner.setWidth(iwidth);
25814 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25815 this.pnode.setWidth(width);
25819 * Show or hide the tab
25820 * @param {Boolean} hidden True to hide or false to show.
25822 setHidden : function(hidden){
25823 this.hidden = hidden;
25824 this.pnode.setStyle("display", hidden ? "none" : "");
25828 * Returns true if this tab is "hidden"
25829 * @return {Boolean}
25831 isHidden : function(){
25832 return this.hidden;
25836 * Returns the text for this tab
25839 getText : function(){
25843 autoSize : function(){
25844 //this.el.beginMeasure();
25845 this.textEl.setWidth(1);
25846 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25847 //this.el.endMeasure();
25851 * Sets the text for the tab (Note: this also sets the tooltip text)
25852 * @param {String} text The tab's text and tooltip
25854 setText : function(text){
25856 this.textEl.update(text);
25857 this.setTooltip(text);
25858 if(!this.tabPanel.resizeTabs){
25863 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25865 activate : function(){
25866 this.tabPanel.activate(this.id);
25870 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25872 disable : function(){
25873 if(this.tabPanel.active != this){
25874 this.disabled = true;
25875 this.pnode.addClass("disabled");
25880 * Enables this TabPanelItem if it was previously disabled.
25882 enable : function(){
25883 this.disabled = false;
25884 this.pnode.removeClass("disabled");
25888 * Sets the content for this TabPanelItem.
25889 * @param {String} content The content
25890 * @param {Boolean} loadScripts true to look for and load scripts
25892 setContent : function(content, loadScripts){
25893 this.bodyEl.update(content, loadScripts);
25897 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25898 * @return {Roo.UpdateManager} The UpdateManager
25900 getUpdateManager : function(){
25901 return this.bodyEl.getUpdateManager();
25905 * Set a URL to be used to load the content for this TabPanelItem.
25906 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25907 * @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)
25908 * @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)
25909 * @return {Roo.UpdateManager} The UpdateManager
25911 setUrl : function(url, params, loadOnce){
25912 if(this.refreshDelegate){
25913 this.un('activate', this.refreshDelegate);
25915 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25916 this.on("activate", this.refreshDelegate);
25917 return this.bodyEl.getUpdateManager();
25921 _handleRefresh : function(url, params, loadOnce){
25922 if(!loadOnce || !this.loaded){
25923 var updater = this.bodyEl.getUpdateManager();
25924 updater.update(url, params, this._setLoaded.createDelegate(this));
25929 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25930 * Will fail silently if the setUrl method has not been called.
25931 * This does not activate the panel, just updates its content.
25933 refresh : function(){
25934 if(this.refreshDelegate){
25935 this.loaded = false;
25936 this.refreshDelegate();
25941 _setLoaded : function(){
25942 this.loaded = true;
25946 closeClick : function(e){
25949 this.fireEvent("beforeclose", this, o);
25950 if(o.cancel !== true){
25951 this.tabPanel.removeTab(this.id);
25955 * The text displayed in the tooltip for the close icon.
25958 closeText : "Close this tab"
25962 Roo.TabPanel.prototype.createStrip = function(container){
25963 var strip = document.createElement("div");
25964 strip.className = "x-tabs-wrap";
25965 container.appendChild(strip);
25969 Roo.TabPanel.prototype.createStripList = function(strip){
25970 // div wrapper for retard IE
25971 // returns the "tr" element.
25972 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
25973 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
25974 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
25975 return strip.firstChild.firstChild.firstChild.firstChild;
25978 Roo.TabPanel.prototype.createBody = function(container){
25979 var body = document.createElement("div");
25980 Roo.id(body, "tab-body");
25981 Roo.fly(body).addClass("x-tabs-body");
25982 container.appendChild(body);
25986 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25987 var body = Roo.getDom(id);
25989 body = document.createElement("div");
25992 Roo.fly(body).addClass("x-tabs-item-body");
25993 bodyEl.insertBefore(body, bodyEl.firstChild);
25997 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25998 var td = document.createElement("td");
25999 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
26000 //stripEl.appendChild(td);
26002 td.className = "x-tabs-closable";
26003 if(!this.closeTpl){
26004 this.closeTpl = new Roo.Template(
26005 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26006 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
26007 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
26010 var el = this.closeTpl.overwrite(td, {"text": text});
26011 var close = el.getElementsByTagName("div")[0];
26012 var inner = el.getElementsByTagName("em")[0];
26013 return {"el": el, "close": close, "inner": inner};
26016 this.tabTpl = new Roo.Template(
26017 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26018 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
26021 var el = this.tabTpl.overwrite(td, {"text": text});
26022 var inner = el.getElementsByTagName("em")[0];
26023 return {"el": el, "inner": inner};
26027 * Ext JS Library 1.1.1
26028 * Copyright(c) 2006-2007, Ext JS, LLC.
26030 * Originally Released Under LGPL - original licence link has changed is not relivant.
26033 * <script type="text/javascript">
26037 * @class Roo.Button
26038 * @extends Roo.util.Observable
26039 * Simple Button class
26040 * @cfg {String} text The button text
26041 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
26042 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
26043 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
26044 * @cfg {Object} scope The scope of the handler
26045 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
26046 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
26047 * @cfg {Boolean} hidden True to start hidden (defaults to false)
26048 * @cfg {Boolean} disabled True to start disabled (defaults to false)
26049 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
26050 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
26051 applies if enableToggle = true)
26052 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
26053 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
26054 an {@link Roo.util.ClickRepeater} config object (defaults to false).
26056 * Create a new button
26057 * @param {Object} config The config object
26059 Roo.Button = function(renderTo, config)
26063 renderTo = config.renderTo || false;
26066 Roo.apply(this, config);
26070 * Fires when this button is clicked
26071 * @param {Button} this
26072 * @param {EventObject} e The click event
26077 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26078 * @param {Button} this
26079 * @param {Boolean} pressed
26084 * Fires when the mouse hovers over the button
26085 * @param {Button} this
26086 * @param {Event} e The event object
26088 'mouseover' : true,
26091 * Fires when the mouse exits the button
26092 * @param {Button} this
26093 * @param {Event} e The event object
26098 * Fires when the button is rendered
26099 * @param {Button} this
26104 this.menu = Roo.menu.MenuMgr.get(this.menu);
26106 // register listeners first!! - so render can be captured..
26107 Roo.util.Observable.call(this);
26109 this.render(renderTo);
26115 Roo.extend(Roo.Button, Roo.util.Observable, {
26121 * Read-only. True if this button is hidden
26126 * Read-only. True if this button is disabled
26131 * Read-only. True if this button is pressed (only if enableToggle = true)
26137 * @cfg {Number} tabIndex
26138 * The DOM tabIndex for this button (defaults to undefined)
26140 tabIndex : undefined,
26143 * @cfg {Boolean} enableToggle
26144 * True to enable pressed/not pressed toggling (defaults to false)
26146 enableToggle: false,
26148 * @cfg {Mixed} menu
26149 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26153 * @cfg {String} menuAlign
26154 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26156 menuAlign : "tl-bl?",
26159 * @cfg {String} iconCls
26160 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26162 iconCls : undefined,
26164 * @cfg {String} type
26165 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26170 menuClassTarget: 'tr',
26173 * @cfg {String} clickEvent
26174 * The type of event to map to the button's event handler (defaults to 'click')
26176 clickEvent : 'click',
26179 * @cfg {Boolean} handleMouseEvents
26180 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26182 handleMouseEvents : true,
26185 * @cfg {String} tooltipType
26186 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26188 tooltipType : 'qtip',
26191 * @cfg {String} cls
26192 * A CSS class to apply to the button's main element.
26196 * @cfg {Roo.Template} template (Optional)
26197 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26198 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26199 * require code modifications if required elements (e.g. a button) aren't present.
26203 render : function(renderTo){
26205 if(this.hideParent){
26206 this.parentEl = Roo.get(renderTo);
26208 if(!this.dhconfig){
26209 if(!this.template){
26210 if(!Roo.Button.buttonTemplate){
26211 // hideous table template
26212 Roo.Button.buttonTemplate = new Roo.Template(
26213 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26214 '<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>',
26215 "</tr></tbody></table>");
26217 this.template = Roo.Button.buttonTemplate;
26219 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26220 var btnEl = btn.child("button:first");
26221 btnEl.on('focus', this.onFocus, this);
26222 btnEl.on('blur', this.onBlur, this);
26224 btn.addClass(this.cls);
26227 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26230 btnEl.addClass(this.iconCls);
26232 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26235 if(this.tabIndex !== undefined){
26236 btnEl.dom.tabIndex = this.tabIndex;
26239 if(typeof this.tooltip == 'object'){
26240 Roo.QuickTips.tips(Roo.apply({
26244 btnEl.dom[this.tooltipType] = this.tooltip;
26248 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26252 this.el.dom.id = this.el.id = this.id;
26255 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26256 this.menu.on("show", this.onMenuShow, this);
26257 this.menu.on("hide", this.onMenuHide, this);
26259 btn.addClass("x-btn");
26260 if(Roo.isIE && !Roo.isIE7){
26261 this.autoWidth.defer(1, this);
26265 if(this.handleMouseEvents){
26266 btn.on("mouseover", this.onMouseOver, this);
26267 btn.on("mouseout", this.onMouseOut, this);
26268 btn.on("mousedown", this.onMouseDown, this);
26270 btn.on(this.clickEvent, this.onClick, this);
26271 //btn.on("mouseup", this.onMouseUp, this);
26278 Roo.ButtonToggleMgr.register(this);
26280 this.el.addClass("x-btn-pressed");
26283 var repeater = new Roo.util.ClickRepeater(btn,
26284 typeof this.repeat == "object" ? this.repeat : {}
26286 repeater.on("click", this.onClick, this);
26289 this.fireEvent('render', this);
26293 * Returns the button's underlying element
26294 * @return {Roo.Element} The element
26296 getEl : function(){
26301 * Destroys this Button and removes any listeners.
26303 destroy : function(){
26304 Roo.ButtonToggleMgr.unregister(this);
26305 this.el.removeAllListeners();
26306 this.purgeListeners();
26311 autoWidth : function(){
26313 this.el.setWidth("auto");
26314 if(Roo.isIE7 && Roo.isStrict){
26315 var ib = this.el.child('button');
26316 if(ib && ib.getWidth() > 20){
26318 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26323 this.el.beginMeasure();
26325 if(this.el.getWidth() < this.minWidth){
26326 this.el.setWidth(this.minWidth);
26329 this.el.endMeasure();
26336 * Assigns this button's click handler
26337 * @param {Function} handler The function to call when the button is clicked
26338 * @param {Object} scope (optional) Scope for the function passed in
26340 setHandler : function(handler, scope){
26341 this.handler = handler;
26342 this.scope = scope;
26346 * Sets this button's text
26347 * @param {String} text The button text
26349 setText : function(text){
26352 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26358 * Gets the text for this button
26359 * @return {String} The button text
26361 getText : function(){
26369 this.hidden = false;
26371 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26379 this.hidden = true;
26381 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26386 * Convenience function for boolean show/hide
26387 * @param {Boolean} visible True to show, false to hide
26389 setVisible: function(visible){
26398 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26399 * @param {Boolean} state (optional) Force a particular state
26401 toggle : function(state){
26402 state = state === undefined ? !this.pressed : state;
26403 if(state != this.pressed){
26405 this.el.addClass("x-btn-pressed");
26406 this.pressed = true;
26407 this.fireEvent("toggle", this, true);
26409 this.el.removeClass("x-btn-pressed");
26410 this.pressed = false;
26411 this.fireEvent("toggle", this, false);
26413 if(this.toggleHandler){
26414 this.toggleHandler.call(this.scope || this, this, state);
26422 focus : function(){
26423 this.el.child('button:first').focus();
26427 * Disable this button
26429 disable : function(){
26431 this.el.addClass("x-btn-disabled");
26433 this.disabled = true;
26437 * Enable this button
26439 enable : function(){
26441 this.el.removeClass("x-btn-disabled");
26443 this.disabled = false;
26447 * Convenience function for boolean enable/disable
26448 * @param {Boolean} enabled True to enable, false to disable
26450 setDisabled : function(v){
26451 this[v !== true ? "enable" : "disable"]();
26455 onClick : function(e){
26457 e.preventDefault();
26462 if(!this.disabled){
26463 if(this.enableToggle){
26466 if(this.menu && !this.menu.isVisible()){
26467 this.menu.show(this.el, this.menuAlign);
26469 this.fireEvent("click", this, e);
26471 this.el.removeClass("x-btn-over");
26472 this.handler.call(this.scope || this, this, e);
26477 onMouseOver : function(e){
26478 if(!this.disabled){
26479 this.el.addClass("x-btn-over");
26480 this.fireEvent('mouseover', this, e);
26484 onMouseOut : function(e){
26485 if(!e.within(this.el, true)){
26486 this.el.removeClass("x-btn-over");
26487 this.fireEvent('mouseout', this, e);
26491 onFocus : function(e){
26492 if(!this.disabled){
26493 this.el.addClass("x-btn-focus");
26497 onBlur : function(e){
26498 this.el.removeClass("x-btn-focus");
26501 onMouseDown : function(e){
26502 if(!this.disabled && e.button == 0){
26503 this.el.addClass("x-btn-click");
26504 Roo.get(document).on('mouseup', this.onMouseUp, this);
26508 onMouseUp : function(e){
26510 this.el.removeClass("x-btn-click");
26511 Roo.get(document).un('mouseup', this.onMouseUp, this);
26515 onMenuShow : function(e){
26516 this.el.addClass("x-btn-menu-active");
26519 onMenuHide : function(e){
26520 this.el.removeClass("x-btn-menu-active");
26524 // Private utility class used by Button
26525 Roo.ButtonToggleMgr = function(){
26528 function toggleGroup(btn, state){
26530 var g = groups[btn.toggleGroup];
26531 for(var i = 0, l = g.length; i < l; i++){
26533 g[i].toggle(false);
26540 register : function(btn){
26541 if(!btn.toggleGroup){
26544 var g = groups[btn.toggleGroup];
26546 g = groups[btn.toggleGroup] = [];
26549 btn.on("toggle", toggleGroup);
26552 unregister : function(btn){
26553 if(!btn.toggleGroup){
26556 var g = groups[btn.toggleGroup];
26559 btn.un("toggle", toggleGroup);
26565 * Ext JS Library 1.1.1
26566 * Copyright(c) 2006-2007, Ext JS, LLC.
26568 * Originally Released Under LGPL - original licence link has changed is not relivant.
26571 * <script type="text/javascript">
26575 * @class Roo.SplitButton
26576 * @extends Roo.Button
26577 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26578 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26579 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26580 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26581 * @cfg {String} arrowTooltip The title attribute of the arrow
26583 * Create a new menu button
26584 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26585 * @param {Object} config The config object
26587 Roo.SplitButton = function(renderTo, config){
26588 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26590 * @event arrowclick
26591 * Fires when this button's arrow is clicked
26592 * @param {SplitButton} this
26593 * @param {EventObject} e The click event
26595 this.addEvents({"arrowclick":true});
26598 Roo.extend(Roo.SplitButton, Roo.Button, {
26599 render : function(renderTo){
26600 // this is one sweet looking template!
26601 var tpl = new Roo.Template(
26602 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26603 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26604 '<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>',
26605 "</tbody></table></td><td>",
26606 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26607 '<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>',
26608 "</tbody></table></td></tr></table>"
26610 var btn = tpl.append(renderTo, [this.text, this.type], true);
26611 var btnEl = btn.child("button");
26613 btn.addClass(this.cls);
26616 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26619 btnEl.addClass(this.iconCls);
26621 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26625 if(this.handleMouseEvents){
26626 btn.on("mouseover", this.onMouseOver, this);
26627 btn.on("mouseout", this.onMouseOut, this);
26628 btn.on("mousedown", this.onMouseDown, this);
26629 btn.on("mouseup", this.onMouseUp, this);
26631 btn.on(this.clickEvent, this.onClick, this);
26633 if(typeof this.tooltip == 'object'){
26634 Roo.QuickTips.tips(Roo.apply({
26638 btnEl.dom[this.tooltipType] = this.tooltip;
26641 if(this.arrowTooltip){
26642 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26651 this.el.addClass("x-btn-pressed");
26653 if(Roo.isIE && !Roo.isIE7){
26654 this.autoWidth.defer(1, this);
26659 this.menu.on("show", this.onMenuShow, this);
26660 this.menu.on("hide", this.onMenuHide, this);
26662 this.fireEvent('render', this);
26666 autoWidth : function(){
26668 var tbl = this.el.child("table:first");
26669 var tbl2 = this.el.child("table:last");
26670 this.el.setWidth("auto");
26671 tbl.setWidth("auto");
26672 if(Roo.isIE7 && Roo.isStrict){
26673 var ib = this.el.child('button:first');
26674 if(ib && ib.getWidth() > 20){
26676 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26681 this.el.beginMeasure();
26683 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26684 tbl.setWidth(this.minWidth-tbl2.getWidth());
26687 this.el.endMeasure();
26690 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26694 * Sets this button's click handler
26695 * @param {Function} handler The function to call when the button is clicked
26696 * @param {Object} scope (optional) Scope for the function passed above
26698 setHandler : function(handler, scope){
26699 this.handler = handler;
26700 this.scope = scope;
26704 * Sets this button's arrow click handler
26705 * @param {Function} handler The function to call when the arrow is clicked
26706 * @param {Object} scope (optional) Scope for the function passed above
26708 setArrowHandler : function(handler, scope){
26709 this.arrowHandler = handler;
26710 this.scope = scope;
26716 focus : function(){
26718 this.el.child("button:first").focus();
26723 onClick : function(e){
26724 e.preventDefault();
26725 if(!this.disabled){
26726 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26727 if(this.menu && !this.menu.isVisible()){
26728 this.menu.show(this.el, this.menuAlign);
26730 this.fireEvent("arrowclick", this, e);
26731 if(this.arrowHandler){
26732 this.arrowHandler.call(this.scope || this, this, e);
26735 this.fireEvent("click", this, e);
26737 this.handler.call(this.scope || this, this, e);
26743 onMouseDown : function(e){
26744 if(!this.disabled){
26745 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26749 onMouseUp : function(e){
26750 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26755 // backwards compat
26756 Roo.MenuButton = Roo.SplitButton;/*
26758 * Ext JS Library 1.1.1
26759 * Copyright(c) 2006-2007, Ext JS, LLC.
26761 * Originally Released Under LGPL - original licence link has changed is not relivant.
26764 * <script type="text/javascript">
26768 * @class Roo.Toolbar
26769 * Basic Toolbar class.
26771 * Creates a new Toolbar
26772 * @param {Object} container The config object
26774 Roo.Toolbar = function(container, buttons, config)
26776 /// old consturctor format still supported..
26777 if(container instanceof Array){ // omit the container for later rendering
26778 buttons = container;
26782 if (typeof(container) == 'object' && container.xtype) {
26783 config = container;
26784 container = config.container;
26785 buttons = config.buttons || []; // not really - use items!!
26788 if (config && config.items) {
26789 xitems = config.items;
26790 delete config.items;
26792 Roo.apply(this, config);
26793 this.buttons = buttons;
26796 this.render(container);
26798 this.xitems = xitems;
26799 Roo.each(xitems, function(b) {
26805 Roo.Toolbar.prototype = {
26807 * @cfg {Array} items
26808 * array of button configs or elements to add (will be converted to a MixedCollection)
26812 * @cfg {String/HTMLElement/Element} container
26813 * The id or element that will contain the toolbar
26816 render : function(ct){
26817 this.el = Roo.get(ct);
26819 this.el.addClass(this.cls);
26821 // using a table allows for vertical alignment
26822 // 100% width is needed by Safari...
26823 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26824 this.tr = this.el.child("tr", true);
26826 this.items = new Roo.util.MixedCollection(false, function(o){
26827 return o.id || ("item" + (++autoId));
26830 this.add.apply(this, this.buttons);
26831 delete this.buttons;
26836 * Adds element(s) to the toolbar -- this function takes a variable number of
26837 * arguments of mixed type and adds them to the toolbar.
26838 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26840 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26841 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26842 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26843 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26844 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26845 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26846 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26847 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26848 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26850 * @param {Mixed} arg2
26851 * @param {Mixed} etc.
26854 var a = arguments, l = a.length;
26855 for(var i = 0; i < l; i++){
26860 _add : function(el) {
26863 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26866 if (el.applyTo){ // some kind of form field
26867 return this.addField(el);
26869 if (el.render){ // some kind of Toolbar.Item
26870 return this.addItem(el);
26872 if (typeof el == "string"){ // string
26873 if(el == "separator" || el == "-"){
26874 return this.addSeparator();
26877 return this.addSpacer();
26880 return this.addFill();
26882 return this.addText(el);
26885 if(el.tagName){ // element
26886 return this.addElement(el);
26888 if(typeof el == "object"){ // must be button config?
26889 return this.addButton(el);
26891 // and now what?!?!
26897 * Add an Xtype element
26898 * @param {Object} xtype Xtype Object
26899 * @return {Object} created Object
26901 addxtype : function(e){
26902 return this.add(e);
26906 * Returns the Element for this toolbar.
26907 * @return {Roo.Element}
26909 getEl : function(){
26915 * @return {Roo.Toolbar.Item} The separator item
26917 addSeparator : function(){
26918 return this.addItem(new Roo.Toolbar.Separator());
26922 * Adds a spacer element
26923 * @return {Roo.Toolbar.Spacer} The spacer item
26925 addSpacer : function(){
26926 return this.addItem(new Roo.Toolbar.Spacer());
26930 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26931 * @return {Roo.Toolbar.Fill} The fill item
26933 addFill : function(){
26934 return this.addItem(new Roo.Toolbar.Fill());
26938 * Adds any standard HTML element to the toolbar
26939 * @param {String/HTMLElement/Element} el The element or id of the element to add
26940 * @return {Roo.Toolbar.Item} The element's item
26942 addElement : function(el){
26943 return this.addItem(new Roo.Toolbar.Item(el));
26946 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26947 * @type Roo.util.MixedCollection
26952 * Adds any Toolbar.Item or subclass
26953 * @param {Roo.Toolbar.Item} item
26954 * @return {Roo.Toolbar.Item} The item
26956 addItem : function(item){
26957 var td = this.nextBlock();
26959 this.items.add(item);
26964 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26965 * @param {Object/Array} config A button config or array of configs
26966 * @return {Roo.Toolbar.Button/Array}
26968 addButton : function(config){
26969 if(config instanceof Array){
26971 for(var i = 0, len = config.length; i < len; i++) {
26972 buttons.push(this.addButton(config[i]));
26977 if(!(config instanceof Roo.Toolbar.Button)){
26979 new Roo.Toolbar.SplitButton(config) :
26980 new Roo.Toolbar.Button(config);
26982 var td = this.nextBlock();
26989 * Adds text to the toolbar
26990 * @param {String} text The text to add
26991 * @return {Roo.Toolbar.Item} The element's item
26993 addText : function(text){
26994 return this.addItem(new Roo.Toolbar.TextItem(text));
26998 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26999 * @param {Number} index The index where the item is to be inserted
27000 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
27001 * @return {Roo.Toolbar.Button/Item}
27003 insertButton : function(index, item){
27004 if(item instanceof Array){
27006 for(var i = 0, len = item.length; i < len; i++) {
27007 buttons.push(this.insertButton(index + i, item[i]));
27011 if (!(item instanceof Roo.Toolbar.Button)){
27012 item = new Roo.Toolbar.Button(item);
27014 var td = document.createElement("td");
27015 this.tr.insertBefore(td, this.tr.childNodes[index]);
27017 this.items.insert(index, item);
27022 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
27023 * @param {Object} config
27024 * @return {Roo.Toolbar.Item} The element's item
27026 addDom : function(config, returnEl){
27027 var td = this.nextBlock();
27028 Roo.DomHelper.overwrite(td, config);
27029 var ti = new Roo.Toolbar.Item(td.firstChild);
27031 this.items.add(ti);
27036 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
27037 * @type Roo.util.MixedCollection
27042 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
27043 * Note: the field should not have been rendered yet. For a field that has already been
27044 * rendered, use {@link #addElement}.
27045 * @param {Roo.form.Field} field
27046 * @return {Roo.ToolbarItem}
27050 addField : function(field) {
27051 if (!this.fields) {
27053 this.fields = new Roo.util.MixedCollection(false, function(o){
27054 return o.id || ("item" + (++autoId));
27059 var td = this.nextBlock();
27061 var ti = new Roo.Toolbar.Item(td.firstChild);
27063 this.items.add(ti);
27064 this.fields.add(field);
27075 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
27076 this.el.child('div').hide();
27084 this.el.child('div').show();
27088 nextBlock : function(){
27089 var td = document.createElement("td");
27090 this.tr.appendChild(td);
27095 destroy : function(){
27096 if(this.items){ // rendered?
27097 Roo.destroy.apply(Roo, this.items.items);
27099 if(this.fields){ // rendered?
27100 Roo.destroy.apply(Roo, this.fields.items);
27102 Roo.Element.uncache(this.el, this.tr);
27107 * @class Roo.Toolbar.Item
27108 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27110 * Creates a new Item
27111 * @param {HTMLElement} el
27113 Roo.Toolbar.Item = function(el){
27114 this.el = Roo.getDom(el);
27115 this.id = Roo.id(this.el);
27116 this.hidden = false;
27119 Roo.Toolbar.Item.prototype = {
27122 * Get this item's HTML Element
27123 * @return {HTMLElement}
27125 getEl : function(){
27130 render : function(td){
27132 td.appendChild(this.el);
27136 * Removes and destroys this item.
27138 destroy : function(){
27139 this.td.parentNode.removeChild(this.td);
27146 this.hidden = false;
27147 this.td.style.display = "";
27154 this.hidden = true;
27155 this.td.style.display = "none";
27159 * Convenience function for boolean show/hide.
27160 * @param {Boolean} visible true to show/false to hide
27162 setVisible: function(visible){
27171 * Try to focus this item.
27173 focus : function(){
27174 Roo.fly(this.el).focus();
27178 * Disables this item.
27180 disable : function(){
27181 Roo.fly(this.td).addClass("x-item-disabled");
27182 this.disabled = true;
27183 this.el.disabled = true;
27187 * Enables this item.
27189 enable : function(){
27190 Roo.fly(this.td).removeClass("x-item-disabled");
27191 this.disabled = false;
27192 this.el.disabled = false;
27198 * @class Roo.Toolbar.Separator
27199 * @extends Roo.Toolbar.Item
27200 * A simple toolbar separator class
27202 * Creates a new Separator
27204 Roo.Toolbar.Separator = function(){
27205 var s = document.createElement("span");
27206 s.className = "ytb-sep";
27207 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27209 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27210 enable:Roo.emptyFn,
27211 disable:Roo.emptyFn,
27216 * @class Roo.Toolbar.Spacer
27217 * @extends Roo.Toolbar.Item
27218 * A simple element that adds extra horizontal space to a toolbar.
27220 * Creates a new Spacer
27222 Roo.Toolbar.Spacer = function(){
27223 var s = document.createElement("div");
27224 s.className = "ytb-spacer";
27225 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27227 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27228 enable:Roo.emptyFn,
27229 disable:Roo.emptyFn,
27234 * @class Roo.Toolbar.Fill
27235 * @extends Roo.Toolbar.Spacer
27236 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27238 * Creates a new Spacer
27240 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27242 render : function(td){
27243 td.style.width = '100%';
27244 Roo.Toolbar.Fill.superclass.render.call(this, td);
27249 * @class Roo.Toolbar.TextItem
27250 * @extends Roo.Toolbar.Item
27251 * A simple class that renders text directly into a toolbar.
27253 * Creates a new TextItem
27254 * @param {String} text
27256 Roo.Toolbar.TextItem = function(text){
27257 if (typeof(text) == 'object') {
27260 var s = document.createElement("span");
27261 s.className = "ytb-text";
27262 s.innerHTML = text;
27263 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27265 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27266 enable:Roo.emptyFn,
27267 disable:Roo.emptyFn,
27272 * @class Roo.Toolbar.Button
27273 * @extends Roo.Button
27274 * A button that renders into a toolbar.
27276 * Creates a new Button
27277 * @param {Object} config A standard {@link Roo.Button} config object
27279 Roo.Toolbar.Button = function(config){
27280 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27282 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27283 render : function(td){
27285 Roo.Toolbar.Button.superclass.render.call(this, td);
27289 * Removes and destroys this button
27291 destroy : function(){
27292 Roo.Toolbar.Button.superclass.destroy.call(this);
27293 this.td.parentNode.removeChild(this.td);
27297 * Shows this button
27300 this.hidden = false;
27301 this.td.style.display = "";
27305 * Hides this button
27308 this.hidden = true;
27309 this.td.style.display = "none";
27313 * Disables this item
27315 disable : function(){
27316 Roo.fly(this.td).addClass("x-item-disabled");
27317 this.disabled = true;
27321 * Enables this item
27323 enable : function(){
27324 Roo.fly(this.td).removeClass("x-item-disabled");
27325 this.disabled = false;
27328 // backwards compat
27329 Roo.ToolbarButton = Roo.Toolbar.Button;
27332 * @class Roo.Toolbar.SplitButton
27333 * @extends Roo.SplitButton
27334 * A menu button that renders into a toolbar.
27336 * Creates a new SplitButton
27337 * @param {Object} config A standard {@link Roo.SplitButton} config object
27339 Roo.Toolbar.SplitButton = function(config){
27340 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27342 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27343 render : function(td){
27345 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27349 * Removes and destroys this button
27351 destroy : function(){
27352 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27353 this.td.parentNode.removeChild(this.td);
27357 * Shows this button
27360 this.hidden = false;
27361 this.td.style.display = "";
27365 * Hides this button
27368 this.hidden = true;
27369 this.td.style.display = "none";
27373 // backwards compat
27374 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27376 * Ext JS Library 1.1.1
27377 * Copyright(c) 2006-2007, Ext JS, LLC.
27379 * Originally Released Under LGPL - original licence link has changed is not relivant.
27382 * <script type="text/javascript">
27386 * @class Roo.PagingToolbar
27387 * @extends Roo.Toolbar
27388 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27390 * Create a new PagingToolbar
27391 * @param {Object} config The config object
27393 Roo.PagingToolbar = function(el, ds, config)
27395 // old args format still supported... - xtype is prefered..
27396 if (typeof(el) == 'object' && el.xtype) {
27397 // created from xtype...
27399 ds = el.dataSource;
27400 el = config.container;
27403 if (config.items) {
27404 items = config.items;
27408 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27411 this.renderButtons(this.el);
27414 // supprot items array.
27416 Roo.each(items, function(e) {
27417 this.add(Roo.factory(e));
27422 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27424 * @cfg {Roo.data.Store} dataSource
27425 * The underlying data store providing the paged data
27428 * @cfg {String/HTMLElement/Element} container
27429 * container The id or element that will contain the toolbar
27432 * @cfg {Boolean} displayInfo
27433 * True to display the displayMsg (defaults to false)
27436 * @cfg {Number} pageSize
27437 * The number of records to display per page (defaults to 20)
27441 * @cfg {String} displayMsg
27442 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27444 displayMsg : 'Displaying {0} - {1} of {2}',
27446 * @cfg {String} emptyMsg
27447 * The message to display when no records are found (defaults to "No data to display")
27449 emptyMsg : 'No data to display',
27451 * Customizable piece of the default paging text (defaults to "Page")
27454 beforePageText : "Page",
27456 * Customizable piece of the default paging text (defaults to "of %0")
27459 afterPageText : "of {0}",
27461 * Customizable piece of the default paging text (defaults to "First Page")
27464 firstText : "First Page",
27466 * Customizable piece of the default paging text (defaults to "Previous Page")
27469 prevText : "Previous Page",
27471 * Customizable piece of the default paging text (defaults to "Next Page")
27474 nextText : "Next Page",
27476 * Customizable piece of the default paging text (defaults to "Last Page")
27479 lastText : "Last Page",
27481 * Customizable piece of the default paging text (defaults to "Refresh")
27484 refreshText : "Refresh",
27487 renderButtons : function(el){
27488 Roo.PagingToolbar.superclass.render.call(this, el);
27489 this.first = this.addButton({
27490 tooltip: this.firstText,
27491 cls: "x-btn-icon x-grid-page-first",
27493 handler: this.onClick.createDelegate(this, ["first"])
27495 this.prev = this.addButton({
27496 tooltip: this.prevText,
27497 cls: "x-btn-icon x-grid-page-prev",
27499 handler: this.onClick.createDelegate(this, ["prev"])
27501 //this.addSeparator();
27502 this.add(this.beforePageText);
27503 this.field = Roo.get(this.addDom({
27508 cls: "x-grid-page-number"
27510 this.field.on("keydown", this.onPagingKeydown, this);
27511 this.field.on("focus", function(){this.dom.select();});
27512 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27513 this.field.setHeight(18);
27514 //this.addSeparator();
27515 this.next = this.addButton({
27516 tooltip: this.nextText,
27517 cls: "x-btn-icon x-grid-page-next",
27519 handler: this.onClick.createDelegate(this, ["next"])
27521 this.last = this.addButton({
27522 tooltip: this.lastText,
27523 cls: "x-btn-icon x-grid-page-last",
27525 handler: this.onClick.createDelegate(this, ["last"])
27527 //this.addSeparator();
27528 this.loading = this.addButton({
27529 tooltip: this.refreshText,
27530 cls: "x-btn-icon x-grid-loading",
27531 handler: this.onClick.createDelegate(this, ["refresh"])
27534 if(this.displayInfo){
27535 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27540 updateInfo : function(){
27541 if(this.displayEl){
27542 var count = this.ds.getCount();
27543 var msg = count == 0 ?
27547 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27549 this.displayEl.update(msg);
27554 onLoad : function(ds, r, o){
27555 this.cursor = o.params ? o.params.start : 0;
27556 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27558 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27559 this.field.dom.value = ap;
27560 this.first.setDisabled(ap == 1);
27561 this.prev.setDisabled(ap == 1);
27562 this.next.setDisabled(ap == ps);
27563 this.last.setDisabled(ap == ps);
27564 this.loading.enable();
27569 getPageData : function(){
27570 var total = this.ds.getTotalCount();
27573 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27574 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27579 onLoadError : function(){
27580 this.loading.enable();
27584 onPagingKeydown : function(e){
27585 var k = e.getKey();
27586 var d = this.getPageData();
27588 var v = this.field.dom.value, pageNum;
27589 if(!v || isNaN(pageNum = parseInt(v, 10))){
27590 this.field.dom.value = d.activePage;
27593 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27594 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27597 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))
27599 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27600 this.field.dom.value = pageNum;
27601 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27604 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27606 var v = this.field.dom.value, pageNum;
27607 var increment = (e.shiftKey) ? 10 : 1;
27608 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27610 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27611 this.field.dom.value = d.activePage;
27614 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27616 this.field.dom.value = parseInt(v, 10) + increment;
27617 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27618 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27625 beforeLoad : function(){
27627 this.loading.disable();
27632 onClick : function(which){
27636 ds.load({params:{start: 0, limit: this.pageSize}});
27639 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27642 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27645 var total = ds.getTotalCount();
27646 var extra = total % this.pageSize;
27647 var lastStart = extra ? (total - extra) : total-this.pageSize;
27648 ds.load({params:{start: lastStart, limit: this.pageSize}});
27651 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27657 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27658 * @param {Roo.data.Store} store The data store to unbind
27660 unbind : function(ds){
27661 ds.un("beforeload", this.beforeLoad, this);
27662 ds.un("load", this.onLoad, this);
27663 ds.un("loadexception", this.onLoadError, this);
27664 ds.un("remove", this.updateInfo, this);
27665 ds.un("add", this.updateInfo, this);
27666 this.ds = undefined;
27670 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27671 * @param {Roo.data.Store} store The data store to bind
27673 bind : function(ds){
27674 ds.on("beforeload", this.beforeLoad, this);
27675 ds.on("load", this.onLoad, this);
27676 ds.on("loadexception", this.onLoadError, this);
27677 ds.on("remove", this.updateInfo, this);
27678 ds.on("add", this.updateInfo, this);
27683 * Ext JS Library 1.1.1
27684 * Copyright(c) 2006-2007, Ext JS, LLC.
27686 * Originally Released Under LGPL - original licence link has changed is not relivant.
27689 * <script type="text/javascript">
27693 * @class Roo.Resizable
27694 * @extends Roo.util.Observable
27695 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27696 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27697 * 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
27698 * the element will be wrapped for you automatically.</p>
27699 * <p>Here is the list of valid resize handles:</p>
27702 ------ -------------------
27711 'hd' horizontal drag
27714 * <p>Here's an example showing the creation of a typical Resizable:</p>
27716 var resizer = new Roo.Resizable("element-id", {
27724 resizer.on("resize", myHandler);
27726 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27727 * resizer.east.setDisplayed(false);</p>
27728 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27729 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27730 * resize operation's new size (defaults to [0, 0])
27731 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27732 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27733 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27734 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27735 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27736 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27737 * @cfg {Number} width The width of the element in pixels (defaults to null)
27738 * @cfg {Number} height The height of the element in pixels (defaults to null)
27739 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27740 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27741 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27742 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27743 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27744 * in favor of the handles config option (defaults to false)
27745 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27746 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27747 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27748 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27749 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27750 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27751 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27752 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27753 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27754 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27755 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27757 * Create a new resizable component
27758 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27759 * @param {Object} config configuration options
27761 Roo.Resizable = function(el, config)
27763 this.el = Roo.get(el);
27765 if(config && config.wrap){
27766 config.resizeChild = this.el;
27767 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27768 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27769 this.el.setStyle("overflow", "hidden");
27770 this.el.setPositioning(config.resizeChild.getPositioning());
27771 config.resizeChild.clearPositioning();
27772 if(!config.width || !config.height){
27773 var csize = config.resizeChild.getSize();
27774 this.el.setSize(csize.width, csize.height);
27776 if(config.pinned && !config.adjustments){
27777 config.adjustments = "auto";
27781 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27782 this.proxy.unselectable();
27783 this.proxy.enableDisplayMode('block');
27785 Roo.apply(this, config);
27788 this.disableTrackOver = true;
27789 this.el.addClass("x-resizable-pinned");
27791 // if the element isn't positioned, make it relative
27792 var position = this.el.getStyle("position");
27793 if(position != "absolute" && position != "fixed"){
27794 this.el.setStyle("position", "relative");
27796 if(!this.handles){ // no handles passed, must be legacy style
27797 this.handles = 's,e,se';
27798 if(this.multiDirectional){
27799 this.handles += ',n,w';
27802 if(this.handles == "all"){
27803 this.handles = "n s e w ne nw se sw";
27805 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27806 var ps = Roo.Resizable.positions;
27807 for(var i = 0, len = hs.length; i < len; i++){
27808 if(hs[i] && ps[hs[i]]){
27809 var pos = ps[hs[i]];
27810 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27814 this.corner = this.southeast;
27816 // updateBox = the box can move..
27817 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27818 this.updateBox = true;
27821 this.activeHandle = null;
27823 if(this.resizeChild){
27824 if(typeof this.resizeChild == "boolean"){
27825 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27827 this.resizeChild = Roo.get(this.resizeChild, true);
27831 if(this.adjustments == "auto"){
27832 var rc = this.resizeChild;
27833 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27834 if(rc && (hw || hn)){
27835 rc.position("relative");
27836 rc.setLeft(hw ? hw.el.getWidth() : 0);
27837 rc.setTop(hn ? hn.el.getHeight() : 0);
27839 this.adjustments = [
27840 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27841 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27845 if(this.draggable){
27846 this.dd = this.dynamic ?
27847 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27848 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27854 * @event beforeresize
27855 * Fired before resize is allowed. Set enabled to false to cancel resize.
27856 * @param {Roo.Resizable} this
27857 * @param {Roo.EventObject} e The mousedown event
27859 "beforeresize" : true,
27862 * Fired after a resize.
27863 * @param {Roo.Resizable} this
27864 * @param {Number} width The new width
27865 * @param {Number} height The new height
27866 * @param {Roo.EventObject} e The mouseup event
27871 if(this.width !== null && this.height !== null){
27872 this.resizeTo(this.width, this.height);
27874 this.updateChildSize();
27877 this.el.dom.style.zoom = 1;
27879 Roo.Resizable.superclass.constructor.call(this);
27882 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27883 resizeChild : false,
27884 adjustments : [0, 0],
27894 multiDirectional : false,
27895 disableTrackOver : false,
27896 easing : 'easeOutStrong',
27897 widthIncrement : 0,
27898 heightIncrement : 0,
27902 preserveRatio : false,
27903 transparent: false,
27909 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27911 constrainTo: undefined,
27913 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27915 resizeRegion: undefined,
27919 * Perform a manual resize
27920 * @param {Number} width
27921 * @param {Number} height
27923 resizeTo : function(width, height){
27924 this.el.setSize(width, height);
27925 this.updateChildSize();
27926 this.fireEvent("resize", this, width, height, null);
27930 startSizing : function(e, handle){
27931 this.fireEvent("beforeresize", this, e);
27932 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27935 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27936 this.overlay.unselectable();
27937 this.overlay.enableDisplayMode("block");
27938 this.overlay.on("mousemove", this.onMouseMove, this);
27939 this.overlay.on("mouseup", this.onMouseUp, this);
27941 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27943 this.resizing = true;
27944 this.startBox = this.el.getBox();
27945 this.startPoint = e.getXY();
27946 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27947 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27949 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27950 this.overlay.show();
27952 if(this.constrainTo) {
27953 var ct = Roo.get(this.constrainTo);
27954 this.resizeRegion = ct.getRegion().adjust(
27955 ct.getFrameWidth('t'),
27956 ct.getFrameWidth('l'),
27957 -ct.getFrameWidth('b'),
27958 -ct.getFrameWidth('r')
27962 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27964 this.proxy.setBox(this.startBox);
27966 this.proxy.setStyle('visibility', 'visible');
27972 onMouseDown : function(handle, e){
27975 this.activeHandle = handle;
27976 this.startSizing(e, handle);
27981 onMouseUp : function(e){
27982 var size = this.resizeElement();
27983 this.resizing = false;
27985 this.overlay.hide();
27987 this.fireEvent("resize", this, size.width, size.height, e);
27991 updateChildSize : function(){
27992 if(this.resizeChild){
27994 var child = this.resizeChild;
27995 var adj = this.adjustments;
27996 if(el.dom.offsetWidth){
27997 var b = el.getSize(true);
27998 child.setSize(b.width+adj[0], b.height+adj[1]);
28000 // Second call here for IE
28001 // The first call enables instant resizing and
28002 // the second call corrects scroll bars if they
28005 setTimeout(function(){
28006 if(el.dom.offsetWidth){
28007 var b = el.getSize(true);
28008 child.setSize(b.width+adj[0], b.height+adj[1]);
28016 snap : function(value, inc, min){
28017 if(!inc || !value) return value;
28018 var newValue = value;
28019 var m = value % inc;
28022 newValue = value + (inc-m);
28024 newValue = value - m;
28027 return Math.max(min, newValue);
28031 resizeElement : function(){
28032 var box = this.proxy.getBox();
28033 if(this.updateBox){
28034 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
28036 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
28038 this.updateChildSize();
28046 constrain : function(v, diff, m, mx){
28049 }else if(v - diff > mx){
28056 onMouseMove : function(e){
28058 try{// try catch so if something goes wrong the user doesn't get hung
28060 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
28064 //var curXY = this.startPoint;
28065 var curSize = this.curSize || this.startBox;
28066 var x = this.startBox.x, y = this.startBox.y;
28067 var ox = x, oy = y;
28068 var w = curSize.width, h = curSize.height;
28069 var ow = w, oh = h;
28070 var mw = this.minWidth, mh = this.minHeight;
28071 var mxw = this.maxWidth, mxh = this.maxHeight;
28072 var wi = this.widthIncrement;
28073 var hi = this.heightIncrement;
28075 var eventXY = e.getXY();
28076 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
28077 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28079 var pos = this.activeHandle.position;
28084 w = Math.min(Math.max(mw, w), mxw);
28089 h = Math.min(Math.max(mh, h), mxh);
28094 w = Math.min(Math.max(mw, w), mxw);
28095 h = Math.min(Math.max(mh, h), mxh);
28098 diffY = this.constrain(h, diffY, mh, mxh);
28105 var adiffX = Math.abs(diffX);
28106 var sub = (adiffX % wi); // how much
28107 if (sub > (wi/2)) { // far enough to snap
28108 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28110 // remove difference..
28111 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28115 x = Math.max(this.minX, x);
28118 diffX = this.constrain(w, diffX, mw, mxw);
28124 w = Math.min(Math.max(mw, w), mxw);
28125 diffY = this.constrain(h, diffY, mh, mxh);
28130 diffX = this.constrain(w, diffX, mw, mxw);
28131 diffY = this.constrain(h, diffY, mh, mxh);
28138 diffX = this.constrain(w, diffX, mw, mxw);
28140 h = Math.min(Math.max(mh, h), mxh);
28146 var sw = this.snap(w, wi, mw);
28147 var sh = this.snap(h, hi, mh);
28148 if(sw != w || sh != h){
28171 if(this.preserveRatio){
28176 h = Math.min(Math.max(mh, h), mxh);
28181 w = Math.min(Math.max(mw, w), mxw);
28186 w = Math.min(Math.max(mw, w), mxw);
28192 w = Math.min(Math.max(mw, w), mxw);
28198 h = Math.min(Math.max(mh, h), mxh);
28206 h = Math.min(Math.max(mh, h), mxh);
28216 h = Math.min(Math.max(mh, h), mxh);
28224 if (pos == 'hdrag') {
28227 this.proxy.setBounds(x, y, w, h);
28229 this.resizeElement();
28236 handleOver : function(){
28238 this.el.addClass("x-resizable-over");
28243 handleOut : function(){
28244 if(!this.resizing){
28245 this.el.removeClass("x-resizable-over");
28250 * Returns the element this component is bound to.
28251 * @return {Roo.Element}
28253 getEl : function(){
28258 * Returns the resizeChild element (or null).
28259 * @return {Roo.Element}
28261 getResizeChild : function(){
28262 return this.resizeChild;
28266 * Destroys this resizable. If the element was wrapped and
28267 * removeEl is not true then the element remains.
28268 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28270 destroy : function(removeEl){
28271 this.proxy.remove();
28273 this.overlay.removeAllListeners();
28274 this.overlay.remove();
28276 var ps = Roo.Resizable.positions;
28278 if(typeof ps[k] != "function" && this[ps[k]]){
28279 var h = this[ps[k]];
28280 h.el.removeAllListeners();
28285 this.el.update("");
28292 // hash to map config positions to true positions
28293 Roo.Resizable.positions = {
28294 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28299 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28301 // only initialize the template if resizable is used
28302 var tpl = Roo.DomHelper.createTemplate(
28303 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28306 Roo.Resizable.Handle.prototype.tpl = tpl;
28308 this.position = pos;
28310 // show north drag fro topdra
28311 var handlepos = pos == 'hdrag' ? 'north' : pos;
28313 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28314 if (pos == 'hdrag') {
28315 this.el.setStyle('cursor', 'pointer');
28317 this.el.unselectable();
28319 this.el.setOpacity(0);
28321 this.el.on("mousedown", this.onMouseDown, this);
28322 if(!disableTrackOver){
28323 this.el.on("mouseover", this.onMouseOver, this);
28324 this.el.on("mouseout", this.onMouseOut, this);
28329 Roo.Resizable.Handle.prototype = {
28330 afterResize : function(rz){
28334 onMouseDown : function(e){
28335 this.rz.onMouseDown(this, e);
28338 onMouseOver : function(e){
28339 this.rz.handleOver(this, e);
28342 onMouseOut : function(e){
28343 this.rz.handleOut(this, e);
28347 * Ext JS Library 1.1.1
28348 * Copyright(c) 2006-2007, Ext JS, LLC.
28350 * Originally Released Under LGPL - original licence link has changed is not relivant.
28353 * <script type="text/javascript">
28357 * @class Roo.Editor
28358 * @extends Roo.Component
28359 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28361 * Create a new Editor
28362 * @param {Roo.form.Field} field The Field object (or descendant)
28363 * @param {Object} config The config object
28365 Roo.Editor = function(field, config){
28366 Roo.Editor.superclass.constructor.call(this, config);
28367 this.field = field;
28370 * @event beforestartedit
28371 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28372 * false from the handler of this event.
28373 * @param {Editor} this
28374 * @param {Roo.Element} boundEl The underlying element bound to this editor
28375 * @param {Mixed} value The field value being set
28377 "beforestartedit" : true,
28380 * Fires when this editor is displayed
28381 * @param {Roo.Element} boundEl The underlying element bound to this editor
28382 * @param {Mixed} value The starting field value
28384 "startedit" : true,
28386 * @event beforecomplete
28387 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28388 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28389 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28390 * event will not fire since no edit actually occurred.
28391 * @param {Editor} this
28392 * @param {Mixed} value The current field value
28393 * @param {Mixed} startValue The original field value
28395 "beforecomplete" : true,
28398 * Fires after editing is complete and any changed value has been written to the underlying field.
28399 * @param {Editor} this
28400 * @param {Mixed} value The current field value
28401 * @param {Mixed} startValue The original field value
28405 * @event specialkey
28406 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28407 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28408 * @param {Roo.form.Field} this
28409 * @param {Roo.EventObject} e The event object
28411 "specialkey" : true
28415 Roo.extend(Roo.Editor, Roo.Component, {
28417 * @cfg {Boolean/String} autosize
28418 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28419 * or "height" to adopt the height only (defaults to false)
28422 * @cfg {Boolean} revertInvalid
28423 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28424 * validation fails (defaults to true)
28427 * @cfg {Boolean} ignoreNoChange
28428 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28429 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28430 * will never be ignored.
28433 * @cfg {Boolean} hideEl
28434 * False to keep the bound element visible while the editor is displayed (defaults to true)
28437 * @cfg {Mixed} value
28438 * The data value of the underlying field (defaults to "")
28442 * @cfg {String} alignment
28443 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28447 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28448 * for bottom-right shadow (defaults to "frame")
28452 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28456 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28458 completeOnEnter : false,
28460 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28462 cancelOnEsc : false,
28464 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28469 onRender : function(ct, position){
28470 this.el = new Roo.Layer({
28471 shadow: this.shadow,
28477 constrain: this.constrain
28479 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28480 if(this.field.msgTarget != 'title'){
28481 this.field.msgTarget = 'qtip';
28483 this.field.render(this.el);
28485 this.field.el.dom.setAttribute('autocomplete', 'off');
28487 this.field.on("specialkey", this.onSpecialKey, this);
28488 if(this.swallowKeys){
28489 this.field.el.swallowEvent(['keydown','keypress']);
28492 this.field.on("blur", this.onBlur, this);
28493 if(this.field.grow){
28494 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28498 onSpecialKey : function(field, e)
28500 //Roo.log('editor onSpecialKey');
28501 if(this.completeOnEnter && e.getKey() == e.ENTER){
28503 this.completeEdit();
28506 // do not fire special key otherwise it might hide close the editor...
28507 if(e.getKey() == e.ENTER){
28510 if(this.cancelOnEsc && e.getKey() == e.ESC){
28514 this.fireEvent('specialkey', field, e);
28519 * Starts the editing process and shows the editor.
28520 * @param {String/HTMLElement/Element} el The element to edit
28521 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28522 * to the innerHTML of el.
28524 startEdit : function(el, value){
28526 this.completeEdit();
28528 this.boundEl = Roo.get(el);
28529 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28530 if(!this.rendered){
28531 this.render(this.parentEl || document.body);
28533 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28536 this.startValue = v;
28537 this.field.setValue(v);
28539 var sz = this.boundEl.getSize();
28540 switch(this.autoSize){
28542 this.setSize(sz.width, "");
28545 this.setSize("", sz.height);
28548 this.setSize(sz.width, sz.height);
28551 this.el.alignTo(this.boundEl, this.alignment);
28552 this.editing = true;
28554 Roo.QuickTips.disable();
28560 * Sets the height and width of this editor.
28561 * @param {Number} width The new width
28562 * @param {Number} height The new height
28564 setSize : function(w, h){
28565 this.field.setSize(w, h);
28572 * Realigns the editor to the bound field based on the current alignment config value.
28574 realign : function(){
28575 this.el.alignTo(this.boundEl, this.alignment);
28579 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28580 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28582 completeEdit : function(remainVisible){
28586 var v = this.getValue();
28587 if(this.revertInvalid !== false && !this.field.isValid()){
28588 v = this.startValue;
28589 this.cancelEdit(true);
28591 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28592 this.editing = false;
28596 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28597 this.editing = false;
28598 if(this.updateEl && this.boundEl){
28599 this.boundEl.update(v);
28601 if(remainVisible !== true){
28604 this.fireEvent("complete", this, v, this.startValue);
28609 onShow : function(){
28611 if(this.hideEl !== false){
28612 this.boundEl.hide();
28615 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28616 this.fixIEFocus = true;
28617 this.deferredFocus.defer(50, this);
28619 this.field.focus();
28621 this.fireEvent("startedit", this.boundEl, this.startValue);
28624 deferredFocus : function(){
28626 this.field.focus();
28631 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28632 * reverted to the original starting value.
28633 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28634 * cancel (defaults to false)
28636 cancelEdit : function(remainVisible){
28638 this.setValue(this.startValue);
28639 if(remainVisible !== true){
28646 onBlur : function(){
28647 if(this.allowBlur !== true && this.editing){
28648 this.completeEdit();
28653 onHide : function(){
28655 this.completeEdit();
28659 if(this.field.collapse){
28660 this.field.collapse();
28663 if(this.hideEl !== false){
28664 this.boundEl.show();
28667 Roo.QuickTips.enable();
28672 * Sets the data value of the editor
28673 * @param {Mixed} value Any valid value supported by the underlying field
28675 setValue : function(v){
28676 this.field.setValue(v);
28680 * Gets the data value of the editor
28681 * @return {Mixed} The data value
28683 getValue : function(){
28684 return this.field.getValue();
28688 * Ext JS Library 1.1.1
28689 * Copyright(c) 2006-2007, Ext JS, LLC.
28691 * Originally Released Under LGPL - original licence link has changed is not relivant.
28694 * <script type="text/javascript">
28698 * @class Roo.BasicDialog
28699 * @extends Roo.util.Observable
28700 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28702 var dlg = new Roo.BasicDialog("my-dlg", {
28711 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28712 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28713 dlg.addButton('Cancel', dlg.hide, dlg);
28716 <b>A Dialog should always be a direct child of the body element.</b>
28717 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28718 * @cfg {String} title Default text to display in the title bar (defaults to null)
28719 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28720 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28721 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28722 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28723 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28724 * (defaults to null with no animation)
28725 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28726 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28727 * property for valid values (defaults to 'all')
28728 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28729 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28730 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28731 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28732 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28733 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28734 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28735 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28736 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28737 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28738 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28739 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28740 * draggable = true (defaults to false)
28741 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28742 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28743 * shadow (defaults to false)
28744 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28745 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28746 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28747 * @cfg {Array} buttons Array of buttons
28748 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28750 * Create a new BasicDialog.
28751 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28752 * @param {Object} config Configuration options
28754 Roo.BasicDialog = function(el, config){
28755 this.el = Roo.get(el);
28756 var dh = Roo.DomHelper;
28757 if(!this.el && config && config.autoCreate){
28758 if(typeof config.autoCreate == "object"){
28759 if(!config.autoCreate.id){
28760 config.autoCreate.id = el;
28762 this.el = dh.append(document.body,
28763 config.autoCreate, true);
28765 this.el = dh.append(document.body,
28766 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28770 el.setDisplayed(true);
28771 el.hide = this.hideAction;
28773 el.addClass("x-dlg");
28775 Roo.apply(this, config);
28777 this.proxy = el.createProxy("x-dlg-proxy");
28778 this.proxy.hide = this.hideAction;
28779 this.proxy.setOpacity(.5);
28783 el.setWidth(config.width);
28786 el.setHeight(config.height);
28788 this.size = el.getSize();
28789 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28790 this.xy = [config.x,config.y];
28792 this.xy = el.getCenterXY(true);
28794 /** The header element @type Roo.Element */
28795 this.header = el.child("> .x-dlg-hd");
28796 /** The body element @type Roo.Element */
28797 this.body = el.child("> .x-dlg-bd");
28798 /** The footer element @type Roo.Element */
28799 this.footer = el.child("> .x-dlg-ft");
28802 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28805 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28808 this.header.unselectable();
28810 this.header.update(this.title);
28812 // this element allows the dialog to be focused for keyboard event
28813 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28814 this.focusEl.swallowEvent("click", true);
28816 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28818 // wrap the body and footer for special rendering
28819 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28821 this.bwrap.dom.appendChild(this.footer.dom);
28824 this.bg = this.el.createChild({
28825 tag: "div", cls:"x-dlg-bg",
28826 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28828 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28831 if(this.autoScroll !== false && !this.autoTabs){
28832 this.body.setStyle("overflow", "auto");
28835 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28837 if(this.closable !== false){
28838 this.el.addClass("x-dlg-closable");
28839 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28840 this.close.on("click", this.closeClick, this);
28841 this.close.addClassOnOver("x-dlg-close-over");
28843 if(this.collapsible !== false){
28844 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28845 this.collapseBtn.on("click", this.collapseClick, this);
28846 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28847 this.header.on("dblclick", this.collapseClick, this);
28849 if(this.resizable !== false){
28850 this.el.addClass("x-dlg-resizable");
28851 this.resizer = new Roo.Resizable(el, {
28852 minWidth: this.minWidth || 80,
28853 minHeight:this.minHeight || 80,
28854 handles: this.resizeHandles || "all",
28857 this.resizer.on("beforeresize", this.beforeResize, this);
28858 this.resizer.on("resize", this.onResize, this);
28860 if(this.draggable !== false){
28861 el.addClass("x-dlg-draggable");
28862 if (!this.proxyDrag) {
28863 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28866 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28868 dd.setHandleElId(this.header.id);
28869 dd.endDrag = this.endMove.createDelegate(this);
28870 dd.startDrag = this.startMove.createDelegate(this);
28871 dd.onDrag = this.onDrag.createDelegate(this);
28876 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28877 this.mask.enableDisplayMode("block");
28879 this.el.addClass("x-dlg-modal");
28882 this.shadow = new Roo.Shadow({
28883 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28884 offset : this.shadowOffset
28887 this.shadowOffset = 0;
28889 if(Roo.useShims && this.shim !== false){
28890 this.shim = this.el.createShim();
28891 this.shim.hide = this.hideAction;
28899 if (this.buttons) {
28900 var bts= this.buttons;
28902 Roo.each(bts, function(b) {
28911 * Fires when a key is pressed
28912 * @param {Roo.BasicDialog} this
28913 * @param {Roo.EventObject} e
28918 * Fires when this dialog is moved by the user.
28919 * @param {Roo.BasicDialog} this
28920 * @param {Number} x The new page X
28921 * @param {Number} y The new page Y
28926 * Fires when this dialog is resized by the user.
28927 * @param {Roo.BasicDialog} this
28928 * @param {Number} width The new width
28929 * @param {Number} height The new height
28933 * @event beforehide
28934 * Fires before this dialog is hidden.
28935 * @param {Roo.BasicDialog} this
28937 "beforehide" : true,
28940 * Fires when this dialog is hidden.
28941 * @param {Roo.BasicDialog} this
28945 * @event beforeshow
28946 * Fires before this dialog is shown.
28947 * @param {Roo.BasicDialog} this
28949 "beforeshow" : true,
28952 * Fires when this dialog is shown.
28953 * @param {Roo.BasicDialog} this
28957 el.on("keydown", this.onKeyDown, this);
28958 el.on("mousedown", this.toFront, this);
28959 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28961 Roo.DialogManager.register(this);
28962 Roo.BasicDialog.superclass.constructor.call(this);
28965 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28966 shadowOffset: Roo.isIE ? 6 : 5,
28969 minButtonWidth: 75,
28970 defaultButton: null,
28971 buttonAlign: "right",
28976 * Sets the dialog title text
28977 * @param {String} text The title text to display
28978 * @return {Roo.BasicDialog} this
28980 setTitle : function(text){
28981 this.header.update(text);
28986 closeClick : function(){
28991 collapseClick : function(){
28992 this[this.collapsed ? "expand" : "collapse"]();
28996 * Collapses the dialog to its minimized state (only the title bar is visible).
28997 * Equivalent to the user clicking the collapse dialog button.
28999 collapse : function(){
29000 if(!this.collapsed){
29001 this.collapsed = true;
29002 this.el.addClass("x-dlg-collapsed");
29003 this.restoreHeight = this.el.getHeight();
29004 this.resizeTo(this.el.getWidth(), this.header.getHeight());
29009 * Expands a collapsed dialog back to its normal state. Equivalent to the user
29010 * clicking the expand dialog button.
29012 expand : function(){
29013 if(this.collapsed){
29014 this.collapsed = false;
29015 this.el.removeClass("x-dlg-collapsed");
29016 this.resizeTo(this.el.getWidth(), this.restoreHeight);
29021 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
29022 * @return {Roo.TabPanel} The tabs component
29024 initTabs : function(){
29025 var tabs = this.getTabs();
29026 while(tabs.getTab(0)){
29029 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
29031 tabs.addTab(Roo.id(dom), dom.title);
29039 beforeResize : function(){
29040 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
29044 onResize : function(){
29045 this.refreshSize();
29046 this.syncBodyHeight();
29047 this.adjustAssets();
29049 this.fireEvent("resize", this, this.size.width, this.size.height);
29053 onKeyDown : function(e){
29054 if(this.isVisible()){
29055 this.fireEvent("keydown", this, e);
29060 * Resizes the dialog.
29061 * @param {Number} width
29062 * @param {Number} height
29063 * @return {Roo.BasicDialog} this
29065 resizeTo : function(width, height){
29066 this.el.setSize(width, height);
29067 this.size = {width: width, height: height};
29068 this.syncBodyHeight();
29069 if(this.fixedcenter){
29072 if(this.isVisible()){
29073 this.constrainXY();
29074 this.adjustAssets();
29076 this.fireEvent("resize", this, width, height);
29082 * Resizes the dialog to fit the specified content size.
29083 * @param {Number} width
29084 * @param {Number} height
29085 * @return {Roo.BasicDialog} this
29087 setContentSize : function(w, h){
29088 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29089 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29090 //if(!this.el.isBorderBox()){
29091 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29092 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29095 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29096 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29098 this.resizeTo(w, h);
29103 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29104 * executed in response to a particular key being pressed while the dialog is active.
29105 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29106 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29107 * @param {Function} fn The function to call
29108 * @param {Object} scope (optional) The scope of the function
29109 * @return {Roo.BasicDialog} this
29111 addKeyListener : function(key, fn, scope){
29112 var keyCode, shift, ctrl, alt;
29113 if(typeof key == "object" && !(key instanceof Array)){
29114 keyCode = key["key"];
29115 shift = key["shift"];
29116 ctrl = key["ctrl"];
29121 var handler = function(dlg, e){
29122 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29123 var k = e.getKey();
29124 if(keyCode instanceof Array){
29125 for(var i = 0, len = keyCode.length; i < len; i++){
29126 if(keyCode[i] == k){
29127 fn.call(scope || window, dlg, k, e);
29133 fn.call(scope || window, dlg, k, e);
29138 this.on("keydown", handler);
29143 * Returns the TabPanel component (creates it if it doesn't exist).
29144 * Note: If you wish to simply check for the existence of tabs without creating them,
29145 * check for a null 'tabs' property.
29146 * @return {Roo.TabPanel} The tabs component
29148 getTabs : function(){
29150 this.el.addClass("x-dlg-auto-tabs");
29151 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29152 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29158 * Adds a button to the footer section of the dialog.
29159 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29160 * object or a valid Roo.DomHelper element config
29161 * @param {Function} handler The function called when the button is clicked
29162 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29163 * @return {Roo.Button} The new button
29165 addButton : function(config, handler, scope){
29166 var dh = Roo.DomHelper;
29168 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29170 if(!this.btnContainer){
29171 var tb = this.footer.createChild({
29173 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29174 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29176 this.btnContainer = tb.firstChild.firstChild.firstChild;
29181 minWidth: this.minButtonWidth,
29184 if(typeof config == "string"){
29185 bconfig.text = config;
29188 bconfig.dhconfig = config;
29190 Roo.apply(bconfig, config);
29194 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29195 bconfig.position = Math.max(0, bconfig.position);
29196 fc = this.btnContainer.childNodes[bconfig.position];
29199 var btn = new Roo.Button(
29201 this.btnContainer.insertBefore(document.createElement("td"),fc)
29202 : this.btnContainer.appendChild(document.createElement("td")),
29203 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29206 this.syncBodyHeight();
29209 * Array of all the buttons that have been added to this dialog via addButton
29214 this.buttons.push(btn);
29219 * Sets the default button to be focused when the dialog is displayed.
29220 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29221 * @return {Roo.BasicDialog} this
29223 setDefaultButton : function(btn){
29224 this.defaultButton = btn;
29229 getHeaderFooterHeight : function(safe){
29232 height += this.header.getHeight();
29235 var fm = this.footer.getMargins();
29236 height += (this.footer.getHeight()+fm.top+fm.bottom);
29238 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29239 height += this.centerBg.getPadding("tb");
29244 syncBodyHeight : function(){
29245 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29246 var height = this.size.height - this.getHeaderFooterHeight(false);
29247 bd.setHeight(height-bd.getMargins("tb"));
29248 var hh = this.header.getHeight();
29249 var h = this.size.height-hh;
29251 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29252 bw.setHeight(h-cb.getPadding("tb"));
29253 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29254 bd.setWidth(bw.getWidth(true));
29256 this.tabs.syncHeight();
29258 this.tabs.el.repaint();
29264 * Restores the previous state of the dialog if Roo.state is configured.
29265 * @return {Roo.BasicDialog} this
29267 restoreState : function(){
29268 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29269 if(box && box.width){
29270 this.xy = [box.x, box.y];
29271 this.resizeTo(box.width, box.height);
29277 beforeShow : function(){
29279 if(this.fixedcenter){
29280 this.xy = this.el.getCenterXY(true);
29283 Roo.get(document.body).addClass("x-body-masked");
29284 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29287 this.constrainXY();
29291 animShow : function(){
29292 var b = Roo.get(this.animateTarget).getBox();
29293 this.proxy.setSize(b.width, b.height);
29294 this.proxy.setLocation(b.x, b.y);
29296 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29297 true, .35, this.showEl.createDelegate(this));
29301 * Shows the dialog.
29302 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29303 * @return {Roo.BasicDialog} this
29305 show : function(animateTarget){
29306 if (this.fireEvent("beforeshow", this) === false){
29309 if(this.syncHeightBeforeShow){
29310 this.syncBodyHeight();
29311 }else if(this.firstShow){
29312 this.firstShow = false;
29313 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29315 this.animateTarget = animateTarget || this.animateTarget;
29316 if(!this.el.isVisible()){
29318 if(this.animateTarget && Roo.get(this.animateTarget)){
29328 showEl : function(){
29330 this.el.setXY(this.xy);
29332 this.adjustAssets(true);
29335 // IE peekaboo bug - fix found by Dave Fenwick
29339 this.fireEvent("show", this);
29343 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29344 * dialog itself will receive focus.
29346 focus : function(){
29347 if(this.defaultButton){
29348 this.defaultButton.focus();
29350 this.focusEl.focus();
29355 constrainXY : function(){
29356 if(this.constraintoviewport !== false){
29357 if(!this.viewSize){
29358 if(this.container){
29359 var s = this.container.getSize();
29360 this.viewSize = [s.width, s.height];
29362 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29365 var s = Roo.get(this.container||document).getScroll();
29367 var x = this.xy[0], y = this.xy[1];
29368 var w = this.size.width, h = this.size.height;
29369 var vw = this.viewSize[0], vh = this.viewSize[1];
29370 // only move it if it needs it
29372 // first validate right/bottom
29373 if(x + w > vw+s.left){
29377 if(y + h > vh+s.top){
29381 // then make sure top/left isn't negative
29393 if(this.isVisible()){
29394 this.el.setLocation(x, y);
29395 this.adjustAssets();
29402 onDrag : function(){
29403 if(!this.proxyDrag){
29404 this.xy = this.el.getXY();
29405 this.adjustAssets();
29410 adjustAssets : function(doShow){
29411 var x = this.xy[0], y = this.xy[1];
29412 var w = this.size.width, h = this.size.height;
29413 if(doShow === true){
29415 this.shadow.show(this.el);
29421 if(this.shadow && this.shadow.isVisible()){
29422 this.shadow.show(this.el);
29424 if(this.shim && this.shim.isVisible()){
29425 this.shim.setBounds(x, y, w, h);
29430 adjustViewport : function(w, h){
29432 w = Roo.lib.Dom.getViewWidth();
29433 h = Roo.lib.Dom.getViewHeight();
29436 this.viewSize = [w, h];
29437 if(this.modal && this.mask.isVisible()){
29438 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29439 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29441 if(this.isVisible()){
29442 this.constrainXY();
29447 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29448 * shadow, proxy, mask, etc.) Also removes all event listeners.
29449 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29451 destroy : function(removeEl){
29452 if(this.isVisible()){
29453 this.animateTarget = null;
29456 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29458 this.tabs.destroy(removeEl);
29471 for(var i = 0, len = this.buttons.length; i < len; i++){
29472 this.buttons[i].destroy();
29475 this.el.removeAllListeners();
29476 if(removeEl === true){
29477 this.el.update("");
29480 Roo.DialogManager.unregister(this);
29484 startMove : function(){
29485 if(this.proxyDrag){
29488 if(this.constraintoviewport !== false){
29489 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29494 endMove : function(){
29495 if(!this.proxyDrag){
29496 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29498 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29501 this.refreshSize();
29502 this.adjustAssets();
29504 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29508 * Brings this dialog to the front of any other visible dialogs
29509 * @return {Roo.BasicDialog} this
29511 toFront : function(){
29512 Roo.DialogManager.bringToFront(this);
29517 * Sends this dialog to the back (under) of any other visible dialogs
29518 * @return {Roo.BasicDialog} this
29520 toBack : function(){
29521 Roo.DialogManager.sendToBack(this);
29526 * Centers this dialog in the viewport
29527 * @return {Roo.BasicDialog} this
29529 center : function(){
29530 var xy = this.el.getCenterXY(true);
29531 this.moveTo(xy[0], xy[1]);
29536 * Moves the dialog's top-left corner to the specified point
29537 * @param {Number} x
29538 * @param {Number} y
29539 * @return {Roo.BasicDialog} this
29541 moveTo : function(x, y){
29543 if(this.isVisible()){
29544 this.el.setXY(this.xy);
29545 this.adjustAssets();
29551 * Aligns the dialog to the specified element
29552 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29553 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29554 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29555 * @return {Roo.BasicDialog} this
29557 alignTo : function(element, position, offsets){
29558 this.xy = this.el.getAlignToXY(element, position, offsets);
29559 if(this.isVisible()){
29560 this.el.setXY(this.xy);
29561 this.adjustAssets();
29567 * Anchors an element to another element and realigns it when the window is resized.
29568 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29569 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29570 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29571 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29572 * is a number, it is used as the buffer delay (defaults to 50ms).
29573 * @return {Roo.BasicDialog} this
29575 anchorTo : function(el, alignment, offsets, monitorScroll){
29576 var action = function(){
29577 this.alignTo(el, alignment, offsets);
29579 Roo.EventManager.onWindowResize(action, this);
29580 var tm = typeof monitorScroll;
29581 if(tm != 'undefined'){
29582 Roo.EventManager.on(window, 'scroll', action, this,
29583 {buffer: tm == 'number' ? monitorScroll : 50});
29590 * Returns true if the dialog is visible
29591 * @return {Boolean}
29593 isVisible : function(){
29594 return this.el.isVisible();
29598 animHide : function(callback){
29599 var b = Roo.get(this.animateTarget).getBox();
29601 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29603 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29604 this.hideEl.createDelegate(this, [callback]));
29608 * Hides the dialog.
29609 * @param {Function} callback (optional) Function to call when the dialog is hidden
29610 * @return {Roo.BasicDialog} this
29612 hide : function(callback){
29613 if (this.fireEvent("beforehide", this) === false){
29617 this.shadow.hide();
29622 // sometimes animateTarget seems to get set.. causing problems...
29623 // this just double checks..
29624 if(this.animateTarget && Roo.get(this.animateTarget)) {
29625 this.animHide(callback);
29628 this.hideEl(callback);
29634 hideEl : function(callback){
29638 Roo.get(document.body).removeClass("x-body-masked");
29640 this.fireEvent("hide", this);
29641 if(typeof callback == "function"){
29647 hideAction : function(){
29648 this.setLeft("-10000px");
29649 this.setTop("-10000px");
29650 this.setStyle("visibility", "hidden");
29654 refreshSize : function(){
29655 this.size = this.el.getSize();
29656 this.xy = this.el.getXY();
29657 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29661 // z-index is managed by the DialogManager and may be overwritten at any time
29662 setZIndex : function(index){
29664 this.mask.setStyle("z-index", index);
29667 this.shim.setStyle("z-index", ++index);
29670 this.shadow.setZIndex(++index);
29672 this.el.setStyle("z-index", ++index);
29674 this.proxy.setStyle("z-index", ++index);
29677 this.resizer.proxy.setStyle("z-index", ++index);
29680 this.lastZIndex = index;
29684 * Returns the element for this dialog
29685 * @return {Roo.Element} The underlying dialog Element
29687 getEl : function(){
29693 * @class Roo.DialogManager
29694 * Provides global access to BasicDialogs that have been created and
29695 * support for z-indexing (layering) multiple open dialogs.
29697 Roo.DialogManager = function(){
29699 var accessList = [];
29703 var sortDialogs = function(d1, d2){
29704 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29708 var orderDialogs = function(){
29709 accessList.sort(sortDialogs);
29710 var seed = Roo.DialogManager.zseed;
29711 for(var i = 0, len = accessList.length; i < len; i++){
29712 var dlg = accessList[i];
29714 dlg.setZIndex(seed + (i*10));
29721 * The starting z-index for BasicDialogs (defaults to 9000)
29722 * @type Number The z-index value
29727 register : function(dlg){
29728 list[dlg.id] = dlg;
29729 accessList.push(dlg);
29733 unregister : function(dlg){
29734 delete list[dlg.id];
29737 if(!accessList.indexOf){
29738 for( i = 0, len = accessList.length; i < len; i++){
29739 if(accessList[i] == dlg){
29740 accessList.splice(i, 1);
29745 i = accessList.indexOf(dlg);
29747 accessList.splice(i, 1);
29753 * Gets a registered dialog by id
29754 * @param {String/Object} id The id of the dialog or a dialog
29755 * @return {Roo.BasicDialog} this
29757 get : function(id){
29758 return typeof id == "object" ? id : list[id];
29762 * Brings the specified dialog to the front
29763 * @param {String/Object} dlg The id of the dialog or a dialog
29764 * @return {Roo.BasicDialog} this
29766 bringToFront : function(dlg){
29767 dlg = this.get(dlg);
29770 dlg._lastAccess = new Date().getTime();
29777 * Sends the specified dialog to the back
29778 * @param {String/Object} dlg The id of the dialog or a dialog
29779 * @return {Roo.BasicDialog} this
29781 sendToBack : function(dlg){
29782 dlg = this.get(dlg);
29783 dlg._lastAccess = -(new Date().getTime());
29789 * Hides all dialogs
29791 hideAll : function(){
29792 for(var id in list){
29793 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29802 * @class Roo.LayoutDialog
29803 * @extends Roo.BasicDialog
29804 * Dialog which provides adjustments for working with a layout in a Dialog.
29805 * Add your necessary layout config options to the dialog's config.<br>
29806 * Example usage (including a nested layout):
29809 dialog = new Roo.LayoutDialog("download-dlg", {
29818 // layout config merges with the dialog config
29820 tabPosition: "top",
29821 alwaysShowTabs: true
29824 dialog.addKeyListener(27, dialog.hide, dialog);
29825 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29826 dialog.addButton("Build It!", this.getDownload, this);
29828 // we can even add nested layouts
29829 var innerLayout = new Roo.BorderLayout("dl-inner", {
29839 innerLayout.beginUpdate();
29840 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29841 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29842 innerLayout.endUpdate(true);
29844 var layout = dialog.getLayout();
29845 layout.beginUpdate();
29846 layout.add("center", new Roo.ContentPanel("standard-panel",
29847 {title: "Download the Source", fitToFrame:true}));
29848 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29849 {title: "Build your own roo.js"}));
29850 layout.getRegion("center").showPanel(sp);
29851 layout.endUpdate();
29855 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29856 * @param {Object} config configuration options
29858 Roo.LayoutDialog = function(el, cfg){
29861 if (typeof(cfg) == 'undefined') {
29862 config = Roo.apply({}, el);
29863 // not sure why we use documentElement here.. - it should always be body.
29864 // IE7 borks horribly if we use documentElement.
29865 // webkit also does not like documentElement - it creates a body element...
29866 el = Roo.get( document.body || document.documentElement ).createChild();
29867 //config.autoCreate = true;
29871 config.autoTabs = false;
29872 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29873 this.body.setStyle({overflow:"hidden", position:"relative"});
29874 this.layout = new Roo.BorderLayout(this.body.dom, config);
29875 this.layout.monitorWindowResize = false;
29876 this.el.addClass("x-dlg-auto-layout");
29877 // fix case when center region overwrites center function
29878 this.center = Roo.BasicDialog.prototype.center;
29879 this.on("show", this.layout.layout, this.layout, true);
29880 if (config.items) {
29881 var xitems = config.items;
29882 delete config.items;
29883 Roo.each(xitems, this.addxtype, this);
29888 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29890 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29893 endUpdate : function(){
29894 this.layout.endUpdate();
29898 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29901 beginUpdate : function(){
29902 this.layout.beginUpdate();
29906 * Get the BorderLayout for this dialog
29907 * @return {Roo.BorderLayout}
29909 getLayout : function(){
29910 return this.layout;
29913 showEl : function(){
29914 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29916 this.layout.layout();
29921 // Use the syncHeightBeforeShow config option to control this automatically
29922 syncBodyHeight : function(){
29923 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29924 if(this.layout){this.layout.layout();}
29928 * Add an xtype element (actually adds to the layout.)
29929 * @return {Object} xdata xtype object data.
29932 addxtype : function(c) {
29933 return this.layout.addxtype(c);
29937 * Ext JS Library 1.1.1
29938 * Copyright(c) 2006-2007, Ext JS, LLC.
29940 * Originally Released Under LGPL - original licence link has changed is not relivant.
29943 * <script type="text/javascript">
29947 * @class Roo.MessageBox
29948 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29952 Roo.Msg.alert('Status', 'Changes saved successfully.');
29954 // Prompt for user data:
29955 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29957 // process text value...
29961 // Show a dialog using config options:
29963 title:'Save Changes?',
29964 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29965 buttons: Roo.Msg.YESNOCANCEL,
29972 Roo.MessageBox = function(){
29973 var dlg, opt, mask, waitTimer;
29974 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29975 var buttons, activeTextEl, bwidth;
29978 var handleButton = function(button){
29980 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29984 var handleHide = function(){
29985 if(opt && opt.cls){
29986 dlg.el.removeClass(opt.cls);
29989 Roo.TaskMgr.stop(waitTimer);
29995 var updateButtons = function(b){
29998 buttons["ok"].hide();
29999 buttons["cancel"].hide();
30000 buttons["yes"].hide();
30001 buttons["no"].hide();
30002 dlg.footer.dom.style.display = 'none';
30005 dlg.footer.dom.style.display = '';
30006 for(var k in buttons){
30007 if(typeof buttons[k] != "function"){
30010 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
30011 width += buttons[k].el.getWidth()+15;
30021 var handleEsc = function(d, k, e){
30022 if(opt && opt.closable !== false){
30032 * Returns a reference to the underlying {@link Roo.BasicDialog} element
30033 * @return {Roo.BasicDialog} The BasicDialog element
30035 getDialog : function(){
30037 dlg = new Roo.BasicDialog("x-msg-box", {
30042 constraintoviewport:false,
30044 collapsible : false,
30047 width:400, height:100,
30048 buttonAlign:"center",
30049 closeClick : function(){
30050 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
30051 handleButton("no");
30053 handleButton("cancel");
30057 dlg.on("hide", handleHide);
30059 dlg.addKeyListener(27, handleEsc);
30061 var bt = this.buttonText;
30062 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
30063 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
30064 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
30065 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
30066 bodyEl = dlg.body.createChild({
30068 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>'
30070 msgEl = bodyEl.dom.firstChild;
30071 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
30072 textboxEl.enableDisplayMode();
30073 textboxEl.addKeyListener([10,13], function(){
30074 if(dlg.isVisible() && opt && opt.buttons){
30075 if(opt.buttons.ok){
30076 handleButton("ok");
30077 }else if(opt.buttons.yes){
30078 handleButton("yes");
30082 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
30083 textareaEl.enableDisplayMode();
30084 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
30085 progressEl.enableDisplayMode();
30086 var pf = progressEl.dom.firstChild;
30088 pp = Roo.get(pf.firstChild);
30089 pp.setHeight(pf.offsetHeight);
30097 * Updates the message box body text
30098 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30099 * the XHTML-compliant non-breaking space character '&#160;')
30100 * @return {Roo.MessageBox} This message box
30102 updateText : function(text){
30103 if(!dlg.isVisible() && !opt.width){
30104 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30106 msgEl.innerHTML = text || ' ';
30108 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
30109 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
30111 Math.min(opt.width || cw , this.maxWidth),
30112 Math.max(opt.minWidth || this.minWidth, bwidth)
30115 activeTextEl.setWidth(w);
30117 if(dlg.isVisible()){
30118 dlg.fixedcenter = false;
30120 // to big, make it scoll.
30121 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
30122 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
30123 bodyEl.dom.style.overflowY = 'auto !important';
30125 bodyEl.dom.style.height = '';
30126 bodyEl.dom.style.overflowY = '';
30129 bodyEl.dom.style.overflowX = 'auto !important';
30131 bodyEl.dom.style.overflowX = '';
30134 dlg.setContentSize(w, bodyEl.getHeight());
30135 if(dlg.isVisible()){
30136 dlg.fixedcenter = true;
30142 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30143 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30144 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30145 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30146 * @return {Roo.MessageBox} This message box
30148 updateProgress : function(value, text){
30150 this.updateText(text);
30152 if (pp) { // weird bug on my firefox - for some reason this is not defined
30153 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30159 * Returns true if the message box is currently displayed
30160 * @return {Boolean} True if the message box is visible, else false
30162 isVisible : function(){
30163 return dlg && dlg.isVisible();
30167 * Hides the message box if it is displayed
30170 if(this.isVisible()){
30176 * Displays a new message box, or reinitializes an existing message box, based on the config options
30177 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30178 * The following config object properties are supported:
30180 Property Type Description
30181 ---------- --------------- ------------------------------------------------------------------------------------
30182 animEl String/Element An id or Element from which the message box should animate as it opens and
30183 closes (defaults to undefined)
30184 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30185 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30186 closable Boolean False to hide the top-right close button (defaults to true). Note that
30187 progress and wait dialogs will ignore this property and always hide the
30188 close button as they can only be closed programmatically.
30189 cls String A custom CSS class to apply to the message box element
30190 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30191 displayed (defaults to 75)
30192 fn Function A callback function to execute after closing the dialog. The arguments to the
30193 function will be btn (the name of the button that was clicked, if applicable,
30194 e.g. "ok"), and text (the value of the active text field, if applicable).
30195 Progress and wait dialogs will ignore this option since they do not respond to
30196 user actions and can only be closed programmatically, so any required function
30197 should be called by the same code after it closes the dialog.
30198 icon String A CSS class that provides a background image to be used as an icon for
30199 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30200 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30201 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30202 modal Boolean False to allow user interaction with the page while the message box is
30203 displayed (defaults to true)
30204 msg String A string that will replace the existing message box body text (defaults
30205 to the XHTML-compliant non-breaking space character ' ')
30206 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30207 progress Boolean True to display a progress bar (defaults to false)
30208 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30209 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30210 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30211 title String The title text
30212 value String The string value to set into the active textbox element if displayed
30213 wait Boolean True to display a progress bar (defaults to false)
30214 width Number The width of the dialog in pixels
30221 msg: 'Please enter your address:',
30223 buttons: Roo.MessageBox.OKCANCEL,
30226 animEl: 'addAddressBtn'
30229 * @param {Object} config Configuration options
30230 * @return {Roo.MessageBox} This message box
30232 show : function(options)
30235 // this causes nightmares if you show one dialog after another
30236 // especially on callbacks..
30238 if(this.isVisible()){
30241 Roo.log("Old Dialog Message:" + msgEl.innerHTML )
30242 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
30243 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
30246 var d = this.getDialog();
30248 d.setTitle(opt.title || " ");
30249 d.close.setDisplayed(opt.closable !== false);
30250 activeTextEl = textboxEl;
30251 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30256 textareaEl.setHeight(typeof opt.multiline == "number" ?
30257 opt.multiline : this.defaultTextHeight);
30258 activeTextEl = textareaEl;
30267 progressEl.setDisplayed(opt.progress === true);
30268 this.updateProgress(0);
30269 activeTextEl.dom.value = opt.value || "";
30271 dlg.setDefaultButton(activeTextEl);
30273 var bs = opt.buttons;
30276 db = buttons["ok"];
30277 }else if(bs && bs.yes){
30278 db = buttons["yes"];
30280 dlg.setDefaultButton(db);
30282 bwidth = updateButtons(opt.buttons);
30283 this.updateText(opt.msg);
30285 d.el.addClass(opt.cls);
30287 d.proxyDrag = opt.proxyDrag === true;
30288 d.modal = opt.modal !== false;
30289 d.mask = opt.modal !== false ? mask : false;
30290 if(!d.isVisible()){
30291 // force it to the end of the z-index stack so it gets a cursor in FF
30292 document.body.appendChild(dlg.el.dom);
30293 d.animateTarget = null;
30294 d.show(options.animEl);
30300 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30301 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30302 * and closing the message box when the process is complete.
30303 * @param {String} title The title bar text
30304 * @param {String} msg The message box body text
30305 * @return {Roo.MessageBox} This message box
30307 progress : function(title, msg){
30314 minWidth: this.minProgressWidth,
30321 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30322 * If a callback function is passed it will be called after the user clicks the button, and the
30323 * id of the button that was clicked will be passed as the only parameter to the callback
30324 * (could also be the top-right close button).
30325 * @param {String} title The title bar text
30326 * @param {String} msg The message box body text
30327 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30328 * @param {Object} scope (optional) The scope of the callback function
30329 * @return {Roo.MessageBox} This message box
30331 alert : function(title, msg, fn, scope){
30344 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30345 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30346 * You are responsible for closing the message box when the process is complete.
30347 * @param {String} msg The message box body text
30348 * @param {String} title (optional) The title bar text
30349 * @return {Roo.MessageBox} This message box
30351 wait : function(msg, title){
30362 waitTimer = Roo.TaskMgr.start({
30364 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30372 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30373 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30374 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30375 * @param {String} title The title bar text
30376 * @param {String} msg The message box body text
30377 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30378 * @param {Object} scope (optional) The scope of the callback function
30379 * @return {Roo.MessageBox} This message box
30381 confirm : function(title, msg, fn, scope){
30385 buttons: this.YESNO,
30394 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30395 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30396 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30397 * (could also be the top-right close button) and the text that was entered will be passed as the two
30398 * parameters to the callback.
30399 * @param {String} title The title bar text
30400 * @param {String} msg The message box body text
30401 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30402 * @param {Object} scope (optional) The scope of the callback function
30403 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30404 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30405 * @return {Roo.MessageBox} This message box
30407 prompt : function(title, msg, fn, scope, multiline){
30411 buttons: this.OKCANCEL,
30416 multiline: multiline,
30423 * Button config that displays a single OK button
30428 * Button config that displays Yes and No buttons
30431 YESNO : {yes:true, no:true},
30433 * Button config that displays OK and Cancel buttons
30436 OKCANCEL : {ok:true, cancel:true},
30438 * Button config that displays Yes, No and Cancel buttons
30441 YESNOCANCEL : {yes:true, no:true, cancel:true},
30444 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30447 defaultTextHeight : 75,
30449 * The maximum width in pixels of the message box (defaults to 600)
30454 * The minimum width in pixels of the message box (defaults to 100)
30459 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30460 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30463 minProgressWidth : 250,
30465 * An object containing the default button text strings that can be overriden for localized language support.
30466 * Supported properties are: ok, cancel, yes and no.
30467 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30480 * Shorthand for {@link Roo.MessageBox}
30482 Roo.Msg = Roo.MessageBox;/*
30484 * Ext JS Library 1.1.1
30485 * Copyright(c) 2006-2007, Ext JS, LLC.
30487 * Originally Released Under LGPL - original licence link has changed is not relivant.
30490 * <script type="text/javascript">
30493 * @class Roo.QuickTips
30494 * Provides attractive and customizable tooltips for any element.
30497 Roo.QuickTips = function(){
30498 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30499 var ce, bd, xy, dd;
30500 var visible = false, disabled = true, inited = false;
30501 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30503 var onOver = function(e){
30507 var t = e.getTarget();
30508 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30511 if(ce && t == ce.el){
30512 clearTimeout(hideProc);
30515 if(t && tagEls[t.id]){
30516 tagEls[t.id].el = t;
30517 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30520 var ttp, et = Roo.fly(t);
30521 var ns = cfg.namespace;
30522 if(tm.interceptTitles && t.title){
30525 t.removeAttribute("title");
30526 e.preventDefault();
30528 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30531 showProc = show.defer(tm.showDelay, tm, [{
30534 width: et.getAttributeNS(ns, cfg.width),
30535 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30536 title: et.getAttributeNS(ns, cfg.title),
30537 cls: et.getAttributeNS(ns, cfg.cls)
30542 var onOut = function(e){
30543 clearTimeout(showProc);
30544 var t = e.getTarget();
30545 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30546 hideProc = setTimeout(hide, tm.hideDelay);
30550 var onMove = function(e){
30556 if(tm.trackMouse && ce){
30561 var onDown = function(e){
30562 clearTimeout(showProc);
30563 clearTimeout(hideProc);
30565 if(tm.hideOnClick){
30568 tm.enable.defer(100, tm);
30573 var getPad = function(){
30574 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30577 var show = function(o){
30581 clearTimeout(dismissProc);
30583 if(removeCls){ // in case manually hidden
30584 el.removeClass(removeCls);
30588 el.addClass(ce.cls);
30589 removeCls = ce.cls;
30592 tipTitle.update(ce.title);
30595 tipTitle.update('');
30598 el.dom.style.width = tm.maxWidth+'px';
30599 //tipBody.dom.style.width = '';
30600 tipBodyText.update(o.text);
30601 var p = getPad(), w = ce.width;
30603 var td = tipBodyText.dom;
30604 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30605 if(aw > tm.maxWidth){
30607 }else if(aw < tm.minWidth){
30613 //tipBody.setWidth(w);
30614 el.setWidth(parseInt(w, 10) + p);
30615 if(ce.autoHide === false){
30616 close.setDisplayed(true);
30621 close.setDisplayed(false);
30627 el.avoidY = xy[1]-18;
30632 el.setStyle("visibility", "visible");
30633 el.fadeIn({callback: afterShow});
30639 var afterShow = function(){
30643 if(tm.autoDismiss && ce.autoHide !== false){
30644 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30649 var hide = function(noanim){
30650 clearTimeout(dismissProc);
30651 clearTimeout(hideProc);
30653 if(el.isVisible()){
30655 if(noanim !== true && tm.animate){
30656 el.fadeOut({callback: afterHide});
30663 var afterHide = function(){
30666 el.removeClass(removeCls);
30673 * @cfg {Number} minWidth
30674 * The minimum width of the quick tip (defaults to 40)
30678 * @cfg {Number} maxWidth
30679 * The maximum width of the quick tip (defaults to 300)
30683 * @cfg {Boolean} interceptTitles
30684 * True to automatically use the element's DOM title value if available (defaults to false)
30686 interceptTitles : false,
30688 * @cfg {Boolean} trackMouse
30689 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30691 trackMouse : false,
30693 * @cfg {Boolean} hideOnClick
30694 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30696 hideOnClick : true,
30698 * @cfg {Number} showDelay
30699 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30703 * @cfg {Number} hideDelay
30704 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30708 * @cfg {Boolean} autoHide
30709 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30710 * Used in conjunction with hideDelay.
30715 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30716 * (defaults to true). Used in conjunction with autoDismissDelay.
30718 autoDismiss : true,
30721 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30723 autoDismissDelay : 5000,
30725 * @cfg {Boolean} animate
30726 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30731 * @cfg {String} title
30732 * Title text to display (defaults to ''). This can be any valid HTML markup.
30736 * @cfg {String} text
30737 * Body text to display (defaults to ''). This can be any valid HTML markup.
30741 * @cfg {String} cls
30742 * A CSS class to apply to the base quick tip element (defaults to '').
30746 * @cfg {Number} width
30747 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30748 * minWidth or maxWidth.
30753 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30754 * or display QuickTips in a page.
30757 tm = Roo.QuickTips;
30758 cfg = tm.tagConfig;
30760 if(!Roo.isReady){ // allow calling of init() before onReady
30761 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30764 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30765 el.fxDefaults = {stopFx: true};
30766 // maximum custom styling
30767 //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>');
30768 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>');
30769 tipTitle = el.child('h3');
30770 tipTitle.enableDisplayMode("block");
30771 tipBody = el.child('div.x-tip-bd');
30772 tipBodyText = el.child('div.x-tip-bd-inner');
30773 //bdLeft = el.child('div.x-tip-bd-left');
30774 //bdRight = el.child('div.x-tip-bd-right');
30775 close = el.child('div.x-tip-close');
30776 close.enableDisplayMode("block");
30777 close.on("click", hide);
30778 var d = Roo.get(document);
30779 d.on("mousedown", onDown);
30780 d.on("mouseover", onOver);
30781 d.on("mouseout", onOut);
30782 d.on("mousemove", onMove);
30783 esc = d.addKeyListener(27, hide);
30786 dd = el.initDD("default", null, {
30787 onDrag : function(){
30791 dd.setHandleElId(tipTitle.id);
30800 * Configures a new quick tip instance and assigns it to a target element. The following config options
30803 Property Type Description
30804 ---------- --------------------- ------------------------------------------------------------------------
30805 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30807 * @param {Object} config The config object
30809 register : function(config){
30810 var cs = config instanceof Array ? config : arguments;
30811 for(var i = 0, len = cs.length; i < len; i++) {
30813 var target = c.target;
30815 if(target instanceof Array){
30816 for(var j = 0, jlen = target.length; j < jlen; j++){
30817 tagEls[target[j]] = c;
30820 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30827 * Removes this quick tip from its element and destroys it.
30828 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30830 unregister : function(el){
30831 delete tagEls[Roo.id(el)];
30835 * Enable this quick tip.
30837 enable : function(){
30838 if(inited && disabled){
30840 if(locks.length < 1){
30847 * Disable this quick tip.
30849 disable : function(){
30851 clearTimeout(showProc);
30852 clearTimeout(hideProc);
30853 clearTimeout(dismissProc);
30861 * Returns true if the quick tip is enabled, else false.
30863 isEnabled : function(){
30870 attribute : "qtip",
30880 // backwards compat
30881 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30883 * Ext JS Library 1.1.1
30884 * Copyright(c) 2006-2007, Ext JS, LLC.
30886 * Originally Released Under LGPL - original licence link has changed is not relivant.
30889 * <script type="text/javascript">
30894 * @class Roo.tree.TreePanel
30895 * @extends Roo.data.Tree
30897 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30898 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30899 * @cfg {Boolean} enableDD true to enable drag and drop
30900 * @cfg {Boolean} enableDrag true to enable just drag
30901 * @cfg {Boolean} enableDrop true to enable just drop
30902 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30903 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30904 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30905 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30906 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30907 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30908 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30909 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30910 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30911 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30912 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30913 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30914 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
30915 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30916 * @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>
30917 * @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>
30920 * @param {String/HTMLElement/Element} el The container element
30921 * @param {Object} config
30923 Roo.tree.TreePanel = function(el, config){
30925 var loader = false;
30927 root = config.root;
30928 delete config.root;
30930 if (config.loader) {
30931 loader = config.loader;
30932 delete config.loader;
30935 Roo.apply(this, config);
30936 Roo.tree.TreePanel.superclass.constructor.call(this);
30937 this.el = Roo.get(el);
30938 this.el.addClass('x-tree');
30939 //console.log(root);
30941 this.setRootNode( Roo.factory(root, Roo.tree));
30944 this.loader = Roo.factory(loader, Roo.tree);
30947 * Read-only. The id of the container element becomes this TreePanel's id.
30949 this.id = this.el.id;
30952 * @event beforeload
30953 * Fires before a node is loaded, return false to cancel
30954 * @param {Node} node The node being loaded
30956 "beforeload" : true,
30959 * Fires when a node is loaded
30960 * @param {Node} node The node that was loaded
30964 * @event textchange
30965 * Fires when the text for a node is changed
30966 * @param {Node} node The node
30967 * @param {String} text The new text
30968 * @param {String} oldText The old text
30970 "textchange" : true,
30972 * @event beforeexpand
30973 * Fires before a node is expanded, return false to cancel.
30974 * @param {Node} node The node
30975 * @param {Boolean} deep
30976 * @param {Boolean} anim
30978 "beforeexpand" : true,
30980 * @event beforecollapse
30981 * Fires before a node is collapsed, return false to cancel.
30982 * @param {Node} node The node
30983 * @param {Boolean} deep
30984 * @param {Boolean} anim
30986 "beforecollapse" : true,
30989 * Fires when a node is expanded
30990 * @param {Node} node The node
30994 * @event disabledchange
30995 * Fires when the disabled status of a node changes
30996 * @param {Node} node The node
30997 * @param {Boolean} disabled
30999 "disabledchange" : true,
31002 * Fires when a node is collapsed
31003 * @param {Node} node The node
31007 * @event beforeclick
31008 * Fires before click processing on a node. Return false to cancel the default action.
31009 * @param {Node} node The node
31010 * @param {Roo.EventObject} e The event object
31012 "beforeclick":true,
31014 * @event checkchange
31015 * Fires when a node with a checkbox's checked property changes
31016 * @param {Node} this This node
31017 * @param {Boolean} checked
31019 "checkchange":true,
31022 * Fires when a node is clicked
31023 * @param {Node} node The node
31024 * @param {Roo.EventObject} e The event object
31029 * Fires when a node is double clicked
31030 * @param {Node} node The node
31031 * @param {Roo.EventObject} e The event object
31035 * @event contextmenu
31036 * Fires when a node is right clicked
31037 * @param {Node} node The node
31038 * @param {Roo.EventObject} e The event object
31040 "contextmenu":true,
31042 * @event beforechildrenrendered
31043 * Fires right before the child nodes for a node are rendered
31044 * @param {Node} node The node
31046 "beforechildrenrendered":true,
31049 * Fires when a node starts being dragged
31050 * @param {Roo.tree.TreePanel} this
31051 * @param {Roo.tree.TreeNode} node
31052 * @param {event} e The raw browser event
31054 "startdrag" : true,
31057 * Fires when a drag operation is complete
31058 * @param {Roo.tree.TreePanel} this
31059 * @param {Roo.tree.TreeNode} node
31060 * @param {event} e The raw browser event
31065 * Fires when a dragged node is dropped on a valid DD target
31066 * @param {Roo.tree.TreePanel} this
31067 * @param {Roo.tree.TreeNode} node
31068 * @param {DD} dd The dd it was dropped on
31069 * @param {event} e The raw browser event
31073 * @event beforenodedrop
31074 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
31075 * passed to handlers has the following properties:<br />
31076 * <ul style="padding:5px;padding-left:16px;">
31077 * <li>tree - The TreePanel</li>
31078 * <li>target - The node being targeted for the drop</li>
31079 * <li>data - The drag data from the drag source</li>
31080 * <li>point - The point of the drop - append, above or below</li>
31081 * <li>source - The drag source</li>
31082 * <li>rawEvent - Raw mouse event</li>
31083 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
31084 * to be inserted by setting them on this object.</li>
31085 * <li>cancel - Set this to true to cancel the drop.</li>
31087 * @param {Object} dropEvent
31089 "beforenodedrop" : true,
31092 * Fires after a DD object is dropped on a node in this tree. The dropEvent
31093 * passed to handlers has the following properties:<br />
31094 * <ul style="padding:5px;padding-left:16px;">
31095 * <li>tree - The TreePanel</li>
31096 * <li>target - The node being targeted for the drop</li>
31097 * <li>data - The drag data from the drag source</li>
31098 * <li>point - The point of the drop - append, above or below</li>
31099 * <li>source - The drag source</li>
31100 * <li>rawEvent - Raw mouse event</li>
31101 * <li>dropNode - Dropped node(s).</li>
31103 * @param {Object} dropEvent
31107 * @event nodedragover
31108 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31109 * passed to handlers has the following properties:<br />
31110 * <ul style="padding:5px;padding-left:16px;">
31111 * <li>tree - The TreePanel</li>
31112 * <li>target - The node being targeted for the drop</li>
31113 * <li>data - The drag data from the drag source</li>
31114 * <li>point - The point of the drop - append, above or below</li>
31115 * <li>source - The drag source</li>
31116 * <li>rawEvent - Raw mouse event</li>
31117 * <li>dropNode - Drop node(s) provided by the source.</li>
31118 * <li>cancel - Set this to true to signal drop not allowed.</li>
31120 * @param {Object} dragOverEvent
31122 "nodedragover" : true
31125 if(this.singleExpand){
31126 this.on("beforeexpand", this.restrictExpand, this);
31129 this.editor.tree = this;
31130 this.editor = Roo.factory(this.editor, Roo.tree);
31133 if (this.selModel) {
31134 this.selModel = Roo.factory(this.selModel, Roo.tree);
31138 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31139 rootVisible : true,
31140 animate: Roo.enableFx,
31143 hlDrop : Roo.enableFx,
31147 rendererTip: false,
31149 restrictExpand : function(node){
31150 var p = node.parentNode;
31152 if(p.expandedChild && p.expandedChild.parentNode == p){
31153 p.expandedChild.collapse();
31155 p.expandedChild = node;
31159 // private override
31160 setRootNode : function(node){
31161 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31162 if(!this.rootVisible){
31163 node.ui = new Roo.tree.RootTreeNodeUI(node);
31169 * Returns the container element for this TreePanel
31171 getEl : function(){
31176 * Returns the default TreeLoader for this TreePanel
31178 getLoader : function(){
31179 return this.loader;
31185 expandAll : function(){
31186 this.root.expand(true);
31190 * Collapse all nodes
31192 collapseAll : function(){
31193 this.root.collapse(true);
31197 * Returns the selection model used by this TreePanel
31199 getSelectionModel : function(){
31200 if(!this.selModel){
31201 this.selModel = new Roo.tree.DefaultSelectionModel();
31203 return this.selModel;
31207 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31208 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31209 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31212 getChecked : function(a, startNode){
31213 startNode = startNode || this.root;
31215 var f = function(){
31216 if(this.attributes.checked){
31217 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31220 startNode.cascade(f);
31225 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31226 * @param {String} path
31227 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31228 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31229 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31231 expandPath : function(path, attr, callback){
31232 attr = attr || "id";
31233 var keys = path.split(this.pathSeparator);
31234 var curNode = this.root;
31235 if(curNode.attributes[attr] != keys[1]){ // invalid root
31237 callback(false, null);
31242 var f = function(){
31243 if(++index == keys.length){
31245 callback(true, curNode);
31249 var c = curNode.findChild(attr, keys[index]);
31252 callback(false, curNode);
31257 c.expand(false, false, f);
31259 curNode.expand(false, false, f);
31263 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31264 * @param {String} path
31265 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31266 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31267 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31269 selectPath : function(path, attr, callback){
31270 attr = attr || "id";
31271 var keys = path.split(this.pathSeparator);
31272 var v = keys.pop();
31273 if(keys.length > 0){
31274 var f = function(success, node){
31275 if(success && node){
31276 var n = node.findChild(attr, v);
31282 }else if(callback){
31283 callback(false, n);
31287 callback(false, n);
31291 this.expandPath(keys.join(this.pathSeparator), attr, f);
31293 this.root.select();
31295 callback(true, this.root);
31300 getTreeEl : function(){
31305 * Trigger rendering of this TreePanel
31307 render : function(){
31308 if (this.innerCt) {
31309 return this; // stop it rendering more than once!!
31312 this.innerCt = this.el.createChild({tag:"ul",
31313 cls:"x-tree-root-ct " +
31314 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31316 if(this.containerScroll){
31317 Roo.dd.ScrollManager.register(this.el);
31319 if((this.enableDD || this.enableDrop) && !this.dropZone){
31321 * The dropZone used by this tree if drop is enabled
31322 * @type Roo.tree.TreeDropZone
31324 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31325 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31328 if((this.enableDD || this.enableDrag) && !this.dragZone){
31330 * The dragZone used by this tree if drag is enabled
31331 * @type Roo.tree.TreeDragZone
31333 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31334 ddGroup: this.ddGroup || "TreeDD",
31335 scroll: this.ddScroll
31338 this.getSelectionModel().init(this);
31340 console.log("ROOT not set in tree");
31343 this.root.render();
31344 if(!this.rootVisible){
31345 this.root.renderChildren();
31351 * Ext JS Library 1.1.1
31352 * Copyright(c) 2006-2007, Ext JS, LLC.
31354 * Originally Released Under LGPL - original licence link has changed is not relivant.
31357 * <script type="text/javascript">
31362 * @class Roo.tree.DefaultSelectionModel
31363 * @extends Roo.util.Observable
31364 * The default single selection for a TreePanel.
31365 * @param {Object} cfg Configuration
31367 Roo.tree.DefaultSelectionModel = function(cfg){
31368 this.selNode = null;
31374 * @event selectionchange
31375 * Fires when the selected node changes
31376 * @param {DefaultSelectionModel} this
31377 * @param {TreeNode} node the new selection
31379 "selectionchange" : true,
31382 * @event beforeselect
31383 * Fires before the selected node changes, return false to cancel the change
31384 * @param {DefaultSelectionModel} this
31385 * @param {TreeNode} node the new selection
31386 * @param {TreeNode} node the old selection
31388 "beforeselect" : true
31391 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
31394 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31395 init : function(tree){
31397 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31398 tree.on("click", this.onNodeClick, this);
31401 onNodeClick : function(node, e){
31402 if (e.ctrlKey && this.selNode == node) {
31403 this.unselect(node);
31411 * @param {TreeNode} node The node to select
31412 * @return {TreeNode} The selected node
31414 select : function(node){
31415 var last = this.selNode;
31416 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31418 last.ui.onSelectedChange(false);
31420 this.selNode = node;
31421 node.ui.onSelectedChange(true);
31422 this.fireEvent("selectionchange", this, node, last);
31429 * @param {TreeNode} node The node to unselect
31431 unselect : function(node){
31432 if(this.selNode == node){
31433 this.clearSelections();
31438 * Clear all selections
31440 clearSelections : function(){
31441 var n = this.selNode;
31443 n.ui.onSelectedChange(false);
31444 this.selNode = null;
31445 this.fireEvent("selectionchange", this, null);
31451 * Get the selected node
31452 * @return {TreeNode} The selected node
31454 getSelectedNode : function(){
31455 return this.selNode;
31459 * Returns true if the node is selected
31460 * @param {TreeNode} node The node to check
31461 * @return {Boolean}
31463 isSelected : function(node){
31464 return this.selNode == node;
31468 * Selects the node above the selected node in the tree, intelligently walking the nodes
31469 * @return TreeNode The new selection
31471 selectPrevious : function(){
31472 var s = this.selNode || this.lastSelNode;
31476 var ps = s.previousSibling;
31478 if(!ps.isExpanded() || ps.childNodes.length < 1){
31479 return this.select(ps);
31481 var lc = ps.lastChild;
31482 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31485 return this.select(lc);
31487 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31488 return this.select(s.parentNode);
31494 * Selects the node above the selected node in the tree, intelligently walking the nodes
31495 * @return TreeNode The new selection
31497 selectNext : function(){
31498 var s = this.selNode || this.lastSelNode;
31502 if(s.firstChild && s.isExpanded()){
31503 return this.select(s.firstChild);
31504 }else if(s.nextSibling){
31505 return this.select(s.nextSibling);
31506 }else if(s.parentNode){
31508 s.parentNode.bubble(function(){
31509 if(this.nextSibling){
31510 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31519 onKeyDown : function(e){
31520 var s = this.selNode || this.lastSelNode;
31521 // undesirable, but required
31526 var k = e.getKey();
31534 this.selectPrevious();
31537 e.preventDefault();
31538 if(s.hasChildNodes()){
31539 if(!s.isExpanded()){
31541 }else if(s.firstChild){
31542 this.select(s.firstChild, e);
31547 e.preventDefault();
31548 if(s.hasChildNodes() && s.isExpanded()){
31550 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31551 this.select(s.parentNode, e);
31559 * @class Roo.tree.MultiSelectionModel
31560 * @extends Roo.util.Observable
31561 * Multi selection for a TreePanel.
31562 * @param {Object} cfg Configuration
31564 Roo.tree.MultiSelectionModel = function(){
31565 this.selNodes = [];
31569 * @event selectionchange
31570 * Fires when the selected nodes change
31571 * @param {MultiSelectionModel} this
31572 * @param {Array} nodes Array of the selected nodes
31574 "selectionchange" : true
31576 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
31580 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31581 init : function(tree){
31583 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31584 tree.on("click", this.onNodeClick, this);
31587 onNodeClick : function(node, e){
31588 this.select(node, e, e.ctrlKey);
31593 * @param {TreeNode} node The node to select
31594 * @param {EventObject} e (optional) An event associated with the selection
31595 * @param {Boolean} keepExisting True to retain existing selections
31596 * @return {TreeNode} The selected node
31598 select : function(node, e, keepExisting){
31599 if(keepExisting !== true){
31600 this.clearSelections(true);
31602 if(this.isSelected(node)){
31603 this.lastSelNode = node;
31606 this.selNodes.push(node);
31607 this.selMap[node.id] = node;
31608 this.lastSelNode = node;
31609 node.ui.onSelectedChange(true);
31610 this.fireEvent("selectionchange", this, this.selNodes);
31616 * @param {TreeNode} node The node to unselect
31618 unselect : function(node){
31619 if(this.selMap[node.id]){
31620 node.ui.onSelectedChange(false);
31621 var sn = this.selNodes;
31624 index = sn.indexOf(node);
31626 for(var i = 0, len = sn.length; i < len; i++){
31634 this.selNodes.splice(index, 1);
31636 delete this.selMap[node.id];
31637 this.fireEvent("selectionchange", this, this.selNodes);
31642 * Clear all selections
31644 clearSelections : function(suppressEvent){
31645 var sn = this.selNodes;
31647 for(var i = 0, len = sn.length; i < len; i++){
31648 sn[i].ui.onSelectedChange(false);
31650 this.selNodes = [];
31652 if(suppressEvent !== true){
31653 this.fireEvent("selectionchange", this, this.selNodes);
31659 * Returns true if the node is selected
31660 * @param {TreeNode} node The node to check
31661 * @return {Boolean}
31663 isSelected : function(node){
31664 return this.selMap[node.id] ? true : false;
31668 * Returns an array of the selected nodes
31671 getSelectedNodes : function(){
31672 return this.selNodes;
31675 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31677 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31679 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31682 * Ext JS Library 1.1.1
31683 * Copyright(c) 2006-2007, Ext JS, LLC.
31685 * Originally Released Under LGPL - original licence link has changed is not relivant.
31688 * <script type="text/javascript">
31692 * @class Roo.tree.TreeNode
31693 * @extends Roo.data.Node
31694 * @cfg {String} text The text for this node
31695 * @cfg {Boolean} expanded true to start the node expanded
31696 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31697 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31698 * @cfg {Boolean} disabled true to start the node disabled
31699 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31700 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31701 * @cfg {String} cls A css class to be added to the node
31702 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31703 * @cfg {String} href URL of the link used for the node (defaults to #)
31704 * @cfg {String} hrefTarget target frame for the link
31705 * @cfg {String} qtip An Ext QuickTip for the node
31706 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31707 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31708 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31709 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31710 * (defaults to undefined with no checkbox rendered)
31712 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31714 Roo.tree.TreeNode = function(attributes){
31715 attributes = attributes || {};
31716 if(typeof attributes == "string"){
31717 attributes = {text: attributes};
31719 this.childrenRendered = false;
31720 this.rendered = false;
31721 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31722 this.expanded = attributes.expanded === true;
31723 this.isTarget = attributes.isTarget !== false;
31724 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31725 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31728 * Read-only. The text for this node. To change it use setText().
31731 this.text = attributes.text;
31733 * True if this node is disabled.
31736 this.disabled = attributes.disabled === true;
31740 * @event textchange
31741 * Fires when the text for this node is changed
31742 * @param {Node} this This node
31743 * @param {String} text The new text
31744 * @param {String} oldText The old text
31746 "textchange" : true,
31748 * @event beforeexpand
31749 * Fires before this node is expanded, return false to cancel.
31750 * @param {Node} this This node
31751 * @param {Boolean} deep
31752 * @param {Boolean} anim
31754 "beforeexpand" : true,
31756 * @event beforecollapse
31757 * Fires before this node is collapsed, return false to cancel.
31758 * @param {Node} this This node
31759 * @param {Boolean} deep
31760 * @param {Boolean} anim
31762 "beforecollapse" : true,
31765 * Fires when this node is expanded
31766 * @param {Node} this This node
31770 * @event disabledchange
31771 * Fires when the disabled status of this node changes
31772 * @param {Node} this This node
31773 * @param {Boolean} disabled
31775 "disabledchange" : true,
31778 * Fires when this node is collapsed
31779 * @param {Node} this This node
31783 * @event beforeclick
31784 * Fires before click processing. Return false to cancel the default action.
31785 * @param {Node} this This node
31786 * @param {Roo.EventObject} e The event object
31788 "beforeclick":true,
31790 * @event checkchange
31791 * Fires when a node with a checkbox's checked property changes
31792 * @param {Node} this This node
31793 * @param {Boolean} checked
31795 "checkchange":true,
31798 * Fires when this node is clicked
31799 * @param {Node} this This node
31800 * @param {Roo.EventObject} e The event object
31805 * Fires when this node is double clicked
31806 * @param {Node} this This node
31807 * @param {Roo.EventObject} e The event object
31811 * @event contextmenu
31812 * Fires when this node is right clicked
31813 * @param {Node} this This node
31814 * @param {Roo.EventObject} e The event object
31816 "contextmenu":true,
31818 * @event beforechildrenrendered
31819 * Fires right before the child nodes for this node are rendered
31820 * @param {Node} this This node
31822 "beforechildrenrendered":true
31825 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31828 * Read-only. The UI for this node
31831 this.ui = new uiClass(this);
31833 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31834 preventHScroll: true,
31836 * Returns true if this node is expanded
31837 * @return {Boolean}
31839 isExpanded : function(){
31840 return this.expanded;
31844 * Returns the UI object for this node
31845 * @return {TreeNodeUI}
31847 getUI : function(){
31851 // private override
31852 setFirstChild : function(node){
31853 var of = this.firstChild;
31854 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31855 if(this.childrenRendered && of && node != of){
31856 of.renderIndent(true, true);
31859 this.renderIndent(true, true);
31863 // private override
31864 setLastChild : function(node){
31865 var ol = this.lastChild;
31866 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31867 if(this.childrenRendered && ol && node != ol){
31868 ol.renderIndent(true, true);
31871 this.renderIndent(true, true);
31875 // these methods are overridden to provide lazy rendering support
31876 // private override
31877 appendChild : function(){
31878 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31879 if(node && this.childrenRendered){
31882 this.ui.updateExpandIcon();
31886 // private override
31887 removeChild : function(node){
31888 this.ownerTree.getSelectionModel().unselect(node);
31889 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31890 // if it's been rendered remove dom node
31891 if(this.childrenRendered){
31894 if(this.childNodes.length < 1){
31895 this.collapse(false, false);
31897 this.ui.updateExpandIcon();
31899 if(!this.firstChild) {
31900 this.childrenRendered = false;
31905 // private override
31906 insertBefore : function(node, refNode){
31907 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31908 if(newNode && refNode && this.childrenRendered){
31911 this.ui.updateExpandIcon();
31916 * Sets the text for this node
31917 * @param {String} text
31919 setText : function(text){
31920 var oldText = this.text;
31922 this.attributes.text = text;
31923 if(this.rendered){ // event without subscribing
31924 this.ui.onTextChange(this, text, oldText);
31926 this.fireEvent("textchange", this, text, oldText);
31930 * Triggers selection of this node
31932 select : function(){
31933 this.getOwnerTree().getSelectionModel().select(this);
31937 * Triggers deselection of this node
31939 unselect : function(){
31940 this.getOwnerTree().getSelectionModel().unselect(this);
31944 * Returns true if this node is selected
31945 * @return {Boolean}
31947 isSelected : function(){
31948 return this.getOwnerTree().getSelectionModel().isSelected(this);
31952 * Expand this node.
31953 * @param {Boolean} deep (optional) True to expand all children as well
31954 * @param {Boolean} anim (optional) false to cancel the default animation
31955 * @param {Function} callback (optional) A callback to be called when
31956 * expanding this node completes (does not wait for deep expand to complete).
31957 * Called with 1 parameter, this node.
31959 expand : function(deep, anim, callback){
31960 if(!this.expanded){
31961 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31964 if(!this.childrenRendered){
31965 this.renderChildren();
31967 this.expanded = true;
31968 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31969 this.ui.animExpand(function(){
31970 this.fireEvent("expand", this);
31971 if(typeof callback == "function"){
31975 this.expandChildNodes(true);
31977 }.createDelegate(this));
31981 this.fireEvent("expand", this);
31982 if(typeof callback == "function"){
31987 if(typeof callback == "function"){
31992 this.expandChildNodes(true);
31996 isHiddenRoot : function(){
31997 return this.isRoot && !this.getOwnerTree().rootVisible;
32001 * Collapse this node.
32002 * @param {Boolean} deep (optional) True to collapse all children as well
32003 * @param {Boolean} anim (optional) false to cancel the default animation
32005 collapse : function(deep, anim){
32006 if(this.expanded && !this.isHiddenRoot()){
32007 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
32010 this.expanded = false;
32011 if((this.getOwnerTree().animate && anim !== false) || anim){
32012 this.ui.animCollapse(function(){
32013 this.fireEvent("collapse", this);
32015 this.collapseChildNodes(true);
32017 }.createDelegate(this));
32020 this.ui.collapse();
32021 this.fireEvent("collapse", this);
32025 var cs = this.childNodes;
32026 for(var i = 0, len = cs.length; i < len; i++) {
32027 cs[i].collapse(true, false);
32033 delayedExpand : function(delay){
32034 if(!this.expandProcId){
32035 this.expandProcId = this.expand.defer(delay, this);
32040 cancelExpand : function(){
32041 if(this.expandProcId){
32042 clearTimeout(this.expandProcId);
32044 this.expandProcId = false;
32048 * Toggles expanded/collapsed state of the node
32050 toggle : function(){
32059 * Ensures all parent nodes are expanded
32061 ensureVisible : function(callback){
32062 var tree = this.getOwnerTree();
32063 tree.expandPath(this.parentNode.getPath(), false, function(){
32064 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
32065 Roo.callback(callback);
32066 }.createDelegate(this));
32070 * Expand all child nodes
32071 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
32073 expandChildNodes : function(deep){
32074 var cs = this.childNodes;
32075 for(var i = 0, len = cs.length; i < len; i++) {
32076 cs[i].expand(deep);
32081 * Collapse all child nodes
32082 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
32084 collapseChildNodes : function(deep){
32085 var cs = this.childNodes;
32086 for(var i = 0, len = cs.length; i < len; i++) {
32087 cs[i].collapse(deep);
32092 * Disables this node
32094 disable : function(){
32095 this.disabled = true;
32097 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32098 this.ui.onDisableChange(this, true);
32100 this.fireEvent("disabledchange", this, true);
32104 * Enables this node
32106 enable : function(){
32107 this.disabled = false;
32108 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32109 this.ui.onDisableChange(this, false);
32111 this.fireEvent("disabledchange", this, false);
32115 renderChildren : function(suppressEvent){
32116 if(suppressEvent !== false){
32117 this.fireEvent("beforechildrenrendered", this);
32119 var cs = this.childNodes;
32120 for(var i = 0, len = cs.length; i < len; i++){
32121 cs[i].render(true);
32123 this.childrenRendered = true;
32127 sort : function(fn, scope){
32128 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32129 if(this.childrenRendered){
32130 var cs = this.childNodes;
32131 for(var i = 0, len = cs.length; i < len; i++){
32132 cs[i].render(true);
32138 render : function(bulkRender){
32139 this.ui.render(bulkRender);
32140 if(!this.rendered){
32141 this.rendered = true;
32143 this.expanded = false;
32144 this.expand(false, false);
32150 renderIndent : function(deep, refresh){
32152 this.ui.childIndent = null;
32154 this.ui.renderIndent();
32155 if(deep === true && this.childrenRendered){
32156 var cs = this.childNodes;
32157 for(var i = 0, len = cs.length; i < len; i++){
32158 cs[i].renderIndent(true, refresh);
32164 * Ext JS Library 1.1.1
32165 * Copyright(c) 2006-2007, Ext JS, LLC.
32167 * Originally Released Under LGPL - original licence link has changed is not relivant.
32170 * <script type="text/javascript">
32174 * @class Roo.tree.AsyncTreeNode
32175 * @extends Roo.tree.TreeNode
32176 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32178 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32180 Roo.tree.AsyncTreeNode = function(config){
32181 this.loaded = false;
32182 this.loading = false;
32183 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32185 * @event beforeload
32186 * Fires before this node is loaded, return false to cancel
32187 * @param {Node} this This node
32189 this.addEvents({'beforeload':true, 'load': true});
32192 * Fires when this node is loaded
32193 * @param {Node} this This node
32196 * The loader used by this node (defaults to using the tree's defined loader)
32201 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32202 expand : function(deep, anim, callback){
32203 if(this.loading){ // if an async load is already running, waiting til it's done
32205 var f = function(){
32206 if(!this.loading){ // done loading
32207 clearInterval(timer);
32208 this.expand(deep, anim, callback);
32210 }.createDelegate(this);
32211 timer = setInterval(f, 200);
32215 if(this.fireEvent("beforeload", this) === false){
32218 this.loading = true;
32219 this.ui.beforeLoad(this);
32220 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32222 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32226 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32230 * Returns true if this node is currently loading
32231 * @return {Boolean}
32233 isLoading : function(){
32234 return this.loading;
32237 loadComplete : function(deep, anim, callback){
32238 this.loading = false;
32239 this.loaded = true;
32240 this.ui.afterLoad(this);
32241 this.fireEvent("load", this);
32242 this.expand(deep, anim, callback);
32246 * Returns true if this node has been loaded
32247 * @return {Boolean}
32249 isLoaded : function(){
32250 return this.loaded;
32253 hasChildNodes : function(){
32254 if(!this.isLeaf() && !this.loaded){
32257 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32262 * Trigger a reload for this node
32263 * @param {Function} callback
32265 reload : function(callback){
32266 this.collapse(false, false);
32267 while(this.firstChild){
32268 this.removeChild(this.firstChild);
32270 this.childrenRendered = false;
32271 this.loaded = false;
32272 if(this.isHiddenRoot()){
32273 this.expanded = false;
32275 this.expand(false, false, callback);
32279 * Ext JS Library 1.1.1
32280 * Copyright(c) 2006-2007, Ext JS, LLC.
32282 * Originally Released Under LGPL - original licence link has changed is not relivant.
32285 * <script type="text/javascript">
32289 * @class Roo.tree.TreeNodeUI
32291 * @param {Object} node The node to render
32292 * The TreeNode UI implementation is separate from the
32293 * tree implementation. Unless you are customizing the tree UI,
32294 * you should never have to use this directly.
32296 Roo.tree.TreeNodeUI = function(node){
32298 this.rendered = false;
32299 this.animating = false;
32300 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32303 Roo.tree.TreeNodeUI.prototype = {
32304 removeChild : function(node){
32306 this.ctNode.removeChild(node.ui.getEl());
32310 beforeLoad : function(){
32311 this.addClass("x-tree-node-loading");
32314 afterLoad : function(){
32315 this.removeClass("x-tree-node-loading");
32318 onTextChange : function(node, text, oldText){
32320 this.textNode.innerHTML = text;
32324 onDisableChange : function(node, state){
32325 this.disabled = state;
32327 this.addClass("x-tree-node-disabled");
32329 this.removeClass("x-tree-node-disabled");
32333 onSelectedChange : function(state){
32336 this.addClass("x-tree-selected");
32339 this.removeClass("x-tree-selected");
32343 onMove : function(tree, node, oldParent, newParent, index, refNode){
32344 this.childIndent = null;
32346 var targetNode = newParent.ui.getContainer();
32347 if(!targetNode){//target not rendered
32348 this.holder = document.createElement("div");
32349 this.holder.appendChild(this.wrap);
32352 var insertBefore = refNode ? refNode.ui.getEl() : null;
32354 targetNode.insertBefore(this.wrap, insertBefore);
32356 targetNode.appendChild(this.wrap);
32358 this.node.renderIndent(true);
32362 addClass : function(cls){
32364 Roo.fly(this.elNode).addClass(cls);
32368 removeClass : function(cls){
32370 Roo.fly(this.elNode).removeClass(cls);
32374 remove : function(){
32376 this.holder = document.createElement("div");
32377 this.holder.appendChild(this.wrap);
32381 fireEvent : function(){
32382 return this.node.fireEvent.apply(this.node, arguments);
32385 initEvents : function(){
32386 this.node.on("move", this.onMove, this);
32387 var E = Roo.EventManager;
32388 var a = this.anchor;
32390 var el = Roo.fly(a, '_treeui');
32392 if(Roo.isOpera){ // opera render bug ignores the CSS
32393 el.setStyle("text-decoration", "none");
32396 el.on("click", this.onClick, this);
32397 el.on("dblclick", this.onDblClick, this);
32400 Roo.EventManager.on(this.checkbox,
32401 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32404 el.on("contextmenu", this.onContextMenu, this);
32406 var icon = Roo.fly(this.iconNode);
32407 icon.on("click", this.onClick, this);
32408 icon.on("dblclick", this.onDblClick, this);
32409 icon.on("contextmenu", this.onContextMenu, this);
32410 E.on(this.ecNode, "click", this.ecClick, this, true);
32412 if(this.node.disabled){
32413 this.addClass("x-tree-node-disabled");
32415 if(this.node.hidden){
32416 this.addClass("x-tree-node-disabled");
32418 var ot = this.node.getOwnerTree();
32419 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32420 if(dd && (!this.node.isRoot || ot.rootVisible)){
32421 Roo.dd.Registry.register(this.elNode, {
32423 handles: this.getDDHandles(),
32429 getDDHandles : function(){
32430 return [this.iconNode, this.textNode];
32435 this.wrap.style.display = "none";
32441 this.wrap.style.display = "";
32445 onContextMenu : function(e){
32446 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32447 e.preventDefault();
32449 this.fireEvent("contextmenu", this.node, e);
32453 onClick : function(e){
32458 if(this.fireEvent("beforeclick", this.node, e) !== false){
32459 if(!this.disabled && this.node.attributes.href){
32460 this.fireEvent("click", this.node, e);
32463 e.preventDefault();
32468 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32469 this.node.toggle();
32472 this.fireEvent("click", this.node, e);
32478 onDblClick : function(e){
32479 e.preventDefault();
32484 this.toggleCheck();
32486 if(!this.animating && this.node.hasChildNodes()){
32487 this.node.toggle();
32489 this.fireEvent("dblclick", this.node, e);
32492 onCheckChange : function(){
32493 var checked = this.checkbox.checked;
32494 this.node.attributes.checked = checked;
32495 this.fireEvent('checkchange', this.node, checked);
32498 ecClick : function(e){
32499 if(!this.animating && this.node.hasChildNodes()){
32500 this.node.toggle();
32504 startDrop : function(){
32505 this.dropping = true;
32508 // delayed drop so the click event doesn't get fired on a drop
32509 endDrop : function(){
32510 setTimeout(function(){
32511 this.dropping = false;
32512 }.createDelegate(this), 50);
32515 expand : function(){
32516 this.updateExpandIcon();
32517 this.ctNode.style.display = "";
32520 focus : function(){
32521 if(!this.node.preventHScroll){
32522 try{this.anchor.focus();
32524 }else if(!Roo.isIE){
32526 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32527 var l = noscroll.scrollLeft;
32528 this.anchor.focus();
32529 noscroll.scrollLeft = l;
32534 toggleCheck : function(value){
32535 var cb = this.checkbox;
32537 cb.checked = (value === undefined ? !cb.checked : value);
32543 this.anchor.blur();
32547 animExpand : function(callback){
32548 var ct = Roo.get(this.ctNode);
32550 if(!this.node.hasChildNodes()){
32551 this.updateExpandIcon();
32552 this.ctNode.style.display = "";
32553 Roo.callback(callback);
32556 this.animating = true;
32557 this.updateExpandIcon();
32560 callback : function(){
32561 this.animating = false;
32562 Roo.callback(callback);
32565 duration: this.node.ownerTree.duration || .25
32569 highlight : function(){
32570 var tree = this.node.getOwnerTree();
32571 Roo.fly(this.wrap).highlight(
32572 tree.hlColor || "C3DAF9",
32573 {endColor: tree.hlBaseColor}
32577 collapse : function(){
32578 this.updateExpandIcon();
32579 this.ctNode.style.display = "none";
32582 animCollapse : function(callback){
32583 var ct = Roo.get(this.ctNode);
32584 ct.enableDisplayMode('block');
32587 this.animating = true;
32588 this.updateExpandIcon();
32591 callback : function(){
32592 this.animating = false;
32593 Roo.callback(callback);
32596 duration: this.node.ownerTree.duration || .25
32600 getContainer : function(){
32601 return this.ctNode;
32604 getEl : function(){
32608 appendDDGhost : function(ghostNode){
32609 ghostNode.appendChild(this.elNode.cloneNode(true));
32612 getDDRepairXY : function(){
32613 return Roo.lib.Dom.getXY(this.iconNode);
32616 onRender : function(){
32620 render : function(bulkRender){
32621 var n = this.node, a = n.attributes;
32622 var targetNode = n.parentNode ?
32623 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32625 if(!this.rendered){
32626 this.rendered = true;
32628 this.renderElements(n, a, targetNode, bulkRender);
32631 if(this.textNode.setAttributeNS){
32632 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32634 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32637 this.textNode.setAttribute("ext:qtip", a.qtip);
32639 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32642 }else if(a.qtipCfg){
32643 a.qtipCfg.target = Roo.id(this.textNode);
32644 Roo.QuickTips.register(a.qtipCfg);
32647 if(!this.node.expanded){
32648 this.updateExpandIcon();
32651 if(bulkRender === true) {
32652 targetNode.appendChild(this.wrap);
32657 renderElements : function(n, a, targetNode, bulkRender)
32659 // add some indent caching, this helps performance when rendering a large tree
32660 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32661 var t = n.getOwnerTree();
32662 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32663 if (typeof(n.attributes.html) != 'undefined') {
32664 txt = n.attributes.html;
32666 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32667 var cb = typeof a.checked == 'boolean';
32668 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32669 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32670 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32671 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32672 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32673 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32674 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32675 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32676 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32677 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32680 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32681 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32682 n.nextSibling.ui.getEl(), buf.join(""));
32684 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32687 this.elNode = this.wrap.childNodes[0];
32688 this.ctNode = this.wrap.childNodes[1];
32689 var cs = this.elNode.childNodes;
32690 this.indentNode = cs[0];
32691 this.ecNode = cs[1];
32692 this.iconNode = cs[2];
32695 this.checkbox = cs[3];
32698 this.anchor = cs[index];
32699 this.textNode = cs[index].firstChild;
32702 getAnchor : function(){
32703 return this.anchor;
32706 getTextEl : function(){
32707 return this.textNode;
32710 getIconEl : function(){
32711 return this.iconNode;
32714 isChecked : function(){
32715 return this.checkbox ? this.checkbox.checked : false;
32718 updateExpandIcon : function(){
32720 var n = this.node, c1, c2;
32721 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32722 var hasChild = n.hasChildNodes();
32726 c1 = "x-tree-node-collapsed";
32727 c2 = "x-tree-node-expanded";
32730 c1 = "x-tree-node-expanded";
32731 c2 = "x-tree-node-collapsed";
32734 this.removeClass("x-tree-node-leaf");
32735 this.wasLeaf = false;
32737 if(this.c1 != c1 || this.c2 != c2){
32738 Roo.fly(this.elNode).replaceClass(c1, c2);
32739 this.c1 = c1; this.c2 = c2;
32742 // this changes non-leafs into leafs if they have no children.
32743 // it's not very rational behaviour..
32745 if(!this.wasLeaf && this.node.leaf){
32746 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32749 this.wasLeaf = true;
32752 var ecc = "x-tree-ec-icon "+cls;
32753 if(this.ecc != ecc){
32754 this.ecNode.className = ecc;
32760 getChildIndent : function(){
32761 if(!this.childIndent){
32765 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32767 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32769 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32774 this.childIndent = buf.join("");
32776 return this.childIndent;
32779 renderIndent : function(){
32782 var p = this.node.parentNode;
32784 indent = p.ui.getChildIndent();
32786 if(this.indentMarkup != indent){ // don't rerender if not required
32787 this.indentNode.innerHTML = indent;
32788 this.indentMarkup = indent;
32790 this.updateExpandIcon();
32795 Roo.tree.RootTreeNodeUI = function(){
32796 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32798 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32799 render : function(){
32800 if(!this.rendered){
32801 var targetNode = this.node.ownerTree.innerCt.dom;
32802 this.node.expanded = true;
32803 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32804 this.wrap = this.ctNode = targetNode.firstChild;
32807 collapse : function(){
32809 expand : function(){
32813 * Ext JS Library 1.1.1
32814 * Copyright(c) 2006-2007, Ext JS, LLC.
32816 * Originally Released Under LGPL - original licence link has changed is not relivant.
32819 * <script type="text/javascript">
32822 * @class Roo.tree.TreeLoader
32823 * @extends Roo.util.Observable
32824 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32825 * nodes from a specified URL. The response must be a javascript Array definition
32826 * who's elements are node definition objects. eg:
32828 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32829 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32832 * A server request is sent, and child nodes are loaded only when a node is expanded.
32833 * The loading node's id is passed to the server under the parameter name "node" to
32834 * enable the server to produce the correct child nodes.
32836 * To pass extra parameters, an event handler may be attached to the "beforeload"
32837 * event, and the parameters specified in the TreeLoader's baseParams property:
32839 myTreeLoader.on("beforeload", function(treeLoader, node) {
32840 this.baseParams.category = node.attributes.category;
32843 * This would pass an HTTP parameter called "category" to the server containing
32844 * the value of the Node's "category" attribute.
32846 * Creates a new Treeloader.
32847 * @param {Object} config A config object containing config properties.
32849 Roo.tree.TreeLoader = function(config){
32850 this.baseParams = {};
32851 this.requestMethod = "POST";
32852 Roo.apply(this, config);
32857 * @event beforeload
32858 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32859 * @param {Object} This TreeLoader object.
32860 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32861 * @param {Object} callback The callback function specified in the {@link #load} call.
32866 * Fires when the node has been successfuly loaded.
32867 * @param {Object} This TreeLoader object.
32868 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32869 * @param {Object} response The response object containing the data from the server.
32873 * @event loadexception
32874 * Fires if the network request failed.
32875 * @param {Object} This TreeLoader object.
32876 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32877 * @param {Object} response The response object containing the data from the server.
32879 loadexception : true,
32882 * Fires before a node is created, enabling you to return custom Node types
32883 * @param {Object} This TreeLoader object.
32884 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32889 Roo.tree.TreeLoader.superclass.constructor.call(this);
32892 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32894 * @cfg {String} dataUrl The URL from which to request a Json string which
32895 * specifies an array of node definition object representing the child nodes
32899 * @cfg {Object} baseParams (optional) An object containing properties which
32900 * specify HTTP parameters to be passed to each request for child nodes.
32903 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32904 * created by this loader. If the attributes sent by the server have an attribute in this object,
32905 * they take priority.
32908 * @cfg {Object} uiProviders (optional) An object containing properties which
32910 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
32911 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32912 * <i>uiProvider</i> attribute of a returned child node is a string rather
32913 * than a reference to a TreeNodeUI implementation, this that string value
32914 * is used as a property name in the uiProviders object. You can define the provider named
32915 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32920 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32921 * child nodes before loading.
32923 clearOnLoad : true,
32926 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32927 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32928 * Grid query { data : [ .....] }
32933 * @cfg {String} queryParam (optional)
32934 * Name of the query as it will be passed on the querystring (defaults to 'node')
32935 * eg. the request will be ?node=[id]
32942 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32943 * This is called automatically when a node is expanded, but may be used to reload
32944 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32945 * @param {Roo.tree.TreeNode} node
32946 * @param {Function} callback
32948 load : function(node, callback){
32949 if(this.clearOnLoad){
32950 while(node.firstChild){
32951 node.removeChild(node.firstChild);
32954 if(node.attributes.children){ // preloaded json children
32955 var cs = node.attributes.children;
32956 for(var i = 0, len = cs.length; i < len; i++){
32957 node.appendChild(this.createNode(cs[i]));
32959 if(typeof callback == "function"){
32962 }else if(this.dataUrl){
32963 this.requestData(node, callback);
32967 getParams: function(node){
32968 var buf = [], bp = this.baseParams;
32969 for(var key in bp){
32970 if(typeof bp[key] != "function"){
32971 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32974 var n = this.queryParam === false ? 'node' : this.queryParam;
32975 buf.push(n + "=", encodeURIComponent(node.id));
32976 return buf.join("");
32979 requestData : function(node, callback){
32980 if(this.fireEvent("beforeload", this, node, callback) !== false){
32981 this.transId = Roo.Ajax.request({
32982 method:this.requestMethod,
32983 url: this.dataUrl||this.url,
32984 success: this.handleResponse,
32985 failure: this.handleFailure,
32987 argument: {callback: callback, node: node},
32988 params: this.getParams(node)
32991 // if the load is cancelled, make sure we notify
32992 // the node that we are done
32993 if(typeof callback == "function"){
32999 isLoading : function(){
33000 return this.transId ? true : false;
33003 abort : function(){
33004 if(this.isLoading()){
33005 Roo.Ajax.abort(this.transId);
33010 createNode : function(attr)
33012 // apply baseAttrs, nice idea Corey!
33013 if(this.baseAttrs){
33014 Roo.applyIf(attr, this.baseAttrs);
33016 if(this.applyLoader !== false){
33017 attr.loader = this;
33019 // uiProvider = depreciated..
33021 if(typeof(attr.uiProvider) == 'string'){
33022 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
33023 /** eval:var:attr */ eval(attr.uiProvider);
33025 if(typeof(this.uiProviders['default']) != 'undefined') {
33026 attr.uiProvider = this.uiProviders['default'];
33029 this.fireEvent('create', this, attr);
33031 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
33033 new Roo.tree.TreeNode(attr) :
33034 new Roo.tree.AsyncTreeNode(attr));
33037 processResponse : function(response, node, callback)
33039 var json = response.responseText;
33042 var o = Roo.decode(json);
33045 // it's a failure condition.
33046 var a = response.argument;
33047 this.fireEvent("loadexception", this, a.node, response);
33048 Roo.log("Load failed - should have a handler really");
33052 if (this.root !== false) {
33056 for(var i = 0, len = o.length; i < len; i++){
33057 var n = this.createNode(o[i]);
33059 node.appendChild(n);
33062 if(typeof callback == "function"){
33063 callback(this, node);
33066 this.handleFailure(response);
33070 handleResponse : function(response){
33071 this.transId = false;
33072 var a = response.argument;
33073 this.processResponse(response, a.node, a.callback);
33074 this.fireEvent("load", this, a.node, response);
33077 handleFailure : function(response)
33079 // should handle failure better..
33080 this.transId = false;
33081 var a = response.argument;
33082 this.fireEvent("loadexception", this, a.node, response);
33083 if(typeof a.callback == "function"){
33084 a.callback(this, a.node);
33089 * Ext JS Library 1.1.1
33090 * Copyright(c) 2006-2007, Ext JS, LLC.
33092 * Originally Released Under LGPL - original licence link has changed is not relivant.
33095 * <script type="text/javascript">
33099 * @class Roo.tree.TreeFilter
33100 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
33101 * @param {TreePanel} tree
33102 * @param {Object} config (optional)
33104 Roo.tree.TreeFilter = function(tree, config){
33106 this.filtered = {};
33107 Roo.apply(this, config);
33110 Roo.tree.TreeFilter.prototype = {
33117 * Filter the data by a specific attribute.
33118 * @param {String/RegExp} value Either string that the attribute value
33119 * should start with or a RegExp to test against the attribute
33120 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
33121 * @param {TreeNode} startNode (optional) The node to start the filter at.
33123 filter : function(value, attr, startNode){
33124 attr = attr || "text";
33126 if(typeof value == "string"){
33127 var vlen = value.length;
33128 // auto clear empty filter
33129 if(vlen == 0 && this.clearBlank){
33133 value = value.toLowerCase();
33135 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
33137 }else if(value.exec){ // regex?
33139 return value.test(n.attributes[attr]);
33142 throw 'Illegal filter type, must be string or regex';
33144 this.filterBy(f, null, startNode);
33148 * Filter by a function. The passed function will be called with each
33149 * node in the tree (or from the startNode). If the function returns true, the node is kept
33150 * otherwise it is filtered. If a node is filtered, its children are also filtered.
33151 * @param {Function} fn The filter function
33152 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33154 filterBy : function(fn, scope, startNode){
33155 startNode = startNode || this.tree.root;
33156 if(this.autoClear){
33159 var af = this.filtered, rv = this.reverse;
33160 var f = function(n){
33161 if(n == startNode){
33167 var m = fn.call(scope || n, n);
33175 startNode.cascade(f);
33178 if(typeof id != "function"){
33180 if(n && n.parentNode){
33181 n.parentNode.removeChild(n);
33189 * Clears the current filter. Note: with the "remove" option
33190 * set a filter cannot be cleared.
33192 clear : function(){
33194 var af = this.filtered;
33196 if(typeof id != "function"){
33203 this.filtered = {};
33208 * Ext JS Library 1.1.1
33209 * Copyright(c) 2006-2007, Ext JS, LLC.
33211 * Originally Released Under LGPL - original licence link has changed is not relivant.
33214 * <script type="text/javascript">
33219 * @class Roo.tree.TreeSorter
33220 * Provides sorting of nodes in a TreePanel
33222 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33223 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33224 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33225 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33226 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33227 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33229 * @param {TreePanel} tree
33230 * @param {Object} config
33232 Roo.tree.TreeSorter = function(tree, config){
33233 Roo.apply(this, config);
33234 tree.on("beforechildrenrendered", this.doSort, this);
33235 tree.on("append", this.updateSort, this);
33236 tree.on("insert", this.updateSort, this);
33238 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33239 var p = this.property || "text";
33240 var sortType = this.sortType;
33241 var fs = this.folderSort;
33242 var cs = this.caseSensitive === true;
33243 var leafAttr = this.leafAttr || 'leaf';
33245 this.sortFn = function(n1, n2){
33247 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33250 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33254 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33255 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33257 return dsc ? +1 : -1;
33259 return dsc ? -1 : +1;
33266 Roo.tree.TreeSorter.prototype = {
33267 doSort : function(node){
33268 node.sort(this.sortFn);
33271 compareNodes : function(n1, n2){
33272 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33275 updateSort : function(tree, node){
33276 if(node.childrenRendered){
33277 this.doSort.defer(1, this, [node]);
33282 * Ext JS Library 1.1.1
33283 * Copyright(c) 2006-2007, Ext JS, LLC.
33285 * Originally Released Under LGPL - original licence link has changed is not relivant.
33288 * <script type="text/javascript">
33291 if(Roo.dd.DropZone){
33293 Roo.tree.TreeDropZone = function(tree, config){
33294 this.allowParentInsert = false;
33295 this.allowContainerDrop = false;
33296 this.appendOnly = false;
33297 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33299 this.lastInsertClass = "x-tree-no-status";
33300 this.dragOverData = {};
33303 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33304 ddGroup : "TreeDD",
33306 expandDelay : 1000,
33308 expandNode : function(node){
33309 if(node.hasChildNodes() && !node.isExpanded()){
33310 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33314 queueExpand : function(node){
33315 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33318 cancelExpand : function(){
33319 if(this.expandProcId){
33320 clearTimeout(this.expandProcId);
33321 this.expandProcId = false;
33325 isValidDropPoint : function(n, pt, dd, e, data){
33326 if(!n || !data){ return false; }
33327 var targetNode = n.node;
33328 var dropNode = data.node;
33329 // default drop rules
33330 if(!(targetNode && targetNode.isTarget && pt)){
33333 if(pt == "append" && targetNode.allowChildren === false){
33336 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33339 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33342 // reuse the object
33343 var overEvent = this.dragOverData;
33344 overEvent.tree = this.tree;
33345 overEvent.target = targetNode;
33346 overEvent.data = data;
33347 overEvent.point = pt;
33348 overEvent.source = dd;
33349 overEvent.rawEvent = e;
33350 overEvent.dropNode = dropNode;
33351 overEvent.cancel = false;
33352 var result = this.tree.fireEvent("nodedragover", overEvent);
33353 return overEvent.cancel === false && result !== false;
33356 getDropPoint : function(e, n, dd){
33359 return tn.allowChildren !== false ? "append" : false; // always append for root
33361 var dragEl = n.ddel;
33362 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33363 var y = Roo.lib.Event.getPageY(e);
33364 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33366 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33367 var noAppend = tn.allowChildren === false;
33368 if(this.appendOnly || tn.parentNode.allowChildren === false){
33369 return noAppend ? false : "append";
33371 var noBelow = false;
33372 if(!this.allowParentInsert){
33373 noBelow = tn.hasChildNodes() && tn.isExpanded();
33375 var q = (b - t) / (noAppend ? 2 : 3);
33376 if(y >= t && y < (t + q)){
33378 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33385 onNodeEnter : function(n, dd, e, data){
33386 this.cancelExpand();
33389 onNodeOver : function(n, dd, e, data){
33390 var pt = this.getDropPoint(e, n, dd);
33393 // auto node expand check
33394 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33395 this.queueExpand(node);
33396 }else if(pt != "append"){
33397 this.cancelExpand();
33400 // set the insert point style on the target node
33401 var returnCls = this.dropNotAllowed;
33402 if(this.isValidDropPoint(n, pt, dd, e, data)){
33407 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33408 cls = "x-tree-drag-insert-above";
33409 }else if(pt == "below"){
33410 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33411 cls = "x-tree-drag-insert-below";
33413 returnCls = "x-tree-drop-ok-append";
33414 cls = "x-tree-drag-append";
33416 if(this.lastInsertClass != cls){
33417 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33418 this.lastInsertClass = cls;
33425 onNodeOut : function(n, dd, e, data){
33426 this.cancelExpand();
33427 this.removeDropIndicators(n);
33430 onNodeDrop : function(n, dd, e, data){
33431 var point = this.getDropPoint(e, n, dd);
33432 var targetNode = n.node;
33433 targetNode.ui.startDrop();
33434 if(!this.isValidDropPoint(n, point, dd, e, data)){
33435 targetNode.ui.endDrop();
33438 // first try to find the drop node
33439 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33442 target: targetNode,
33447 dropNode: dropNode,
33450 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33451 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33452 targetNode.ui.endDrop();
33455 // allow target changing
33456 targetNode = dropEvent.target;
33457 if(point == "append" && !targetNode.isExpanded()){
33458 targetNode.expand(false, null, function(){
33459 this.completeDrop(dropEvent);
33460 }.createDelegate(this));
33462 this.completeDrop(dropEvent);
33467 completeDrop : function(de){
33468 var ns = de.dropNode, p = de.point, t = de.target;
33469 if(!(ns instanceof Array)){
33473 for(var i = 0, len = ns.length; i < len; i++){
33476 t.parentNode.insertBefore(n, t);
33477 }else if(p == "below"){
33478 t.parentNode.insertBefore(n, t.nextSibling);
33484 if(this.tree.hlDrop){
33488 this.tree.fireEvent("nodedrop", de);
33491 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33492 if(this.tree.hlDrop){
33493 dropNode.ui.focus();
33494 dropNode.ui.highlight();
33496 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33499 getTree : function(){
33503 removeDropIndicators : function(n){
33506 Roo.fly(el).removeClass([
33507 "x-tree-drag-insert-above",
33508 "x-tree-drag-insert-below",
33509 "x-tree-drag-append"]);
33510 this.lastInsertClass = "_noclass";
33514 beforeDragDrop : function(target, e, id){
33515 this.cancelExpand();
33519 afterRepair : function(data){
33520 if(data && Roo.enableFx){
33521 data.node.ui.highlight();
33530 * Ext JS Library 1.1.1
33531 * Copyright(c) 2006-2007, Ext JS, LLC.
33533 * Originally Released Under LGPL - original licence link has changed is not relivant.
33536 * <script type="text/javascript">
33540 if(Roo.dd.DragZone){
33541 Roo.tree.TreeDragZone = function(tree, config){
33542 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33546 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33547 ddGroup : "TreeDD",
33549 onBeforeDrag : function(data, e){
33551 return n && n.draggable && !n.disabled;
33554 onInitDrag : function(e){
33555 var data = this.dragData;
33556 this.tree.getSelectionModel().select(data.node);
33557 this.proxy.update("");
33558 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33559 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33562 getRepairXY : function(e, data){
33563 return data.node.ui.getDDRepairXY();
33566 onEndDrag : function(data, e){
33567 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33570 onValidDrop : function(dd, e, id){
33571 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33575 beforeInvalidDrop : function(e, id){
33576 // this scrolls the original position back into view
33577 var sm = this.tree.getSelectionModel();
33578 sm.clearSelections();
33579 sm.select(this.dragData.node);
33584 * Ext JS Library 1.1.1
33585 * Copyright(c) 2006-2007, Ext JS, LLC.
33587 * Originally Released Under LGPL - original licence link has changed is not relivant.
33590 * <script type="text/javascript">
33593 * @class Roo.tree.TreeEditor
33594 * @extends Roo.Editor
33595 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33596 * as the editor field.
33598 * @param {Object} config (used to be the tree panel.)
33599 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33601 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
33602 * @cfg {Roo.form.TextField|Object} field The field configuration
33606 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
33609 if (oldconfig) { // old style..
33610 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
33613 tree = config.tree;
33614 config.field = config.field || {};
33615 config.field.xtype = 'TextField';
33616 field = Roo.factory(config.field, Roo.form);
33618 config = config || {};
33623 * @event beforenodeedit
33624 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
33625 * false from the handler of this event.
33626 * @param {Editor} this
33627 * @param {Roo.tree.Node} node
33629 "beforenodeedit" : true
33633 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
33637 tree.on('beforeclick', this.beforeNodeClick, this);
33638 tree.getTreeEl().on('mousedown', this.hide, this);
33639 this.on('complete', this.updateNode, this);
33640 this.on('beforestartedit', this.fitToTree, this);
33641 this.on('startedit', this.bindScroll, this, {delay:10});
33642 this.on('specialkey', this.onSpecialKey, this);
33645 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33647 * @cfg {String} alignment
33648 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33654 * @cfg {Boolean} hideEl
33655 * True to hide the bound element while the editor is displayed (defaults to false)
33659 * @cfg {String} cls
33660 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33662 cls: "x-small-editor x-tree-editor",
33664 * @cfg {Boolean} shim
33665 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33671 * @cfg {Number} maxWidth
33672 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33673 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33674 * scroll and client offsets into account prior to each edit.
33681 fitToTree : function(ed, el){
33682 var td = this.tree.getTreeEl().dom, nd = el.dom;
33683 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33684 td.scrollLeft = nd.offsetLeft;
33688 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33689 this.setSize(w, '');
33691 return this.fireEvent('beforenodeedit', this, this.editNode);
33696 triggerEdit : function(node){
33697 this.completeEdit();
33698 this.editNode = node;
33699 this.startEdit(node.ui.textNode, node.text);
33703 bindScroll : function(){
33704 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33708 beforeNodeClick : function(node, e){
33709 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33710 this.lastClick = new Date();
33711 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33713 this.triggerEdit(node);
33720 updateNode : function(ed, value){
33721 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33722 this.editNode.setText(value);
33726 onHide : function(){
33727 Roo.tree.TreeEditor.superclass.onHide.call(this);
33729 this.editNode.ui.focus();
33734 onSpecialKey : function(field, e){
33735 var k = e.getKey();
33739 }else if(k == e.ENTER && !e.hasModifier()){
33741 this.completeEdit();
33744 });//<Script type="text/javascript">
33747 * Ext JS Library 1.1.1
33748 * Copyright(c) 2006-2007, Ext JS, LLC.
33750 * Originally Released Under LGPL - original licence link has changed is not relivant.
33753 * <script type="text/javascript">
33757 * Not documented??? - probably should be...
33760 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33761 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33763 renderElements : function(n, a, targetNode, bulkRender){
33764 //consel.log("renderElements?");
33765 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33767 var t = n.getOwnerTree();
33768 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33770 var cols = t.columns;
33771 var bw = t.borderWidth;
33773 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33774 var cb = typeof a.checked == "boolean";
33775 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33776 var colcls = 'x-t-' + tid + '-c0';
33778 '<li class="x-tree-node">',
33781 '<div class="x-tree-node-el ', a.cls,'">',
33783 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33786 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33787 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33788 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33789 (a.icon ? ' x-tree-node-inline-icon' : ''),
33790 (a.iconCls ? ' '+a.iconCls : ''),
33791 '" unselectable="on" />',
33792 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33793 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33795 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33796 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33797 '<span unselectable="on" qtip="' + tx + '">',
33801 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33802 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33804 for(var i = 1, len = cols.length; i < len; i++){
33806 colcls = 'x-t-' + tid + '-c' +i;
33807 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33808 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33809 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33815 '<div class="x-clear"></div></div>',
33816 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33819 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33820 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33821 n.nextSibling.ui.getEl(), buf.join(""));
33823 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33825 var el = this.wrap.firstChild;
33827 this.elNode = el.firstChild;
33828 this.ranchor = el.childNodes[1];
33829 this.ctNode = this.wrap.childNodes[1];
33830 var cs = el.firstChild.childNodes;
33831 this.indentNode = cs[0];
33832 this.ecNode = cs[1];
33833 this.iconNode = cs[2];
33836 this.checkbox = cs[3];
33839 this.anchor = cs[index];
33841 this.textNode = cs[index].firstChild;
33843 //el.on("click", this.onClick, this);
33844 //el.on("dblclick", this.onDblClick, this);
33847 // console.log(this);
33849 initEvents : function(){
33850 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33853 var a = this.ranchor;
33855 var el = Roo.get(a);
33857 if(Roo.isOpera){ // opera render bug ignores the CSS
33858 el.setStyle("text-decoration", "none");
33861 el.on("click", this.onClick, this);
33862 el.on("dblclick", this.onDblClick, this);
33863 el.on("contextmenu", this.onContextMenu, this);
33867 /*onSelectedChange : function(state){
33870 this.addClass("x-tree-selected");
33873 this.removeClass("x-tree-selected");
33876 addClass : function(cls){
33878 Roo.fly(this.elRow).addClass(cls);
33884 removeClass : function(cls){
33886 Roo.fly(this.elRow).removeClass(cls);
33892 });//<Script type="text/javascript">
33896 * Ext JS Library 1.1.1
33897 * Copyright(c) 2006-2007, Ext JS, LLC.
33899 * Originally Released Under LGPL - original licence link has changed is not relivant.
33902 * <script type="text/javascript">
33907 * @class Roo.tree.ColumnTree
33908 * @extends Roo.data.TreePanel
33909 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33910 * @cfg {int} borderWidth compined right/left border allowance
33912 * @param {String/HTMLElement/Element} el The container element
33913 * @param {Object} config
33915 Roo.tree.ColumnTree = function(el, config)
33917 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33921 * Fire this event on a container when it resizes
33922 * @param {int} w Width
33923 * @param {int} h Height
33927 this.on('resize', this.onResize, this);
33930 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33934 borderWidth: Roo.isBorderBox ? 0 : 2,
33937 render : function(){
33938 // add the header.....
33940 Roo.tree.ColumnTree.superclass.render.apply(this);
33942 this.el.addClass('x-column-tree');
33944 this.headers = this.el.createChild(
33945 {cls:'x-tree-headers'},this.innerCt.dom);
33947 var cols = this.columns, c;
33948 var totalWidth = 0;
33950 var len = cols.length;
33951 for(var i = 0; i < len; i++){
33953 totalWidth += c.width;
33954 this.headEls.push(this.headers.createChild({
33955 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33957 cls:'x-tree-hd-text',
33960 style:'width:'+(c.width-this.borderWidth)+'px;'
33963 this.headers.createChild({cls:'x-clear'});
33964 // prevent floats from wrapping when clipped
33965 this.headers.setWidth(totalWidth);
33966 //this.innerCt.setWidth(totalWidth);
33967 this.innerCt.setStyle({ overflow: 'auto' });
33968 this.onResize(this.width, this.height);
33972 onResize : function(w,h)
33977 this.innerCt.setWidth(this.width);
33978 this.innerCt.setHeight(this.height-20);
33981 var cols = this.columns, c;
33982 var totalWidth = 0;
33984 var len = cols.length;
33985 for(var i = 0; i < len; i++){
33987 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33988 // it's the expander..
33989 expEl = this.headEls[i];
33992 totalWidth += c.width;
33996 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33998 this.headers.setWidth(w-20);
34007 * Ext JS Library 1.1.1
34008 * Copyright(c) 2006-2007, Ext JS, LLC.
34010 * Originally Released Under LGPL - original licence link has changed is not relivant.
34013 * <script type="text/javascript">
34017 * @class Roo.menu.Menu
34018 * @extends Roo.util.Observable
34019 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
34020 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
34022 * Creates a new Menu
34023 * @param {Object} config Configuration options
34025 Roo.menu.Menu = function(config){
34026 Roo.apply(this, config);
34027 this.id = this.id || Roo.id();
34030 * @event beforeshow
34031 * Fires before this menu is displayed
34032 * @param {Roo.menu.Menu} this
34036 * @event beforehide
34037 * Fires before this menu is hidden
34038 * @param {Roo.menu.Menu} this
34043 * Fires after this menu is displayed
34044 * @param {Roo.menu.Menu} this
34049 * Fires after this menu is hidden
34050 * @param {Roo.menu.Menu} this
34055 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
34056 * @param {Roo.menu.Menu} this
34057 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34058 * @param {Roo.EventObject} e
34063 * Fires when the mouse is hovering over this menu
34064 * @param {Roo.menu.Menu} this
34065 * @param {Roo.EventObject} e
34066 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34071 * Fires when the mouse exits this menu
34072 * @param {Roo.menu.Menu} this
34073 * @param {Roo.EventObject} e
34074 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34079 * Fires when a menu item contained in this menu is clicked
34080 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
34081 * @param {Roo.EventObject} e
34085 if (this.registerMenu) {
34086 Roo.menu.MenuMgr.register(this);
34089 var mis = this.items;
34090 this.items = new Roo.util.MixedCollection();
34092 this.add.apply(this, mis);
34096 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
34098 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
34102 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
34103 * for bottom-right shadow (defaults to "sides")
34107 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
34108 * this menu (defaults to "tl-tr?")
34110 subMenuAlign : "tl-tr?",
34112 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
34113 * relative to its element of origin (defaults to "tl-bl?")
34115 defaultAlign : "tl-bl?",
34117 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
34119 allowOtherMenus : false,
34121 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
34123 registerMenu : true,
34128 render : function(){
34132 var el = this.el = new Roo.Layer({
34134 shadow:this.shadow,
34136 parentEl: this.parentEl || document.body,
34140 this.keyNav = new Roo.menu.MenuNav(this);
34143 el.addClass("x-menu-plain");
34146 el.addClass(this.cls);
34148 // generic focus element
34149 this.focusEl = el.createChild({
34150 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
34152 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
34153 ul.on("click", this.onClick, this);
34154 ul.on("mouseover", this.onMouseOver, this);
34155 ul.on("mouseout", this.onMouseOut, this);
34156 this.items.each(function(item){
34157 var li = document.createElement("li");
34158 li.className = "x-menu-list-item";
34159 ul.dom.appendChild(li);
34160 item.render(li, this);
34167 autoWidth : function(){
34168 var el = this.el, ul = this.ul;
34172 var w = this.width;
34175 }else if(Roo.isIE){
34176 el.setWidth(this.minWidth);
34177 var t = el.dom.offsetWidth; // force recalc
34178 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34183 delayAutoWidth : function(){
34186 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
34188 this.awTask.delay(20);
34193 findTargetItem : function(e){
34194 var t = e.getTarget(".x-menu-list-item", this.ul, true);
34195 if(t && t.menuItemId){
34196 return this.items.get(t.menuItemId);
34201 onClick : function(e){
34203 if(t = this.findTargetItem(e)){
34205 this.fireEvent("click", this, t, e);
34210 setActiveItem : function(item, autoExpand){
34211 if(item != this.activeItem){
34212 if(this.activeItem){
34213 this.activeItem.deactivate();
34215 this.activeItem = item;
34216 item.activate(autoExpand);
34217 }else if(autoExpand){
34223 tryActivate : function(start, step){
34224 var items = this.items;
34225 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34226 var item = items.get(i);
34227 if(!item.disabled && item.canActivate){
34228 this.setActiveItem(item, false);
34236 onMouseOver : function(e){
34238 if(t = this.findTargetItem(e)){
34239 if(t.canActivate && !t.disabled){
34240 this.setActiveItem(t, true);
34243 this.fireEvent("mouseover", this, e, t);
34247 onMouseOut : function(e){
34249 if(t = this.findTargetItem(e)){
34250 if(t == this.activeItem && t.shouldDeactivate(e)){
34251 this.activeItem.deactivate();
34252 delete this.activeItem;
34255 this.fireEvent("mouseout", this, e, t);
34259 * Read-only. Returns true if the menu is currently displayed, else false.
34262 isVisible : function(){
34263 return this.el && !this.hidden;
34267 * Displays this menu relative to another element
34268 * @param {String/HTMLElement/Roo.Element} element The element to align to
34269 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34270 * the element (defaults to this.defaultAlign)
34271 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34273 show : function(el, pos, parentMenu){
34274 this.parentMenu = parentMenu;
34278 this.fireEvent("beforeshow", this);
34279 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34283 * Displays this menu at a specific xy position
34284 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34285 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34287 showAt : function(xy, parentMenu, /* private: */_e){
34288 this.parentMenu = parentMenu;
34293 this.fireEvent("beforeshow", this);
34294 xy = this.el.adjustForConstraints(xy);
34298 this.hidden = false;
34300 this.fireEvent("show", this);
34303 focus : function(){
34305 this.doFocus.defer(50, this);
34309 doFocus : function(){
34311 this.focusEl.focus();
34316 * Hides this menu and optionally all parent menus
34317 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34319 hide : function(deep){
34320 if(this.el && this.isVisible()){
34321 this.fireEvent("beforehide", this);
34322 if(this.activeItem){
34323 this.activeItem.deactivate();
34324 this.activeItem = null;
34327 this.hidden = true;
34328 this.fireEvent("hide", this);
34330 if(deep === true && this.parentMenu){
34331 this.parentMenu.hide(true);
34336 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34337 * Any of the following are valid:
34339 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34340 * <li>An HTMLElement object which will be converted to a menu item</li>
34341 * <li>A menu item config object that will be created as a new menu item</li>
34342 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34343 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34348 var menu = new Roo.menu.Menu();
34350 // Create a menu item to add by reference
34351 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34353 // Add a bunch of items at once using different methods.
34354 // Only the last item added will be returned.
34355 var item = menu.add(
34356 menuItem, // add existing item by ref
34357 'Dynamic Item', // new TextItem
34358 '-', // new separator
34359 { text: 'Config Item' } // new item by config
34362 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34363 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34366 var a = arguments, l = a.length, item;
34367 for(var i = 0; i < l; i++){
34369 if ((typeof(el) == "object") && el.xtype && el.xns) {
34370 el = Roo.factory(el, Roo.menu);
34373 if(el.render){ // some kind of Item
34374 item = this.addItem(el);
34375 }else if(typeof el == "string"){ // string
34376 if(el == "separator" || el == "-"){
34377 item = this.addSeparator();
34379 item = this.addText(el);
34381 }else if(el.tagName || el.el){ // element
34382 item = this.addElement(el);
34383 }else if(typeof el == "object"){ // must be menu item config?
34384 item = this.addMenuItem(el);
34391 * Returns this menu's underlying {@link Roo.Element} object
34392 * @return {Roo.Element} The element
34394 getEl : function(){
34402 * Adds a separator bar to the menu
34403 * @return {Roo.menu.Item} The menu item that was added
34405 addSeparator : function(){
34406 return this.addItem(new Roo.menu.Separator());
34410 * Adds an {@link Roo.Element} object to the menu
34411 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34412 * @return {Roo.menu.Item} The menu item that was added
34414 addElement : function(el){
34415 return this.addItem(new Roo.menu.BaseItem(el));
34419 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34420 * @param {Roo.menu.Item} item The menu item to add
34421 * @return {Roo.menu.Item} The menu item that was added
34423 addItem : function(item){
34424 this.items.add(item);
34426 var li = document.createElement("li");
34427 li.className = "x-menu-list-item";
34428 this.ul.dom.appendChild(li);
34429 item.render(li, this);
34430 this.delayAutoWidth();
34436 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34437 * @param {Object} config A MenuItem config object
34438 * @return {Roo.menu.Item} The menu item that was added
34440 addMenuItem : function(config){
34441 if(!(config instanceof Roo.menu.Item)){
34442 if(typeof config.checked == "boolean"){ // must be check menu item config?
34443 config = new Roo.menu.CheckItem(config);
34445 config = new Roo.menu.Item(config);
34448 return this.addItem(config);
34452 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34453 * @param {String} text The text to display in the menu item
34454 * @return {Roo.menu.Item} The menu item that was added
34456 addText : function(text){
34457 return this.addItem(new Roo.menu.TextItem({ text : text }));
34461 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34462 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34463 * @param {Roo.menu.Item} item The menu item to add
34464 * @return {Roo.menu.Item} The menu item that was added
34466 insert : function(index, item){
34467 this.items.insert(index, item);
34469 var li = document.createElement("li");
34470 li.className = "x-menu-list-item";
34471 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34472 item.render(li, this);
34473 this.delayAutoWidth();
34479 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34480 * @param {Roo.menu.Item} item The menu item to remove
34482 remove : function(item){
34483 this.items.removeKey(item.id);
34488 * Removes and destroys all items in the menu
34490 removeAll : function(){
34492 while(f = this.items.first()){
34498 // MenuNav is a private utility class used internally by the Menu
34499 Roo.menu.MenuNav = function(menu){
34500 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34501 this.scope = this.menu = menu;
34504 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34505 doRelay : function(e, h){
34506 var k = e.getKey();
34507 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34508 this.menu.tryActivate(0, 1);
34511 return h.call(this.scope || this, e, this.menu);
34514 up : function(e, m){
34515 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34516 m.tryActivate(m.items.length-1, -1);
34520 down : function(e, m){
34521 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34522 m.tryActivate(0, 1);
34526 right : function(e, m){
34528 m.activeItem.expandMenu(true);
34532 left : function(e, m){
34534 if(m.parentMenu && m.parentMenu.activeItem){
34535 m.parentMenu.activeItem.activate();
34539 enter : function(e, m){
34541 e.stopPropagation();
34542 m.activeItem.onClick(e);
34543 m.fireEvent("click", this, m.activeItem);
34549 * Ext JS Library 1.1.1
34550 * Copyright(c) 2006-2007, Ext JS, LLC.
34552 * Originally Released Under LGPL - original licence link has changed is not relivant.
34555 * <script type="text/javascript">
34559 * @class Roo.menu.MenuMgr
34560 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34563 Roo.menu.MenuMgr = function(){
34564 var menus, active, groups = {}, attached = false, lastShow = new Date();
34566 // private - called when first menu is created
34569 active = new Roo.util.MixedCollection();
34570 Roo.get(document).addKeyListener(27, function(){
34571 if(active.length > 0){
34578 function hideAll(){
34579 if(active && active.length > 0){
34580 var c = active.clone();
34581 c.each(function(m){
34588 function onHide(m){
34590 if(active.length < 1){
34591 Roo.get(document).un("mousedown", onMouseDown);
34597 function onShow(m){
34598 var last = active.last();
34599 lastShow = new Date();
34602 Roo.get(document).on("mousedown", onMouseDown);
34606 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34607 m.parentMenu.activeChild = m;
34608 }else if(last && last.isVisible()){
34609 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34614 function onBeforeHide(m){
34616 m.activeChild.hide();
34618 if(m.autoHideTimer){
34619 clearTimeout(m.autoHideTimer);
34620 delete m.autoHideTimer;
34625 function onBeforeShow(m){
34626 var pm = m.parentMenu;
34627 if(!pm && !m.allowOtherMenus){
34629 }else if(pm && pm.activeChild && active != m){
34630 pm.activeChild.hide();
34635 function onMouseDown(e){
34636 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34642 function onBeforeCheck(mi, state){
34644 var g = groups[mi.group];
34645 for(var i = 0, l = g.length; i < l; i++){
34647 g[i].setChecked(false);
34656 * Hides all menus that are currently visible
34658 hideAll : function(){
34663 register : function(menu){
34667 menus[menu.id] = menu;
34668 menu.on("beforehide", onBeforeHide);
34669 menu.on("hide", onHide);
34670 menu.on("beforeshow", onBeforeShow);
34671 menu.on("show", onShow);
34672 var g = menu.group;
34673 if(g && menu.events["checkchange"]){
34677 groups[g].push(menu);
34678 menu.on("checkchange", onCheck);
34683 * Returns a {@link Roo.menu.Menu} object
34684 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34685 * be used to generate and return a new Menu instance.
34687 get : function(menu){
34688 if(typeof menu == "string"){ // menu id
34689 return menus[menu];
34690 }else if(menu.events){ // menu instance
34692 }else if(typeof menu.length == 'number'){ // array of menu items?
34693 return new Roo.menu.Menu({items:menu});
34694 }else{ // otherwise, must be a config
34695 return new Roo.menu.Menu(menu);
34700 unregister : function(menu){
34701 delete menus[menu.id];
34702 menu.un("beforehide", onBeforeHide);
34703 menu.un("hide", onHide);
34704 menu.un("beforeshow", onBeforeShow);
34705 menu.un("show", onShow);
34706 var g = menu.group;
34707 if(g && menu.events["checkchange"]){
34708 groups[g].remove(menu);
34709 menu.un("checkchange", onCheck);
34714 registerCheckable : function(menuItem){
34715 var g = menuItem.group;
34720 groups[g].push(menuItem);
34721 menuItem.on("beforecheckchange", onBeforeCheck);
34726 unregisterCheckable : function(menuItem){
34727 var g = menuItem.group;
34729 groups[g].remove(menuItem);
34730 menuItem.un("beforecheckchange", onBeforeCheck);
34736 * Ext JS Library 1.1.1
34737 * Copyright(c) 2006-2007, Ext JS, LLC.
34739 * Originally Released Under LGPL - original licence link has changed is not relivant.
34742 * <script type="text/javascript">
34747 * @class Roo.menu.BaseItem
34748 * @extends Roo.Component
34749 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34750 * management and base configuration options shared by all menu components.
34752 * Creates a new BaseItem
34753 * @param {Object} config Configuration options
34755 Roo.menu.BaseItem = function(config){
34756 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34761 * Fires when this item is clicked
34762 * @param {Roo.menu.BaseItem} this
34763 * @param {Roo.EventObject} e
34768 * Fires when this item is activated
34769 * @param {Roo.menu.BaseItem} this
34773 * @event deactivate
34774 * Fires when this item is deactivated
34775 * @param {Roo.menu.BaseItem} this
34781 this.on("click", this.handler, this.scope, true);
34785 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34787 * @cfg {Function} handler
34788 * A function that will handle the click event of this menu item (defaults to undefined)
34791 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34793 canActivate : false,
34795 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34797 activeClass : "x-menu-item-active",
34799 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34801 hideOnClick : true,
34803 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34808 ctype: "Roo.menu.BaseItem",
34811 actionMode : "container",
34814 render : function(container, parentMenu){
34815 this.parentMenu = parentMenu;
34816 Roo.menu.BaseItem.superclass.render.call(this, container);
34817 this.container.menuItemId = this.id;
34821 onRender : function(container, position){
34822 this.el = Roo.get(this.el);
34823 container.dom.appendChild(this.el.dom);
34827 onClick : function(e){
34828 if(!this.disabled && this.fireEvent("click", this, e) !== false
34829 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34830 this.handleClick(e);
34837 activate : function(){
34841 var li = this.container;
34842 li.addClass(this.activeClass);
34843 this.region = li.getRegion().adjust(2, 2, -2, -2);
34844 this.fireEvent("activate", this);
34849 deactivate : function(){
34850 this.container.removeClass(this.activeClass);
34851 this.fireEvent("deactivate", this);
34855 shouldDeactivate : function(e){
34856 return !this.region || !this.region.contains(e.getPoint());
34860 handleClick : function(e){
34861 if(this.hideOnClick){
34862 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34867 expandMenu : function(autoActivate){
34872 hideMenu : function(){
34877 * Ext JS Library 1.1.1
34878 * Copyright(c) 2006-2007, Ext JS, LLC.
34880 * Originally Released Under LGPL - original licence link has changed is not relivant.
34883 * <script type="text/javascript">
34887 * @class Roo.menu.Adapter
34888 * @extends Roo.menu.BaseItem
34889 * 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.
34890 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34892 * Creates a new Adapter
34893 * @param {Object} config Configuration options
34895 Roo.menu.Adapter = function(component, config){
34896 Roo.menu.Adapter.superclass.constructor.call(this, config);
34897 this.component = component;
34899 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34901 canActivate : true,
34904 onRender : function(container, position){
34905 this.component.render(container);
34906 this.el = this.component.getEl();
34910 activate : function(){
34914 this.component.focus();
34915 this.fireEvent("activate", this);
34920 deactivate : function(){
34921 this.fireEvent("deactivate", this);
34925 disable : function(){
34926 this.component.disable();
34927 Roo.menu.Adapter.superclass.disable.call(this);
34931 enable : function(){
34932 this.component.enable();
34933 Roo.menu.Adapter.superclass.enable.call(this);
34937 * Ext JS Library 1.1.1
34938 * Copyright(c) 2006-2007, Ext JS, LLC.
34940 * Originally Released Under LGPL - original licence link has changed is not relivant.
34943 * <script type="text/javascript">
34947 * @class Roo.menu.TextItem
34948 * @extends Roo.menu.BaseItem
34949 * Adds a static text string to a menu, usually used as either a heading or group separator.
34950 * Note: old style constructor with text is still supported.
34953 * Creates a new TextItem
34954 * @param {Object} cfg Configuration
34956 Roo.menu.TextItem = function(cfg){
34957 if (typeof(cfg) == 'string') {
34960 Roo.apply(this,cfg);
34963 Roo.menu.TextItem.superclass.constructor.call(this);
34966 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34968 * @cfg {Boolean} text Text to show on item.
34973 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34975 hideOnClick : false,
34977 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34979 itemCls : "x-menu-text",
34982 onRender : function(){
34983 var s = document.createElement("span");
34984 s.className = this.itemCls;
34985 s.innerHTML = this.text;
34987 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34991 * Ext JS Library 1.1.1
34992 * Copyright(c) 2006-2007, Ext JS, LLC.
34994 * Originally Released Under LGPL - original licence link has changed is not relivant.
34997 * <script type="text/javascript">
35001 * @class Roo.menu.Separator
35002 * @extends Roo.menu.BaseItem
35003 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
35004 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
35006 * @param {Object} config Configuration options
35008 Roo.menu.Separator = function(config){
35009 Roo.menu.Separator.superclass.constructor.call(this, config);
35012 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
35014 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
35016 itemCls : "x-menu-sep",
35018 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35020 hideOnClick : false,
35023 onRender : function(li){
35024 var s = document.createElement("span");
35025 s.className = this.itemCls;
35026 s.innerHTML = " ";
35028 li.addClass("x-menu-sep-li");
35029 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
35033 * Ext JS Library 1.1.1
35034 * Copyright(c) 2006-2007, Ext JS, LLC.
35036 * Originally Released Under LGPL - original licence link has changed is not relivant.
35039 * <script type="text/javascript">
35042 * @class Roo.menu.Item
35043 * @extends Roo.menu.BaseItem
35044 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
35045 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
35046 * activation and click handling.
35048 * Creates a new Item
35049 * @param {Object} config Configuration options
35051 Roo.menu.Item = function(config){
35052 Roo.menu.Item.superclass.constructor.call(this, config);
35054 this.menu = Roo.menu.MenuMgr.get(this.menu);
35057 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
35060 * @cfg {String} text
35061 * The text to show on the menu item.
35065 * @cfg {String} HTML to render in menu
35066 * The text to show on the menu item (HTML version).
35070 * @cfg {String} icon
35071 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
35075 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
35077 itemCls : "x-menu-item",
35079 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
35081 canActivate : true,
35083 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
35086 // doc'd in BaseItem
35090 ctype: "Roo.menu.Item",
35093 onRender : function(container, position){
35094 var el = document.createElement("a");
35095 el.hideFocus = true;
35096 el.unselectable = "on";
35097 el.href = this.href || "#";
35098 if(this.hrefTarget){
35099 el.target = this.hrefTarget;
35101 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
35103 var html = this.html.length ? this.html : String.format('{0}',this.text);
35105 el.innerHTML = String.format(
35106 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
35107 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
35109 Roo.menu.Item.superclass.onRender.call(this, container, position);
35113 * Sets the text to display in this menu item
35114 * @param {String} text The text to display
35115 * @param {Boolean} isHTML true to indicate text is pure html.
35117 setText : function(text, isHTML){
35125 var html = this.html.length ? this.html : String.format('{0}',this.text);
35127 this.el.update(String.format(
35128 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
35129 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
35130 this.parentMenu.autoWidth();
35135 handleClick : function(e){
35136 if(!this.href){ // if no link defined, stop the event automatically
35139 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
35143 activate : function(autoExpand){
35144 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
35154 shouldDeactivate : function(e){
35155 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
35156 if(this.menu && this.menu.isVisible()){
35157 return !this.menu.getEl().getRegion().contains(e.getPoint());
35165 deactivate : function(){
35166 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
35171 expandMenu : function(autoActivate){
35172 if(!this.disabled && this.menu){
35173 clearTimeout(this.hideTimer);
35174 delete this.hideTimer;
35175 if(!this.menu.isVisible() && !this.showTimer){
35176 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
35177 }else if (this.menu.isVisible() && autoActivate){
35178 this.menu.tryActivate(0, 1);
35184 deferExpand : function(autoActivate){
35185 delete this.showTimer;
35186 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35188 this.menu.tryActivate(0, 1);
35193 hideMenu : function(){
35194 clearTimeout(this.showTimer);
35195 delete this.showTimer;
35196 if(!this.hideTimer && this.menu && this.menu.isVisible()){
35197 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35202 deferHide : function(){
35203 delete this.hideTimer;
35208 * Ext JS Library 1.1.1
35209 * Copyright(c) 2006-2007, Ext JS, LLC.
35211 * Originally Released Under LGPL - original licence link has changed is not relivant.
35214 * <script type="text/javascript">
35218 * @class Roo.menu.CheckItem
35219 * @extends Roo.menu.Item
35220 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35222 * Creates a new CheckItem
35223 * @param {Object} config Configuration options
35225 Roo.menu.CheckItem = function(config){
35226 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35229 * @event beforecheckchange
35230 * Fires before the checked value is set, providing an opportunity to cancel if needed
35231 * @param {Roo.menu.CheckItem} this
35232 * @param {Boolean} checked The new checked value that will be set
35234 "beforecheckchange" : true,
35236 * @event checkchange
35237 * Fires after the checked value has been set
35238 * @param {Roo.menu.CheckItem} this
35239 * @param {Boolean} checked The checked value that was set
35241 "checkchange" : true
35243 if(this.checkHandler){
35244 this.on('checkchange', this.checkHandler, this.scope);
35247 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35249 * @cfg {String} group
35250 * All check items with the same group name will automatically be grouped into a single-select
35251 * radio button group (defaults to '')
35254 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35256 itemCls : "x-menu-item x-menu-check-item",
35258 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35260 groupClass : "x-menu-group-item",
35263 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35264 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35265 * initialized with checked = true will be rendered as checked.
35270 ctype: "Roo.menu.CheckItem",
35273 onRender : function(c){
35274 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35276 this.el.addClass(this.groupClass);
35278 Roo.menu.MenuMgr.registerCheckable(this);
35280 this.checked = false;
35281 this.setChecked(true, true);
35286 destroy : function(){
35288 Roo.menu.MenuMgr.unregisterCheckable(this);
35290 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35294 * Set the checked state of this item
35295 * @param {Boolean} checked The new checked value
35296 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35298 setChecked : function(state, suppressEvent){
35299 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35300 if(this.container){
35301 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35303 this.checked = state;
35304 if(suppressEvent !== true){
35305 this.fireEvent("checkchange", this, state);
35311 handleClick : function(e){
35312 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35313 this.setChecked(!this.checked);
35315 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35319 * Ext JS Library 1.1.1
35320 * Copyright(c) 2006-2007, Ext JS, LLC.
35322 * Originally Released Under LGPL - original licence link has changed is not relivant.
35325 * <script type="text/javascript">
35329 * @class Roo.menu.DateItem
35330 * @extends Roo.menu.Adapter
35331 * A menu item that wraps the {@link Roo.DatPicker} component.
35333 * Creates a new DateItem
35334 * @param {Object} config Configuration options
35336 Roo.menu.DateItem = function(config){
35337 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35338 /** The Roo.DatePicker object @type Roo.DatePicker */
35339 this.picker = this.component;
35340 this.addEvents({select: true});
35342 this.picker.on("render", function(picker){
35343 picker.getEl().swallowEvent("click");
35344 picker.container.addClass("x-menu-date-item");
35347 this.picker.on("select", this.onSelect, this);
35350 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35352 onSelect : function(picker, date){
35353 this.fireEvent("select", this, date, picker);
35354 Roo.menu.DateItem.superclass.handleClick.call(this);
35358 * Ext JS Library 1.1.1
35359 * Copyright(c) 2006-2007, Ext JS, LLC.
35361 * Originally Released Under LGPL - original licence link has changed is not relivant.
35364 * <script type="text/javascript">
35368 * @class Roo.menu.ColorItem
35369 * @extends Roo.menu.Adapter
35370 * A menu item that wraps the {@link Roo.ColorPalette} component.
35372 * Creates a new ColorItem
35373 * @param {Object} config Configuration options
35375 Roo.menu.ColorItem = function(config){
35376 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35377 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35378 this.palette = this.component;
35379 this.relayEvents(this.palette, ["select"]);
35380 if(this.selectHandler){
35381 this.on('select', this.selectHandler, this.scope);
35384 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35386 * Ext JS Library 1.1.1
35387 * Copyright(c) 2006-2007, Ext JS, LLC.
35389 * Originally Released Under LGPL - original licence link has changed is not relivant.
35392 * <script type="text/javascript">
35397 * @class Roo.menu.DateMenu
35398 * @extends Roo.menu.Menu
35399 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35401 * Creates a new DateMenu
35402 * @param {Object} config Configuration options
35404 Roo.menu.DateMenu = function(config){
35405 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35407 var di = new Roo.menu.DateItem(config);
35410 * The {@link Roo.DatePicker} instance for this DateMenu
35413 this.picker = di.picker;
35416 * @param {DatePicker} picker
35417 * @param {Date} date
35419 this.relayEvents(di, ["select"]);
35421 this.on('beforeshow', function(){
35423 this.picker.hideMonthPicker(true);
35427 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35431 * Ext JS Library 1.1.1
35432 * Copyright(c) 2006-2007, Ext JS, LLC.
35434 * Originally Released Under LGPL - original licence link has changed is not relivant.
35437 * <script type="text/javascript">
35442 * @class Roo.menu.ColorMenu
35443 * @extends Roo.menu.Menu
35444 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35446 * Creates a new ColorMenu
35447 * @param {Object} config Configuration options
35449 Roo.menu.ColorMenu = function(config){
35450 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35452 var ci = new Roo.menu.ColorItem(config);
35455 * The {@link Roo.ColorPalette} instance for this ColorMenu
35456 * @type ColorPalette
35458 this.palette = ci.palette;
35461 * @param {ColorPalette} palette
35462 * @param {String} color
35464 this.relayEvents(ci, ["select"]);
35466 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35468 * Ext JS Library 1.1.1
35469 * Copyright(c) 2006-2007, Ext JS, LLC.
35471 * Originally Released Under LGPL - original licence link has changed is not relivant.
35474 * <script type="text/javascript">
35478 * @class Roo.form.Field
35479 * @extends Roo.BoxComponent
35480 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35482 * Creates a new Field
35483 * @param {Object} config Configuration options
35485 Roo.form.Field = function(config){
35486 Roo.form.Field.superclass.constructor.call(this, config);
35489 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35491 * @cfg {String} fieldLabel Label to use when rendering a form.
35494 * @cfg {String} qtip Mouse over tip
35498 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35500 invalidClass : "x-form-invalid",
35502 * @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")
35504 invalidText : "The value in this field is invalid",
35506 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35508 focusClass : "x-form-focus",
35510 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35511 automatic validation (defaults to "keyup").
35513 validationEvent : "keyup",
35515 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35517 validateOnBlur : true,
35519 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35521 validationDelay : 250,
35523 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35524 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35526 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35528 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35530 fieldClass : "x-form-field",
35532 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35535 ----------- ----------------------------------------------------------------------
35536 qtip Display a quick tip when the user hovers over the field
35537 title Display a default browser title attribute popup
35538 under Add a block div beneath the field containing the error text
35539 side Add an error icon to the right of the field with a popup on hover
35540 [element id] Add the error text directly to the innerHTML of the specified element
35543 msgTarget : 'qtip',
35545 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35550 * @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.
35555 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35560 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35562 inputType : undefined,
35565 * @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).
35567 tabIndex : undefined,
35570 isFormField : true,
35575 * @property {Roo.Element} fieldEl
35576 * Element Containing the rendered Field (with label etc.)
35579 * @cfg {Mixed} value A value to initialize this field with.
35584 * @cfg {String} name The field's HTML name attribute.
35587 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35591 initComponent : function(){
35592 Roo.form.Field.superclass.initComponent.call(this);
35596 * Fires when this field receives input focus.
35597 * @param {Roo.form.Field} this
35602 * Fires when this field loses input focus.
35603 * @param {Roo.form.Field} this
35607 * @event specialkey
35608 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35609 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35610 * @param {Roo.form.Field} this
35611 * @param {Roo.EventObject} e The event object
35616 * Fires just before the field blurs if the field value has changed.
35617 * @param {Roo.form.Field} this
35618 * @param {Mixed} newValue The new value
35619 * @param {Mixed} oldValue The original value
35624 * Fires after the field has been marked as invalid.
35625 * @param {Roo.form.Field} this
35626 * @param {String} msg The validation message
35631 * Fires after the field has been validated with no errors.
35632 * @param {Roo.form.Field} this
35637 * Fires after the key up
35638 * @param {Roo.form.Field} this
35639 * @param {Roo.EventObject} e The event Object
35646 * Returns the name attribute of the field if available
35647 * @return {String} name The field name
35649 getName: function(){
35650 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35654 onRender : function(ct, position){
35655 Roo.form.Field.superclass.onRender.call(this, ct, position);
35657 var cfg = this.getAutoCreate();
35659 cfg.name = this.name || this.id;
35661 if(this.inputType){
35662 cfg.type = this.inputType;
35664 this.el = ct.createChild(cfg, position);
35666 var type = this.el.dom.type;
35668 if(type == 'password'){
35671 this.el.addClass('x-form-'+type);
35674 this.el.dom.readOnly = true;
35676 if(this.tabIndex !== undefined){
35677 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35680 this.el.addClass([this.fieldClass, this.cls]);
35685 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35686 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35687 * @return {Roo.form.Field} this
35689 applyTo : function(target){
35690 this.allowDomMove = false;
35691 this.el = Roo.get(target);
35692 this.render(this.el.dom.parentNode);
35697 initValue : function(){
35698 if(this.value !== undefined){
35699 this.setValue(this.value);
35700 }else if(this.el.dom.value.length > 0){
35701 this.setValue(this.el.dom.value);
35706 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35708 isDirty : function() {
35709 if(this.disabled) {
35712 return String(this.getValue()) !== String(this.originalValue);
35716 afterRender : function(){
35717 Roo.form.Field.superclass.afterRender.call(this);
35722 fireKey : function(e){
35723 //Roo.log('field ' + e.getKey());
35724 if(e.isNavKeyPress()){
35725 this.fireEvent("specialkey", this, e);
35730 * Resets the current field value to the originally loaded value and clears any validation messages
35732 reset : function(){
35733 this.setValue(this.originalValue);
35734 this.clearInvalid();
35738 initEvents : function(){
35739 // safari killled keypress - so keydown is now used..
35740 this.el.on("keydown" , this.fireKey, this);
35741 this.el.on("focus", this.onFocus, this);
35742 this.el.on("blur", this.onBlur, this);
35743 this.el.relayEvent('keyup', this);
35745 // reference to original value for reset
35746 this.originalValue = this.getValue();
35750 onFocus : function(){
35751 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35752 this.el.addClass(this.focusClass);
35754 if(!this.hasFocus){
35755 this.hasFocus = true;
35756 this.startValue = this.getValue();
35757 this.fireEvent("focus", this);
35761 beforeBlur : Roo.emptyFn,
35764 onBlur : function(){
35766 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35767 this.el.removeClass(this.focusClass);
35769 this.hasFocus = false;
35770 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35773 var v = this.getValue();
35774 if(String(v) !== String(this.startValue)){
35775 this.fireEvent('change', this, v, this.startValue);
35777 this.fireEvent("blur", this);
35781 * Returns whether or not the field value is currently valid
35782 * @param {Boolean} preventMark True to disable marking the field invalid
35783 * @return {Boolean} True if the value is valid, else false
35785 isValid : function(preventMark){
35789 var restore = this.preventMark;
35790 this.preventMark = preventMark === true;
35791 var v = this.validateValue(this.processValue(this.getRawValue()));
35792 this.preventMark = restore;
35797 * Validates the field value
35798 * @return {Boolean} True if the value is valid, else false
35800 validate : function(){
35801 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35802 this.clearInvalid();
35808 processValue : function(value){
35813 // Subclasses should provide the validation implementation by overriding this
35814 validateValue : function(value){
35819 * Mark this field as invalid
35820 * @param {String} msg The validation message
35822 markInvalid : function(msg){
35823 if(!this.rendered || this.preventMark){ // not rendered
35826 this.el.addClass(this.invalidClass);
35827 msg = msg || this.invalidText;
35828 switch(this.msgTarget){
35830 this.el.dom.qtip = msg;
35831 this.el.dom.qclass = 'x-form-invalid-tip';
35832 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35833 Roo.QuickTips.enable();
35837 this.el.dom.title = msg;
35841 var elp = this.el.findParent('.x-form-element', 5, true);
35842 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35843 this.errorEl.setWidth(elp.getWidth(true)-20);
35845 this.errorEl.update(msg);
35846 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35849 if(!this.errorIcon){
35850 var elp = this.el.findParent('.x-form-element', 5, true);
35851 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35853 this.alignErrorIcon();
35854 this.errorIcon.dom.qtip = msg;
35855 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35856 this.errorIcon.show();
35857 this.on('resize', this.alignErrorIcon, this);
35860 var t = Roo.getDom(this.msgTarget);
35862 t.style.display = this.msgDisplay;
35865 this.fireEvent('invalid', this, msg);
35869 alignErrorIcon : function(){
35870 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35874 * Clear any invalid styles/messages for this field
35876 clearInvalid : function(){
35877 if(!this.rendered || this.preventMark){ // not rendered
35880 this.el.removeClass(this.invalidClass);
35881 switch(this.msgTarget){
35883 this.el.dom.qtip = '';
35886 this.el.dom.title = '';
35890 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35894 if(this.errorIcon){
35895 this.errorIcon.dom.qtip = '';
35896 this.errorIcon.hide();
35897 this.un('resize', this.alignErrorIcon, this);
35901 var t = Roo.getDom(this.msgTarget);
35903 t.style.display = 'none';
35906 this.fireEvent('valid', this);
35910 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35911 * @return {Mixed} value The field value
35913 getRawValue : function(){
35914 var v = this.el.getValue();
35915 if(v === this.emptyText){
35922 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35923 * @return {Mixed} value The field value
35925 getValue : function(){
35926 var v = this.el.getValue();
35927 if(v === this.emptyText || v === undefined){
35934 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35935 * @param {Mixed} value The value to set
35937 setRawValue : function(v){
35938 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35942 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35943 * @param {Mixed} value The value to set
35945 setValue : function(v){
35948 this.el.dom.value = (v === null || v === undefined ? '' : v);
35953 adjustSize : function(w, h){
35954 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35955 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35959 adjustWidth : function(tag, w){
35960 tag = tag.toLowerCase();
35961 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35962 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35963 if(tag == 'input'){
35966 if(tag = 'textarea'){
35969 }else if(Roo.isOpera){
35970 if(tag == 'input'){
35973 if(tag = 'textarea'){
35983 // anything other than normal should be considered experimental
35984 Roo.form.Field.msgFx = {
35986 show: function(msgEl, f){
35987 msgEl.setDisplayed('block');
35990 hide : function(msgEl, f){
35991 msgEl.setDisplayed(false).update('');
35996 show: function(msgEl, f){
35997 msgEl.slideIn('t', {stopFx:true});
36000 hide : function(msgEl, f){
36001 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
36006 show: function(msgEl, f){
36007 msgEl.fixDisplay();
36008 msgEl.alignTo(f.el, 'tl-tr');
36009 msgEl.slideIn('l', {stopFx:true});
36012 hide : function(msgEl, f){
36013 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
36018 * Ext JS Library 1.1.1
36019 * Copyright(c) 2006-2007, Ext JS, LLC.
36021 * Originally Released Under LGPL - original licence link has changed is not relivant.
36024 * <script type="text/javascript">
36029 * @class Roo.form.TextField
36030 * @extends Roo.form.Field
36031 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
36032 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
36034 * Creates a new TextField
36035 * @param {Object} config Configuration options
36037 Roo.form.TextField = function(config){
36038 Roo.form.TextField.superclass.constructor.call(this, config);
36042 * Fires when the autosize function is triggered. The field may or may not have actually changed size
36043 * according to the default logic, but this event provides a hook for the developer to apply additional
36044 * logic at runtime to resize the field if needed.
36045 * @param {Roo.form.Field} this This text field
36046 * @param {Number} width The new field width
36052 Roo.extend(Roo.form.TextField, Roo.form.Field, {
36054 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
36058 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
36062 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
36066 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
36070 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
36074 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
36076 disableKeyFilter : false,
36078 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
36082 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
36086 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
36088 maxLength : Number.MAX_VALUE,
36090 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
36092 minLengthText : "The minimum length for this field is {0}",
36094 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
36096 maxLengthText : "The maximum length for this field is {0}",
36098 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
36100 selectOnFocus : false,
36102 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
36104 blankText : "This field is required",
36106 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
36107 * If available, this function will be called only after the basic validators all return true, and will be passed the
36108 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
36112 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
36113 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
36114 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
36118 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
36122 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
36126 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
36127 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
36129 emptyClass : 'x-form-empty-field',
36132 initEvents : function(){
36133 Roo.form.TextField.superclass.initEvents.call(this);
36134 if(this.validationEvent == 'keyup'){
36135 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
36136 this.el.on('keyup', this.filterValidation, this);
36138 else if(this.validationEvent !== false){
36139 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
36141 if(this.selectOnFocus || this.emptyText){
36142 this.on("focus", this.preFocus, this);
36143 if(this.emptyText){
36144 this.on('blur', this.postBlur, this);
36145 this.applyEmptyText();
36148 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
36149 this.el.on("keypress", this.filterKeys, this);
36152 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
36153 this.el.on("click", this.autoSize, this);
36157 processValue : function(value){
36158 if(this.stripCharsRe){
36159 var newValue = value.replace(this.stripCharsRe, '');
36160 if(newValue !== value){
36161 this.setRawValue(newValue);
36168 filterValidation : function(e){
36169 if(!e.isNavKeyPress()){
36170 this.validationTask.delay(this.validationDelay);
36175 onKeyUp : function(e){
36176 if(!e.isNavKeyPress()){
36182 * Resets the current field value to the originally-loaded value and clears any validation messages.
36183 * Also adds emptyText and emptyClass if the original value was blank.
36185 reset : function(){
36186 Roo.form.TextField.superclass.reset.call(this);
36187 this.applyEmptyText();
36190 applyEmptyText : function(){
36191 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
36192 this.setRawValue(this.emptyText);
36193 this.el.addClass(this.emptyClass);
36198 preFocus : function(){
36199 if(this.emptyText){
36200 if(this.el.dom.value == this.emptyText){
36201 this.setRawValue('');
36203 this.el.removeClass(this.emptyClass);
36205 if(this.selectOnFocus){
36206 this.el.dom.select();
36211 postBlur : function(){
36212 this.applyEmptyText();
36216 filterKeys : function(e){
36217 var k = e.getKey();
36218 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36221 var c = e.getCharCode(), cc = String.fromCharCode(c);
36222 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36225 if(!this.maskRe.test(cc)){
36230 setValue : function(v){
36231 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
36232 this.el.removeClass(this.emptyClass);
36234 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36235 this.applyEmptyText();
36240 * Validates a value according to the field's validation rules and marks the field as invalid
36241 * if the validation fails
36242 * @param {Mixed} value The value to validate
36243 * @return {Boolean} True if the value is valid, else false
36245 validateValue : function(value){
36246 if(value.length < 1 || value === this.emptyText){ // if it's blank
36247 if(this.allowBlank){
36248 this.clearInvalid();
36251 this.markInvalid(this.blankText);
36255 if(value.length < this.minLength){
36256 this.markInvalid(String.format(this.minLengthText, this.minLength));
36259 if(value.length > this.maxLength){
36260 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36264 var vt = Roo.form.VTypes;
36265 if(!vt[this.vtype](value, this)){
36266 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36270 if(typeof this.validator == "function"){
36271 var msg = this.validator(value);
36273 this.markInvalid(msg);
36277 if(this.regex && !this.regex.test(value)){
36278 this.markInvalid(this.regexText);
36285 * Selects text in this field
36286 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36287 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36289 selectText : function(start, end){
36290 var v = this.getRawValue();
36292 start = start === undefined ? 0 : start;
36293 end = end === undefined ? v.length : end;
36294 var d = this.el.dom;
36295 if(d.setSelectionRange){
36296 d.setSelectionRange(start, end);
36297 }else if(d.createTextRange){
36298 var range = d.createTextRange();
36299 range.moveStart("character", start);
36300 range.moveEnd("character", v.length-end);
36307 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36308 * This only takes effect if grow = true, and fires the autosize event.
36310 autoSize : function(){
36311 if(!this.grow || !this.rendered){
36315 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36318 var v = el.dom.value;
36319 var d = document.createElement('div');
36320 d.appendChild(document.createTextNode(v));
36324 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36325 this.el.setWidth(w);
36326 this.fireEvent("autosize", this, w);
36330 * Ext JS Library 1.1.1
36331 * Copyright(c) 2006-2007, Ext JS, LLC.
36333 * Originally Released Under LGPL - original licence link has changed is not relivant.
36336 * <script type="text/javascript">
36340 * @class Roo.form.Hidden
36341 * @extends Roo.form.TextField
36342 * Simple Hidden element used on forms
36344 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36347 * Creates a new Hidden form element.
36348 * @param {Object} config Configuration options
36353 // easy hidden field...
36354 Roo.form.Hidden = function(config){
36355 Roo.form.Hidden.superclass.constructor.call(this, config);
36358 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36360 inputType: 'hidden',
36363 labelSeparator: '',
36365 itemCls : 'x-form-item-display-none'
36373 * Ext JS Library 1.1.1
36374 * Copyright(c) 2006-2007, Ext JS, LLC.
36376 * Originally Released Under LGPL - original licence link has changed is not relivant.
36379 * <script type="text/javascript">
36383 * @class Roo.form.TriggerField
36384 * @extends Roo.form.TextField
36385 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36386 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36387 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36388 * for which you can provide a custom implementation. For example:
36390 var trigger = new Roo.form.TriggerField();
36391 trigger.onTriggerClick = myTriggerFn;
36392 trigger.applyTo('my-field');
36395 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36396 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36397 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36398 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36400 * Create a new TriggerField.
36401 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36402 * to the base TextField)
36404 Roo.form.TriggerField = function(config){
36405 this.mimicing = false;
36406 Roo.form.TriggerField.superclass.constructor.call(this, config);
36409 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36411 * @cfg {String} triggerClass A CSS class to apply to the trigger
36414 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36415 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36417 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36419 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36423 /** @cfg {Boolean} grow @hide */
36424 /** @cfg {Number} growMin @hide */
36425 /** @cfg {Number} growMax @hide */
36431 autoSize: Roo.emptyFn,
36435 deferHeight : true,
36438 actionMode : 'wrap',
36440 onResize : function(w, h){
36441 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36442 if(typeof w == 'number'){
36443 var x = w - this.trigger.getWidth();
36444 this.el.setWidth(this.adjustWidth('input', x));
36445 this.trigger.setStyle('left', x+'px');
36450 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36453 getResizeEl : function(){
36458 getPositionEl : function(){
36463 alignErrorIcon : function(){
36464 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36468 onRender : function(ct, position){
36469 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36470 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36471 this.trigger = this.wrap.createChild(this.triggerConfig ||
36472 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36473 if(this.hideTrigger){
36474 this.trigger.setDisplayed(false);
36476 this.initTrigger();
36478 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36483 initTrigger : function(){
36484 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36485 this.trigger.addClassOnOver('x-form-trigger-over');
36486 this.trigger.addClassOnClick('x-form-trigger-click');
36490 onDestroy : function(){
36492 this.trigger.removeAllListeners();
36493 this.trigger.remove();
36496 this.wrap.remove();
36498 Roo.form.TriggerField.superclass.onDestroy.call(this);
36502 onFocus : function(){
36503 Roo.form.TriggerField.superclass.onFocus.call(this);
36504 if(!this.mimicing){
36505 this.wrap.addClass('x-trigger-wrap-focus');
36506 this.mimicing = true;
36507 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36508 if(this.monitorTab){
36509 this.el.on("keydown", this.checkTab, this);
36515 checkTab : function(e){
36516 if(e.getKey() == e.TAB){
36517 this.triggerBlur();
36522 onBlur : function(){
36527 mimicBlur : function(e, t){
36528 if(!this.wrap.contains(t) && this.validateBlur()){
36529 this.triggerBlur();
36534 triggerBlur : function(){
36535 this.mimicing = false;
36536 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36537 if(this.monitorTab){
36538 this.el.un("keydown", this.checkTab, this);
36540 this.wrap.removeClass('x-trigger-wrap-focus');
36541 Roo.form.TriggerField.superclass.onBlur.call(this);
36545 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36546 validateBlur : function(e, t){
36551 onDisable : function(){
36552 Roo.form.TriggerField.superclass.onDisable.call(this);
36554 this.wrap.addClass('x-item-disabled');
36559 onEnable : function(){
36560 Roo.form.TriggerField.superclass.onEnable.call(this);
36562 this.wrap.removeClass('x-item-disabled');
36567 onShow : function(){
36568 var ae = this.getActionEl();
36571 ae.dom.style.display = '';
36572 ae.dom.style.visibility = 'visible';
36578 onHide : function(){
36579 var ae = this.getActionEl();
36580 ae.dom.style.display = 'none';
36584 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36585 * by an implementing function.
36587 * @param {EventObject} e
36589 onTriggerClick : Roo.emptyFn
36592 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36593 // to be extended by an implementing class. For an example of implementing this class, see the custom
36594 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36595 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36596 initComponent : function(){
36597 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36599 this.triggerConfig = {
36600 tag:'span', cls:'x-form-twin-triggers', cn:[
36601 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36602 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36606 getTrigger : function(index){
36607 return this.triggers[index];
36610 initTrigger : function(){
36611 var ts = this.trigger.select('.x-form-trigger', true);
36612 this.wrap.setStyle('overflow', 'hidden');
36613 var triggerField = this;
36614 ts.each(function(t, all, index){
36615 t.hide = function(){
36616 var w = triggerField.wrap.getWidth();
36617 this.dom.style.display = 'none';
36618 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36620 t.show = function(){
36621 var w = triggerField.wrap.getWidth();
36622 this.dom.style.display = '';
36623 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36625 var triggerIndex = 'Trigger'+(index+1);
36627 if(this['hide'+triggerIndex]){
36628 t.dom.style.display = 'none';
36630 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36631 t.addClassOnOver('x-form-trigger-over');
36632 t.addClassOnClick('x-form-trigger-click');
36634 this.triggers = ts.elements;
36637 onTrigger1Click : Roo.emptyFn,
36638 onTrigger2Click : Roo.emptyFn
36641 * Ext JS Library 1.1.1
36642 * Copyright(c) 2006-2007, Ext JS, LLC.
36644 * Originally Released Under LGPL - original licence link has changed is not relivant.
36647 * <script type="text/javascript">
36651 * @class Roo.form.TextArea
36652 * @extends Roo.form.TextField
36653 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36654 * support for auto-sizing.
36656 * Creates a new TextArea
36657 * @param {Object} config Configuration options
36659 Roo.form.TextArea = function(config){
36660 Roo.form.TextArea.superclass.constructor.call(this, config);
36661 // these are provided exchanges for backwards compat
36662 // minHeight/maxHeight were replaced by growMin/growMax to be
36663 // compatible with TextField growing config values
36664 if(this.minHeight !== undefined){
36665 this.growMin = this.minHeight;
36667 if(this.maxHeight !== undefined){
36668 this.growMax = this.maxHeight;
36672 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36674 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36678 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36682 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36683 * in the field (equivalent to setting overflow: hidden, defaults to false)
36685 preventScrollbars: false,
36687 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36688 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36692 onRender : function(ct, position){
36694 this.defaultAutoCreate = {
36696 style:"width:300px;height:60px;",
36697 autocomplete: "off"
36700 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36702 this.textSizeEl = Roo.DomHelper.append(document.body, {
36703 tag: "pre", cls: "x-form-grow-sizer"
36705 if(this.preventScrollbars){
36706 this.el.setStyle("overflow", "hidden");
36708 this.el.setHeight(this.growMin);
36712 onDestroy : function(){
36713 if(this.textSizeEl){
36714 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36716 Roo.form.TextArea.superclass.onDestroy.call(this);
36720 onKeyUp : function(e){
36721 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36727 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36728 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36730 autoSize : function(){
36731 if(!this.grow || !this.textSizeEl){
36735 var v = el.dom.value;
36736 var ts = this.textSizeEl;
36739 ts.appendChild(document.createTextNode(v));
36742 Roo.fly(ts).setWidth(this.el.getWidth());
36744 v = "  ";
36747 v = v.replace(/\n/g, '<p> </p>');
36749 v += " \n ";
36752 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36753 if(h != this.lastHeight){
36754 this.lastHeight = h;
36755 this.el.setHeight(h);
36756 this.fireEvent("autosize", this, h);
36761 * Ext JS Library 1.1.1
36762 * Copyright(c) 2006-2007, Ext JS, LLC.
36764 * Originally Released Under LGPL - original licence link has changed is not relivant.
36767 * <script type="text/javascript">
36772 * @class Roo.form.NumberField
36773 * @extends Roo.form.TextField
36774 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36776 * Creates a new NumberField
36777 * @param {Object} config Configuration options
36779 Roo.form.NumberField = function(config){
36780 Roo.form.NumberField.superclass.constructor.call(this, config);
36783 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36785 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36787 fieldClass: "x-form-field x-form-num-field",
36789 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36791 allowDecimals : true,
36793 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36795 decimalSeparator : ".",
36797 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36799 decimalPrecision : 2,
36801 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36803 allowNegative : true,
36805 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36807 minValue : Number.NEGATIVE_INFINITY,
36809 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36811 maxValue : Number.MAX_VALUE,
36813 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36815 minText : "The minimum value for this field is {0}",
36817 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36819 maxText : "The maximum value for this field is {0}",
36821 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36822 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36824 nanText : "{0} is not a valid number",
36827 initEvents : function(){
36828 Roo.form.NumberField.superclass.initEvents.call(this);
36829 var allowed = "0123456789";
36830 if(this.allowDecimals){
36831 allowed += this.decimalSeparator;
36833 if(this.allowNegative){
36836 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36837 var keyPress = function(e){
36838 var k = e.getKey();
36839 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36842 var c = e.getCharCode();
36843 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36847 this.el.on("keypress", keyPress, this);
36851 validateValue : function(value){
36852 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36855 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36858 var num = this.parseValue(value);
36860 this.markInvalid(String.format(this.nanText, value));
36863 if(num < this.minValue){
36864 this.markInvalid(String.format(this.minText, this.minValue));
36867 if(num > this.maxValue){
36868 this.markInvalid(String.format(this.maxText, this.maxValue));
36874 getValue : function(){
36875 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36879 parseValue : function(value){
36880 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36881 return isNaN(value) ? '' : value;
36885 fixPrecision : function(value){
36886 var nan = isNaN(value);
36887 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36888 return nan ? '' : value;
36890 return parseFloat(value).toFixed(this.decimalPrecision);
36893 setValue : function(v){
36894 v = this.fixPrecision(v);
36895 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36899 decimalPrecisionFcn : function(v){
36900 return Math.floor(v);
36903 beforeBlur : function(){
36904 var v = this.parseValue(this.getRawValue());
36911 * Ext JS Library 1.1.1
36912 * Copyright(c) 2006-2007, Ext JS, LLC.
36914 * Originally Released Under LGPL - original licence link has changed is not relivant.
36917 * <script type="text/javascript">
36921 * @class Roo.form.DateField
36922 * @extends Roo.form.TriggerField
36923 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36925 * Create a new DateField
36926 * @param {Object} config
36928 Roo.form.DateField = function(config){
36929 Roo.form.DateField.superclass.constructor.call(this, config);
36935 * Fires when a date is selected
36936 * @param {Roo.form.DateField} combo This combo box
36937 * @param {Date} date The date selected
36944 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36945 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36946 this.ddMatch = null;
36947 if(this.disabledDates){
36948 var dd = this.disabledDates;
36950 for(var i = 0; i < dd.length; i++){
36952 if(i != dd.length-1) re += "|";
36954 this.ddMatch = new RegExp(re + ")");
36958 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36960 * @cfg {String} format
36961 * The default date format string which can be overriden for localization support. The format must be
36962 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36966 * @cfg {String} altFormats
36967 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36968 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36970 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36972 * @cfg {Array} disabledDays
36973 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36975 disabledDays : null,
36977 * @cfg {String} disabledDaysText
36978 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36980 disabledDaysText : "Disabled",
36982 * @cfg {Array} disabledDates
36983 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36984 * expression so they are very powerful. Some examples:
36986 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36987 * <li>["03/08", "09/16"] would disable those days for every year</li>
36988 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36989 * <li>["03/../2006"] would disable every day in March 2006</li>
36990 * <li>["^03"] would disable every day in every March</li>
36992 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36993 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36995 disabledDates : null,
36997 * @cfg {String} disabledDatesText
36998 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
37000 disabledDatesText : "Disabled",
37002 * @cfg {Date/String} minValue
37003 * The minimum allowed date. Can be either a Javascript date object or a string date in a
37004 * valid format (defaults to null).
37008 * @cfg {Date/String} maxValue
37009 * The maximum allowed date. Can be either a Javascript date object or a string date in a
37010 * valid format (defaults to null).
37014 * @cfg {String} minText
37015 * The error text to display when the date in the cell is before minValue (defaults to
37016 * 'The date in this field must be after {minValue}').
37018 minText : "The date in this field must be equal to or after {0}",
37020 * @cfg {String} maxText
37021 * The error text to display when the date in the cell is after maxValue (defaults to
37022 * 'The date in this field must be before {maxValue}').
37024 maxText : "The date in this field must be equal to or before {0}",
37026 * @cfg {String} invalidText
37027 * The error text to display when the date in the field is invalid (defaults to
37028 * '{value} is not a valid date - it must be in the format {format}').
37030 invalidText : "{0} is not a valid date - it must be in the format {1}",
37032 * @cfg {String} triggerClass
37033 * An additional CSS class used to style the trigger button. The trigger will always get the
37034 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
37035 * which displays a calendar icon).
37037 triggerClass : 'x-form-date-trigger',
37041 * @cfg {bool} useIso
37042 * if enabled, then the date field will use a hidden field to store the
37043 * real value as iso formated date. default (false)
37047 * @cfg {String/Object} autoCreate
37048 * A DomHelper element spec, or true for a default element spec (defaults to
37049 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
37052 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
37055 hiddenField: false,
37057 onRender : function(ct, position)
37059 Roo.form.DateField.superclass.onRender.call(this, ct, position);
37061 this.el.dom.removeAttribute('name');
37062 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
37064 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
37065 // prevent input submission
37066 this.hiddenName = this.name;
37073 validateValue : function(value)
37075 value = this.formatDate(value);
37076 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
37079 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37082 var svalue = value;
37083 value = this.parseDate(value);
37085 this.markInvalid(String.format(this.invalidText, svalue, this.format));
37088 var time = value.getTime();
37089 if(this.minValue && time < this.minValue.getTime()){
37090 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
37093 if(this.maxValue && time > this.maxValue.getTime()){
37094 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
37097 if(this.disabledDays){
37098 var day = value.getDay();
37099 for(var i = 0; i < this.disabledDays.length; i++) {
37100 if(day === this.disabledDays[i]){
37101 this.markInvalid(this.disabledDaysText);
37106 var fvalue = this.formatDate(value);
37107 if(this.ddMatch && this.ddMatch.test(fvalue)){
37108 this.markInvalid(String.format(this.disabledDatesText, fvalue));
37115 // Provides logic to override the default TriggerField.validateBlur which just returns true
37116 validateBlur : function(){
37117 return !this.menu || !this.menu.isVisible();
37121 * Returns the current date value of the date field.
37122 * @return {Date} The date value
37124 getValue : function(){
37126 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
37130 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
37131 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
37132 * (the default format used is "m/d/y").
37135 //All of these calls set the same date value (May 4, 2006)
37137 //Pass a date object:
37138 var dt = new Date('5/4/06');
37139 dateField.setValue(dt);
37141 //Pass a date string (default format):
37142 dateField.setValue('5/4/06');
37144 //Pass a date string (custom format):
37145 dateField.format = 'Y-m-d';
37146 dateField.setValue('2006-5-4');
37148 * @param {String/Date} date The date or valid date string
37150 setValue : function(date){
37151 if (this.hiddenField) {
37152 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
37154 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
37158 parseDate : function(value){
37159 if(!value || value instanceof Date){
37162 var v = Date.parseDate(value, this.format);
37163 if(!v && this.altFormats){
37164 if(!this.altFormatsArray){
37165 this.altFormatsArray = this.altFormats.split("|");
37167 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
37168 v = Date.parseDate(value, this.altFormatsArray[i]);
37175 formatDate : function(date, fmt){
37176 return (!date || !(date instanceof Date)) ?
37177 date : date.dateFormat(fmt || this.format);
37182 select: function(m, d){
37184 this.fireEvent('select', this, d);
37186 show : function(){ // retain focus styling
37190 this.focus.defer(10, this);
37191 var ml = this.menuListeners;
37192 this.menu.un("select", ml.select, this);
37193 this.menu.un("show", ml.show, this);
37194 this.menu.un("hide", ml.hide, this);
37199 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37200 onTriggerClick : function(){
37204 if(this.menu == null){
37205 this.menu = new Roo.menu.DateMenu();
37207 Roo.apply(this.menu.picker, {
37208 showClear: this.allowBlank,
37209 minDate : this.minValue,
37210 maxDate : this.maxValue,
37211 disabledDatesRE : this.ddMatch,
37212 disabledDatesText : this.disabledDatesText,
37213 disabledDays : this.disabledDays,
37214 disabledDaysText : this.disabledDaysText,
37215 format : this.format,
37216 minText : String.format(this.minText, this.formatDate(this.minValue)),
37217 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37219 this.menu.on(Roo.apply({}, this.menuListeners, {
37222 this.menu.picker.setValue(this.getValue() || new Date());
37223 this.menu.show(this.el, "tl-bl?");
37226 beforeBlur : function(){
37227 var v = this.parseDate(this.getRawValue());
37233 /** @cfg {Boolean} grow @hide */
37234 /** @cfg {Number} growMin @hide */
37235 /** @cfg {Number} growMax @hide */
37242 * Ext JS Library 1.1.1
37243 * Copyright(c) 2006-2007, Ext JS, LLC.
37245 * Originally Released Under LGPL - original licence link has changed is not relivant.
37248 * <script type="text/javascript">
37253 * @class Roo.form.ComboBox
37254 * @extends Roo.form.TriggerField
37255 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
37257 * Create a new ComboBox.
37258 * @param {Object} config Configuration options
37260 Roo.form.ComboBox = function(config){
37261 Roo.form.ComboBox.superclass.constructor.call(this, config);
37265 * Fires when the dropdown list is expanded
37266 * @param {Roo.form.ComboBox} combo This combo box
37271 * Fires when the dropdown list is collapsed
37272 * @param {Roo.form.ComboBox} combo This combo box
37276 * @event beforeselect
37277 * Fires before a list item is selected. Return false to cancel the selection.
37278 * @param {Roo.form.ComboBox} combo This combo box
37279 * @param {Roo.data.Record} record The data record returned from the underlying store
37280 * @param {Number} index The index of the selected item in the dropdown list
37282 'beforeselect' : true,
37285 * Fires when a list item is selected
37286 * @param {Roo.form.ComboBox} combo This combo box
37287 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37288 * @param {Number} index The index of the selected item in the dropdown list
37292 * @event beforequery
37293 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37294 * The event object passed has these properties:
37295 * @param {Roo.form.ComboBox} combo This combo box
37296 * @param {String} query The query
37297 * @param {Boolean} forceAll true to force "all" query
37298 * @param {Boolean} cancel true to cancel the query
37299 * @param {Object} e The query event object
37301 'beforequery': true,
37304 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37305 * @param {Roo.form.ComboBox} combo This combo box
37310 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37311 * @param {Roo.form.ComboBox} combo This combo box
37312 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37318 if(this.transform){
37319 this.allowDomMove = false;
37320 var s = Roo.getDom(this.transform);
37321 if(!this.hiddenName){
37322 this.hiddenName = s.name;
37325 this.mode = 'local';
37326 var d = [], opts = s.options;
37327 for(var i = 0, len = opts.length;i < len; i++){
37329 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37331 this.value = value;
37333 d.push([value, o.text]);
37335 this.store = new Roo.data.SimpleStore({
37337 fields: ['value', 'text'],
37340 this.valueField = 'value';
37341 this.displayField = 'text';
37343 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37344 if(!this.lazyRender){
37345 this.target = true;
37346 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37347 s.parentNode.removeChild(s); // remove it
37348 this.render(this.el.parentNode);
37350 s.parentNode.removeChild(s); // remove it
37355 this.store = Roo.factory(this.store, Roo.data);
37358 this.selectedIndex = -1;
37359 if(this.mode == 'local'){
37360 if(config.queryDelay === undefined){
37361 this.queryDelay = 10;
37363 if(config.minChars === undefined){
37369 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37371 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37374 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37375 * rendering into an Roo.Editor, defaults to false)
37378 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37379 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37382 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37385 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37386 * the dropdown list (defaults to undefined, with no header element)
37390 * @cfg {String/Roo.Template} tpl The template to use to render the output
37394 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37396 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37398 listWidth: undefined,
37400 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37401 * mode = 'remote' or 'text' if mode = 'local')
37403 displayField: undefined,
37405 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37406 * mode = 'remote' or 'value' if mode = 'local').
37407 * Note: use of a valueField requires the user make a selection
37408 * in order for a value to be mapped.
37410 valueField: undefined,
37414 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37415 * field's data value (defaults to the underlying DOM element's name)
37417 hiddenName: undefined,
37419 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37423 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37425 selectedClass: 'x-combo-selected',
37427 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37428 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37429 * which displays a downward arrow icon).
37431 triggerClass : 'x-form-arrow-trigger',
37433 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37437 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37438 * anchor positions (defaults to 'tl-bl')
37440 listAlign: 'tl-bl?',
37442 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37446 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37447 * query specified by the allQuery config option (defaults to 'query')
37449 triggerAction: 'query',
37451 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37452 * (defaults to 4, does not apply if editable = false)
37456 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37457 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37461 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37462 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37466 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37467 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37471 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37472 * when editable = true (defaults to false)
37474 selectOnFocus:false,
37476 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37478 queryParam: 'query',
37480 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37481 * when mode = 'remote' (defaults to 'Loading...')
37483 loadingText: 'Loading...',
37485 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37489 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37493 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37494 * traditional select (defaults to true)
37498 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37502 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37506 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37507 * listWidth has a higher value)
37511 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37512 * allow the user to set arbitrary text into the field (defaults to false)
37514 forceSelection:false,
37516 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37517 * if typeAhead = true (defaults to 250)
37519 typeAheadDelay : 250,
37521 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37522 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37524 valueNotFoundText : undefined,
37526 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37528 blockFocus : false,
37531 * @cfg {Boolean} disableClear Disable showing of clear button.
37533 disableClear : false,
37535 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37537 alwaysQuery : false,
37543 // element that contains real text value.. (when hidden is used..)
37546 onRender : function(ct, position){
37547 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37548 if(this.hiddenName){
37549 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37551 this.hiddenField.value =
37552 this.hiddenValue !== undefined ? this.hiddenValue :
37553 this.value !== undefined ? this.value : '';
37555 // prevent input submission
37556 this.el.dom.removeAttribute('name');
37561 this.el.dom.setAttribute('autocomplete', 'off');
37564 var cls = 'x-combo-list';
37566 this.list = new Roo.Layer({
37567 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37570 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37571 this.list.setWidth(lw);
37572 this.list.swallowEvent('mousewheel');
37573 this.assetHeight = 0;
37576 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37577 this.assetHeight += this.header.getHeight();
37580 this.innerList = this.list.createChild({cls:cls+'-inner'});
37581 this.innerList.on('mouseover', this.onViewOver, this);
37582 this.innerList.on('mousemove', this.onViewMove, this);
37583 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37585 if(this.allowBlank && !this.pageSize && !this.disableClear){
37586 this.footer = this.list.createChild({cls:cls+'-ft'});
37587 this.pageTb = new Roo.Toolbar(this.footer);
37591 this.footer = this.list.createChild({cls:cls+'-ft'});
37592 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37593 {pageSize: this.pageSize});
37597 if (this.pageTb && this.allowBlank && !this.disableClear) {
37599 this.pageTb.add(new Roo.Toolbar.Fill(), {
37600 cls: 'x-btn-icon x-btn-clear',
37602 handler: function()
37605 _this.clearValue();
37606 _this.onSelect(false, -1);
37611 this.assetHeight += this.footer.getHeight();
37616 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37619 this.view = new Roo.View(this.innerList, this.tpl, {
37620 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37623 this.view.on('click', this.onViewClick, this);
37625 this.store.on('beforeload', this.onBeforeLoad, this);
37626 this.store.on('load', this.onLoad, this);
37627 this.store.on('loadexception', this.onLoadException, this);
37629 if(this.resizable){
37630 this.resizer = new Roo.Resizable(this.list, {
37631 pinned:true, handles:'se'
37633 this.resizer.on('resize', function(r, w, h){
37634 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37635 this.listWidth = w;
37636 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37637 this.restrictHeight();
37639 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37641 if(!this.editable){
37642 this.editable = true;
37643 this.setEditable(false);
37647 if (typeof(this.events.add.listeners) != 'undefined') {
37649 this.addicon = this.wrap.createChild(
37650 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37652 this.addicon.on('click', function(e) {
37653 this.fireEvent('add', this);
37656 if (typeof(this.events.edit.listeners) != 'undefined') {
37658 this.editicon = this.wrap.createChild(
37659 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37660 if (this.addicon) {
37661 this.editicon.setStyle('margin-left', '40px');
37663 this.editicon.on('click', function(e) {
37665 // we fire even if inothing is selected..
37666 this.fireEvent('edit', this, this.lastData );
37676 initEvents : function(){
37677 Roo.form.ComboBox.superclass.initEvents.call(this);
37679 this.keyNav = new Roo.KeyNav(this.el, {
37680 "up" : function(e){
37681 this.inKeyMode = true;
37685 "down" : function(e){
37686 if(!this.isExpanded()){
37687 this.onTriggerClick();
37689 this.inKeyMode = true;
37694 "enter" : function(e){
37695 this.onViewClick();
37699 "esc" : function(e){
37703 "tab" : function(e){
37704 this.onViewClick(false);
37705 this.fireEvent("specialkey", this, e);
37711 doRelay : function(foo, bar, hname){
37712 if(hname == 'down' || this.scope.isExpanded()){
37713 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37720 this.queryDelay = Math.max(this.queryDelay || 10,
37721 this.mode == 'local' ? 10 : 250);
37722 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37723 if(this.typeAhead){
37724 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37726 if(this.editable !== false){
37727 this.el.on("keyup", this.onKeyUp, this);
37729 if(this.forceSelection){
37730 this.on('blur', this.doForce, this);
37734 onDestroy : function(){
37736 this.view.setStore(null);
37737 this.view.el.removeAllListeners();
37738 this.view.el.remove();
37739 this.view.purgeListeners();
37742 this.list.destroy();
37745 this.store.un('beforeload', this.onBeforeLoad, this);
37746 this.store.un('load', this.onLoad, this);
37747 this.store.un('loadexception', this.onLoadException, this);
37749 Roo.form.ComboBox.superclass.onDestroy.call(this);
37753 fireKey : function(e){
37754 if(e.isNavKeyPress() && !this.list.isVisible()){
37755 this.fireEvent("specialkey", this, e);
37760 onResize: function(w, h){
37761 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37763 if(typeof w != 'number'){
37764 // we do not handle it!?!?
37767 var tw = this.trigger.getWidth();
37768 tw += this.addicon ? this.addicon.getWidth() : 0;
37769 tw += this.editicon ? this.editicon.getWidth() : 0;
37771 this.el.setWidth( this.adjustWidth('input', x));
37773 this.trigger.setStyle('left', x+'px');
37775 if(this.list && this.listWidth === undefined){
37776 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37777 this.list.setWidth(lw);
37778 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37786 * Allow or prevent the user from directly editing the field text. If false is passed,
37787 * the user will only be able to select from the items defined in the dropdown list. This method
37788 * is the runtime equivalent of setting the 'editable' config option at config time.
37789 * @param {Boolean} value True to allow the user to directly edit the field text
37791 setEditable : function(value){
37792 if(value == this.editable){
37795 this.editable = value;
37797 this.el.dom.setAttribute('readOnly', true);
37798 this.el.on('mousedown', this.onTriggerClick, this);
37799 this.el.addClass('x-combo-noedit');
37801 this.el.dom.setAttribute('readOnly', false);
37802 this.el.un('mousedown', this.onTriggerClick, this);
37803 this.el.removeClass('x-combo-noedit');
37808 onBeforeLoad : function(){
37809 if(!this.hasFocus){
37812 this.innerList.update(this.loadingText ?
37813 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37814 this.restrictHeight();
37815 this.selectedIndex = -1;
37819 onLoad : function(){
37820 if(!this.hasFocus){
37823 if(this.store.getCount() > 0){
37825 this.restrictHeight();
37826 if(this.lastQuery == this.allQuery){
37828 this.el.dom.select();
37830 if(!this.selectByValue(this.value, true)){
37831 this.select(0, true);
37835 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37836 this.taTask.delay(this.typeAheadDelay);
37840 this.onEmptyResults();
37845 onLoadException : function()
37848 Roo.log(this.store.reader.jsonData);
37849 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
37850 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
37856 onTypeAhead : function(){
37857 if(this.store.getCount() > 0){
37858 var r = this.store.getAt(0);
37859 var newValue = r.data[this.displayField];
37860 var len = newValue.length;
37861 var selStart = this.getRawValue().length;
37862 if(selStart != len){
37863 this.setRawValue(newValue);
37864 this.selectText(selStart, newValue.length);
37870 onSelect : function(record, index){
37871 if(this.fireEvent('beforeselect', this, record, index) !== false){
37872 this.setFromData(index > -1 ? record.data : false);
37874 this.fireEvent('select', this, record, index);
37879 * Returns the currently selected field value or empty string if no value is set.
37880 * @return {String} value The selected value
37882 getValue : function(){
37883 if(this.valueField){
37884 return typeof this.value != 'undefined' ? this.value : '';
37886 return Roo.form.ComboBox.superclass.getValue.call(this);
37891 * Clears any text/value currently set in the field
37893 clearValue : function(){
37894 if(this.hiddenField){
37895 this.hiddenField.value = '';
37898 this.setRawValue('');
37899 this.lastSelectionText = '';
37900 this.applyEmptyText();
37904 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37905 * will be displayed in the field. If the value does not match the data value of an existing item,
37906 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37907 * Otherwise the field will be blank (although the value will still be set).
37908 * @param {String} value The value to match
37910 setValue : function(v){
37912 if(this.valueField){
37913 var r = this.findRecord(this.valueField, v);
37915 text = r.data[this.displayField];
37916 }else if(this.valueNotFoundText !== undefined){
37917 text = this.valueNotFoundText;
37920 this.lastSelectionText = text;
37921 if(this.hiddenField){
37922 this.hiddenField.value = v;
37924 Roo.form.ComboBox.superclass.setValue.call(this, text);
37928 * @property {Object} the last set data for the element
37933 * Sets the value of the field based on a object which is related to the record format for the store.
37934 * @param {Object} value the value to set as. or false on reset?
37936 setFromData : function(o){
37937 var dv = ''; // display value
37938 var vv = ''; // value value..
37940 if (this.displayField) {
37941 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37943 // this is an error condition!!!
37944 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
37947 if(this.valueField){
37948 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37950 if(this.hiddenField){
37951 this.hiddenField.value = vv;
37953 this.lastSelectionText = dv;
37954 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37958 // no hidden field.. - we store the value in 'value', but still display
37959 // display field!!!!
37960 this.lastSelectionText = dv;
37961 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37967 reset : function(){
37968 // overridden so that last data is reset..
37969 this.setValue(this.originalValue);
37970 this.clearInvalid();
37971 this.lastData = false;
37974 findRecord : function(prop, value){
37976 if(this.store.getCount() > 0){
37977 this.store.each(function(r){
37978 if(r.data[prop] == value){
37988 getName: function()
37990 // returns hidden if it's set..
37991 if (!this.rendered) {return ''};
37992 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37996 onViewMove : function(e, t){
37997 this.inKeyMode = false;
38001 onViewOver : function(e, t){
38002 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
38005 var item = this.view.findItemFromChild(t);
38007 var index = this.view.indexOf(item);
38008 this.select(index, false);
38013 onViewClick : function(doFocus)
38015 var index = this.view.getSelectedIndexes()[0];
38016 var r = this.store.getAt(index);
38018 this.onSelect(r, index);
38020 if(doFocus !== false && !this.blockFocus){
38026 restrictHeight : function(){
38027 this.innerList.dom.style.height = '';
38028 var inner = this.innerList.dom;
38029 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
38030 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
38031 this.list.beginUpdate();
38032 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
38033 this.list.alignTo(this.el, this.listAlign);
38034 this.list.endUpdate();
38038 onEmptyResults : function(){
38043 * Returns true if the dropdown list is expanded, else false.
38045 isExpanded : function(){
38046 return this.list.isVisible();
38050 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
38051 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
38052 * @param {String} value The data value of the item to select
38053 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
38054 * selected item if it is not currently in view (defaults to true)
38055 * @return {Boolean} True if the value matched an item in the list, else false
38057 selectByValue : function(v, scrollIntoView){
38058 if(v !== undefined && v !== null){
38059 var r = this.findRecord(this.valueField || this.displayField, v);
38061 this.select(this.store.indexOf(r), scrollIntoView);
38069 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
38070 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
38071 * @param {Number} index The zero-based index of the list item to select
38072 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
38073 * selected item if it is not currently in view (defaults to true)
38075 select : function(index, scrollIntoView){
38076 this.selectedIndex = index;
38077 this.view.select(index);
38078 if(scrollIntoView !== false){
38079 var el = this.view.getNode(index);
38081 this.innerList.scrollChildIntoView(el, false);
38087 selectNext : function(){
38088 var ct = this.store.getCount();
38090 if(this.selectedIndex == -1){
38092 }else if(this.selectedIndex < ct-1){
38093 this.select(this.selectedIndex+1);
38099 selectPrev : function(){
38100 var ct = this.store.getCount();
38102 if(this.selectedIndex == -1){
38104 }else if(this.selectedIndex != 0){
38105 this.select(this.selectedIndex-1);
38111 onKeyUp : function(e){
38112 if(this.editable !== false && !e.isSpecialKey()){
38113 this.lastKey = e.getKey();
38114 this.dqTask.delay(this.queryDelay);
38119 validateBlur : function(){
38120 return !this.list || !this.list.isVisible();
38124 initQuery : function(){
38125 this.doQuery(this.getRawValue());
38129 doForce : function(){
38130 if(this.el.dom.value.length > 0){
38131 this.el.dom.value =
38132 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
38133 this.applyEmptyText();
38138 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
38139 * query allowing the query action to be canceled if needed.
38140 * @param {String} query The SQL query to execute
38141 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
38142 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
38143 * saved in the current store (defaults to false)
38145 doQuery : function(q, forceAll){
38146 if(q === undefined || q === null){
38151 forceAll: forceAll,
38155 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
38159 forceAll = qe.forceAll;
38160 if(forceAll === true || (q.length >= this.minChars)){
38161 if(this.lastQuery != q || this.alwaysQuery){
38162 this.lastQuery = q;
38163 if(this.mode == 'local'){
38164 this.selectedIndex = -1;
38166 this.store.clearFilter();
38168 this.store.filter(this.displayField, q);
38172 this.store.baseParams[this.queryParam] = q;
38174 params: this.getParams(q)
38179 this.selectedIndex = -1;
38186 getParams : function(q){
38188 //p[this.queryParam] = q;
38191 p.limit = this.pageSize;
38197 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
38199 collapse : function(){
38200 if(!this.isExpanded()){
38204 Roo.get(document).un('mousedown', this.collapseIf, this);
38205 Roo.get(document).un('mousewheel', this.collapseIf, this);
38206 if (!this.editable) {
38207 Roo.get(document).un('keydown', this.listKeyPress, this);
38209 this.fireEvent('collapse', this);
38213 collapseIf : function(e){
38214 if(!e.within(this.wrap) && !e.within(this.list)){
38220 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
38222 expand : function(){
38223 if(this.isExpanded() || !this.hasFocus){
38226 this.list.alignTo(this.el, this.listAlign);
38228 Roo.get(document).on('mousedown', this.collapseIf, this);
38229 Roo.get(document).on('mousewheel', this.collapseIf, this);
38230 if (!this.editable) {
38231 Roo.get(document).on('keydown', this.listKeyPress, this);
38234 this.fireEvent('expand', this);
38238 // Implements the default empty TriggerField.onTriggerClick function
38239 onTriggerClick : function(){
38243 if(this.isExpanded()){
38245 if (!this.blockFocus) {
38250 this.hasFocus = true;
38251 if(this.triggerAction == 'all') {
38252 this.doQuery(this.allQuery, true);
38254 this.doQuery(this.getRawValue());
38256 if (!this.blockFocus) {
38261 listKeyPress : function(e)
38263 //Roo.log('listkeypress');
38264 // scroll to first matching element based on key pres..
38265 if (e.isSpecialKey()) {
38268 var k = String.fromCharCode(e.getKey()).toUpperCase();
38271 var csel = this.view.getSelectedNodes();
38272 var cselitem = false;
38274 var ix = this.view.indexOf(csel[0]);
38275 cselitem = this.store.getAt(ix);
38276 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
38282 this.store.each(function(v) {
38284 // start at existing selection.
38285 if (cselitem.id == v.id) {
38291 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
38292 match = this.store.indexOf(v);
38297 if (match === false) {
38298 return true; // no more action?
38301 this.view.select(match);
38302 var sn = Roo.get(this.view.getSelectedNodes()[0])
38303 sn.scrollIntoView(sn.dom.parentNode, false);
38307 * @cfg {Boolean} grow
38311 * @cfg {Number} growMin
38315 * @cfg {Number} growMax
38324 * Ext JS Library 1.1.1
38325 * Copyright(c) 2006-2007, Ext JS, LLC.
38327 * Originally Released Under LGPL - original licence link has changed is not relivant.
38330 * <script type="text/javascript">
38333 * @class Roo.form.Checkbox
38334 * @extends Roo.form.Field
38335 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
38337 * Creates a new Checkbox
38338 * @param {Object} config Configuration options
38340 Roo.form.Checkbox = function(config){
38341 Roo.form.Checkbox.superclass.constructor.call(this, config);
38345 * Fires when the checkbox is checked or unchecked.
38346 * @param {Roo.form.Checkbox} this This checkbox
38347 * @param {Boolean} checked The new checked value
38353 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38355 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38357 focusClass : undefined,
38359 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38361 fieldClass: "x-form-field",
38363 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38367 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38368 * {tag: "input", type: "checkbox", autocomplete: "off"})
38370 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38372 * @cfg {String} boxLabel The text that appears beside the checkbox
38376 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38380 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38382 valueOff: '0', // value when not checked..
38384 actionMode : 'viewEl',
38387 itemCls : 'x-menu-check-item x-form-item',
38388 groupClass : 'x-menu-group-item',
38389 inputType : 'hidden',
38392 inSetChecked: false, // check that we are not calling self...
38394 inputElement: false, // real input element?
38395 basedOn: false, // ????
38397 isFormField: true, // not sure where this is needed!!!!
38399 onResize : function(){
38400 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38401 if(!this.boxLabel){
38402 this.el.alignTo(this.wrap, 'c-c');
38406 initEvents : function(){
38407 Roo.form.Checkbox.superclass.initEvents.call(this);
38408 this.el.on("click", this.onClick, this);
38409 this.el.on("change", this.onClick, this);
38413 getResizeEl : function(){
38417 getPositionEl : function(){
38422 onRender : function(ct, position){
38423 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38425 if(this.inputValue !== undefined){
38426 this.el.dom.value = this.inputValue;
38429 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38430 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38431 var viewEl = this.wrap.createChild({
38432 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38433 this.viewEl = viewEl;
38434 this.wrap.on('click', this.onClick, this);
38436 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38437 this.el.on('propertychange', this.setFromHidden, this); //ie
38442 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38443 // viewEl.on('click', this.onClick, this);
38445 //if(this.checked){
38446 this.setChecked(this.checked);
38448 //this.checked = this.el.dom;
38454 initValue : Roo.emptyFn,
38457 * Returns the checked state of the checkbox.
38458 * @return {Boolean} True if checked, else false
38460 getValue : function(){
38462 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38464 return this.valueOff;
38469 onClick : function(){
38470 this.setChecked(!this.checked);
38472 //if(this.el.dom.checked != this.checked){
38473 // this.setValue(this.el.dom.checked);
38478 * Sets the checked state of the checkbox.
38479 * On is always based on a string comparison between inputValue and the param.
38480 * @param {Boolean/String} value - the value to set
38481 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38483 setValue : function(v,suppressEvent){
38486 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38487 //if(this.el && this.el.dom){
38488 // this.el.dom.checked = this.checked;
38489 // this.el.dom.defaultChecked = this.checked;
38491 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38492 //this.fireEvent("check", this, this.checked);
38495 setChecked : function(state,suppressEvent)
38497 if (this.inSetChecked) {
38498 this.checked = state;
38504 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38506 this.checked = state;
38507 if(suppressEvent !== true){
38508 this.fireEvent('check', this, state);
38510 this.inSetChecked = true;
38511 this.el.dom.value = state ? this.inputValue : this.valueOff;
38512 this.inSetChecked = false;
38515 // handle setting of hidden value by some other method!!?!?
38516 setFromHidden: function()
38521 //console.log("SET FROM HIDDEN");
38522 //alert('setFrom hidden');
38523 this.setValue(this.el.dom.value);
38526 onDestroy : function()
38529 Roo.get(this.viewEl).remove();
38532 Roo.form.Checkbox.superclass.onDestroy.call(this);
38537 * Ext JS Library 1.1.1
38538 * Copyright(c) 2006-2007, Ext JS, LLC.
38540 * Originally Released Under LGPL - original licence link has changed is not relivant.
38543 * <script type="text/javascript">
38547 * @class Roo.form.Radio
38548 * @extends Roo.form.Checkbox
38549 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38550 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38552 * Creates a new Radio
38553 * @param {Object} config Configuration options
38555 Roo.form.Radio = function(){
38556 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38558 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38559 inputType: 'radio',
38562 * If this radio is part of a group, it will return the selected value
38565 getGroupValue : function(){
38566 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38568 });//<script type="text/javascript">
38571 * Ext JS Library 1.1.1
38572 * Copyright(c) 2006-2007, Ext JS, LLC.
38573 * licensing@extjs.com
38575 * http://www.extjs.com/license
38581 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38582 * - IE ? - no idea how much works there.
38590 * @class Ext.form.HtmlEditor
38591 * @extends Ext.form.Field
38592 * Provides a lightweight HTML Editor component.
38593 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38595 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38596 * supported by this editor.</b><br/><br/>
38597 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38598 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38600 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38602 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38606 * @cfg {String} createLinkText The default text for the create link prompt
38608 createLinkText : 'Please enter the URL for the link:',
38610 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38612 defaultLinkValue : 'http:/'+'/',
38615 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
38620 * @cfg {Number} height (in pixels)
38624 * @cfg {Number} width (in pixels)
38629 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
38632 stylesheets: false,
38637 // private properties
38638 validationEvent : false,
38640 initialized : false,
38642 sourceEditMode : false,
38643 onFocus : Roo.emptyFn,
38645 hideMode:'offsets',
38647 defaultAutoCreate : { // modified by initCompnoent..
38649 style:"width:500px;height:300px;",
38650 autocomplete: "off"
38654 initComponent : function(){
38657 * @event initialize
38658 * Fires when the editor is fully initialized (including the iframe)
38659 * @param {HtmlEditor} this
38664 * Fires when the editor is first receives the focus. Any insertion must wait
38665 * until after this event.
38666 * @param {HtmlEditor} this
38670 * @event beforesync
38671 * Fires before the textarea is updated with content from the editor iframe. Return false
38672 * to cancel the sync.
38673 * @param {HtmlEditor} this
38674 * @param {String} html
38678 * @event beforepush
38679 * Fires before the iframe editor is updated with content from the textarea. Return false
38680 * to cancel the push.
38681 * @param {HtmlEditor} this
38682 * @param {String} html
38687 * Fires when the textarea is updated with content from the editor iframe.
38688 * @param {HtmlEditor} this
38689 * @param {String} html
38694 * Fires when the iframe editor is updated with content from the textarea.
38695 * @param {HtmlEditor} this
38696 * @param {String} html
38700 * @event editmodechange
38701 * Fires when the editor switches edit modes
38702 * @param {HtmlEditor} this
38703 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38705 editmodechange: true,
38707 * @event editorevent
38708 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38709 * @param {HtmlEditor} this
38713 this.defaultAutoCreate = {
38715 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
38716 autocomplete: "off"
38721 * Protected method that will not generally be called directly. It
38722 * is called when the editor creates its toolbar. Override this method if you need to
38723 * add custom toolbar buttons.
38724 * @param {HtmlEditor} editor
38726 createToolbar : function(editor){
38727 if (!editor.toolbars || !editor.toolbars.length) {
38728 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38731 for (var i =0 ; i < editor.toolbars.length;i++) {
38732 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38733 editor.toolbars[i].init(editor);
38740 * Protected method that will not generally be called directly. It
38741 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38742 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38744 getDocMarkup : function(){
38747 if (this.stylesheets === false) {
38749 Roo.get(document.head).select('style').each(function(node) {
38750 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
38753 Roo.get(document.head).select('link').each(function(node) {
38754 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
38757 } else if (!this.stylesheets.length) {
38759 st = '<style type="text/css">' +
38760 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
38763 Roo.each(this.stylesheets, function(s) {
38764 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
38769 return '<html><head>' + st +
38770 //<style type="text/css">' +
38771 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
38773 ' </head><body></body></html>';
38777 onRender : function(ct, position)
38780 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38781 this.el.dom.style.border = '0 none';
38782 this.el.dom.setAttribute('tabIndex', -1);
38783 this.el.addClass('x-hidden');
38784 if(Roo.isIE){ // fix IE 1px bogus margin
38785 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38787 this.wrap = this.el.wrap({
38788 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38791 if (this.resizable) {
38792 this.resizeEl = new Roo.Resizable(this.wrap, {
38796 minHeight : this.height,
38797 height: this.height,
38798 handles : this.resizable,
38801 resize : function(r, w, h) {
38802 _t.onResize(w,h); // -something
38809 this.frameId = Roo.id();
38811 this.createToolbar(this);
38815 var iframe = this.wrap.createChild({
38818 name: this.frameId,
38819 frameBorder : 'no',
38820 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38824 // console.log(iframe);
38825 //this.wrap.dom.appendChild(iframe);
38827 this.iframe = iframe.dom;
38829 this.assignDocWin();
38831 this.doc.designMode = 'on';
38834 this.doc.write(this.getDocMarkup());
38838 var task = { // must defer to wait for browser to be ready
38840 //console.log("run task?" + this.doc.readyState);
38841 this.assignDocWin();
38842 if(this.doc.body || this.doc.readyState == 'complete'){
38844 this.doc.designMode="on";
38848 Roo.TaskMgr.stop(task);
38849 this.initEditor.defer(10, this);
38856 Roo.TaskMgr.start(task);
38859 this.setSize(this.wrap.getSize());
38861 if (this.resizeEl) {
38862 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
38863 // should trigger onReize..
38868 onResize : function(w, h)
38870 //Roo.log('resize: ' +w + ',' + h );
38871 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38872 if(this.el && this.iframe){
38873 if(typeof w == 'number'){
38874 var aw = w - this.wrap.getFrameWidth('lr');
38875 this.el.setWidth(this.adjustWidth('textarea', aw));
38876 this.iframe.style.width = aw + 'px';
38878 if(typeof h == 'number'){
38880 for (var i =0; i < this.toolbars.length;i++) {
38881 // fixme - ask toolbars for heights?
38882 tbh += this.toolbars[i].tb.el.getHeight();
38883 if (this.toolbars[i].footer) {
38884 tbh += this.toolbars[i].footer.el.getHeight();
38891 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38892 ah -= 5; // knock a few pixes off for look..
38893 this.el.setHeight(this.adjustWidth('textarea', ah));
38894 this.iframe.style.height = ah + 'px';
38896 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38903 * Toggles the editor between standard and source edit mode.
38904 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38906 toggleSourceEdit : function(sourceEditMode){
38908 this.sourceEditMode = sourceEditMode === true;
38910 if(this.sourceEditMode){
38913 this.iframe.className = 'x-hidden';
38914 this.el.removeClass('x-hidden');
38915 this.el.dom.removeAttribute('tabIndex');
38920 this.iframe.className = '';
38921 this.el.addClass('x-hidden');
38922 this.el.dom.setAttribute('tabIndex', -1);
38925 this.setSize(this.wrap.getSize());
38926 this.fireEvent('editmodechange', this, this.sourceEditMode);
38929 // private used internally
38930 createLink : function(){
38931 var url = prompt(this.createLinkText, this.defaultLinkValue);
38932 if(url && url != 'http:/'+'/'){
38933 this.relayCmd('createlink', url);
38937 // private (for BoxComponent)
38938 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38940 // private (for BoxComponent)
38941 getResizeEl : function(){
38945 // private (for BoxComponent)
38946 getPositionEl : function(){
38951 initEvents : function(){
38952 this.originalValue = this.getValue();
38956 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38959 markInvalid : Roo.emptyFn,
38961 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38964 clearInvalid : Roo.emptyFn,
38966 setValue : function(v){
38967 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38972 * Protected method that will not generally be called directly. If you need/want
38973 * custom HTML cleanup, this is the method you should override.
38974 * @param {String} html The HTML to be cleaned
38975 * return {String} The cleaned HTML
38977 cleanHtml : function(html){
38978 html = String(html);
38979 if(html.length > 5){
38980 if(Roo.isSafari){ // strip safari nonsense
38981 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38984 if(html == ' '){
38991 * Protected method that will not generally be called directly. Syncs the contents
38992 * of the editor iframe with the textarea.
38994 syncValue : function(){
38995 if(this.initialized){
38996 var bd = (this.doc.body || this.doc.documentElement);
38997 //this.cleanUpPaste();
38998 var html = bd.innerHTML;
39000 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
39001 var m = bs.match(/text-align:(.*?);/i);
39003 html = '<div style="'+m[0]+'">' + html + '</div>';
39006 html = this.cleanHtml(html);
39007 if(this.fireEvent('beforesync', this, html) !== false){
39008 this.el.dom.value = html;
39009 this.fireEvent('sync', this, html);
39015 * Protected method that will not generally be called directly. Pushes the value of the textarea
39016 * into the iframe editor.
39018 pushValue : function(){
39019 if(this.initialized){
39020 var v = this.el.dom.value;
39025 if(this.fireEvent('beforepush', this, v) !== false){
39026 var d = (this.doc.body || this.doc.documentElement);
39028 this.cleanUpPaste();
39029 this.el.dom.value = d.innerHTML;
39030 this.fireEvent('push', this, v);
39036 deferFocus : function(){
39037 this.focus.defer(10, this);
39041 focus : function(){
39042 if(this.win && !this.sourceEditMode){
39049 assignDocWin: function()
39051 var iframe = this.iframe;
39054 this.doc = iframe.contentWindow.document;
39055 this.win = iframe.contentWindow;
39057 if (!Roo.get(this.frameId)) {
39060 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
39061 this.win = Roo.get(this.frameId).dom.contentWindow;
39066 initEditor : function(){
39067 //console.log("INIT EDITOR");
39068 this.assignDocWin();
39072 this.doc.designMode="on";
39074 this.doc.write(this.getDocMarkup());
39077 var dbody = (this.doc.body || this.doc.documentElement);
39078 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
39079 // this copies styles from the containing element into thsi one..
39080 // not sure why we need all of this..
39081 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
39082 ss['background-attachment'] = 'fixed'; // w3c
39083 dbody.bgProperties = 'fixed'; // ie
39084 Roo.DomHelper.applyStyles(dbody, ss);
39085 Roo.EventManager.on(this.doc, {
39086 //'mousedown': this.onEditorEvent,
39087 'mouseup': this.onEditorEvent,
39088 'dblclick': this.onEditorEvent,
39089 'click': this.onEditorEvent,
39090 'keyup': this.onEditorEvent,
39095 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
39097 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
39098 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
39100 this.initialized = true;
39102 this.fireEvent('initialize', this);
39107 onDestroy : function(){
39113 for (var i =0; i < this.toolbars.length;i++) {
39114 // fixme - ask toolbars for heights?
39115 this.toolbars[i].onDestroy();
39118 this.wrap.dom.innerHTML = '';
39119 this.wrap.remove();
39124 onFirstFocus : function(){
39126 this.assignDocWin();
39129 this.activated = true;
39130 for (var i =0; i < this.toolbars.length;i++) {
39131 this.toolbars[i].onFirstFocus();
39134 if(Roo.isGecko){ // prevent silly gecko errors
39136 var s = this.win.getSelection();
39137 if(!s.focusNode || s.focusNode.nodeType != 3){
39138 var r = s.getRangeAt(0);
39139 r.selectNodeContents((this.doc.body || this.doc.documentElement));
39144 this.execCmd('useCSS', true);
39145 this.execCmd('styleWithCSS', false);
39148 this.fireEvent('activate', this);
39152 adjustFont: function(btn){
39153 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
39154 //if(Roo.isSafari){ // safari
39157 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
39158 if(Roo.isSafari){ // safari
39159 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
39160 v = (v < 10) ? 10 : v;
39161 v = (v > 48) ? 48 : v;
39162 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
39167 v = Math.max(1, v+adjust);
39169 this.execCmd('FontSize', v );
39172 onEditorEvent : function(e){
39173 this.fireEvent('editorevent', this, e);
39174 // this.updateToolbar();
39175 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
39178 insertTag : function(tg)
39180 // could be a bit smarter... -> wrap the current selected tRoo..
39182 this.execCmd("formatblock", tg);
39186 insertText : function(txt)
39190 range = this.createRange();
39191 range.deleteContents();
39192 //alert(Sender.getAttribute('label'));
39194 range.insertNode(this.doc.createTextNode(txt));
39198 relayBtnCmd : function(btn){
39199 this.relayCmd(btn.cmd);
39203 * Executes a Midas editor command on the editor document and performs necessary focus and
39204 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
39205 * @param {String} cmd The Midas command
39206 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
39208 relayCmd : function(cmd, value){
39210 this.execCmd(cmd, value);
39211 this.fireEvent('editorevent', this);
39212 //this.updateToolbar();
39217 * Executes a Midas editor command directly on the editor document.
39218 * For visual commands, you should use {@link #relayCmd} instead.
39219 * <b>This should only be called after the editor is initialized.</b>
39220 * @param {String} cmd The Midas command
39221 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
39223 execCmd : function(cmd, value){
39224 this.doc.execCommand(cmd, false, value === undefined ? null : value);
39230 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
39232 * @param {String} text
39234 insertAtCursor : function(text){
39235 if(!this.activated){
39240 var r = this.doc.selection.createRange();
39247 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
39249 this.execCmd('InsertHTML', text);
39254 mozKeyPress : function(e){
39256 var c = e.getCharCode(), cmd;
39259 c = String.fromCharCode(c).toLowerCase();
39271 this.cleanUpPaste.defer(100, this);
39279 e.preventDefault();
39287 fixKeys : function(){ // load time branching for fastest keydown performance
39289 return function(e){
39290 var k = e.getKey(), r;
39293 r = this.doc.selection.createRange();
39296 r.pasteHTML('    ');
39303 r = this.doc.selection.createRange();
39305 var target = r.parentElement();
39306 if(!target || target.tagName.toLowerCase() != 'li'){
39308 r.pasteHTML('<br />');
39314 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39315 this.cleanUpPaste.defer(100, this);
39321 }else if(Roo.isOpera){
39322 return function(e){
39323 var k = e.getKey();
39327 this.execCmd('InsertHTML','    ');
39330 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39331 this.cleanUpPaste.defer(100, this);
39336 }else if(Roo.isSafari){
39337 return function(e){
39338 var k = e.getKey();
39342 this.execCmd('InsertText','\t');
39346 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39347 this.cleanUpPaste.defer(100, this);
39355 getAllAncestors: function()
39357 var p = this.getSelectedNode();
39360 a.push(p); // push blank onto stack..
39361 p = this.getParentElement();
39365 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
39369 a.push(this.doc.body);
39373 lastSelNode : false,
39376 getSelection : function()
39378 this.assignDocWin();
39379 return Roo.isIE ? this.doc.selection : this.win.getSelection();
39382 getSelectedNode: function()
39384 // this may only work on Gecko!!!
39386 // should we cache this!!!!
39391 var range = this.createRange(this.getSelection()).cloneRange();
39394 var parent = range.parentElement();
39396 var testRange = range.duplicate();
39397 testRange.moveToElementText(parent);
39398 if (testRange.inRange(range)) {
39401 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
39404 parent = parent.parentElement;
39409 // is ancestor a text element.
39410 var ac = range.commonAncestorContainer;
39411 if (ac.nodeType == 3) {
39412 ac = ac.parentNode;
39415 var ar = ac.childNodes;
39418 var other_nodes = [];
39419 var has_other_nodes = false;
39420 for (var i=0;i<ar.length;i++) {
39421 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
39424 // fullly contained node.
39426 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
39431 // probably selected..
39432 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
39433 other_nodes.push(ar[i]);
39437 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39442 has_other_nodes = true;
39444 if (!nodes.length && other_nodes.length) {
39445 nodes= other_nodes;
39447 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39453 createRange: function(sel)
39455 // this has strange effects when using with
39456 // top toolbar - not sure if it's a great idea.
39457 //this.editor.contentWindow.focus();
39458 if (typeof sel != "undefined") {
39460 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39462 return this.doc.createRange();
39465 return this.doc.createRange();
39468 getParentElement: function()
39471 this.assignDocWin();
39472 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39474 var range = this.createRange(sel);
39477 var p = range.commonAncestorContainer;
39478 while (p.nodeType == 3) { // text node
39489 * Range intersection.. the hard stuff...
39493 * [ -- selected range --- ]
39497 * if end is before start or hits it. fail.
39498 * if start is after end or hits it fail.
39500 * if either hits (but other is outside. - then it's not
39506 // @see http://www.thismuchiknow.co.uk/?p=64.
39507 rangeIntersectsNode : function(range, node)
39509 var nodeRange = node.ownerDocument.createRange();
39511 nodeRange.selectNode(node);
39513 nodeRange.selectNodeContents(node);
39516 var rangeStartRange = range.cloneRange();
39517 rangeStartRange.collapse(true);
39519 var rangeEndRange = range.cloneRange();
39520 rangeEndRange.collapse(false);
39522 var nodeStartRange = nodeRange.cloneRange();
39523 nodeStartRange.collapse(true);
39525 var nodeEndRange = nodeRange.cloneRange();
39526 nodeEndRange.collapse(false);
39528 return rangeStartRange.compareBoundaryPoints(
39529 Range.START_TO_START, nodeEndRange) == -1 &&
39530 rangeEndRange.compareBoundaryPoints(
39531 Range.START_TO_START, nodeStartRange) == 1;
39535 rangeCompareNode : function(range, node)
39537 var nodeRange = node.ownerDocument.createRange();
39539 nodeRange.selectNode(node);
39541 nodeRange.selectNodeContents(node);
39545 range.collapse(true);
39547 nodeRange.collapse(true);
39549 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
39550 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
39552 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
39554 var nodeIsBefore = ss == 1;
39555 var nodeIsAfter = ee == -1;
39557 if (nodeIsBefore && nodeIsAfter)
39559 if (!nodeIsBefore && nodeIsAfter)
39560 return 1; //right trailed.
39562 if (nodeIsBefore && !nodeIsAfter)
39563 return 2; // left trailed.
39568 // private? - in a new class?
39569 cleanUpPaste : function()
39571 // cleans up the whole document..
39572 Roo.log('cleanuppaste');
39573 this.cleanUpChildren(this.doc.body);
39574 var clean = this.cleanWordChars(this.doc.body.innerHTML);
39575 if (clean != this.doc.body.innerHTML) {
39576 this.doc.body.innerHTML = clean;
39581 cleanWordChars : function(input) {
39582 var he = Roo.form.HtmlEditor;
39584 var output = input;
39585 Roo.each(he.swapCodes, function(sw) {
39587 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
39588 output = output.replace(swapper, sw[1]);
39594 cleanUpChildren : function (n)
39596 if (!n.childNodes.length) {
39599 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39600 this.cleanUpChild(n.childNodes[i]);
39607 cleanUpChild : function (node)
39609 //console.log(node);
39610 if (node.nodeName == "#text") {
39611 // clean up silly Windows -- stuff?
39614 if (node.nodeName == "#comment") {
39615 node.parentNode.removeChild(node);
39616 // clean up silly Windows -- stuff?
39620 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39622 node.parentNode.removeChild(node);
39627 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
39629 // remove <a name=....> as rendering on yahoo mailer is bored with this.
39631 if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
39632 remove_keep_children = true;
39635 if (remove_keep_children) {
39636 this.cleanUpChildren(node);
39637 // inserts everything just before this node...
39638 while (node.childNodes.length) {
39639 var cn = node.childNodes[0];
39640 node.removeChild(cn);
39641 node.parentNode.insertBefore(cn, node);
39643 node.parentNode.removeChild(node);
39647 if (!node.attributes || !node.attributes.length) {
39648 this.cleanUpChildren(node);
39652 function cleanAttr(n,v)
39655 if (v.match(/^\./) || v.match(/^\//)) {
39658 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39661 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39662 node.removeAttribute(n);
39666 function cleanStyle(n,v)
39668 if (v.match(/expression/)) { //XSS?? should we even bother..
39669 node.removeAttribute(n);
39674 var parts = v.split(/;/);
39675 Roo.each(parts, function(p) {
39676 p = p.replace(/\s+/g,'');
39680 var l = p.split(':').shift().replace(/\s+/g,'');
39682 // only allow 'c whitelisted system attributes'
39683 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39684 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39685 node.removeAttribute(n);
39695 for (var i = node.attributes.length-1; i > -1 ; i--) {
39696 var a = node.attributes[i];
39698 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39699 node.removeAttribute(a.name);
39702 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39703 cleanAttr(a.name,a.value); // fixme..
39706 if (a.name == 'style') {
39707 cleanStyle(a.name,a.value);
39709 /// clean up MS crap..
39710 // tecnically this should be a list of valid class'es..
39713 if (a.name == 'class') {
39714 if (a.value.match(/^Mso/)) {
39715 node.className = '';
39718 if (a.value.match(/body/)) {
39719 node.className = '';
39729 this.cleanUpChildren(node);
39735 // hide stuff that is not compatible
39749 * @event specialkey
39753 * @cfg {String} fieldClass @hide
39756 * @cfg {String} focusClass @hide
39759 * @cfg {String} autoCreate @hide
39762 * @cfg {String} inputType @hide
39765 * @cfg {String} invalidClass @hide
39768 * @cfg {String} invalidText @hide
39771 * @cfg {String} msgFx @hide
39774 * @cfg {String} validateOnBlur @hide
39778 Roo.form.HtmlEditor.white = [
39779 'area', 'br', 'img', 'input', 'hr', 'wbr',
39781 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39782 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39783 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39784 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39785 'table', 'ul', 'xmp',
39787 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39790 'dir', 'menu', 'ol', 'ul', 'dl',
39796 Roo.form.HtmlEditor.black = [
39797 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39799 'base', 'basefont', 'bgsound', 'blink', 'body',
39800 'frame', 'frameset', 'head', 'html', 'ilayer',
39801 'iframe', 'layer', 'link', 'meta', 'object',
39802 'script', 'style' ,'title', 'xml' // clean later..
39804 Roo.form.HtmlEditor.clean = [
39805 'script', 'style', 'title', 'xml'
39807 Roo.form.HtmlEditor.remove = [
39812 Roo.form.HtmlEditor.ablack = [
39816 Roo.form.HtmlEditor.aclean = [
39817 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39821 Roo.form.HtmlEditor.pwhite= [
39822 'http', 'https', 'mailto'
39825 // white listed style attributes.
39826 Roo.form.HtmlEditor.cwhite= [
39832 Roo.form.HtmlEditor.swapCodes =[
39843 // <script type="text/javascript">
39846 * Ext JS Library 1.1.1
39847 * Copyright(c) 2006-2007, Ext JS, LLC.
39853 * @class Roo.form.HtmlEditorToolbar1
39858 new Roo.form.HtmlEditor({
39861 new Roo.form.HtmlEditorToolbar1({
39862 disable : { fonts: 1 , format: 1, ..., ... , ...],
39868 * @cfg {Object} disable List of elements to disable..
39869 * @cfg {Array} btns List of additional buttons.
39873 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39876 Roo.form.HtmlEditor.ToolbarStandard = function(config)
39879 Roo.apply(this, config);
39881 // default disabled, based on 'good practice'..
39882 this.disable = this.disable || {};
39883 Roo.applyIf(this.disable, {
39886 specialElements : true
39890 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39891 // dont call parent... till later.
39894 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
39902 * @cfg {Object} disable List of toolbar elements to disable
39907 * @cfg {Array} fontFamilies An array of available font families
39925 // "á" , ?? a acute?
39930 "°" // , // degrees
39932 // "é" , // e ecute
39933 // "ú" , // u ecute?
39936 specialElements : [
39938 text: "Insert Table",
39941 ihtml : '<table><tr><td>Cell</td></tr></table>'
39945 text: "Insert Image",
39948 ihtml : '<img src="about:blank"/>'
39957 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
39958 "input:submit", "input:button", "select", "textarea", "label" ],
39961 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
39963 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39966 * @cfg {String} defaultFont default font to use.
39968 defaultFont: 'tahoma',
39970 fontSelect : false,
39973 formatCombo : false,
39975 init : function(editor)
39977 this.editor = editor;
39980 var fid = editor.frameId;
39982 function btn(id, toggle, handler){
39983 var xid = fid + '-'+ id ;
39987 cls : 'x-btn-icon x-edit-'+id,
39988 enableToggle:toggle !== false,
39989 scope: editor, // was editor...
39990 handler:handler||editor.relayBtnCmd,
39991 clickEvent:'mousedown',
39992 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39999 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
40001 // stop form submits
40002 tb.el.on('click', function(e){
40003 e.preventDefault(); // what does this do?
40006 if(!this.disable.font && !Roo.isSafari){
40007 /* why no safari for fonts
40008 editor.fontSelect = tb.el.createChild({
40011 cls:'x-font-select',
40012 html: editor.createFontOptions()
40014 editor.fontSelect.on('change', function(){
40015 var font = editor.fontSelect.dom.value;
40016 editor.relayCmd('fontname', font);
40017 editor.deferFocus();
40020 editor.fontSelect.dom,
40025 if(!this.disable.formats){
40026 this.formatCombo = new Roo.form.ComboBox({
40027 store: new Roo.data.SimpleStore({
40030 data : this.formats // from states.js
40033 //autoCreate : {tag: "div", size: "20"},
40034 displayField:'tag',
40038 triggerAction: 'all',
40039 emptyText:'Add tag',
40040 selectOnFocus:true,
40043 'select': function(c, r, i) {
40044 editor.insertTag(r.get('tag'));
40050 tb.addField(this.formatCombo);
40054 if(!this.disable.format){
40061 if(!this.disable.fontSize){
40066 btn('increasefontsize', false, editor.adjustFont),
40067 btn('decreasefontsize', false, editor.adjustFont)
40072 if(!this.disable.colors){
40075 id:editor.frameId +'-forecolor',
40076 cls:'x-btn-icon x-edit-forecolor',
40077 clickEvent:'mousedown',
40078 tooltip: this.buttonTips['forecolor'] || undefined,
40080 menu : new Roo.menu.ColorMenu({
40081 allowReselect: true,
40082 focus: Roo.emptyFn,
40085 selectHandler: function(cp, color){
40086 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
40087 editor.deferFocus();
40090 clickEvent:'mousedown'
40093 id:editor.frameId +'backcolor',
40094 cls:'x-btn-icon x-edit-backcolor',
40095 clickEvent:'mousedown',
40096 tooltip: this.buttonTips['backcolor'] || undefined,
40098 menu : new Roo.menu.ColorMenu({
40099 focus: Roo.emptyFn,
40102 allowReselect: true,
40103 selectHandler: function(cp, color){
40105 editor.execCmd('useCSS', false);
40106 editor.execCmd('hilitecolor', color);
40107 editor.execCmd('useCSS', true);
40108 editor.deferFocus();
40110 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
40111 Roo.isSafari || Roo.isIE ? '#'+color : color);
40112 editor.deferFocus();
40116 clickEvent:'mousedown'
40121 // now add all the items...
40124 if(!this.disable.alignments){
40127 btn('justifyleft'),
40128 btn('justifycenter'),
40129 btn('justifyright')
40133 //if(!Roo.isSafari){
40134 if(!this.disable.links){
40137 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
40141 if(!this.disable.lists){
40144 btn('insertorderedlist'),
40145 btn('insertunorderedlist')
40148 if(!this.disable.sourceEdit){
40151 btn('sourceedit', true, function(btn){
40152 this.toggleSourceEdit(btn.pressed);
40159 // special menu.. - needs to be tidied up..
40160 if (!this.disable.special) {
40163 cls: 'x-edit-none',
40169 for (var i =0; i < this.specialChars.length; i++) {
40170 smenu.menu.items.push({
40172 html: this.specialChars[i],
40173 handler: function(a,b) {
40174 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
40187 if (!this.disable.specialElements) {
40190 cls: 'x-edit-none',
40195 for (var i =0; i < this.specialElements.length; i++) {
40196 semenu.menu.items.push(
40198 handler: function(a,b) {
40199 editor.insertAtCursor(this.ihtml);
40201 }, this.specialElements[i])
40213 for(var i =0; i< this.btns.length;i++) {
40214 var b = this.btns[i];
40215 b.cls = 'x-edit-none';
40224 // disable everything...
40226 this.tb.items.each(function(item){
40227 if(item.id != editor.frameId+ '-sourceedit'){
40231 this.rendered = true;
40233 // the all the btns;
40234 editor.on('editorevent', this.updateToolbar, this);
40235 // other toolbars need to implement this..
40236 //editor.on('editmodechange', this.updateToolbar, this);
40242 * Protected method that will not generally be called directly. It triggers
40243 * a toolbar update by reading the markup state of the current selection in the editor.
40245 updateToolbar: function(){
40247 if(!this.editor.activated){
40248 this.editor.onFirstFocus();
40252 var btns = this.tb.items.map,
40253 doc = this.editor.doc,
40254 frameId = this.editor.frameId;
40256 if(!this.disable.font && !Roo.isSafari){
40258 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
40259 if(name != this.fontSelect.dom.value){
40260 this.fontSelect.dom.value = name;
40264 if(!this.disable.format){
40265 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
40266 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
40267 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
40269 if(!this.disable.alignments){
40270 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
40271 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
40272 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
40274 if(!Roo.isSafari && !this.disable.lists){
40275 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
40276 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
40279 var ans = this.editor.getAllAncestors();
40280 if (this.formatCombo) {
40283 var store = this.formatCombo.store;
40284 this.formatCombo.setValue("");
40285 for (var i =0; i < ans.length;i++) {
40286 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
40288 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
40296 // hides menus... - so this cant be on a menu...
40297 Roo.menu.MenuMgr.hideAll();
40299 //this.editorsyncValue();
40303 createFontOptions : function(){
40304 var buf = [], fs = this.fontFamilies, ff, lc;
40305 for(var i = 0, len = fs.length; i< len; i++){
40307 lc = ff.toLowerCase();
40309 '<option value="',lc,'" style="font-family:',ff,';"',
40310 (this.defaultFont == lc ? ' selected="true">' : '>'),
40315 return buf.join('');
40318 toggleSourceEdit : function(sourceEditMode){
40319 if(sourceEditMode === undefined){
40320 sourceEditMode = !this.sourceEditMode;
40322 this.sourceEditMode = sourceEditMode === true;
40323 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
40324 // just toggle the button?
40325 if(btn.pressed !== this.editor.sourceEditMode){
40326 btn.toggle(this.editor.sourceEditMode);
40330 if(this.sourceEditMode){
40331 this.tb.items.each(function(item){
40332 if(item.cmd != 'sourceedit'){
40338 if(this.initialized){
40339 this.tb.items.each(function(item){
40345 // tell the editor that it's been pressed..
40346 this.editor.toggleSourceEdit(sourceEditMode);
40350 * Object collection of toolbar tooltips for the buttons in the editor. The key
40351 * is the command id associated with that button and the value is a valid QuickTips object.
40356 title: 'Bold (Ctrl+B)',
40357 text: 'Make the selected text bold.',
40358 cls: 'x-html-editor-tip'
40361 title: 'Italic (Ctrl+I)',
40362 text: 'Make the selected text italic.',
40363 cls: 'x-html-editor-tip'
40371 title: 'Bold (Ctrl+B)',
40372 text: 'Make the selected text bold.',
40373 cls: 'x-html-editor-tip'
40376 title: 'Italic (Ctrl+I)',
40377 text: 'Make the selected text italic.',
40378 cls: 'x-html-editor-tip'
40381 title: 'Underline (Ctrl+U)',
40382 text: 'Underline the selected text.',
40383 cls: 'x-html-editor-tip'
40385 increasefontsize : {
40386 title: 'Grow Text',
40387 text: 'Increase the font size.',
40388 cls: 'x-html-editor-tip'
40390 decreasefontsize : {
40391 title: 'Shrink Text',
40392 text: 'Decrease the font size.',
40393 cls: 'x-html-editor-tip'
40396 title: 'Text Highlight Color',
40397 text: 'Change the background color of the selected text.',
40398 cls: 'x-html-editor-tip'
40401 title: 'Font Color',
40402 text: 'Change the color of the selected text.',
40403 cls: 'x-html-editor-tip'
40406 title: 'Align Text Left',
40407 text: 'Align text to the left.',
40408 cls: 'x-html-editor-tip'
40411 title: 'Center Text',
40412 text: 'Center text in the editor.',
40413 cls: 'x-html-editor-tip'
40416 title: 'Align Text Right',
40417 text: 'Align text to the right.',
40418 cls: 'x-html-editor-tip'
40420 insertunorderedlist : {
40421 title: 'Bullet List',
40422 text: 'Start a bulleted list.',
40423 cls: 'x-html-editor-tip'
40425 insertorderedlist : {
40426 title: 'Numbered List',
40427 text: 'Start a numbered list.',
40428 cls: 'x-html-editor-tip'
40431 title: 'Hyperlink',
40432 text: 'Make the selected text a hyperlink.',
40433 cls: 'x-html-editor-tip'
40436 title: 'Source Edit',
40437 text: 'Switch to source editing mode.',
40438 cls: 'x-html-editor-tip'
40442 onDestroy : function(){
40445 this.tb.items.each(function(item){
40447 item.menu.removeAll();
40449 item.menu.el.destroy();
40457 onFirstFocus: function() {
40458 this.tb.items.each(function(item){
40467 // <script type="text/javascript">
40470 * Ext JS Library 1.1.1
40471 * Copyright(c) 2006-2007, Ext JS, LLC.
40478 * @class Roo.form.HtmlEditor.ToolbarContext
40483 new Roo.form.HtmlEditor({
40486 { xtype: 'ToolbarStandard', styles : {} }
40487 { xtype: 'ToolbarContext', disable : {} }
40493 * @config : {Object} disable List of elements to disable.. (not done yet.)
40494 * @config : {Object} styles Map of styles available.
40498 Roo.form.HtmlEditor.ToolbarContext = function(config)
40501 Roo.apply(this, config);
40502 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
40503 // dont call parent... till later.
40504 this.styles = this.styles || {};
40506 Roo.form.HtmlEditor.ToolbarContext.types = {
40518 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
40580 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
40585 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40639 // should we really allow this??
40640 // should this just be
40655 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40663 * @cfg {Object} disable List of toolbar elements to disable
40668 * @cfg {Object} styles List of styles
40669 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
40671 * These must be defined in the page, so they get rendered correctly..
40682 init : function(editor)
40684 this.editor = editor;
40687 var fid = editor.frameId;
40689 function btn(id, toggle, handler){
40690 var xid = fid + '-'+ id ;
40694 cls : 'x-btn-icon x-edit-'+id,
40695 enableToggle:toggle !== false,
40696 scope: editor, // was editor...
40697 handler:handler||editor.relayBtnCmd,
40698 clickEvent:'mousedown',
40699 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40703 // create a new element.
40704 var wdiv = editor.wrap.createChild({
40706 }, editor.wrap.dom.firstChild.nextSibling, true);
40708 // can we do this more than once??
40710 // stop form submits
40713 // disable everything...
40714 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40715 this.toolbars = {};
40717 for (var i in ty) {
40719 this.toolbars[i] = this.buildToolbar(ty[i],i);
40721 this.tb = this.toolbars.BODY;
40723 this.buildFooter();
40724 this.footer.show();
40726 this.rendered = true;
40728 // the all the btns;
40729 editor.on('editorevent', this.updateToolbar, this);
40730 // other toolbars need to implement this..
40731 //editor.on('editmodechange', this.updateToolbar, this);
40737 * Protected method that will not generally be called directly. It triggers
40738 * a toolbar update by reading the markup state of the current selection in the editor.
40740 updateToolbar: function(ignore_a,ignore_b,sel){
40743 if(!this.editor.activated){
40744 this.editor.onFirstFocus();
40747 var updateFooter = sel ? false : true;
40750 var ans = this.editor.getAllAncestors();
40753 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40756 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40757 sel = sel ? sel : this.editor.doc.body;
40758 sel = sel.tagName.length ? sel : this.editor.doc.body;
40761 // pick a menu that exists..
40762 var tn = sel.tagName.toUpperCase();
40763 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40765 tn = sel.tagName.toUpperCase();
40767 var lastSel = this.tb.selectedNode
40769 this.tb.selectedNode = sel;
40771 // if current menu does not match..
40772 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
40775 ///console.log("show: " + tn);
40776 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
40779 this.tb.items.first().el.innerHTML = tn + ': ';
40782 // update attributes
40783 if (this.tb.fields) {
40784 this.tb.fields.each(function(e) {
40785 e.setValue(sel.getAttribute(e.name));
40790 var st = this.tb.fields.item(0);
40791 st.store.removeAll();
40792 var cn = sel.className.split(/\s+/);
40795 if (this.styles['*']) {
40797 Roo.each(this.styles['*'], function(v) {
40798 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
40801 if (this.styles[tn]) {
40802 Roo.each(this.styles[tn], function(v) {
40803 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
40807 st.store.loadData(avs);
40811 // flag our selected Node.
40812 this.tb.selectedNode = sel;
40815 Roo.menu.MenuMgr.hideAll();
40819 if (!updateFooter) {
40822 // update the footer
40826 this.footerEls = ans.reverse();
40827 Roo.each(this.footerEls, function(a,i) {
40828 if (!a) { return; }
40829 html += html.length ? ' > ' : '';
40831 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
40836 var sz = this.footDisp.up('td').getSize();
40837 this.footDisp.dom.style.width = (sz.width -10) + 'px';
40838 this.footDisp.dom.style.marginLeft = '5px';
40840 this.footDisp.dom.style.overflow = 'hidden';
40842 this.footDisp.dom.innerHTML = html;
40844 //this.editorsyncValue();
40849 onDestroy : function(){
40852 this.tb.items.each(function(item){
40854 item.menu.removeAll();
40856 item.menu.el.destroy();
40864 onFirstFocus: function() {
40865 // need to do this for all the toolbars..
40866 this.tb.items.each(function(item){
40870 buildToolbar: function(tlist, nm)
40872 var editor = this.editor;
40873 // create a new element.
40874 var wdiv = editor.wrap.createChild({
40876 }, editor.wrap.dom.firstChild.nextSibling, true);
40879 var tb = new Roo.Toolbar(wdiv);
40882 tb.add(nm+ ": ");
40887 // this needs a multi-select checkbox...
40888 tb.addField( new Roo.form.ComboBox({
40889 store: new Roo.data.SimpleStore({
40891 fields: ['val', 'selected'],
40894 name : 'className',
40895 displayField:'val',
40899 triggerAction: 'all',
40900 emptyText:'Select Style',
40901 selectOnFocus:true,
40904 'select': function(c, r, i) {
40905 // initial support only for on class per el..
40906 tb.selectedNode.className = r ? r.get('val') : '';
40915 for (var i in tlist) {
40917 var item = tlist[i];
40918 tb.add(item.title + ": ");
40924 // opts == pulldown..
40925 tb.addField( new Roo.form.ComboBox({
40926 store: new Roo.data.SimpleStore({
40932 displayField:'val',
40936 triggerAction: 'all',
40937 emptyText:'Select',
40938 selectOnFocus:true,
40939 width: item.width ? item.width : 130,
40941 'select': function(c, r, i) {
40942 tb.selectedNode.setAttribute(c.name, r.get('val'));
40951 tb.addField( new Roo.form.TextField({
40954 //allowBlank:false,
40959 tb.addField( new Roo.form.TextField({
40965 'change' : function(f, nv, ov) {
40966 tb.selectedNode.setAttribute(f.name, nv);
40972 tb.el.on('click', function(e){
40973 e.preventDefault(); // what does this do?
40975 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40978 // dont need to disable them... as they will get hidden
40983 buildFooter : function()
40986 var fel = this.editor.wrap.createChild();
40987 this.footer = new Roo.Toolbar(fel);
40988 // toolbar has scrolly on left / right?
40989 var footDisp= new Roo.Toolbar.Fill();
40995 handler : function() {
40996 _t.footDisp.scrollTo('left',0,true)
41000 this.footer.add( footDisp );
41005 handler : function() {
41007 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
41011 var fel = Roo.get(footDisp.el);
41012 fel.addClass('x-editor-context');
41013 this.footDispWrap = fel;
41014 this.footDispWrap.overflow = 'hidden';
41016 this.footDisp = fel.createChild();
41017 this.footDispWrap.on('click', this.onContextClick, this)
41021 onContextClick : function (ev,dom)
41023 ev.preventDefault();
41024 var cn = dom.className;
41026 if (!cn.match(/x-ed-loc-/)) {
41029 var n = cn.split('-').pop();
41030 var ans = this.footerEls;
41034 var range = this.editor.createRange();
41036 range.selectNodeContents(sel);
41037 //range.selectNode(sel);
41040 var selection = this.editor.getSelection();
41041 selection.removeAllRanges();
41042 selection.addRange(range);
41046 this.updateToolbar(null, null, sel);
41063 * Ext JS Library 1.1.1
41064 * Copyright(c) 2006-2007, Ext JS, LLC.
41066 * Originally Released Under LGPL - original licence link has changed is not relivant.
41069 * <script type="text/javascript">
41073 * @class Roo.form.BasicForm
41074 * @extends Roo.util.Observable
41075 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
41077 * @param {String/HTMLElement/Roo.Element} el The form element or its id
41078 * @param {Object} config Configuration options
41080 Roo.form.BasicForm = function(el, config){
41081 this.allItems = [];
41082 this.childForms = [];
41083 Roo.apply(this, config);
41085 * The Roo.form.Field items in this form.
41086 * @type MixedCollection
41090 this.items = new Roo.util.MixedCollection(false, function(o){
41091 return o.id || (o.id = Roo.id());
41095 * @event beforeaction
41096 * Fires before any action is performed. Return false to cancel the action.
41097 * @param {Form} this
41098 * @param {Action} action The action to be performed
41100 beforeaction: true,
41102 * @event actionfailed
41103 * Fires when an action fails.
41104 * @param {Form} this
41105 * @param {Action} action The action that failed
41107 actionfailed : true,
41109 * @event actioncomplete
41110 * Fires when an action is completed.
41111 * @param {Form} this
41112 * @param {Action} action The action that completed
41114 actioncomplete : true
41119 Roo.form.BasicForm.superclass.constructor.call(this);
41122 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
41124 * @cfg {String} method
41125 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
41128 * @cfg {DataReader} reader
41129 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
41130 * This is optional as there is built-in support for processing JSON.
41133 * @cfg {DataReader} errorReader
41134 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
41135 * This is completely optional as there is built-in support for processing JSON.
41138 * @cfg {String} url
41139 * The URL to use for form actions if one isn't supplied in the action options.
41142 * @cfg {Boolean} fileUpload
41143 * Set to true if this form is a file upload.
41147 * @cfg {Object} baseParams
41148 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
41153 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
41158 activeAction : null,
41161 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
41162 * or setValues() data instead of when the form was first created.
41164 trackResetOnLoad : false,
41168 * childForms - used for multi-tab forms
41171 childForms : false,
41174 * allItems - full list of fields.
41180 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
41181 * element by passing it or its id or mask the form itself by passing in true.
41184 waitMsgTarget : false,
41187 initEl : function(el){
41188 this.el = Roo.get(el);
41189 this.id = this.el.id || Roo.id();
41190 this.el.on('submit', this.onSubmit, this);
41191 this.el.addClass('x-form');
41195 onSubmit : function(e){
41200 * Returns true if client-side validation on the form is successful.
41203 isValid : function(){
41205 this.items.each(function(f){
41214 * Returns true if any fields in this form have changed since their original load.
41217 isDirty : function(){
41219 this.items.each(function(f){
41229 * Performs a predefined action (submit or load) or custom actions you define on this form.
41230 * @param {String} actionName The name of the action type
41231 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
41232 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
41233 * accept other config options):
41235 Property Type Description
41236 ---------------- --------------- ----------------------------------------------------------------------------------
41237 url String The url for the action (defaults to the form's url)
41238 method String The form method to use (defaults to the form's method, or POST if not defined)
41239 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
41240 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
41241 validate the form on the client (defaults to false)
41243 * @return {BasicForm} this
41245 doAction : function(action, options){
41246 if(typeof action == 'string'){
41247 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
41249 if(this.fireEvent('beforeaction', this, action) !== false){
41250 this.beforeAction(action);
41251 action.run.defer(100, action);
41257 * Shortcut to do a submit action.
41258 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
41259 * @return {BasicForm} this
41261 submit : function(options){
41262 this.doAction('submit', options);
41267 * Shortcut to do a load action.
41268 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
41269 * @return {BasicForm} this
41271 load : function(options){
41272 this.doAction('load', options);
41277 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
41278 * @param {Record} record The record to edit
41279 * @return {BasicForm} this
41281 updateRecord : function(record){
41282 record.beginEdit();
41283 var fs = record.fields;
41284 fs.each(function(f){
41285 var field = this.findField(f.name);
41287 record.set(f.name, field.getValue());
41295 * Loads an Roo.data.Record into this form.
41296 * @param {Record} record The record to load
41297 * @return {BasicForm} this
41299 loadRecord : function(record){
41300 this.setValues(record.data);
41305 beforeAction : function(action){
41306 var o = action.options;
41309 if(this.waitMsgTarget === true){
41310 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
41311 }else if(this.waitMsgTarget){
41312 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
41313 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
41315 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
41321 afterAction : function(action, success){
41322 this.activeAction = null;
41323 var o = action.options;
41325 if(this.waitMsgTarget === true){
41327 }else if(this.waitMsgTarget){
41328 this.waitMsgTarget.unmask();
41330 Roo.MessageBox.updateProgress(1);
41331 Roo.MessageBox.hide();
41338 Roo.callback(o.success, o.scope, [this, action]);
41339 this.fireEvent('actioncomplete', this, action);
41342 Roo.callback(o.failure, o.scope, [this, action]);
41343 // show an error message if no failed handler is set..
41344 if (!this.hasListener('actionfailed')) {
41345 Roo.MessageBox.alert("Error",
41346 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
41347 action.result.errorMsg :
41348 "Saving Failed, please check your entries"
41352 this.fireEvent('actionfailed', this, action);
41358 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
41359 * @param {String} id The value to search for
41362 findField : function(id){
41363 var field = this.items.get(id);
41365 this.items.each(function(f){
41366 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
41372 return field || null;
41376 * Add a secondary form to this one,
41377 * Used to provide tabbed forms. One form is primary, with hidden values
41378 * which mirror the elements from the other forms.
41380 * @param {Roo.form.Form} form to add.
41383 addForm : function(form)
41386 if (this.childForms.indexOf(form) > -1) {
41390 this.childForms.push(form);
41392 Roo.each(form.allItems, function (fe) {
41394 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
41395 if (this.findField(n)) { // already added..
41398 var add = new Roo.form.Hidden({
41401 add.render(this.el);
41408 * Mark fields in this form invalid in bulk.
41409 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
41410 * @return {BasicForm} this
41412 markInvalid : function(errors){
41413 if(errors instanceof Array){
41414 for(var i = 0, len = errors.length; i < len; i++){
41415 var fieldError = errors[i];
41416 var f = this.findField(fieldError.id);
41418 f.markInvalid(fieldError.msg);
41424 if(typeof errors[id] != 'function' && (field = this.findField(id))){
41425 field.markInvalid(errors[id]);
41429 Roo.each(this.childForms || [], function (f) {
41430 f.markInvalid(errors);
41437 * Set values for fields in this form in bulk.
41438 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
41439 * @return {BasicForm} this
41441 setValues : function(values){
41442 if(values instanceof Array){ // array of objects
41443 for(var i = 0, len = values.length; i < len; i++){
41445 var f = this.findField(v.id);
41447 f.setValue(v.value);
41448 if(this.trackResetOnLoad){
41449 f.originalValue = f.getValue();
41453 }else{ // object hash
41456 if(typeof values[id] != 'function' && (field = this.findField(id))){
41458 if (field.setFromData &&
41459 field.valueField &&
41460 field.displayField &&
41461 // combos' with local stores can
41462 // be queried via setValue()
41463 // to set their value..
41464 (field.store && !field.store.isLocal)
41468 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
41469 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
41470 field.setFromData(sd);
41473 field.setValue(values[id]);
41477 if(this.trackResetOnLoad){
41478 field.originalValue = field.getValue();
41484 Roo.each(this.childForms || [], function (f) {
41485 f.setValues(values);
41492 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
41493 * they are returned as an array.
41494 * @param {Boolean} asString
41497 getValues : function(asString){
41498 if (this.childForms) {
41499 // copy values from the child forms
41500 Roo.each(this.childForms, function (f) {
41501 this.setValues(f.getValues());
41507 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
41508 if(asString === true){
41511 return Roo.urlDecode(fs);
41515 * Returns the fields in this form as an object with key/value pairs.
41516 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
41519 getFieldValues : function(with_hidden)
41521 if (this.childForms) {
41522 // copy values from the child forms
41523 // should this call getFieldValues - probably not as we do not currently copy
41524 // hidden fields when we generate..
41525 Roo.each(this.childForms, function (f) {
41526 this.setValues(f.getValues());
41531 this.items.each(function(f){
41532 if (!f.getName()) {
41535 var v = f.getValue();
41536 // not sure if this supported any more..
41537 if ((typeof(v) == 'object') && f.getRawValue) {
41538 v = f.getRawValue() ; // dates..
41540 // combo boxes where name != hiddenName...
41541 if (f.name != f.getName()) {
41542 ret[f.name] = f.getRawValue();
41544 ret[f.getName()] = v;
41551 * Clears all invalid messages in this form.
41552 * @return {BasicForm} this
41554 clearInvalid : function(){
41555 this.items.each(function(f){
41559 Roo.each(this.childForms || [], function (f) {
41568 * Resets this form.
41569 * @return {BasicForm} this
41571 reset : function(){
41572 this.items.each(function(f){
41576 Roo.each(this.childForms || [], function (f) {
41585 * Add Roo.form components to this form.
41586 * @param {Field} field1
41587 * @param {Field} field2 (optional)
41588 * @param {Field} etc (optional)
41589 * @return {BasicForm} this
41592 this.items.addAll(Array.prototype.slice.call(arguments, 0));
41598 * Removes a field from the items collection (does NOT remove its markup).
41599 * @param {Field} field
41600 * @return {BasicForm} this
41602 remove : function(field){
41603 this.items.remove(field);
41608 * Looks at the fields in this form, checks them for an id attribute,
41609 * and calls applyTo on the existing dom element with that id.
41610 * @return {BasicForm} this
41612 render : function(){
41613 this.items.each(function(f){
41614 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
41622 * Calls {@link Ext#apply} for all fields in this form with the passed object.
41623 * @param {Object} values
41624 * @return {BasicForm} this
41626 applyToFields : function(o){
41627 this.items.each(function(f){
41634 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
41635 * @param {Object} values
41636 * @return {BasicForm} this
41638 applyIfToFields : function(o){
41639 this.items.each(function(f){
41647 Roo.BasicForm = Roo.form.BasicForm;/*
41649 * Ext JS Library 1.1.1
41650 * Copyright(c) 2006-2007, Ext JS, LLC.
41652 * Originally Released Under LGPL - original licence link has changed is not relivant.
41655 * <script type="text/javascript">
41659 * @class Roo.form.Form
41660 * @extends Roo.form.BasicForm
41661 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
41663 * @param {Object} config Configuration options
41665 Roo.form.Form = function(config){
41667 if (config.items) {
41668 xitems = config.items;
41669 delete config.items;
41673 Roo.form.Form.superclass.constructor.call(this, null, config);
41674 this.url = this.url || this.action;
41676 this.root = new Roo.form.Layout(Roo.applyIf({
41680 this.active = this.root;
41682 * Array of all the buttons that have been added to this form via {@link addButton}
41686 this.allItems = [];
41689 * @event clientvalidation
41690 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
41691 * @param {Form} this
41692 * @param {Boolean} valid true if the form has passed client-side validation
41694 clientvalidation: true,
41697 * Fires when the form is rendered
41698 * @param {Roo.form.Form} form
41703 if (this.progressUrl) {
41704 // push a hidden field onto the list of fields..
41708 name : 'UPLOAD_IDENTIFIER'
41713 Roo.each(xitems, this.addxtype, this);
41719 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
41721 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
41724 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
41727 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
41729 buttonAlign:'center',
41732 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
41737 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
41738 * This property cascades to child containers if not set.
41743 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
41744 * fires a looping event with that state. This is required to bind buttons to the valid
41745 * state using the config value formBind:true on the button.
41747 monitorValid : false,
41750 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
41755 * @cfg {String} progressUrl - Url to return progress data
41758 progressUrl : false,
41761 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
41762 * fields are added and the column is closed. If no fields are passed the column remains open
41763 * until end() is called.
41764 * @param {Object} config The config to pass to the column
41765 * @param {Field} field1 (optional)
41766 * @param {Field} field2 (optional)
41767 * @param {Field} etc (optional)
41768 * @return Column The column container object
41770 column : function(c){
41771 var col = new Roo.form.Column(c);
41773 if(arguments.length > 1){ // duplicate code required because of Opera
41774 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41781 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
41782 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
41783 * until end() is called.
41784 * @param {Object} config The config to pass to the fieldset
41785 * @param {Field} field1 (optional)
41786 * @param {Field} field2 (optional)
41787 * @param {Field} etc (optional)
41788 * @return FieldSet The fieldset container object
41790 fieldset : function(c){
41791 var fs = new Roo.form.FieldSet(c);
41793 if(arguments.length > 1){ // duplicate code required because of Opera
41794 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41801 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
41802 * fields are added and the container is closed. If no fields are passed the container remains open
41803 * until end() is called.
41804 * @param {Object} config The config to pass to the Layout
41805 * @param {Field} field1 (optional)
41806 * @param {Field} field2 (optional)
41807 * @param {Field} etc (optional)
41808 * @return Layout The container object
41810 container : function(c){
41811 var l = new Roo.form.Layout(c);
41813 if(arguments.length > 1){ // duplicate code required because of Opera
41814 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41821 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41822 * @param {Object} container A Roo.form.Layout or subclass of Layout
41823 * @return {Form} this
41825 start : function(c){
41826 // cascade label info
41827 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
41828 this.active.stack.push(c);
41829 c.ownerCt = this.active;
41835 * Closes the current open container
41836 * @return {Form} this
41839 if(this.active == this.root){
41842 this.active = this.active.ownerCt;
41847 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
41848 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
41849 * as the label of the field.
41850 * @param {Field} field1
41851 * @param {Field} field2 (optional)
41852 * @param {Field} etc. (optional)
41853 * @return {Form} this
41856 this.active.stack.push.apply(this.active.stack, arguments);
41857 this.allItems.push.apply(this.allItems,arguments);
41859 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
41860 if(a[i].isFormField){
41865 Roo.form.Form.superclass.add.apply(this, r);
41875 * Find any element that has been added to a form, using it's ID or name
41876 * This can include framesets, columns etc. along with regular fields..
41877 * @param {String} id - id or name to find.
41879 * @return {Element} e - or false if nothing found.
41881 findbyId : function(id)
41887 Roo.each(this.allItems, function(f){
41888 if (f.id == id || f.name == id ){
41899 * Render this form into the passed container. This should only be called once!
41900 * @param {String/HTMLElement/Element} container The element this component should be rendered into
41901 * @return {Form} this
41903 render : function(ct)
41909 var o = this.autoCreate || {
41911 method : this.method || 'POST',
41912 id : this.id || Roo.id()
41914 this.initEl(ct.createChild(o));
41916 this.root.render(this.el);
41920 this.items.each(function(f){
41921 f.render('x-form-el-'+f.id);
41924 if(this.buttons.length > 0){
41925 // tables are required to maintain order and for correct IE layout
41926 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
41927 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
41928 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
41930 var tr = tb.getElementsByTagName('tr')[0];
41931 for(var i = 0, len = this.buttons.length; i < len; i++) {
41932 var b = this.buttons[i];
41933 var td = document.createElement('td');
41934 td.className = 'x-form-btn-td';
41935 b.render(tr.appendChild(td));
41938 if(this.monitorValid){ // initialize after render
41939 this.startMonitoring();
41941 this.fireEvent('rendered', this);
41946 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
41947 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
41948 * object or a valid Roo.DomHelper element config
41949 * @param {Function} handler The function called when the button is clicked
41950 * @param {Object} scope (optional) The scope of the handler function
41951 * @return {Roo.Button}
41953 addButton : function(config, handler, scope){
41957 minWidth: this.minButtonWidth,
41960 if(typeof config == "string"){
41963 Roo.apply(bc, config);
41965 var btn = new Roo.Button(null, bc);
41966 this.buttons.push(btn);
41971 * Adds a series of form elements (using the xtype property as the factory method.
41972 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41973 * @param {Object} config
41976 addxtype : function()
41978 var ar = Array.prototype.slice.call(arguments, 0);
41980 for(var i = 0; i < ar.length; i++) {
41982 continue; // skip -- if this happends something invalid got sent, we
41983 // should ignore it, as basically that interface element will not show up
41984 // and that should be pretty obvious!!
41987 if (Roo.form[ar[i].xtype]) {
41989 var fe = Roo.factory(ar[i], Roo.form);
41995 fe.store.form = this;
42000 this.allItems.push(fe);
42001 if (fe.items && fe.addxtype) {
42002 fe.addxtype.apply(fe, fe.items);
42012 // console.log('adding ' + ar[i].xtype);
42014 if (ar[i].xtype == 'Button') {
42015 //console.log('adding button');
42016 //console.log(ar[i]);
42017 this.addButton(ar[i]);
42018 this.allItems.push(fe);
42022 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
42023 alert('end is not supported on xtype any more, use items');
42025 // //console.log('adding end');
42033 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
42034 * option "monitorValid"
42036 startMonitoring : function(){
42039 Roo.TaskMgr.start({
42040 run : this.bindHandler,
42041 interval : this.monitorPoll || 200,
42048 * Stops monitoring of the valid state of this form
42050 stopMonitoring : function(){
42051 this.bound = false;
42055 bindHandler : function(){
42057 return false; // stops binding
42060 this.items.each(function(f){
42061 if(!f.isValid(true)){
42066 for(var i = 0, len = this.buttons.length; i < len; i++){
42067 var btn = this.buttons[i];
42068 if(btn.formBind === true && btn.disabled === valid){
42069 btn.setDisabled(!valid);
42072 this.fireEvent('clientvalidation', this, valid);
42086 Roo.Form = Roo.form.Form;
42089 * Ext JS Library 1.1.1
42090 * Copyright(c) 2006-2007, Ext JS, LLC.
42092 * Originally Released Under LGPL - original licence link has changed is not relivant.
42095 * <script type="text/javascript">
42099 * @class Roo.form.Action
42100 * Internal Class used to handle form actions
42102 * @param {Roo.form.BasicForm} el The form element or its id
42103 * @param {Object} config Configuration options
42107 // define the action interface
42108 Roo.form.Action = function(form, options){
42110 this.options = options || {};
42113 * Client Validation Failed
42116 Roo.form.Action.CLIENT_INVALID = 'client';
42118 * Server Validation Failed
42121 Roo.form.Action.SERVER_INVALID = 'server';
42123 * Connect to Server Failed
42126 Roo.form.Action.CONNECT_FAILURE = 'connect';
42128 * Reading Data from Server Failed
42131 Roo.form.Action.LOAD_FAILURE = 'load';
42133 Roo.form.Action.prototype = {
42135 failureType : undefined,
42136 response : undefined,
42137 result : undefined,
42139 // interface method
42140 run : function(options){
42144 // interface method
42145 success : function(response){
42149 // interface method
42150 handleResponse : function(response){
42154 // default connection failure
42155 failure : function(response){
42157 this.response = response;
42158 this.failureType = Roo.form.Action.CONNECT_FAILURE;
42159 this.form.afterAction(this, false);
42162 processResponse : function(response){
42163 this.response = response;
42164 if(!response.responseText){
42167 this.result = this.handleResponse(response);
42168 return this.result;
42171 // utility functions used internally
42172 getUrl : function(appendParams){
42173 var url = this.options.url || this.form.url || this.form.el.dom.action;
42175 var p = this.getParams();
42177 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
42183 getMethod : function(){
42184 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
42187 getParams : function(){
42188 var bp = this.form.baseParams;
42189 var p = this.options.params;
42191 if(typeof p == "object"){
42192 p = Roo.urlEncode(Roo.applyIf(p, bp));
42193 }else if(typeof p == 'string' && bp){
42194 p += '&' + Roo.urlEncode(bp);
42197 p = Roo.urlEncode(bp);
42202 createCallback : function(){
42204 success: this.success,
42205 failure: this.failure,
42207 timeout: (this.form.timeout*1000),
42208 upload: this.form.fileUpload ? this.success : undefined
42213 Roo.form.Action.Submit = function(form, options){
42214 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
42217 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
42220 haveProgress : false,
42221 uploadComplete : false,
42223 // uploadProgress indicator.
42224 uploadProgress : function()
42226 if (!this.form.progressUrl) {
42230 if (!this.haveProgress) {
42231 Roo.MessageBox.progress("Uploading", "Uploading");
42233 if (this.uploadComplete) {
42234 Roo.MessageBox.hide();
42238 this.haveProgress = true;
42240 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
42242 var c = new Roo.data.Connection();
42244 url : this.form.progressUrl,
42249 success : function(req){
42250 //console.log(data);
42254 rdata = Roo.decode(req.responseText)
42256 Roo.log("Invalid data from server..");
42260 if (!rdata || !rdata.success) {
42264 var data = rdata.data;
42266 if (this.uploadComplete) {
42267 Roo.MessageBox.hide();
42272 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
42273 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
42276 this.uploadProgress.defer(2000,this);
42279 failure: function(data) {
42280 Roo.log('progress url failed ');
42291 // run get Values on the form, so it syncs any secondary forms.
42292 this.form.getValues();
42294 var o = this.options;
42295 var method = this.getMethod();
42296 var isPost = method == 'POST';
42297 if(o.clientValidation === false || this.form.isValid()){
42299 if (this.form.progressUrl) {
42300 this.form.findField('UPLOAD_IDENTIFIER').setValue(
42301 (new Date() * 1) + '' + Math.random());
42306 Roo.Ajax.request(Roo.apply(this.createCallback(), {
42307 form:this.form.el.dom,
42308 url:this.getUrl(!isPost),
42310 params:isPost ? this.getParams() : null,
42311 isUpload: this.form.fileUpload
42314 this.uploadProgress();
42316 }else if (o.clientValidation !== false){ // client validation failed
42317 this.failureType = Roo.form.Action.CLIENT_INVALID;
42318 this.form.afterAction(this, false);
42322 success : function(response)
42324 this.uploadComplete= true;
42325 if (this.haveProgress) {
42326 Roo.MessageBox.hide();
42330 var result = this.processResponse(response);
42331 if(result === true || result.success){
42332 this.form.afterAction(this, true);
42336 this.form.markInvalid(result.errors);
42337 this.failureType = Roo.form.Action.SERVER_INVALID;
42339 this.form.afterAction(this, false);
42341 failure : function(response)
42343 this.uploadComplete= true;
42344 if (this.haveProgress) {
42345 Roo.MessageBox.hide();
42348 this.response = response;
42349 this.failureType = Roo.form.Action.CONNECT_FAILURE;
42350 this.form.afterAction(this, false);
42353 handleResponse : function(response){
42354 if(this.form.errorReader){
42355 var rs = this.form.errorReader.read(response);
42358 for(var i = 0, len = rs.records.length; i < len; i++) {
42359 var r = rs.records[i];
42360 errors[i] = r.data;
42363 if(errors.length < 1){
42367 success : rs.success,
42373 ret = Roo.decode(response.responseText);
42377 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
42387 Roo.form.Action.Load = function(form, options){
42388 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
42389 this.reader = this.form.reader;
42392 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
42397 Roo.Ajax.request(Roo.apply(
42398 this.createCallback(), {
42399 method:this.getMethod(),
42400 url:this.getUrl(false),
42401 params:this.getParams()
42405 success : function(response){
42407 var result = this.processResponse(response);
42408 if(result === true || !result.success || !result.data){
42409 this.failureType = Roo.form.Action.LOAD_FAILURE;
42410 this.form.afterAction(this, false);
42413 this.form.clearInvalid();
42414 this.form.setValues(result.data);
42415 this.form.afterAction(this, true);
42418 handleResponse : function(response){
42419 if(this.form.reader){
42420 var rs = this.form.reader.read(response);
42421 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
42423 success : rs.success,
42427 return Roo.decode(response.responseText);
42431 Roo.form.Action.ACTION_TYPES = {
42432 'load' : Roo.form.Action.Load,
42433 'submit' : Roo.form.Action.Submit
42436 * Ext JS Library 1.1.1
42437 * Copyright(c) 2006-2007, Ext JS, LLC.
42439 * Originally Released Under LGPL - original licence link has changed is not relivant.
42442 * <script type="text/javascript">
42446 * @class Roo.form.Layout
42447 * @extends Roo.Component
42448 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
42450 * @param {Object} config Configuration options
42452 Roo.form.Layout = function(config){
42454 if (config.items) {
42455 xitems = config.items;
42456 delete config.items;
42458 Roo.form.Layout.superclass.constructor.call(this, config);
42460 Roo.each(xitems, this.addxtype, this);
42464 Roo.extend(Roo.form.Layout, Roo.Component, {
42466 * @cfg {String/Object} autoCreate
42467 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
42470 * @cfg {String/Object/Function} style
42471 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
42472 * a function which returns such a specification.
42475 * @cfg {String} labelAlign
42476 * Valid values are "left," "top" and "right" (defaults to "left")
42479 * @cfg {Number} labelWidth
42480 * Fixed width in pixels of all field labels (defaults to undefined)
42483 * @cfg {Boolean} clear
42484 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
42488 * @cfg {String} labelSeparator
42489 * The separator to use after field labels (defaults to ':')
42491 labelSeparator : ':',
42493 * @cfg {Boolean} hideLabels
42494 * True to suppress the display of field labels in this layout (defaults to false)
42496 hideLabels : false,
42499 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
42504 onRender : function(ct, position){
42505 if(this.el){ // from markup
42506 this.el = Roo.get(this.el);
42507 }else { // generate
42508 var cfg = this.getAutoCreate();
42509 this.el = ct.createChild(cfg, position);
42512 this.el.applyStyles(this.style);
42514 if(this.labelAlign){
42515 this.el.addClass('x-form-label-'+this.labelAlign);
42517 if(this.hideLabels){
42518 this.labelStyle = "display:none";
42519 this.elementStyle = "padding-left:0;";
42521 if(typeof this.labelWidth == 'number'){
42522 this.labelStyle = "width:"+this.labelWidth+"px;";
42523 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
42525 if(this.labelAlign == 'top'){
42526 this.labelStyle = "width:auto;";
42527 this.elementStyle = "padding-left:0;";
42530 var stack = this.stack;
42531 var slen = stack.length;
42533 if(!this.fieldTpl){
42534 var t = new Roo.Template(
42535 '<div class="x-form-item {5}">',
42536 '<label for="{0}" style="{2}">{1}{4}</label>',
42537 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
42539 '</div><div class="x-form-clear-left"></div>'
42541 t.disableFormats = true;
42543 Roo.form.Layout.prototype.fieldTpl = t;
42545 for(var i = 0; i < slen; i++) {
42546 if(stack[i].isFormField){
42547 this.renderField(stack[i]);
42549 this.renderComponent(stack[i]);
42554 this.el.createChild({cls:'x-form-clear'});
42559 renderField : function(f){
42560 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
42563 f.labelStyle||this.labelStyle||'', //2
42564 this.elementStyle||'', //3
42565 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
42566 f.itemCls||this.itemCls||'' //5
42567 ], true).getPrevSibling());
42571 renderComponent : function(c){
42572 c.render(c.isLayout ? this.el : this.el.createChild());
42575 * Adds a object form elements (using the xtype property as the factory method.)
42576 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
42577 * @param {Object} config
42579 addxtype : function(o)
42581 // create the lement.
42582 o.form = this.form;
42583 var fe = Roo.factory(o, Roo.form);
42584 this.form.allItems.push(fe);
42585 this.stack.push(fe);
42587 if (fe.isFormField) {
42588 this.form.items.add(fe);
42596 * @class Roo.form.Column
42597 * @extends Roo.form.Layout
42598 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
42600 * @param {Object} config Configuration options
42602 Roo.form.Column = function(config){
42603 Roo.form.Column.superclass.constructor.call(this, config);
42606 Roo.extend(Roo.form.Column, Roo.form.Layout, {
42608 * @cfg {Number/String} width
42609 * The fixed width of the column in pixels or CSS value (defaults to "auto")
42612 * @cfg {String/Object} autoCreate
42613 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
42617 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
42620 onRender : function(ct, position){
42621 Roo.form.Column.superclass.onRender.call(this, ct, position);
42623 this.el.setWidth(this.width);
42630 * @class Roo.form.Row
42631 * @extends Roo.form.Layout
42632 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
42634 * @param {Object} config Configuration options
42638 Roo.form.Row = function(config){
42639 Roo.form.Row.superclass.constructor.call(this, config);
42642 Roo.extend(Roo.form.Row, Roo.form.Layout, {
42644 * @cfg {Number/String} width
42645 * The fixed width of the column in pixels or CSS value (defaults to "auto")
42648 * @cfg {Number/String} height
42649 * The fixed height of the column in pixels or CSS value (defaults to "auto")
42651 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
42655 onRender : function(ct, position){
42656 //console.log('row render');
42658 var t = new Roo.Template(
42659 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
42660 '<label for="{0}" style="{2}">{1}{4}</label>',
42661 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
42665 t.disableFormats = true;
42667 Roo.form.Layout.prototype.rowTpl = t;
42669 this.fieldTpl = this.rowTpl;
42671 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
42672 var labelWidth = 100;
42674 if ((this.labelAlign != 'top')) {
42675 if (typeof this.labelWidth == 'number') {
42676 labelWidth = this.labelWidth
42678 this.padWidth = 20 + labelWidth;
42682 Roo.form.Column.superclass.onRender.call(this, ct, position);
42684 this.el.setWidth(this.width);
42687 this.el.setHeight(this.height);
42692 renderField : function(f){
42693 f.fieldEl = this.fieldTpl.append(this.el, [
42694 f.id, f.fieldLabel,
42695 f.labelStyle||this.labelStyle||'',
42696 this.elementStyle||'',
42697 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
42698 f.itemCls||this.itemCls||'',
42699 f.width ? f.width + this.padWidth : 160 + this.padWidth
42706 * @class Roo.form.FieldSet
42707 * @extends Roo.form.Layout
42708 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
42710 * @param {Object} config Configuration options
42712 Roo.form.FieldSet = function(config){
42713 Roo.form.FieldSet.superclass.constructor.call(this, config);
42716 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
42718 * @cfg {String} legend
42719 * The text to display as the legend for the FieldSet (defaults to '')
42722 * @cfg {String/Object} autoCreate
42723 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
42727 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
42730 onRender : function(ct, position){
42731 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
42733 this.setLegend(this.legend);
42738 setLegend : function(text){
42740 this.el.child('legend').update(text);
42745 * Ext JS Library 1.1.1
42746 * Copyright(c) 2006-2007, Ext JS, LLC.
42748 * Originally Released Under LGPL - original licence link has changed is not relivant.
42751 * <script type="text/javascript">
42754 * @class Roo.form.VTypes
42755 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
42758 Roo.form.VTypes = function(){
42759 // closure these in so they are only created once.
42760 var alpha = /^[a-zA-Z_]+$/;
42761 var alphanum = /^[a-zA-Z0-9_]+$/;
42762 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
42763 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
42765 // All these messages and functions are configurable
42768 * The function used to validate email addresses
42769 * @param {String} value The email address
42771 'email' : function(v){
42772 return email.test(v);
42775 * The error text to display when the email validation function returns false
42778 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
42780 * The keystroke filter mask to be applied on email input
42783 'emailMask' : /[a-z0-9_\.\-@]/i,
42786 * The function used to validate URLs
42787 * @param {String} value The URL
42789 'url' : function(v){
42790 return url.test(v);
42793 * The error text to display when the url validation function returns false
42796 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
42799 * The function used to validate alpha values
42800 * @param {String} value The value
42802 'alpha' : function(v){
42803 return alpha.test(v);
42806 * The error text to display when the alpha validation function returns false
42809 'alphaText' : 'This field should only contain letters and _',
42811 * The keystroke filter mask to be applied on alpha input
42814 'alphaMask' : /[a-z_]/i,
42817 * The function used to validate alphanumeric values
42818 * @param {String} value The value
42820 'alphanum' : function(v){
42821 return alphanum.test(v);
42824 * The error text to display when the alphanumeric validation function returns false
42827 'alphanumText' : 'This field should only contain letters, numbers and _',
42829 * The keystroke filter mask to be applied on alphanumeric input
42832 'alphanumMask' : /[a-z0-9_]/i
42834 }();//<script type="text/javascript">
42837 * @class Roo.form.FCKeditor
42838 * @extends Roo.form.TextArea
42839 * Wrapper around the FCKEditor http://www.fckeditor.net
42841 * Creates a new FCKeditor
42842 * @param {Object} config Configuration options
42844 Roo.form.FCKeditor = function(config){
42845 Roo.form.FCKeditor.superclass.constructor.call(this, config);
42848 * @event editorinit
42849 * Fired when the editor is initialized - you can add extra handlers here..
42850 * @param {FCKeditor} this
42851 * @param {Object} the FCK object.
42858 Roo.form.FCKeditor.editors = { };
42859 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
42861 //defaultAutoCreate : {
42862 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
42866 * @cfg {Object} fck options - see fck manual for details.
42871 * @cfg {Object} fck toolbar set (Basic or Default)
42873 toolbarSet : 'Basic',
42875 * @cfg {Object} fck BasePath
42877 basePath : '/fckeditor/',
42885 onRender : function(ct, position)
42888 this.defaultAutoCreate = {
42890 style:"width:300px;height:60px;",
42891 autocomplete: "off"
42894 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
42897 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
42898 if(this.preventScrollbars){
42899 this.el.setStyle("overflow", "hidden");
42901 this.el.setHeight(this.growMin);
42904 //console.log('onrender' + this.getId() );
42905 Roo.form.FCKeditor.editors[this.getId()] = this;
42908 this.replaceTextarea() ;
42912 getEditor : function() {
42913 return this.fckEditor;
42916 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
42917 * @param {Mixed} value The value to set
42921 setValue : function(value)
42923 //console.log('setValue: ' + value);
42925 if(typeof(value) == 'undefined') { // not sure why this is happending...
42928 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42930 //if(!this.el || !this.getEditor()) {
42931 // this.value = value;
42932 //this.setValue.defer(100,this,[value]);
42936 if(!this.getEditor()) {
42940 this.getEditor().SetData(value);
42947 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
42948 * @return {Mixed} value The field value
42950 getValue : function()
42953 if (this.frame && this.frame.dom.style.display == 'none') {
42954 return Roo.form.FCKeditor.superclass.getValue.call(this);
42957 if(!this.el || !this.getEditor()) {
42959 // this.getValue.defer(100,this);
42964 var value=this.getEditor().GetData();
42965 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42966 return Roo.form.FCKeditor.superclass.getValue.call(this);
42972 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
42973 * @return {Mixed} value The field value
42975 getRawValue : function()
42977 if (this.frame && this.frame.dom.style.display == 'none') {
42978 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42981 if(!this.el || !this.getEditor()) {
42982 //this.getRawValue.defer(100,this);
42989 var value=this.getEditor().GetData();
42990 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
42991 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42995 setSize : function(w,h) {
42999 //if (this.frame && this.frame.dom.style.display == 'none') {
43000 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
43003 //if(!this.el || !this.getEditor()) {
43004 // this.setSize.defer(100,this, [w,h]);
43010 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
43012 this.frame.dom.setAttribute('width', w);
43013 this.frame.dom.setAttribute('height', h);
43014 this.frame.setSize(w,h);
43018 toggleSourceEdit : function(value) {
43022 this.el.dom.style.display = value ? '' : 'none';
43023 this.frame.dom.style.display = value ? 'none' : '';
43028 focus: function(tag)
43030 if (this.frame.dom.style.display == 'none') {
43031 return Roo.form.FCKeditor.superclass.focus.call(this);
43033 if(!this.el || !this.getEditor()) {
43034 this.focus.defer(100,this, [tag]);
43041 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
43042 this.getEditor().Focus();
43044 if (!this.getEditor().Selection.GetSelection()) {
43045 this.focus.defer(100,this, [tag]);
43050 var r = this.getEditor().EditorDocument.createRange();
43051 r.setStart(tgs[0],0);
43052 r.setEnd(tgs[0],0);
43053 this.getEditor().Selection.GetSelection().removeAllRanges();
43054 this.getEditor().Selection.GetSelection().addRange(r);
43055 this.getEditor().Focus();
43062 replaceTextarea : function()
43064 if ( document.getElementById( this.getId() + '___Frame' ) )
43066 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
43068 // We must check the elements firstly using the Id and then the name.
43069 var oTextarea = document.getElementById( this.getId() );
43071 var colElementsByName = document.getElementsByName( this.getId() ) ;
43073 oTextarea.style.display = 'none' ;
43075 if ( oTextarea.tabIndex ) {
43076 this.TabIndex = oTextarea.tabIndex ;
43079 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
43080 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
43081 this.frame = Roo.get(this.getId() + '___Frame')
43084 _getConfigHtml : function()
43088 for ( var o in this.fckconfig ) {
43089 sConfig += sConfig.length > 0 ? '&' : '';
43090 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
43093 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
43097 _getIFrameHtml : function()
43099 var sFile = 'fckeditor.html' ;
43100 /* no idea what this is about..
43103 if ( (/fcksource=true/i).test( window.top.location.search ) )
43104 sFile = 'fckeditor.original.html' ;
43109 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
43110 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
43113 var html = '<iframe id="' + this.getId() +
43114 '___Frame" src="' + sLink +
43115 '" width="' + this.width +
43116 '" height="' + this.height + '"' +
43117 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
43118 ' frameborder="0" scrolling="no"></iframe>' ;
43123 _insertHtmlBefore : function( html, element )
43125 if ( element.insertAdjacentHTML ) {
43127 element.insertAdjacentHTML( 'beforeBegin', html ) ;
43129 var oRange = document.createRange() ;
43130 oRange.setStartBefore( element ) ;
43131 var oFragment = oRange.createContextualFragment( html );
43132 element.parentNode.insertBefore( oFragment, element ) ;
43145 //Roo.reg('fckeditor', Roo.form.FCKeditor);
43147 function FCKeditor_OnComplete(editorInstance){
43148 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
43149 f.fckEditor = editorInstance;
43150 //console.log("loaded");
43151 f.fireEvent('editorinit', f, editorInstance);
43171 //<script type="text/javascript">
43173 * @class Roo.form.GridField
43174 * @extends Roo.form.Field
43175 * Embed a grid (or editable grid into a form)
43178 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
43180 * xgrid.store = Roo.data.Store
43181 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
43182 * xgrid.store.reader = Roo.data.JsonReader
43186 * Creates a new GridField
43187 * @param {Object} config Configuration options
43189 Roo.form.GridField = function(config){
43190 Roo.form.GridField.superclass.constructor.call(this, config);
43194 Roo.extend(Roo.form.GridField, Roo.form.Field, {
43196 * @cfg {Number} width - used to restrict width of grid..
43200 * @cfg {Number} height - used to restrict height of grid..
43204 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
43210 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43211 * {tag: "input", type: "checkbox", autocomplete: "off"})
43213 // defaultAutoCreate : { tag: 'div' },
43214 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
43216 * @cfg {String} addTitle Text to include for adding a title.
43220 onResize : function(){
43221 Roo.form.Field.superclass.onResize.apply(this, arguments);
43224 initEvents : function(){
43225 // Roo.form.Checkbox.superclass.initEvents.call(this);
43226 // has no events...
43231 getResizeEl : function(){
43235 getPositionEl : function(){
43240 onRender : function(ct, position){
43242 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
43243 var style = this.style;
43246 Roo.form.GridField.superclass.onRender.call(this, ct, position);
43247 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
43248 this.viewEl = this.wrap.createChild({ tag: 'div' });
43250 this.viewEl.applyStyles(style);
43253 this.viewEl.setWidth(this.width);
43256 this.viewEl.setHeight(this.height);
43258 //if(this.inputValue !== undefined){
43259 //this.setValue(this.value);
43262 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
43265 this.grid.render();
43266 this.grid.getDataSource().on('remove', this.refreshValue, this);
43267 this.grid.getDataSource().on('update', this.refreshValue, this);
43268 this.grid.on('afteredit', this.refreshValue, this);
43274 * Sets the value of the item.
43275 * @param {String} either an object or a string..
43277 setValue : function(v){
43279 v = v || []; // empty set..
43280 // this does not seem smart - it really only affects memoryproxy grids..
43281 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
43282 var ds = this.grid.getDataSource();
43283 // assumes a json reader..
43285 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
43286 ds.loadData( data);
43288 // clear selection so it does not get stale.
43289 if (this.grid.sm) {
43290 this.grid.sm.clearSelections();
43293 Roo.form.GridField.superclass.setValue.call(this, v);
43294 this.refreshValue();
43295 // should load data in the grid really....
43299 refreshValue: function() {
43301 this.grid.getDataSource().each(function(r) {
43304 this.el.dom.value = Roo.encode(val);
43312 * Ext JS Library 1.1.1
43313 * Copyright(c) 2006-2007, Ext JS, LLC.
43315 * Originally Released Under LGPL - original licence link has changed is not relivant.
43318 * <script type="text/javascript">
43321 * @class Roo.form.DisplayField
43322 * @extends Roo.form.Field
43323 * A generic Field to display non-editable data.
43325 * Creates a new Display Field item.
43326 * @param {Object} config Configuration options
43328 Roo.form.DisplayField = function(config){
43329 Roo.form.DisplayField.superclass.constructor.call(this, config);
43333 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
43334 inputType: 'hidden',
43340 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43342 focusClass : undefined,
43344 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43346 fieldClass: 'x-form-field',
43349 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
43351 valueRenderer: undefined,
43355 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43356 * {tag: "input", type: "checkbox", autocomplete: "off"})
43359 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
43361 onResize : function(){
43362 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
43366 initEvents : function(){
43367 // Roo.form.Checkbox.superclass.initEvents.call(this);
43368 // has no events...
43373 getResizeEl : function(){
43377 getPositionEl : function(){
43382 onRender : function(ct, position){
43384 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
43385 //if(this.inputValue !== undefined){
43386 this.wrap = this.el.wrap();
43388 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
43390 if (this.bodyStyle) {
43391 this.viewEl.applyStyles(this.bodyStyle);
43393 //this.viewEl.setStyle('padding', '2px');
43395 this.setValue(this.value);
43400 initValue : Roo.emptyFn,
43405 onClick : function(){
43410 * Sets the checked state of the checkbox.
43411 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
43413 setValue : function(v){
43415 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
43416 // this might be called before we have a dom element..
43417 if (!this.viewEl) {
43420 this.viewEl.dom.innerHTML = html;
43421 Roo.form.DisplayField.superclass.setValue.call(this, v);
43431 * @class Roo.form.DayPicker
43432 * @extends Roo.form.Field
43433 * A Day picker show [M] [T] [W] ....
43435 * Creates a new Day Picker
43436 * @param {Object} config Configuration options
43438 Roo.form.DayPicker= function(config){
43439 Roo.form.DayPicker.superclass.constructor.call(this, config);
43443 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
43445 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43447 focusClass : undefined,
43449 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43451 fieldClass: "x-form-field",
43454 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43455 * {tag: "input", type: "checkbox", autocomplete: "off"})
43457 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
43460 actionMode : 'viewEl',
43464 inputType : 'hidden',
43467 inputElement: false, // real input element?
43468 basedOn: false, // ????
43470 isFormField: true, // not sure where this is needed!!!!
43472 onResize : function(){
43473 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
43474 if(!this.boxLabel){
43475 this.el.alignTo(this.wrap, 'c-c');
43479 initEvents : function(){
43480 Roo.form.Checkbox.superclass.initEvents.call(this);
43481 this.el.on("click", this.onClick, this);
43482 this.el.on("change", this.onClick, this);
43486 getResizeEl : function(){
43490 getPositionEl : function(){
43496 onRender : function(ct, position){
43497 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43499 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
43501 var r1 = '<table><tr>';
43502 var r2 = '<tr class="x-form-daypick-icons">';
43503 for (var i=0; i < 7; i++) {
43504 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
43505 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
43508 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
43509 viewEl.select('img').on('click', this.onClick, this);
43510 this.viewEl = viewEl;
43513 // this will not work on Chrome!!!
43514 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43515 this.el.on('propertychange', this.setFromHidden, this); //ie
43523 initValue : Roo.emptyFn,
43526 * Returns the checked state of the checkbox.
43527 * @return {Boolean} True if checked, else false
43529 getValue : function(){
43530 return this.el.dom.value;
43535 onClick : function(e){
43536 //this.setChecked(!this.checked);
43537 Roo.get(e.target).toggleClass('x-menu-item-checked');
43538 this.refreshValue();
43539 //if(this.el.dom.checked != this.checked){
43540 // this.setValue(this.el.dom.checked);
43545 refreshValue : function()
43548 this.viewEl.select('img',true).each(function(e,i,n) {
43549 val += e.is(".x-menu-item-checked") ? String(n) : '';
43551 this.setValue(val, true);
43555 * Sets the checked state of the checkbox.
43556 * On is always based on a string comparison between inputValue and the param.
43557 * @param {Boolean/String} value - the value to set
43558 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
43560 setValue : function(v,suppressEvent){
43561 if (!this.el.dom) {
43564 var old = this.el.dom.value ;
43565 this.el.dom.value = v;
43566 if (suppressEvent) {
43570 // update display..
43571 this.viewEl.select('img',true).each(function(e,i,n) {
43573 var on = e.is(".x-menu-item-checked");
43574 var newv = v.indexOf(String(n)) > -1;
43576 e.toggleClass('x-menu-item-checked');
43582 this.fireEvent('change', this, v, old);
43587 // handle setting of hidden value by some other method!!?!?
43588 setFromHidden: function()
43593 //console.log("SET FROM HIDDEN");
43594 //alert('setFrom hidden');
43595 this.setValue(this.el.dom.value);
43598 onDestroy : function()
43601 Roo.get(this.viewEl).remove();
43604 Roo.form.DayPicker.superclass.onDestroy.call(this);
43608 * RooJS Library 1.1.1
43609 * Copyright(c) 2008-2011 Alan Knowles
43616 * @class Roo.form.ComboCheck
43617 * @extends Roo.form.ComboBox
43618 * A combobox for multiple select items.
43620 * FIXME - could do with a reset button..
43623 * Create a new ComboCheck
43624 * @param {Object} config Configuration options
43626 Roo.form.ComboCheck = function(config){
43627 Roo.form.ComboCheck.superclass.constructor.call(this, config);
43628 // should verify some data...
43630 // hiddenName = required..
43631 // displayField = required
43632 // valudField == required
43633 var req= [ 'hiddenName', 'displayField', 'valueField' ];
43635 Roo.each(req, function(e) {
43636 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
43637 throw "Roo.form.ComboCheck : missing value for: " + e;
43644 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
43649 selectedClass: 'x-menu-item-checked',
43652 onRender : function(ct, position){
43658 var cls = 'x-combo-list';
43661 this.tpl = new Roo.Template({
43662 html : '<div class="'+cls+'-item x-menu-check-item">' +
43663 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
43664 '<span>{' + this.displayField + '}</span>' +
43671 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
43672 this.view.singleSelect = false;
43673 this.view.multiSelect = true;
43674 this.view.toggleSelect = true;
43675 this.pageTb.add(new Roo.Toolbar.Fill(), {
43678 handler: function()
43685 onViewOver : function(e, t){
43691 onViewClick : function(doFocus,index){
43695 select: function () {
43696 //Roo.log("SELECT CALLED");
43699 selectByValue : function(xv, scrollIntoView){
43700 var ar = this.getValueArray();
43703 Roo.each(ar, function(v) {
43704 if(v === undefined || v === null){
43707 var r = this.findRecord(this.valueField, v);
43709 sels.push(this.store.indexOf(r))
43713 this.view.select(sels);
43719 onSelect : function(record, index){
43720 // Roo.log("onselect Called");
43721 // this is only called by the clear button now..
43722 this.view.clearSelections();
43723 this.setValue('[]');
43724 if (this.value != this.valueBefore) {
43725 this.fireEvent('change', this, this.value, this.valueBefore);
43728 getValueArray : function()
43733 //Roo.log(this.value);
43734 if (typeof(this.value) == 'undefined') {
43737 var ar = Roo.decode(this.value);
43738 return ar instanceof Array ? ar : []; //?? valid?
43741 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
43746 expand : function ()
43748 Roo.form.ComboCheck.superclass.expand.call(this);
43749 this.valueBefore = this.value;
43754 collapse : function(){
43755 Roo.form.ComboCheck.superclass.collapse.call(this);
43756 var sl = this.view.getSelectedIndexes();
43757 var st = this.store;
43761 Roo.each(sl, function(i) {
43763 nv.push(r.get(this.valueField));
43765 this.setValue(Roo.encode(nv));
43766 if (this.value != this.valueBefore) {
43768 this.fireEvent('change', this, this.value, this.valueBefore);
43773 setValue : function(v){
43777 var vals = this.getValueArray();
43779 Roo.each(vals, function(k) {
43780 var r = this.findRecord(this.valueField, k);
43782 tv.push(r.data[this.displayField]);
43783 }else if(this.valueNotFoundText !== undefined){
43784 tv.push( this.valueNotFoundText );
43789 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
43790 this.hiddenField.value = v;
43794 });//<script type="text/javasscript">
43798 * @class Roo.DDView
43799 * A DnD enabled version of Roo.View.
43800 * @param {Element/String} container The Element in which to create the View.
43801 * @param {String} tpl The template string used to create the markup for each element of the View
43802 * @param {Object} config The configuration properties. These include all the config options of
43803 * {@link Roo.View} plus some specific to this class.<br>
43805 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
43806 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
43808 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
43809 .x-view-drag-insert-above {
43810 border-top:1px dotted #3366cc;
43812 .x-view-drag-insert-below {
43813 border-bottom:1px dotted #3366cc;
43819 Roo.DDView = function(container, tpl, config) {
43820 Roo.DDView.superclass.constructor.apply(this, arguments);
43821 this.getEl().setStyle("outline", "0px none");
43822 this.getEl().unselectable();
43823 if (this.dragGroup) {
43824 this.setDraggable(this.dragGroup.split(","));
43826 if (this.dropGroup) {
43827 this.setDroppable(this.dropGroup.split(","));
43829 if (this.deletable) {
43830 this.setDeletable();
43832 this.isDirtyFlag = false;
43838 Roo.extend(Roo.DDView, Roo.View, {
43839 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
43840 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
43841 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
43842 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
43846 reset: Roo.emptyFn,
43848 clearInvalid: Roo.form.Field.prototype.clearInvalid,
43850 validate: function() {
43854 destroy: function() {
43855 this.purgeListeners();
43856 this.getEl.removeAllListeners();
43857 this.getEl().remove();
43858 if (this.dragZone) {
43859 if (this.dragZone.destroy) {
43860 this.dragZone.destroy();
43863 if (this.dropZone) {
43864 if (this.dropZone.destroy) {
43865 this.dropZone.destroy();
43870 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
43871 getName: function() {
43875 /** Loads the View from a JSON string representing the Records to put into the Store. */
43876 setValue: function(v) {
43878 throw "DDView.setValue(). DDView must be constructed with a valid Store";
43881 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
43882 this.store.proxy = new Roo.data.MemoryProxy(data);
43886 /** @return {String} a parenthesised list of the ids of the Records in the View. */
43887 getValue: function() {
43889 this.store.each(function(rec) {
43890 result += rec.id + ',';
43892 return result.substr(0, result.length - 1) + ')';
43895 getIds: function() {
43896 var i = 0, result = new Array(this.store.getCount());
43897 this.store.each(function(rec) {
43898 result[i++] = rec.id;
43903 isDirty: function() {
43904 return this.isDirtyFlag;
43908 * Part of the Roo.dd.DropZone interface. If no target node is found, the
43909 * whole Element becomes the target, and this causes the drop gesture to append.
43911 getTargetFromEvent : function(e) {
43912 var target = e.getTarget();
43913 while ((target !== null) && (target.parentNode != this.el.dom)) {
43914 target = target.parentNode;
43917 target = this.el.dom.lastChild || this.el.dom;
43923 * Create the drag data which consists of an object which has the property "ddel" as
43924 * the drag proxy element.
43926 getDragData : function(e) {
43927 var target = this.findItemFromChild(e.getTarget());
43929 this.handleSelection(e);
43930 var selNodes = this.getSelectedNodes();
43933 copy: this.copy || (this.allowCopy && e.ctrlKey),
43937 var selectedIndices = this.getSelectedIndexes();
43938 for (var i = 0; i < selectedIndices.length; i++) {
43939 dragData.records.push(this.store.getAt(selectedIndices[i]));
43941 if (selNodes.length == 1) {
43942 dragData.ddel = target.cloneNode(true); // the div element
43944 var div = document.createElement('div'); // create the multi element drag "ghost"
43945 div.className = 'multi-proxy';
43946 for (var i = 0, len = selNodes.length; i < len; i++) {
43947 div.appendChild(selNodes[i].cloneNode(true));
43949 dragData.ddel = div;
43951 //console.log(dragData)
43952 //console.log(dragData.ddel.innerHTML)
43955 //console.log('nodragData')
43959 /** Specify to which ddGroup items in this DDView may be dragged. */
43960 setDraggable: function(ddGroup) {
43961 if (ddGroup instanceof Array) {
43962 Roo.each(ddGroup, this.setDraggable, this);
43965 if (this.dragZone) {
43966 this.dragZone.addToGroup(ddGroup);
43968 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
43969 containerScroll: true,
43973 // Draggability implies selection. DragZone's mousedown selects the element.
43974 if (!this.multiSelect) { this.singleSelect = true; }
43976 // Wire the DragZone's handlers up to methods in *this*
43977 this.dragZone.getDragData = this.getDragData.createDelegate(this);
43981 /** Specify from which ddGroup this DDView accepts drops. */
43982 setDroppable: function(ddGroup) {
43983 if (ddGroup instanceof Array) {
43984 Roo.each(ddGroup, this.setDroppable, this);
43987 if (this.dropZone) {
43988 this.dropZone.addToGroup(ddGroup);
43990 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
43991 containerScroll: true,
43995 // Wire the DropZone's handlers up to methods in *this*
43996 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
43997 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
43998 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
43999 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
44000 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
44004 /** Decide whether to drop above or below a View node. */
44005 getDropPoint : function(e, n, dd){
44006 if (n == this.el.dom) { return "above"; }
44007 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
44008 var c = t + (b - t) / 2;
44009 var y = Roo.lib.Event.getPageY(e);
44017 onNodeEnter : function(n, dd, e, data){
44021 onNodeOver : function(n, dd, e, data){
44022 var pt = this.getDropPoint(e, n, dd);
44023 // set the insert point style on the target node
44024 var dragElClass = this.dropNotAllowed;
44027 if (pt == "above"){
44028 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
44029 targetElClass = "x-view-drag-insert-above";
44031 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
44032 targetElClass = "x-view-drag-insert-below";
44034 if (this.lastInsertClass != targetElClass){
44035 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
44036 this.lastInsertClass = targetElClass;
44039 return dragElClass;
44042 onNodeOut : function(n, dd, e, data){
44043 this.removeDropIndicators(n);
44046 onNodeDrop : function(n, dd, e, data){
44047 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
44050 var pt = this.getDropPoint(e, n, dd);
44051 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
44052 if (pt == "below") { insertAt++; }
44053 for (var i = 0; i < data.records.length; i++) {
44054 var r = data.records[i];
44055 var dup = this.store.getById(r.id);
44056 if (dup && (dd != this.dragZone)) {
44057 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
44060 this.store.insert(insertAt++, r.copy());
44062 data.source.isDirtyFlag = true;
44064 this.store.insert(insertAt++, r);
44066 this.isDirtyFlag = true;
44069 this.dragZone.cachedTarget = null;
44073 removeDropIndicators : function(n){
44075 Roo.fly(n).removeClass([
44076 "x-view-drag-insert-above",
44077 "x-view-drag-insert-below"]);
44078 this.lastInsertClass = "_noclass";
44083 * Utility method. Add a delete option to the DDView's context menu.
44084 * @param {String} imageUrl The URL of the "delete" icon image.
44086 setDeletable: function(imageUrl) {
44087 if (!this.singleSelect && !this.multiSelect) {
44088 this.singleSelect = true;
44090 var c = this.getContextMenu();
44091 this.contextMenu.on("itemclick", function(item) {
44094 this.remove(this.getSelectedIndexes());
44098 this.contextMenu.add({
44105 /** Return the context menu for this DDView. */
44106 getContextMenu: function() {
44107 if (!this.contextMenu) {
44108 // Create the View's context menu
44109 this.contextMenu = new Roo.menu.Menu({
44110 id: this.id + "-contextmenu"
44112 this.el.on("contextmenu", this.showContextMenu, this);
44114 return this.contextMenu;
44117 disableContextMenu: function() {
44118 if (this.contextMenu) {
44119 this.el.un("contextmenu", this.showContextMenu, this);
44123 showContextMenu: function(e, item) {
44124 item = this.findItemFromChild(e.getTarget());
44127 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
44128 this.contextMenu.showAt(e.getXY());
44133 * Remove {@link Roo.data.Record}s at the specified indices.
44134 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
44136 remove: function(selectedIndices) {
44137 selectedIndices = [].concat(selectedIndices);
44138 for (var i = 0; i < selectedIndices.length; i++) {
44139 var rec = this.store.getAt(selectedIndices[i]);
44140 this.store.remove(rec);
44145 * Double click fires the event, but also, if this is draggable, and there is only one other
44146 * related DropZone, it transfers the selected node.
44148 onDblClick : function(e){
44149 var item = this.findItemFromChild(e.getTarget());
44151 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
44154 if (this.dragGroup) {
44155 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
44156 while (targets.indexOf(this.dropZone) > -1) {
44157 targets.remove(this.dropZone);
44159 if (targets.length == 1) {
44160 this.dragZone.cachedTarget = null;
44161 var el = Roo.get(targets[0].getEl());
44162 var box = el.getBox(true);
44163 targets[0].onNodeDrop(el.dom, {
44165 xy: [box.x, box.y + box.height - 1]
44166 }, null, this.getDragData(e));
44172 handleSelection: function(e) {
44173 this.dragZone.cachedTarget = null;
44174 var item = this.findItemFromChild(e.getTarget());
44176 this.clearSelections(true);
44179 if (item && (this.multiSelect || this.singleSelect)){
44180 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
44181 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
44182 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
44183 this.unselect(item);
44185 this.select(item, this.multiSelect && e.ctrlKey);
44186 this.lastSelection = item;
44191 onItemClick : function(item, index, e){
44192 if(this.fireEvent("beforeclick", this, index, item, e) === false){
44198 unselect : function(nodeInfo, suppressEvent){
44199 var node = this.getNode(nodeInfo);
44200 if(node && this.isSelected(node)){
44201 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
44202 Roo.fly(node).removeClass(this.selectedClass);
44203 this.selections.remove(node);
44204 if(!suppressEvent){
44205 this.fireEvent("selectionchange", this, this.selections);
44213 * Ext JS Library 1.1.1
44214 * Copyright(c) 2006-2007, Ext JS, LLC.
44216 * Originally Released Under LGPL - original licence link has changed is not relivant.
44219 * <script type="text/javascript">
44223 * @class Roo.LayoutManager
44224 * @extends Roo.util.Observable
44225 * Base class for layout managers.
44227 Roo.LayoutManager = function(container, config){
44228 Roo.LayoutManager.superclass.constructor.call(this);
44229 this.el = Roo.get(container);
44230 // ie scrollbar fix
44231 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
44232 document.body.scroll = "no";
44233 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
44234 this.el.position('relative');
44236 this.id = this.el.id;
44237 this.el.addClass("x-layout-container");
44238 /** false to disable window resize monitoring @type Boolean */
44239 this.monitorWindowResize = true;
44244 * Fires when a layout is performed.
44245 * @param {Roo.LayoutManager} this
44249 * @event regionresized
44250 * Fires when the user resizes a region.
44251 * @param {Roo.LayoutRegion} region The resized region
44252 * @param {Number} newSize The new size (width for east/west, height for north/south)
44254 "regionresized" : true,
44256 * @event regioncollapsed
44257 * Fires when a region is collapsed.
44258 * @param {Roo.LayoutRegion} region The collapsed region
44260 "regioncollapsed" : true,
44262 * @event regionexpanded
44263 * Fires when a region is expanded.
44264 * @param {Roo.LayoutRegion} region The expanded region
44266 "regionexpanded" : true
44268 this.updating = false;
44269 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
44272 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
44274 * Returns true if this layout is currently being updated
44275 * @return {Boolean}
44277 isUpdating : function(){
44278 return this.updating;
44282 * Suspend the LayoutManager from doing auto-layouts while
44283 * making multiple add or remove calls
44285 beginUpdate : function(){
44286 this.updating = true;
44290 * Restore auto-layouts and optionally disable the manager from performing a layout
44291 * @param {Boolean} noLayout true to disable a layout update
44293 endUpdate : function(noLayout){
44294 this.updating = false;
44300 layout: function(){
44304 onRegionResized : function(region, newSize){
44305 this.fireEvent("regionresized", region, newSize);
44309 onRegionCollapsed : function(region){
44310 this.fireEvent("regioncollapsed", region);
44313 onRegionExpanded : function(region){
44314 this.fireEvent("regionexpanded", region);
44318 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
44319 * performs box-model adjustments.
44320 * @return {Object} The size as an object {width: (the width), height: (the height)}
44322 getViewSize : function(){
44324 if(this.el.dom != document.body){
44325 size = this.el.getSize();
44327 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
44329 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
44330 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
44335 * Returns the Element this layout is bound to.
44336 * @return {Roo.Element}
44338 getEl : function(){
44343 * Returns the specified region.
44344 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
44345 * @return {Roo.LayoutRegion}
44347 getRegion : function(target){
44348 return this.regions[target.toLowerCase()];
44351 onWindowResize : function(){
44352 if(this.monitorWindowResize){
44358 * Ext JS Library 1.1.1
44359 * Copyright(c) 2006-2007, Ext JS, LLC.
44361 * Originally Released Under LGPL - original licence link has changed is not relivant.
44364 * <script type="text/javascript">
44367 * @class Roo.BorderLayout
44368 * @extends Roo.LayoutManager
44369 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
44370 * please see: <br><br>
44371 * <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>
44372 * <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>
44375 var layout = new Roo.BorderLayout(document.body, {
44409 preferredTabWidth: 150
44414 var CP = Roo.ContentPanel;
44416 layout.beginUpdate();
44417 layout.add("north", new CP("north", "North"));
44418 layout.add("south", new CP("south", {title: "South", closable: true}));
44419 layout.add("west", new CP("west", {title: "West"}));
44420 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
44421 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
44422 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
44423 layout.getRegion("center").showPanel("center1");
44424 layout.endUpdate();
44427 <b>The container the layout is rendered into can be either the body element or any other element.
44428 If it is not the body element, the container needs to either be an absolute positioned element,
44429 or you will need to add "position:relative" to the css of the container. You will also need to specify
44430 the container size if it is not the body element.</b>
44433 * Create a new BorderLayout
44434 * @param {String/HTMLElement/Element} container The container this layout is bound to
44435 * @param {Object} config Configuration options
44437 Roo.BorderLayout = function(container, config){
44438 config = config || {};
44439 Roo.BorderLayout.superclass.constructor.call(this, container, config);
44440 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
44441 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
44442 var target = this.factory.validRegions[i];
44443 if(config[target]){
44444 this.addRegion(target, config[target]);
44449 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
44451 * Creates and adds a new region if it doesn't already exist.
44452 * @param {String} target The target region key (north, south, east, west or center).
44453 * @param {Object} config The regions config object
44454 * @return {BorderLayoutRegion} The new region
44456 addRegion : function(target, config){
44457 if(!this.regions[target]){
44458 var r = this.factory.create(target, this, config);
44459 this.bindRegion(target, r);
44461 return this.regions[target];
44465 bindRegion : function(name, r){
44466 this.regions[name] = r;
44467 r.on("visibilitychange", this.layout, this);
44468 r.on("paneladded", this.layout, this);
44469 r.on("panelremoved", this.layout, this);
44470 r.on("invalidated", this.layout, this);
44471 r.on("resized", this.onRegionResized, this);
44472 r.on("collapsed", this.onRegionCollapsed, this);
44473 r.on("expanded", this.onRegionExpanded, this);
44477 * Performs a layout update.
44479 layout : function(){
44480 if(this.updating) return;
44481 var size = this.getViewSize();
44482 var w = size.width;
44483 var h = size.height;
44488 //var x = 0, y = 0;
44490 var rs = this.regions;
44491 var north = rs["north"];
44492 var south = rs["south"];
44493 var west = rs["west"];
44494 var east = rs["east"];
44495 var center = rs["center"];
44496 //if(this.hideOnLayout){ // not supported anymore
44497 //c.el.setStyle("display", "none");
44499 if(north && north.isVisible()){
44500 var b = north.getBox();
44501 var m = north.getMargins();
44502 b.width = w - (m.left+m.right);
44505 centerY = b.height + b.y + m.bottom;
44506 centerH -= centerY;
44507 north.updateBox(this.safeBox(b));
44509 if(south && south.isVisible()){
44510 var b = south.getBox();
44511 var m = south.getMargins();
44512 b.width = w - (m.left+m.right);
44514 var totalHeight = (b.height + m.top + m.bottom);
44515 b.y = h - totalHeight + m.top;
44516 centerH -= totalHeight;
44517 south.updateBox(this.safeBox(b));
44519 if(west && west.isVisible()){
44520 var b = west.getBox();
44521 var m = west.getMargins();
44522 b.height = centerH - (m.top+m.bottom);
44524 b.y = centerY + m.top;
44525 var totalWidth = (b.width + m.left + m.right);
44526 centerX += totalWidth;
44527 centerW -= totalWidth;
44528 west.updateBox(this.safeBox(b));
44530 if(east && east.isVisible()){
44531 var b = east.getBox();
44532 var m = east.getMargins();
44533 b.height = centerH - (m.top+m.bottom);
44534 var totalWidth = (b.width + m.left + m.right);
44535 b.x = w - totalWidth + m.left;
44536 b.y = centerY + m.top;
44537 centerW -= totalWidth;
44538 east.updateBox(this.safeBox(b));
44541 var m = center.getMargins();
44543 x: centerX + m.left,
44544 y: centerY + m.top,
44545 width: centerW - (m.left+m.right),
44546 height: centerH - (m.top+m.bottom)
44548 //if(this.hideOnLayout){
44549 //center.el.setStyle("display", "block");
44551 center.updateBox(this.safeBox(centerBox));
44554 this.fireEvent("layout", this);
44558 safeBox : function(box){
44559 box.width = Math.max(0, box.width);
44560 box.height = Math.max(0, box.height);
44565 * Adds a ContentPanel (or subclass) to this layout.
44566 * @param {String} target The target region key (north, south, east, west or center).
44567 * @param {Roo.ContentPanel} panel The panel to add
44568 * @return {Roo.ContentPanel} The added panel
44570 add : function(target, panel){
44572 target = target.toLowerCase();
44573 return this.regions[target].add(panel);
44577 * Remove a ContentPanel (or subclass) to this layout.
44578 * @param {String} target The target region key (north, south, east, west or center).
44579 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
44580 * @return {Roo.ContentPanel} The removed panel
44582 remove : function(target, panel){
44583 target = target.toLowerCase();
44584 return this.regions[target].remove(panel);
44588 * Searches all regions for a panel with the specified id
44589 * @param {String} panelId
44590 * @return {Roo.ContentPanel} The panel or null if it wasn't found
44592 findPanel : function(panelId){
44593 var rs = this.regions;
44594 for(var target in rs){
44595 if(typeof rs[target] != "function"){
44596 var p = rs[target].getPanel(panelId);
44606 * Searches all regions for a panel with the specified id and activates (shows) it.
44607 * @param {String/ContentPanel} panelId The panels id or the panel itself
44608 * @return {Roo.ContentPanel} The shown panel or null
44610 showPanel : function(panelId) {
44611 var rs = this.regions;
44612 for(var target in rs){
44613 var r = rs[target];
44614 if(typeof r != "function"){
44615 if(r.hasPanel(panelId)){
44616 return r.showPanel(panelId);
44624 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
44625 * @param {Roo.state.Provider} provider (optional) An alternate state provider
44627 restoreState : function(provider){
44629 provider = Roo.state.Manager;
44631 var sm = new Roo.LayoutStateManager();
44632 sm.init(this, provider);
44636 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
44637 * object should contain properties for each region to add ContentPanels to, and each property's value should be
44638 * a valid ContentPanel config object. Example:
44640 // Create the main layout
44641 var layout = new Roo.BorderLayout('main-ct', {
44652 // Create and add multiple ContentPanels at once via configs
44655 id: 'source-files',
44657 title:'Ext Source Files',
44670 * @param {Object} regions An object containing ContentPanel configs by region name
44672 batchAdd : function(regions){
44673 this.beginUpdate();
44674 for(var rname in regions){
44675 var lr = this.regions[rname];
44677 this.addTypedPanels(lr, regions[rname]);
44684 addTypedPanels : function(lr, ps){
44685 if(typeof ps == 'string'){
44686 lr.add(new Roo.ContentPanel(ps));
44688 else if(ps instanceof Array){
44689 for(var i =0, len = ps.length; i < len; i++){
44690 this.addTypedPanels(lr, ps[i]);
44693 else if(!ps.events){ // raw config?
44695 delete ps.el; // prevent conflict
44696 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
44698 else { // panel object assumed!
44703 * Adds a xtype elements to the layout.
44707 xtype : 'ContentPanel',
44714 xtype : 'NestedLayoutPanel',
44720 items : [ ... list of content panels or nested layout panels.. ]
44724 * @param {Object} cfg Xtype definition of item to add.
44726 addxtype : function(cfg)
44728 // basically accepts a pannel...
44729 // can accept a layout region..!?!?
44730 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
44732 if (!cfg.xtype.match(/Panel$/)) {
44737 if (typeof(cfg.region) == 'undefined') {
44738 Roo.log("Failed to add Panel, region was not set");
44742 var region = cfg.region;
44748 xitems = cfg.items;
44755 case 'ContentPanel': // ContentPanel (el, cfg)
44756 case 'ScrollPanel': // ContentPanel (el, cfg)
44757 if(cfg.autoCreate) {
44758 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
44760 var el = this.el.createChild();
44761 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
44764 this.add(region, ret);
44768 case 'TreePanel': // our new panel!
44769 cfg.el = this.el.createChild();
44770 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
44771 this.add(region, ret);
44774 case 'NestedLayoutPanel':
44775 // create a new Layout (which is a Border Layout...
44776 var el = this.el.createChild();
44777 var clayout = cfg.layout;
44779 clayout.items = clayout.items || [];
44780 // replace this exitems with the clayout ones..
44781 xitems = clayout.items;
44784 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
44785 cfg.background = false;
44787 var layout = new Roo.BorderLayout(el, clayout);
44789 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
44790 //console.log('adding nested layout panel ' + cfg.toSource());
44791 this.add(region, ret);
44792 nb = {}; /// find first...
44797 // needs grid and region
44799 //var el = this.getRegion(region).el.createChild();
44800 var el = this.el.createChild();
44801 // create the grid first...
44803 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
44805 if (region == 'center' && this.active ) {
44806 cfg.background = false;
44808 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
44810 this.add(region, ret);
44811 if (cfg.background) {
44812 ret.on('activate', function(gp) {
44813 if (!gp.grid.rendered) {
44826 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
44828 // GridPanel (grid, cfg)
44831 this.beginUpdate();
44835 Roo.each(xitems, function(i) {
44836 region = nb && i.region ? i.region : false;
44838 var add = ret.addxtype(i);
44841 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
44842 if (!i.background) {
44843 abn[region] = nb[region] ;
44850 // make the last non-background panel active..
44851 //if (nb) { Roo.log(abn); }
44854 for(var r in abn) {
44855 region = this.getRegion(r);
44857 // tried using nb[r], but it does not work..
44859 region.showPanel(abn[r]);
44870 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
44871 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
44872 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
44873 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
44876 var CP = Roo.ContentPanel;
44878 var layout = Roo.BorderLayout.create({
44882 panels: [new CP("north", "North")]
44891 panels: [new CP("west", {title: "West"})]
44900 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
44909 panels: [new CP("south", {title: "South", closable: true})]
44916 preferredTabWidth: 150,
44918 new CP("center1", {title: "Close Me", closable: true}),
44919 new CP("center2", {title: "Center Panel", closable: false})
44924 layout.getRegion("center").showPanel("center1");
44929 Roo.BorderLayout.create = function(config, targetEl){
44930 var layout = new Roo.BorderLayout(targetEl || document.body, config);
44931 layout.beginUpdate();
44932 var regions = Roo.BorderLayout.RegionFactory.validRegions;
44933 for(var j = 0, jlen = regions.length; j < jlen; j++){
44934 var lr = regions[j];
44935 if(layout.regions[lr] && config[lr].panels){
44936 var r = layout.regions[lr];
44937 var ps = config[lr].panels;
44938 layout.addTypedPanels(r, ps);
44941 layout.endUpdate();
44946 Roo.BorderLayout.RegionFactory = {
44948 validRegions : ["north","south","east","west","center"],
44951 create : function(target, mgr, config){
44952 target = target.toLowerCase();
44953 if(config.lightweight || config.basic){
44954 return new Roo.BasicLayoutRegion(mgr, config, target);
44958 return new Roo.NorthLayoutRegion(mgr, config);
44960 return new Roo.SouthLayoutRegion(mgr, config);
44962 return new Roo.EastLayoutRegion(mgr, config);
44964 return new Roo.WestLayoutRegion(mgr, config);
44966 return new Roo.CenterLayoutRegion(mgr, config);
44968 throw 'Layout region "'+target+'" not supported.';
44972 * Ext JS Library 1.1.1
44973 * Copyright(c) 2006-2007, Ext JS, LLC.
44975 * Originally Released Under LGPL - original licence link has changed is not relivant.
44978 * <script type="text/javascript">
44982 * @class Roo.BasicLayoutRegion
44983 * @extends Roo.util.Observable
44984 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
44985 * and does not have a titlebar, tabs or any other features. All it does is size and position
44986 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
44988 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
44990 this.position = pos;
44993 * @scope Roo.BasicLayoutRegion
44997 * @event beforeremove
44998 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
44999 * @param {Roo.LayoutRegion} this
45000 * @param {Roo.ContentPanel} panel The panel
45001 * @param {Object} e The cancel event object
45003 "beforeremove" : true,
45005 * @event invalidated
45006 * Fires when the layout for this region is changed.
45007 * @param {Roo.LayoutRegion} this
45009 "invalidated" : true,
45011 * @event visibilitychange
45012 * Fires when this region is shown or hidden
45013 * @param {Roo.LayoutRegion} this
45014 * @param {Boolean} visibility true or false
45016 "visibilitychange" : true,
45018 * @event paneladded
45019 * Fires when a panel is added.
45020 * @param {Roo.LayoutRegion} this
45021 * @param {Roo.ContentPanel} panel The panel
45023 "paneladded" : true,
45025 * @event panelremoved
45026 * Fires when a panel is removed.
45027 * @param {Roo.LayoutRegion} this
45028 * @param {Roo.ContentPanel} panel The panel
45030 "panelremoved" : true,
45033 * Fires when this region is collapsed.
45034 * @param {Roo.LayoutRegion} this
45036 "collapsed" : true,
45039 * Fires when this region is expanded.
45040 * @param {Roo.LayoutRegion} this
45045 * Fires when this region is slid into view.
45046 * @param {Roo.LayoutRegion} this
45048 "slideshow" : true,
45051 * Fires when this region slides out of view.
45052 * @param {Roo.LayoutRegion} this
45054 "slidehide" : true,
45056 * @event panelactivated
45057 * Fires when a panel is activated.
45058 * @param {Roo.LayoutRegion} this
45059 * @param {Roo.ContentPanel} panel The activated panel
45061 "panelactivated" : true,
45064 * Fires when the user resizes this region.
45065 * @param {Roo.LayoutRegion} this
45066 * @param {Number} newSize The new size (width for east/west, height for north/south)
45070 /** A collection of panels in this region. @type Roo.util.MixedCollection */
45071 this.panels = new Roo.util.MixedCollection();
45072 this.panels.getKey = this.getPanelId.createDelegate(this);
45074 this.activePanel = null;
45075 // ensure listeners are added...
45077 if (config.listeners || config.events) {
45078 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
45079 listeners : config.listeners || {},
45080 events : config.events || {}
45084 if(skipConfig !== true){
45085 this.applyConfig(config);
45089 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
45090 getPanelId : function(p){
45094 applyConfig : function(config){
45095 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
45096 this.config = config;
45101 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
45102 * the width, for horizontal (north, south) the height.
45103 * @param {Number} newSize The new width or height
45105 resizeTo : function(newSize){
45106 var el = this.el ? this.el :
45107 (this.activePanel ? this.activePanel.getEl() : null);
45109 switch(this.position){
45112 el.setWidth(newSize);
45113 this.fireEvent("resized", this, newSize);
45117 el.setHeight(newSize);
45118 this.fireEvent("resized", this, newSize);
45124 getBox : function(){
45125 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
45128 getMargins : function(){
45129 return this.margins;
45132 updateBox : function(box){
45134 var el = this.activePanel.getEl();
45135 el.dom.style.left = box.x + "px";
45136 el.dom.style.top = box.y + "px";
45137 this.activePanel.setSize(box.width, box.height);
45141 * Returns the container element for this region.
45142 * @return {Roo.Element}
45144 getEl : function(){
45145 return this.activePanel;
45149 * Returns true if this region is currently visible.
45150 * @return {Boolean}
45152 isVisible : function(){
45153 return this.activePanel ? true : false;
45156 setActivePanel : function(panel){
45157 panel = this.getPanel(panel);
45158 if(this.activePanel && this.activePanel != panel){
45159 this.activePanel.setActiveState(false);
45160 this.activePanel.getEl().setLeftTop(-10000,-10000);
45162 this.activePanel = panel;
45163 panel.setActiveState(true);
45165 panel.setSize(this.box.width, this.box.height);
45167 this.fireEvent("panelactivated", this, panel);
45168 this.fireEvent("invalidated");
45172 * Show the specified panel.
45173 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
45174 * @return {Roo.ContentPanel} The shown panel or null
45176 showPanel : function(panel){
45177 if(panel = this.getPanel(panel)){
45178 this.setActivePanel(panel);
45184 * Get the active panel for this region.
45185 * @return {Roo.ContentPanel} The active panel or null
45187 getActivePanel : function(){
45188 return this.activePanel;
45192 * Add the passed ContentPanel(s)
45193 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
45194 * @return {Roo.ContentPanel} The panel added (if only one was added)
45196 add : function(panel){
45197 if(arguments.length > 1){
45198 for(var i = 0, len = arguments.length; i < len; i++) {
45199 this.add(arguments[i]);
45203 if(this.hasPanel(panel)){
45204 this.showPanel(panel);
45207 var el = panel.getEl();
45208 if(el.dom.parentNode != this.mgr.el.dom){
45209 this.mgr.el.dom.appendChild(el.dom);
45211 if(panel.setRegion){
45212 panel.setRegion(this);
45214 this.panels.add(panel);
45215 el.setStyle("position", "absolute");
45216 if(!panel.background){
45217 this.setActivePanel(panel);
45218 if(this.config.initialSize && this.panels.getCount()==1){
45219 this.resizeTo(this.config.initialSize);
45222 this.fireEvent("paneladded", this, panel);
45227 * Returns true if the panel is in this region.
45228 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45229 * @return {Boolean}
45231 hasPanel : function(panel){
45232 if(typeof panel == "object"){ // must be panel obj
45233 panel = panel.getId();
45235 return this.getPanel(panel) ? true : false;
45239 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
45240 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45241 * @param {Boolean} preservePanel Overrides the config preservePanel option
45242 * @return {Roo.ContentPanel} The panel that was removed
45244 remove : function(panel, preservePanel){
45245 panel = this.getPanel(panel);
45250 this.fireEvent("beforeremove", this, panel, e);
45251 if(e.cancel === true){
45254 var panelId = panel.getId();
45255 this.panels.removeKey(panelId);
45260 * Returns the panel specified or null if it's not in this region.
45261 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45262 * @return {Roo.ContentPanel}
45264 getPanel : function(id){
45265 if(typeof id == "object"){ // must be panel obj
45268 return this.panels.get(id);
45272 * Returns this regions position (north/south/east/west/center).
45275 getPosition: function(){
45276 return this.position;
45280 * Ext JS Library 1.1.1
45281 * Copyright(c) 2006-2007, Ext JS, LLC.
45283 * Originally Released Under LGPL - original licence link has changed is not relivant.
45286 * <script type="text/javascript">
45290 * @class Roo.LayoutRegion
45291 * @extends Roo.BasicLayoutRegion
45292 * This class represents a region in a layout manager.
45293 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
45294 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
45295 * @cfg {Boolean} floatable False to disable floating (defaults to true)
45296 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
45297 * @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})
45298 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
45299 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
45300 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
45301 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
45302 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
45303 * @cfg {String} title The title for the region (overrides panel titles)
45304 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
45305 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
45306 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
45307 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
45308 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
45309 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
45310 * the space available, similar to FireFox 1.5 tabs (defaults to false)
45311 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
45312 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
45313 * @cfg {Boolean} showPin True to show a pin button
45314 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
45315 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
45316 * @cfg {Boolean} disableTabTips True to disable tab tooltips
45317 * @cfg {Number} width For East/West panels
45318 * @cfg {Number} height For North/South panels
45319 * @cfg {Boolean} split To show the splitter
45320 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
45322 Roo.LayoutRegion = function(mgr, config, pos){
45323 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
45324 var dh = Roo.DomHelper;
45325 /** This region's container element
45326 * @type Roo.Element */
45327 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
45328 /** This region's title element
45329 * @type Roo.Element */
45331 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
45332 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
45333 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
45335 this.titleEl.enableDisplayMode();
45336 /** This region's title text element
45337 * @type HTMLElement */
45338 this.titleTextEl = this.titleEl.dom.firstChild;
45339 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
45340 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
45341 this.closeBtn.enableDisplayMode();
45342 this.closeBtn.on("click", this.closeClicked, this);
45343 this.closeBtn.hide();
45345 this.createBody(config);
45346 this.visible = true;
45347 this.collapsed = false;
45349 if(config.hideWhenEmpty){
45351 this.on("paneladded", this.validateVisibility, this);
45352 this.on("panelremoved", this.validateVisibility, this);
45354 this.applyConfig(config);
45357 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
45359 createBody : function(){
45360 /** This region's body element
45361 * @type Roo.Element */
45362 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
45365 applyConfig : function(c){
45366 if(c.collapsible && this.position != "center" && !this.collapsedEl){
45367 var dh = Roo.DomHelper;
45368 if(c.titlebar !== false){
45369 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
45370 this.collapseBtn.on("click", this.collapse, this);
45371 this.collapseBtn.enableDisplayMode();
45373 if(c.showPin === true || this.showPin){
45374 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
45375 this.stickBtn.enableDisplayMode();
45376 this.stickBtn.on("click", this.expand, this);
45377 this.stickBtn.hide();
45380 /** This region's collapsed element
45381 * @type Roo.Element */
45382 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
45383 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
45385 if(c.floatable !== false){
45386 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
45387 this.collapsedEl.on("click", this.collapseClick, this);
45390 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
45391 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
45392 id: "message", unselectable: "on", style:{"float":"left"}});
45393 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
45395 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
45396 this.expandBtn.on("click", this.expand, this);
45398 if(this.collapseBtn){
45399 this.collapseBtn.setVisible(c.collapsible == true);
45401 this.cmargins = c.cmargins || this.cmargins ||
45402 (this.position == "west" || this.position == "east" ?
45403 {top: 0, left: 2, right:2, bottom: 0} :
45404 {top: 2, left: 0, right:0, bottom: 2});
45405 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
45406 this.bottomTabs = c.tabPosition != "top";
45407 this.autoScroll = c.autoScroll || false;
45408 if(this.autoScroll){
45409 this.bodyEl.setStyle("overflow", "auto");
45411 this.bodyEl.setStyle("overflow", "hidden");
45413 //if(c.titlebar !== false){
45414 if((!c.titlebar && !c.title) || c.titlebar === false){
45415 this.titleEl.hide();
45417 this.titleEl.show();
45419 this.titleTextEl.innerHTML = c.title;
45423 this.duration = c.duration || .30;
45424 this.slideDuration = c.slideDuration || .45;
45427 this.collapse(true);
45434 * Returns true if this region is currently visible.
45435 * @return {Boolean}
45437 isVisible : function(){
45438 return this.visible;
45442 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
45443 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
45445 setCollapsedTitle : function(title){
45446 title = title || " ";
45447 if(this.collapsedTitleTextEl){
45448 this.collapsedTitleTextEl.innerHTML = title;
45452 getBox : function(){
45454 if(!this.collapsed){
45455 b = this.el.getBox(false, true);
45457 b = this.collapsedEl.getBox(false, true);
45462 getMargins : function(){
45463 return this.collapsed ? this.cmargins : this.margins;
45466 highlight : function(){
45467 this.el.addClass("x-layout-panel-dragover");
45470 unhighlight : function(){
45471 this.el.removeClass("x-layout-panel-dragover");
45474 updateBox : function(box){
45476 if(!this.collapsed){
45477 this.el.dom.style.left = box.x + "px";
45478 this.el.dom.style.top = box.y + "px";
45479 this.updateBody(box.width, box.height);
45481 this.collapsedEl.dom.style.left = box.x + "px";
45482 this.collapsedEl.dom.style.top = box.y + "px";
45483 this.collapsedEl.setSize(box.width, box.height);
45486 this.tabs.autoSizeTabs();
45490 updateBody : function(w, h){
45492 this.el.setWidth(w);
45493 w -= this.el.getBorderWidth("rl");
45494 if(this.config.adjustments){
45495 w += this.config.adjustments[0];
45499 this.el.setHeight(h);
45500 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
45501 h -= this.el.getBorderWidth("tb");
45502 if(this.config.adjustments){
45503 h += this.config.adjustments[1];
45505 this.bodyEl.setHeight(h);
45507 h = this.tabs.syncHeight(h);
45510 if(this.panelSize){
45511 w = w !== null ? w : this.panelSize.width;
45512 h = h !== null ? h : this.panelSize.height;
45514 if(this.activePanel){
45515 var el = this.activePanel.getEl();
45516 w = w !== null ? w : el.getWidth();
45517 h = h !== null ? h : el.getHeight();
45518 this.panelSize = {width: w, height: h};
45519 this.activePanel.setSize(w, h);
45521 if(Roo.isIE && this.tabs){
45522 this.tabs.el.repaint();
45527 * Returns the container element for this region.
45528 * @return {Roo.Element}
45530 getEl : function(){
45535 * Hides this region.
45538 if(!this.collapsed){
45539 this.el.dom.style.left = "-2000px";
45542 this.collapsedEl.dom.style.left = "-2000px";
45543 this.collapsedEl.hide();
45545 this.visible = false;
45546 this.fireEvent("visibilitychange", this, false);
45550 * Shows this region if it was previously hidden.
45553 if(!this.collapsed){
45556 this.collapsedEl.show();
45558 this.visible = true;
45559 this.fireEvent("visibilitychange", this, true);
45562 closeClicked : function(){
45563 if(this.activePanel){
45564 this.remove(this.activePanel);
45568 collapseClick : function(e){
45570 e.stopPropagation();
45573 e.stopPropagation();
45579 * Collapses this region.
45580 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
45582 collapse : function(skipAnim){
45583 if(this.collapsed) return;
45584 this.collapsed = true;
45586 this.split.el.hide();
45588 if(this.config.animate && skipAnim !== true){
45589 this.fireEvent("invalidated", this);
45590 this.animateCollapse();
45592 this.el.setLocation(-20000,-20000);
45594 this.collapsedEl.show();
45595 this.fireEvent("collapsed", this);
45596 this.fireEvent("invalidated", this);
45600 animateCollapse : function(){
45605 * Expands this region if it was previously collapsed.
45606 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
45607 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
45609 expand : function(e, skipAnim){
45610 if(e) e.stopPropagation();
45611 if(!this.collapsed || this.el.hasActiveFx()) return;
45613 this.afterSlideIn();
45616 this.collapsed = false;
45617 if(this.config.animate && skipAnim !== true){
45618 this.animateExpand();
45622 this.split.el.show();
45624 this.collapsedEl.setLocation(-2000,-2000);
45625 this.collapsedEl.hide();
45626 this.fireEvent("invalidated", this);
45627 this.fireEvent("expanded", this);
45631 animateExpand : function(){
45635 initTabs : function()
45637 this.bodyEl.setStyle("overflow", "hidden");
45638 var ts = new Roo.TabPanel(
45641 tabPosition: this.bottomTabs ? 'bottom' : 'top',
45642 disableTooltips: this.config.disableTabTips,
45643 toolbar : this.config.toolbar
45646 if(this.config.hideTabs){
45647 ts.stripWrap.setDisplayed(false);
45650 ts.resizeTabs = this.config.resizeTabs === true;
45651 ts.minTabWidth = this.config.minTabWidth || 40;
45652 ts.maxTabWidth = this.config.maxTabWidth || 250;
45653 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
45654 ts.monitorResize = false;
45655 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
45656 ts.bodyEl.addClass('x-layout-tabs-body');
45657 this.panels.each(this.initPanelAsTab, this);
45660 initPanelAsTab : function(panel){
45661 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
45662 this.config.closeOnTab && panel.isClosable());
45663 if(panel.tabTip !== undefined){
45664 ti.setTooltip(panel.tabTip);
45666 ti.on("activate", function(){
45667 this.setActivePanel(panel);
45669 if(this.config.closeOnTab){
45670 ti.on("beforeclose", function(t, e){
45672 this.remove(panel);
45678 updatePanelTitle : function(panel, title){
45679 if(this.activePanel == panel){
45680 this.updateTitle(title);
45683 var ti = this.tabs.getTab(panel.getEl().id);
45685 if(panel.tabTip !== undefined){
45686 ti.setTooltip(panel.tabTip);
45691 updateTitle : function(title){
45692 if(this.titleTextEl && !this.config.title){
45693 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
45697 setActivePanel : function(panel){
45698 panel = this.getPanel(panel);
45699 if(this.activePanel && this.activePanel != panel){
45700 this.activePanel.setActiveState(false);
45702 this.activePanel = panel;
45703 panel.setActiveState(true);
45704 if(this.panelSize){
45705 panel.setSize(this.panelSize.width, this.panelSize.height);
45708 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
45710 this.updateTitle(panel.getTitle());
45712 this.fireEvent("invalidated", this);
45714 this.fireEvent("panelactivated", this, panel);
45718 * Shows the specified panel.
45719 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
45720 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
45722 showPanel : function(panel){
45723 if(panel = this.getPanel(panel)){
45725 var tab = this.tabs.getTab(panel.getEl().id);
45726 if(tab.isHidden()){
45727 this.tabs.unhideTab(tab.id);
45731 this.setActivePanel(panel);
45738 * Get the active panel for this region.
45739 * @return {Roo.ContentPanel} The active panel or null
45741 getActivePanel : function(){
45742 return this.activePanel;
45745 validateVisibility : function(){
45746 if(this.panels.getCount() < 1){
45747 this.updateTitle(" ");
45748 this.closeBtn.hide();
45751 if(!this.isVisible()){
45758 * Adds the passed ContentPanel(s) to this region.
45759 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
45760 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
45762 add : function(panel){
45763 if(arguments.length > 1){
45764 for(var i = 0, len = arguments.length; i < len; i++) {
45765 this.add(arguments[i]);
45769 if(this.hasPanel(panel)){
45770 this.showPanel(panel);
45773 panel.setRegion(this);
45774 this.panels.add(panel);
45775 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
45776 this.bodyEl.dom.appendChild(panel.getEl().dom);
45777 if(panel.background !== true){
45778 this.setActivePanel(panel);
45780 this.fireEvent("paneladded", this, panel);
45786 this.initPanelAsTab(panel);
45788 if(panel.background !== true){
45789 this.tabs.activate(panel.getEl().id);
45791 this.fireEvent("paneladded", this, panel);
45796 * Hides the tab for the specified panel.
45797 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
45799 hidePanel : function(panel){
45800 if(this.tabs && (panel = this.getPanel(panel))){
45801 this.tabs.hideTab(panel.getEl().id);
45806 * Unhides the tab for a previously hidden panel.
45807 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
45809 unhidePanel : function(panel){
45810 if(this.tabs && (panel = this.getPanel(panel))){
45811 this.tabs.unhideTab(panel.getEl().id);
45815 clearPanels : function(){
45816 while(this.panels.getCount() > 0){
45817 this.remove(this.panels.first());
45822 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
45823 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
45824 * @param {Boolean} preservePanel Overrides the config preservePanel option
45825 * @return {Roo.ContentPanel} The panel that was removed
45827 remove : function(panel, preservePanel){
45828 panel = this.getPanel(panel);
45833 this.fireEvent("beforeremove", this, panel, e);
45834 if(e.cancel === true){
45837 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
45838 var panelId = panel.getId();
45839 this.panels.removeKey(panelId);
45841 document.body.appendChild(panel.getEl().dom);
45844 this.tabs.removeTab(panel.getEl().id);
45845 }else if (!preservePanel){
45846 this.bodyEl.dom.removeChild(panel.getEl().dom);
45848 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
45849 var p = this.panels.first();
45850 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
45851 tempEl.appendChild(p.getEl().dom);
45852 this.bodyEl.update("");
45853 this.bodyEl.dom.appendChild(p.getEl().dom);
45855 this.updateTitle(p.getTitle());
45857 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
45858 this.setActivePanel(p);
45860 panel.setRegion(null);
45861 if(this.activePanel == panel){
45862 this.activePanel = null;
45864 if(this.config.autoDestroy !== false && preservePanel !== true){
45865 try{panel.destroy();}catch(e){}
45867 this.fireEvent("panelremoved", this, panel);
45872 * Returns the TabPanel component used by this region
45873 * @return {Roo.TabPanel}
45875 getTabs : function(){
45879 createTool : function(parentEl, className){
45880 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
45881 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
45882 btn.addClassOnOver("x-layout-tools-button-over");
45887 * Ext JS Library 1.1.1
45888 * Copyright(c) 2006-2007, Ext JS, LLC.
45890 * Originally Released Under LGPL - original licence link has changed is not relivant.
45893 * <script type="text/javascript">
45899 * @class Roo.SplitLayoutRegion
45900 * @extends Roo.LayoutRegion
45901 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
45903 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
45904 this.cursor = cursor;
45905 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
45908 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
45909 splitTip : "Drag to resize.",
45910 collapsibleSplitTip : "Drag to resize. Double click to hide.",
45911 useSplitTips : false,
45913 applyConfig : function(config){
45914 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
45917 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
45918 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
45919 /** The SplitBar for this region
45920 * @type Roo.SplitBar */
45921 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
45922 this.split.on("moved", this.onSplitMove, this);
45923 this.split.useShim = config.useShim === true;
45924 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
45925 if(this.useSplitTips){
45926 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
45928 if(config.collapsible){
45929 this.split.el.on("dblclick", this.collapse, this);
45932 if(typeof config.minSize != "undefined"){
45933 this.split.minSize = config.minSize;
45935 if(typeof config.maxSize != "undefined"){
45936 this.split.maxSize = config.maxSize;
45938 if(config.hideWhenEmpty || config.hidden || config.collapsed){
45939 this.hideSplitter();
45944 getHMaxSize : function(){
45945 var cmax = this.config.maxSize || 10000;
45946 var center = this.mgr.getRegion("center");
45947 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
45950 getVMaxSize : function(){
45951 var cmax = this.config.maxSize || 10000;
45952 var center = this.mgr.getRegion("center");
45953 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
45956 onSplitMove : function(split, newSize){
45957 this.fireEvent("resized", this, newSize);
45961 * Returns the {@link Roo.SplitBar} for this region.
45962 * @return {Roo.SplitBar}
45964 getSplitBar : function(){
45969 this.hideSplitter();
45970 Roo.SplitLayoutRegion.superclass.hide.call(this);
45973 hideSplitter : function(){
45975 this.split.el.setLocation(-2000,-2000);
45976 this.split.el.hide();
45982 this.split.el.show();
45984 Roo.SplitLayoutRegion.superclass.show.call(this);
45987 beforeSlide: function(){
45988 if(Roo.isGecko){// firefox overflow auto bug workaround
45989 this.bodyEl.clip();
45990 if(this.tabs) this.tabs.bodyEl.clip();
45991 if(this.activePanel){
45992 this.activePanel.getEl().clip();
45994 if(this.activePanel.beforeSlide){
45995 this.activePanel.beforeSlide();
46001 afterSlide : function(){
46002 if(Roo.isGecko){// firefox overflow auto bug workaround
46003 this.bodyEl.unclip();
46004 if(this.tabs) this.tabs.bodyEl.unclip();
46005 if(this.activePanel){
46006 this.activePanel.getEl().unclip();
46007 if(this.activePanel.afterSlide){
46008 this.activePanel.afterSlide();
46014 initAutoHide : function(){
46015 if(this.autoHide !== false){
46016 if(!this.autoHideHd){
46017 var st = new Roo.util.DelayedTask(this.slideIn, this);
46018 this.autoHideHd = {
46019 "mouseout": function(e){
46020 if(!e.within(this.el, true)){
46024 "mouseover" : function(e){
46030 this.el.on(this.autoHideHd);
46034 clearAutoHide : function(){
46035 if(this.autoHide !== false){
46036 this.el.un("mouseout", this.autoHideHd.mouseout);
46037 this.el.un("mouseover", this.autoHideHd.mouseover);
46041 clearMonitor : function(){
46042 Roo.get(document).un("click", this.slideInIf, this);
46045 // these names are backwards but not changed for compat
46046 slideOut : function(){
46047 if(this.isSlid || this.el.hasActiveFx()){
46050 this.isSlid = true;
46051 if(this.collapseBtn){
46052 this.collapseBtn.hide();
46054 this.closeBtnState = this.closeBtn.getStyle('display');
46055 this.closeBtn.hide();
46057 this.stickBtn.show();
46060 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
46061 this.beforeSlide();
46062 this.el.setStyle("z-index", 10001);
46063 this.el.slideIn(this.getSlideAnchor(), {
46064 callback: function(){
46066 this.initAutoHide();
46067 Roo.get(document).on("click", this.slideInIf, this);
46068 this.fireEvent("slideshow", this);
46075 afterSlideIn : function(){
46076 this.clearAutoHide();
46077 this.isSlid = false;
46078 this.clearMonitor();
46079 this.el.setStyle("z-index", "");
46080 if(this.collapseBtn){
46081 this.collapseBtn.show();
46083 this.closeBtn.setStyle('display', this.closeBtnState);
46085 this.stickBtn.hide();
46087 this.fireEvent("slidehide", this);
46090 slideIn : function(cb){
46091 if(!this.isSlid || this.el.hasActiveFx()){
46095 this.isSlid = false;
46096 this.beforeSlide();
46097 this.el.slideOut(this.getSlideAnchor(), {
46098 callback: function(){
46099 this.el.setLeftTop(-10000, -10000);
46101 this.afterSlideIn();
46109 slideInIf : function(e){
46110 if(!e.within(this.el)){
46115 animateCollapse : function(){
46116 this.beforeSlide();
46117 this.el.setStyle("z-index", 20000);
46118 var anchor = this.getSlideAnchor();
46119 this.el.slideOut(anchor, {
46120 callback : function(){
46121 this.el.setStyle("z-index", "");
46122 this.collapsedEl.slideIn(anchor, {duration:.3});
46124 this.el.setLocation(-10000,-10000);
46126 this.fireEvent("collapsed", this);
46133 animateExpand : function(){
46134 this.beforeSlide();
46135 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
46136 this.el.setStyle("z-index", 20000);
46137 this.collapsedEl.hide({
46140 this.el.slideIn(this.getSlideAnchor(), {
46141 callback : function(){
46142 this.el.setStyle("z-index", "");
46145 this.split.el.show();
46147 this.fireEvent("invalidated", this);
46148 this.fireEvent("expanded", this);
46176 getAnchor : function(){
46177 return this.anchors[this.position];
46180 getCollapseAnchor : function(){
46181 return this.canchors[this.position];
46184 getSlideAnchor : function(){
46185 return this.sanchors[this.position];
46188 getAlignAdj : function(){
46189 var cm = this.cmargins;
46190 switch(this.position){
46206 getExpandAdj : function(){
46207 var c = this.collapsedEl, cm = this.cmargins;
46208 switch(this.position){
46210 return [-(cm.right+c.getWidth()+cm.left), 0];
46213 return [cm.right+c.getWidth()+cm.left, 0];
46216 return [0, -(cm.top+cm.bottom+c.getHeight())];
46219 return [0, cm.top+cm.bottom+c.getHeight()];
46225 * Ext JS Library 1.1.1
46226 * Copyright(c) 2006-2007, Ext JS, LLC.
46228 * Originally Released Under LGPL - original licence link has changed is not relivant.
46231 * <script type="text/javascript">
46234 * These classes are private internal classes
46236 Roo.CenterLayoutRegion = function(mgr, config){
46237 Roo.LayoutRegion.call(this, mgr, config, "center");
46238 this.visible = true;
46239 this.minWidth = config.minWidth || 20;
46240 this.minHeight = config.minHeight || 20;
46243 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
46245 // center panel can't be hidden
46249 // center panel can't be hidden
46252 getMinWidth: function(){
46253 return this.minWidth;
46256 getMinHeight: function(){
46257 return this.minHeight;
46262 Roo.NorthLayoutRegion = function(mgr, config){
46263 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
46265 this.split.placement = Roo.SplitBar.TOP;
46266 this.split.orientation = Roo.SplitBar.VERTICAL;
46267 this.split.el.addClass("x-layout-split-v");
46269 var size = config.initialSize || config.height;
46270 if(typeof size != "undefined"){
46271 this.el.setHeight(size);
46274 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
46275 orientation: Roo.SplitBar.VERTICAL,
46276 getBox : function(){
46277 if(this.collapsed){
46278 return this.collapsedEl.getBox();
46280 var box = this.el.getBox();
46282 box.height += this.split.el.getHeight();
46287 updateBox : function(box){
46288 if(this.split && !this.collapsed){
46289 box.height -= this.split.el.getHeight();
46290 this.split.el.setLeft(box.x);
46291 this.split.el.setTop(box.y+box.height);
46292 this.split.el.setWidth(box.width);
46294 if(this.collapsed){
46295 this.updateBody(box.width, null);
46297 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46301 Roo.SouthLayoutRegion = function(mgr, config){
46302 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
46304 this.split.placement = Roo.SplitBar.BOTTOM;
46305 this.split.orientation = Roo.SplitBar.VERTICAL;
46306 this.split.el.addClass("x-layout-split-v");
46308 var size = config.initialSize || config.height;
46309 if(typeof size != "undefined"){
46310 this.el.setHeight(size);
46313 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
46314 orientation: Roo.SplitBar.VERTICAL,
46315 getBox : function(){
46316 if(this.collapsed){
46317 return this.collapsedEl.getBox();
46319 var box = this.el.getBox();
46321 var sh = this.split.el.getHeight();
46328 updateBox : function(box){
46329 if(this.split && !this.collapsed){
46330 var sh = this.split.el.getHeight();
46333 this.split.el.setLeft(box.x);
46334 this.split.el.setTop(box.y-sh);
46335 this.split.el.setWidth(box.width);
46337 if(this.collapsed){
46338 this.updateBody(box.width, null);
46340 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46344 Roo.EastLayoutRegion = function(mgr, config){
46345 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
46347 this.split.placement = Roo.SplitBar.RIGHT;
46348 this.split.orientation = Roo.SplitBar.HORIZONTAL;
46349 this.split.el.addClass("x-layout-split-h");
46351 var size = config.initialSize || config.width;
46352 if(typeof size != "undefined"){
46353 this.el.setWidth(size);
46356 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
46357 orientation: Roo.SplitBar.HORIZONTAL,
46358 getBox : function(){
46359 if(this.collapsed){
46360 return this.collapsedEl.getBox();
46362 var box = this.el.getBox();
46364 var sw = this.split.el.getWidth();
46371 updateBox : function(box){
46372 if(this.split && !this.collapsed){
46373 var sw = this.split.el.getWidth();
46375 this.split.el.setLeft(box.x);
46376 this.split.el.setTop(box.y);
46377 this.split.el.setHeight(box.height);
46380 if(this.collapsed){
46381 this.updateBody(null, box.height);
46383 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46387 Roo.WestLayoutRegion = function(mgr, config){
46388 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
46390 this.split.placement = Roo.SplitBar.LEFT;
46391 this.split.orientation = Roo.SplitBar.HORIZONTAL;
46392 this.split.el.addClass("x-layout-split-h");
46394 var size = config.initialSize || config.width;
46395 if(typeof size != "undefined"){
46396 this.el.setWidth(size);
46399 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
46400 orientation: Roo.SplitBar.HORIZONTAL,
46401 getBox : function(){
46402 if(this.collapsed){
46403 return this.collapsedEl.getBox();
46405 var box = this.el.getBox();
46407 box.width += this.split.el.getWidth();
46412 updateBox : function(box){
46413 if(this.split && !this.collapsed){
46414 var sw = this.split.el.getWidth();
46416 this.split.el.setLeft(box.x+box.width);
46417 this.split.el.setTop(box.y);
46418 this.split.el.setHeight(box.height);
46420 if(this.collapsed){
46421 this.updateBody(null, box.height);
46423 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46428 * Ext JS Library 1.1.1
46429 * Copyright(c) 2006-2007, Ext JS, LLC.
46431 * Originally Released Under LGPL - original licence link has changed is not relivant.
46434 * <script type="text/javascript">
46439 * Private internal class for reading and applying state
46441 Roo.LayoutStateManager = function(layout){
46442 // default empty state
46451 Roo.LayoutStateManager.prototype = {
46452 init : function(layout, provider){
46453 this.provider = provider;
46454 var state = provider.get(layout.id+"-layout-state");
46456 var wasUpdating = layout.isUpdating();
46458 layout.beginUpdate();
46460 for(var key in state){
46461 if(typeof state[key] != "function"){
46462 var rstate = state[key];
46463 var r = layout.getRegion(key);
46466 r.resizeTo(rstate.size);
46468 if(rstate.collapsed == true){
46471 r.expand(null, true);
46477 layout.endUpdate();
46479 this.state = state;
46481 this.layout = layout;
46482 layout.on("regionresized", this.onRegionResized, this);
46483 layout.on("regioncollapsed", this.onRegionCollapsed, this);
46484 layout.on("regionexpanded", this.onRegionExpanded, this);
46487 storeState : function(){
46488 this.provider.set(this.layout.id+"-layout-state", this.state);
46491 onRegionResized : function(region, newSize){
46492 this.state[region.getPosition()].size = newSize;
46496 onRegionCollapsed : function(region){
46497 this.state[region.getPosition()].collapsed = true;
46501 onRegionExpanded : function(region){
46502 this.state[region.getPosition()].collapsed = false;
46507 * Ext JS Library 1.1.1
46508 * Copyright(c) 2006-2007, Ext JS, LLC.
46510 * Originally Released Under LGPL - original licence link has changed is not relivant.
46513 * <script type="text/javascript">
46516 * @class Roo.ContentPanel
46517 * @extends Roo.util.Observable
46518 * A basic ContentPanel element.
46519 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
46520 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
46521 * @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
46522 * @cfg {Boolean} closable True if the panel can be closed/removed
46523 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
46524 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
46525 * @cfg {Toolbar} toolbar A toolbar for this panel
46526 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
46527 * @cfg {String} title The title for this panel
46528 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
46529 * @cfg {String} url Calls {@link #setUrl} with this value
46530 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
46531 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
46532 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
46533 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
46536 * Create a new ContentPanel.
46537 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
46538 * @param {String/Object} config A string to set only the title or a config object
46539 * @param {String} content (optional) Set the HTML content for this panel
46540 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
46542 Roo.ContentPanel = function(el, config, content){
46546 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
46550 if (config && config.parentLayout) {
46551 el = config.parentLayout.el.createChild();
46554 if(el.autoCreate){ // xtype is available if this is called from factory
46558 this.el = Roo.get(el);
46559 if(!this.el && config && config.autoCreate){
46560 if(typeof config.autoCreate == "object"){
46561 if(!config.autoCreate.id){
46562 config.autoCreate.id = config.id||el;
46564 this.el = Roo.DomHelper.append(document.body,
46565 config.autoCreate, true);
46567 this.el = Roo.DomHelper.append(document.body,
46568 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
46571 this.closable = false;
46572 this.loaded = false;
46573 this.active = false;
46574 if(typeof config == "string"){
46575 this.title = config;
46577 Roo.apply(this, config);
46580 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
46581 this.wrapEl = this.el.wrap();
46582 this.toolbar.container = this.el.insertSibling(false, 'before');
46583 this.toolbar = new Roo.Toolbar(this.toolbar);
46589 this.resizeEl = Roo.get(this.resizeEl, true);
46591 this.resizeEl = this.el;
46596 * Fires when this panel is activated.
46597 * @param {Roo.ContentPanel} this
46601 * @event deactivate
46602 * Fires when this panel is activated.
46603 * @param {Roo.ContentPanel} this
46605 "deactivate" : true,
46609 * Fires when this panel is resized if fitToFrame is true.
46610 * @param {Roo.ContentPanel} this
46611 * @param {Number} width The width after any component adjustments
46612 * @param {Number} height The height after any component adjustments
46618 * Fires when this tab is created
46619 * @param {Roo.ContentPanel} this
46626 if(this.autoScroll){
46627 this.resizeEl.setStyle("overflow", "auto");
46629 // fix randome scrolling
46630 this.el.on('scroll', function() {
46631 Roo.log('fix random scolling');
46632 this.scrollTo('top',0);
46635 content = content || this.content;
46637 this.setContent(content);
46639 if(config && config.url){
46640 this.setUrl(this.url, this.params, this.loadOnce);
46645 Roo.ContentPanel.superclass.constructor.call(this);
46647 this.fireEvent('render', this);
46650 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
46652 setRegion : function(region){
46653 this.region = region;
46655 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
46657 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
46662 * Returns the toolbar for this Panel if one was configured.
46663 * @return {Roo.Toolbar}
46665 getToolbar : function(){
46666 return this.toolbar;
46669 setActiveState : function(active){
46670 this.active = active;
46672 this.fireEvent("deactivate", this);
46674 this.fireEvent("activate", this);
46678 * Updates this panel's element
46679 * @param {String} content The new content
46680 * @param {Boolean} loadScripts (optional) true to look for and process scripts
46682 setContent : function(content, loadScripts){
46683 this.el.update(content, loadScripts);
46686 ignoreResize : function(w, h){
46687 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
46690 this.lastSize = {width: w, height: h};
46695 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
46696 * @return {Roo.UpdateManager} The UpdateManager
46698 getUpdateManager : function(){
46699 return this.el.getUpdateManager();
46702 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
46703 * @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:
46706 url: "your-url.php",
46707 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
46708 callback: yourFunction,
46709 scope: yourObject, //(optional scope)
46712 text: "Loading...",
46717 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
46718 * 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.
46719 * @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}
46720 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
46721 * @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.
46722 * @return {Roo.ContentPanel} this
46725 var um = this.el.getUpdateManager();
46726 um.update.apply(um, arguments);
46732 * 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.
46733 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
46734 * @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)
46735 * @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)
46736 * @return {Roo.UpdateManager} The UpdateManager
46738 setUrl : function(url, params, loadOnce){
46739 if(this.refreshDelegate){
46740 this.removeListener("activate", this.refreshDelegate);
46742 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
46743 this.on("activate", this.refreshDelegate);
46744 return this.el.getUpdateManager();
46747 _handleRefresh : function(url, params, loadOnce){
46748 if(!loadOnce || !this.loaded){
46749 var updater = this.el.getUpdateManager();
46750 updater.update(url, params, this._setLoaded.createDelegate(this));
46754 _setLoaded : function(){
46755 this.loaded = true;
46759 * Returns this panel's id
46762 getId : function(){
46767 * Returns this panel's element - used by regiosn to add.
46768 * @return {Roo.Element}
46770 getEl : function(){
46771 return this.wrapEl || this.el;
46774 adjustForComponents : function(width, height){
46775 if(this.resizeEl != this.el){
46776 width -= this.el.getFrameWidth('lr');
46777 height -= this.el.getFrameWidth('tb');
46780 var te = this.toolbar.getEl();
46781 height -= te.getHeight();
46782 te.setWidth(width);
46784 if(this.adjustments){
46785 width += this.adjustments[0];
46786 height += this.adjustments[1];
46788 return {"width": width, "height": height};
46791 setSize : function(width, height){
46792 if(this.fitToFrame && !this.ignoreResize(width, height)){
46793 if(this.fitContainer && this.resizeEl != this.el){
46794 this.el.setSize(width, height);
46796 var size = this.adjustForComponents(width, height);
46797 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
46798 this.fireEvent('resize', this, size.width, size.height);
46803 * Returns this panel's title
46806 getTitle : function(){
46811 * Set this panel's title
46812 * @param {String} title
46814 setTitle : function(title){
46815 this.title = title;
46817 this.region.updatePanelTitle(this, title);
46822 * Returns true is this panel was configured to be closable
46823 * @return {Boolean}
46825 isClosable : function(){
46826 return this.closable;
46829 beforeSlide : function(){
46831 this.resizeEl.clip();
46834 afterSlide : function(){
46836 this.resizeEl.unclip();
46840 * Force a content refresh from the URL specified in the {@link #setUrl} method.
46841 * Will fail silently if the {@link #setUrl} method has not been called.
46842 * This does not activate the panel, just updates its content.
46844 refresh : function(){
46845 if(this.refreshDelegate){
46846 this.loaded = false;
46847 this.refreshDelegate();
46852 * Destroys this panel
46854 destroy : function(){
46855 this.el.removeAllListeners();
46856 var tempEl = document.createElement("span");
46857 tempEl.appendChild(this.el.dom);
46858 tempEl.innerHTML = "";
46864 * form - if the content panel contains a form - this is a reference to it.
46865 * @type {Roo.form.Form}
46869 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
46870 * This contains a reference to it.
46876 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
46886 * @param {Object} cfg Xtype definition of item to add.
46889 addxtype : function(cfg) {
46891 if (cfg.xtype.match(/^Form$/)) {
46892 var el = this.el.createChild();
46894 this.form = new Roo.form.Form(cfg);
46897 if ( this.form.allItems.length) this.form.render(el.dom);
46900 // should only have one of theses..
46901 if (['View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
46903 cfg.el = this.el.appendChild(document.createElement("div"));
46906 var ret = new Roo.factory(cfg);
46907 ret.render && ret.render(false, ''); // render blank..
46916 * @class Roo.GridPanel
46917 * @extends Roo.ContentPanel
46919 * Create a new GridPanel.
46920 * @param {Roo.grid.Grid} grid The grid for this panel
46921 * @param {String/Object} config A string to set only the panel's title, or a config object
46923 Roo.GridPanel = function(grid, config){
46926 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
46927 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
46929 this.wrapper.dom.appendChild(grid.getGridEl().dom);
46931 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
46934 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
46936 // xtype created footer. - not sure if will work as we normally have to render first..
46937 if (this.footer && !this.footer.el && this.footer.xtype) {
46939 this.footer.container = this.grid.getView().getFooterPanel(true);
46940 this.footer.dataSource = this.grid.dataSource;
46941 this.footer = Roo.factory(this.footer, Roo);
46945 grid.monitorWindowResize = false; // turn off autosizing
46946 grid.autoHeight = false;
46947 grid.autoWidth = false;
46949 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
46952 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
46953 getId : function(){
46954 return this.grid.id;
46958 * Returns the grid for this panel
46959 * @return {Roo.grid.Grid}
46961 getGrid : function(){
46965 setSize : function(width, height){
46966 if(!this.ignoreResize(width, height)){
46967 var grid = this.grid;
46968 var size = this.adjustForComponents(width, height);
46969 grid.getGridEl().setSize(size.width, size.height);
46974 beforeSlide : function(){
46975 this.grid.getView().scroller.clip();
46978 afterSlide : function(){
46979 this.grid.getView().scroller.unclip();
46982 destroy : function(){
46983 this.grid.destroy();
46985 Roo.GridPanel.superclass.destroy.call(this);
46991 * @class Roo.NestedLayoutPanel
46992 * @extends Roo.ContentPanel
46994 * Create a new NestedLayoutPanel.
46997 * @param {Roo.BorderLayout} layout The layout for this panel
46998 * @param {String/Object} config A string to set only the title or a config object
47000 Roo.NestedLayoutPanel = function(layout, config)
47002 // construct with only one argument..
47003 /* FIXME - implement nicer consturctors
47004 if (layout.layout) {
47006 layout = config.layout;
47007 delete config.layout;
47009 if (layout.xtype && !layout.getEl) {
47010 // then layout needs constructing..
47011 layout = Roo.factory(layout, Roo);
47016 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
47018 layout.monitorWindowResize = false; // turn off autosizing
47019 this.layout = layout;
47020 this.layout.getEl().addClass("x-layout-nested-layout");
47027 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
47029 setSize : function(width, height){
47030 if(!this.ignoreResize(width, height)){
47031 var size = this.adjustForComponents(width, height);
47032 var el = this.layout.getEl();
47033 el.setSize(size.width, size.height);
47034 var touch = el.dom.offsetWidth;
47035 this.layout.layout();
47036 // ie requires a double layout on the first pass
47037 if(Roo.isIE && !this.initialized){
47038 this.initialized = true;
47039 this.layout.layout();
47044 // activate all subpanels if not currently active..
47046 setActiveState : function(active){
47047 this.active = active;
47049 this.fireEvent("deactivate", this);
47053 this.fireEvent("activate", this);
47054 // not sure if this should happen before or after..
47055 if (!this.layout) {
47056 return; // should not happen..
47059 for (var r in this.layout.regions) {
47060 reg = this.layout.getRegion(r);
47061 if (reg.getActivePanel()) {
47062 //reg.showPanel(reg.getActivePanel()); // force it to activate..
47063 reg.setActivePanel(reg.getActivePanel());
47066 if (!reg.panels.length) {
47069 reg.showPanel(reg.getPanel(0));
47078 * Returns the nested BorderLayout for this panel
47079 * @return {Roo.BorderLayout}
47081 getLayout : function(){
47082 return this.layout;
47086 * Adds a xtype elements to the layout of the nested panel
47090 xtype : 'ContentPanel',
47097 xtype : 'NestedLayoutPanel',
47103 items : [ ... list of content panels or nested layout panels.. ]
47107 * @param {Object} cfg Xtype definition of item to add.
47109 addxtype : function(cfg) {
47110 return this.layout.addxtype(cfg);
47115 Roo.ScrollPanel = function(el, config, content){
47116 config = config || {};
47117 config.fitToFrame = true;
47118 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
47120 this.el.dom.style.overflow = "hidden";
47121 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
47122 this.el.removeClass("x-layout-inactive-content");
47123 this.el.on("mousewheel", this.onWheel, this);
47125 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
47126 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
47127 up.unselectable(); down.unselectable();
47128 up.on("click", this.scrollUp, this);
47129 down.on("click", this.scrollDown, this);
47130 up.addClassOnOver("x-scroller-btn-over");
47131 down.addClassOnOver("x-scroller-btn-over");
47132 up.addClassOnClick("x-scroller-btn-click");
47133 down.addClassOnClick("x-scroller-btn-click");
47134 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
47136 this.resizeEl = this.el;
47137 this.el = wrap; this.up = up; this.down = down;
47140 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
47142 wheelIncrement : 5,
47143 scrollUp : function(){
47144 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
47147 scrollDown : function(){
47148 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
47151 afterScroll : function(){
47152 var el = this.resizeEl;
47153 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
47154 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
47155 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
47158 setSize : function(){
47159 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
47160 this.afterScroll();
47163 onWheel : function(e){
47164 var d = e.getWheelDelta();
47165 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
47166 this.afterScroll();
47170 setContent : function(content, loadScripts){
47171 this.resizeEl.update(content, loadScripts);
47185 * @class Roo.TreePanel
47186 * @extends Roo.ContentPanel
47188 * Create a new TreePanel. - defaults to fit/scoll contents.
47189 * @param {String/Object} config A string to set only the panel's title, or a config object
47190 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
47192 Roo.TreePanel = function(config){
47193 var el = config.el;
47194 var tree = config.tree;
47195 delete config.tree;
47196 delete config.el; // hopefull!
47198 // wrapper for IE7 strict & safari scroll issue
47200 var treeEl = el.createChild();
47201 config.resizeEl = treeEl;
47205 Roo.TreePanel.superclass.constructor.call(this, el, config);
47208 this.tree = new Roo.tree.TreePanel(treeEl , tree);
47209 //console.log(tree);
47210 this.on('activate', function()
47212 if (this.tree.rendered) {
47215 //console.log('render tree');
47216 this.tree.render();
47219 this.on('resize', function (cp, w, h) {
47220 this.tree.innerCt.setWidth(w);
47221 this.tree.innerCt.setHeight(h);
47222 this.tree.innerCt.setStyle('overflow-y', 'auto');
47229 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
47246 * Ext JS Library 1.1.1
47247 * Copyright(c) 2006-2007, Ext JS, LLC.
47249 * Originally Released Under LGPL - original licence link has changed is not relivant.
47252 * <script type="text/javascript">
47257 * @class Roo.ReaderLayout
47258 * @extends Roo.BorderLayout
47259 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
47260 * center region containing two nested regions (a top one for a list view and one for item preview below),
47261 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
47262 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
47263 * expedites the setup of the overall layout and regions for this common application style.
47266 var reader = new Roo.ReaderLayout();
47267 var CP = Roo.ContentPanel; // shortcut for adding
47269 reader.beginUpdate();
47270 reader.add("north", new CP("north", "North"));
47271 reader.add("west", new CP("west", {title: "West"}));
47272 reader.add("east", new CP("east", {title: "East"}));
47274 reader.regions.listView.add(new CP("listView", "List"));
47275 reader.regions.preview.add(new CP("preview", "Preview"));
47276 reader.endUpdate();
47279 * Create a new ReaderLayout
47280 * @param {Object} config Configuration options
47281 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
47282 * document.body if omitted)
47284 Roo.ReaderLayout = function(config, renderTo){
47285 var c = config || {size:{}};
47286 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
47287 north: c.north !== false ? Roo.apply({
47291 }, c.north) : false,
47292 west: c.west !== false ? Roo.apply({
47300 margins:{left:5,right:0,bottom:5,top:5},
47301 cmargins:{left:5,right:5,bottom:5,top:5}
47302 }, c.west) : false,
47303 east: c.east !== false ? Roo.apply({
47311 margins:{left:0,right:5,bottom:5,top:5},
47312 cmargins:{left:5,right:5,bottom:5,top:5}
47313 }, c.east) : false,
47314 center: Roo.apply({
47315 tabPosition: 'top',
47319 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
47323 this.el.addClass('x-reader');
47325 this.beginUpdate();
47327 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
47328 south: c.preview !== false ? Roo.apply({
47335 cmargins:{top:5,left:0, right:0, bottom:0}
47336 }, c.preview) : false,
47337 center: Roo.apply({
47343 this.add('center', new Roo.NestedLayoutPanel(inner,
47344 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
47348 this.regions.preview = inner.getRegion('south');
47349 this.regions.listView = inner.getRegion('center');
47352 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
47354 * Ext JS Library 1.1.1
47355 * Copyright(c) 2006-2007, Ext JS, LLC.
47357 * Originally Released Under LGPL - original licence link has changed is not relivant.
47360 * <script type="text/javascript">
47364 * @class Roo.grid.Grid
47365 * @extends Roo.util.Observable
47366 * This class represents the primary interface of a component based grid control.
47367 * <br><br>Usage:<pre><code>
47368 var grid = new Roo.grid.Grid("my-container-id", {
47371 selModel: mySelectionModel,
47372 autoSizeColumns: true,
47373 monitorWindowResize: false,
47374 trackMouseOver: true
47379 * <b>Common Problems:</b><br/>
47380 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
47381 * element will correct this<br/>
47382 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
47383 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
47384 * are unpredictable.<br/>
47385 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
47386 * grid to calculate dimensions/offsets.<br/>
47388 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
47389 * The container MUST have some type of size defined for the grid to fill. The container will be
47390 * automatically set to position relative if it isn't already.
47391 * @param {Object} config A config object that sets properties on this grid.
47393 Roo.grid.Grid = function(container, config){
47394 // initialize the container
47395 this.container = Roo.get(container);
47396 this.container.update("");
47397 this.container.setStyle("overflow", "hidden");
47398 this.container.addClass('x-grid-container');
47400 this.id = this.container.id;
47402 Roo.apply(this, config);
47403 // check and correct shorthanded configs
47405 this.dataSource = this.ds;
47409 this.colModel = this.cm;
47413 this.selModel = this.sm;
47417 if (this.selModel) {
47418 this.selModel = Roo.factory(this.selModel, Roo.grid);
47419 this.sm = this.selModel;
47420 this.sm.xmodule = this.xmodule || false;
47422 if (typeof(this.colModel.config) == 'undefined') {
47423 this.colModel = new Roo.grid.ColumnModel(this.colModel);
47424 this.cm = this.colModel;
47425 this.cm.xmodule = this.xmodule || false;
47427 if (this.dataSource) {
47428 this.dataSource= Roo.factory(this.dataSource, Roo.data);
47429 this.ds = this.dataSource;
47430 this.ds.xmodule = this.xmodule || false;
47437 this.container.setWidth(this.width);
47441 this.container.setHeight(this.height);
47448 * The raw click event for the entire grid.
47449 * @param {Roo.EventObject} e
47454 * The raw dblclick event for the entire grid.
47455 * @param {Roo.EventObject} e
47459 * @event contextmenu
47460 * The raw contextmenu event for the entire grid.
47461 * @param {Roo.EventObject} e
47463 "contextmenu" : true,
47466 * The raw mousedown event for the entire grid.
47467 * @param {Roo.EventObject} e
47469 "mousedown" : true,
47472 * The raw mouseup event for the entire grid.
47473 * @param {Roo.EventObject} e
47478 * The raw mouseover event for the entire grid.
47479 * @param {Roo.EventObject} e
47481 "mouseover" : true,
47484 * The raw mouseout event for the entire grid.
47485 * @param {Roo.EventObject} e
47490 * The raw keypress event for the entire grid.
47491 * @param {Roo.EventObject} e
47496 * The raw keydown event for the entire grid.
47497 * @param {Roo.EventObject} e
47505 * Fires when a cell is clicked
47506 * @param {Grid} this
47507 * @param {Number} rowIndex
47508 * @param {Number} columnIndex
47509 * @param {Roo.EventObject} e
47511 "cellclick" : true,
47513 * @event celldblclick
47514 * Fires when a cell is double clicked
47515 * @param {Grid} this
47516 * @param {Number} rowIndex
47517 * @param {Number} columnIndex
47518 * @param {Roo.EventObject} e
47520 "celldblclick" : true,
47523 * Fires when a row is clicked
47524 * @param {Grid} this
47525 * @param {Number} rowIndex
47526 * @param {Roo.EventObject} e
47530 * @event rowdblclick
47531 * Fires when a row is double clicked
47532 * @param {Grid} this
47533 * @param {Number} rowIndex
47534 * @param {Roo.EventObject} e
47536 "rowdblclick" : true,
47538 * @event headerclick
47539 * Fires when a header is clicked
47540 * @param {Grid} this
47541 * @param {Number} columnIndex
47542 * @param {Roo.EventObject} e
47544 "headerclick" : true,
47546 * @event headerdblclick
47547 * Fires when a header cell is double clicked
47548 * @param {Grid} this
47549 * @param {Number} columnIndex
47550 * @param {Roo.EventObject} e
47552 "headerdblclick" : true,
47554 * @event rowcontextmenu
47555 * Fires when a row is right clicked
47556 * @param {Grid} this
47557 * @param {Number} rowIndex
47558 * @param {Roo.EventObject} e
47560 "rowcontextmenu" : true,
47562 * @event cellcontextmenu
47563 * Fires when a cell is right clicked
47564 * @param {Grid} this
47565 * @param {Number} rowIndex
47566 * @param {Number} cellIndex
47567 * @param {Roo.EventObject} e
47569 "cellcontextmenu" : true,
47571 * @event headercontextmenu
47572 * Fires when a header is right clicked
47573 * @param {Grid} this
47574 * @param {Number} columnIndex
47575 * @param {Roo.EventObject} e
47577 "headercontextmenu" : true,
47579 * @event bodyscroll
47580 * Fires when the body element is scrolled
47581 * @param {Number} scrollLeft
47582 * @param {Number} scrollTop
47584 "bodyscroll" : true,
47586 * @event columnresize
47587 * Fires when the user resizes a column
47588 * @param {Number} columnIndex
47589 * @param {Number} newSize
47591 "columnresize" : true,
47593 * @event columnmove
47594 * Fires when the user moves a column
47595 * @param {Number} oldIndex
47596 * @param {Number} newIndex
47598 "columnmove" : true,
47601 * Fires when row(s) start being dragged
47602 * @param {Grid} this
47603 * @param {Roo.GridDD} dd The drag drop object
47604 * @param {event} e The raw browser event
47606 "startdrag" : true,
47609 * Fires when a drag operation is complete
47610 * @param {Grid} this
47611 * @param {Roo.GridDD} dd The drag drop object
47612 * @param {event} e The raw browser event
47617 * Fires when dragged row(s) are dropped on a valid DD target
47618 * @param {Grid} this
47619 * @param {Roo.GridDD} dd The drag drop object
47620 * @param {String} targetId The target drag drop object
47621 * @param {event} e The raw browser event
47626 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
47627 * @param {Grid} this
47628 * @param {Roo.GridDD} dd The drag drop object
47629 * @param {String} targetId The target drag drop object
47630 * @param {event} e The raw browser event
47635 * Fires when the dragged row(s) first cross another DD target while being dragged
47636 * @param {Grid} this
47637 * @param {Roo.GridDD} dd The drag drop object
47638 * @param {String} targetId The target drag drop object
47639 * @param {event} e The raw browser event
47641 "dragenter" : true,
47644 * Fires when the dragged row(s) leave another DD target while being dragged
47645 * @param {Grid} this
47646 * @param {Roo.GridDD} dd The drag drop object
47647 * @param {String} targetId The target drag drop object
47648 * @param {event} e The raw browser event
47653 * Fires when a row is rendered, so you can change add a style to it.
47654 * @param {GridView} gridview The grid view
47655 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
47661 * Fires when the grid is rendered
47662 * @param {Grid} grid
47667 Roo.grid.Grid.superclass.constructor.call(this);
47669 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
47672 * @cfg {String} ddGroup - drag drop group.
47676 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
47678 minColumnWidth : 25,
47681 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
47682 * <b>on initial render.</b> It is more efficient to explicitly size the columns
47683 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
47685 autoSizeColumns : false,
47688 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
47690 autoSizeHeaders : true,
47693 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
47695 monitorWindowResize : true,
47698 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
47699 * rows measured to get a columns size. Default is 0 (all rows).
47701 maxRowsToMeasure : 0,
47704 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
47706 trackMouseOver : true,
47709 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
47713 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
47715 enableDragDrop : false,
47718 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
47720 enableColumnMove : true,
47723 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
47725 enableColumnHide : true,
47728 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
47730 enableRowHeightSync : false,
47733 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
47738 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
47740 autoHeight : false,
47743 * @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.
47745 autoExpandColumn : false,
47748 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
47751 autoExpandMin : 50,
47754 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
47756 autoExpandMax : 1000,
47759 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
47764 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
47768 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
47778 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
47779 * of a fixed width. Default is false.
47782 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
47785 * Called once after all setup has been completed and the grid is ready to be rendered.
47786 * @return {Roo.grid.Grid} this
47788 render : function()
47790 var c = this.container;
47791 // try to detect autoHeight/width mode
47792 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
47793 this.autoHeight = true;
47795 var view = this.getView();
47798 c.on("click", this.onClick, this);
47799 c.on("dblclick", this.onDblClick, this);
47800 c.on("contextmenu", this.onContextMenu, this);
47801 c.on("keydown", this.onKeyDown, this);
47803 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
47805 this.getSelectionModel().init(this);
47810 this.loadMask = new Roo.LoadMask(this.container,
47811 Roo.apply({store:this.dataSource}, this.loadMask));
47815 if (this.toolbar && this.toolbar.xtype) {
47816 this.toolbar.container = this.getView().getHeaderPanel(true);
47817 this.toolbar = new Roo.Toolbar(this.toolbar);
47819 if (this.footer && this.footer.xtype) {
47820 this.footer.dataSource = this.getDataSource();
47821 this.footer.container = this.getView().getFooterPanel(true);
47822 this.footer = Roo.factory(this.footer, Roo);
47824 if (this.dropTarget && this.dropTarget.xtype) {
47825 delete this.dropTarget.xtype;
47826 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
47830 this.rendered = true;
47831 this.fireEvent('render', this);
47836 * Reconfigures the grid to use a different Store and Column Model.
47837 * The View will be bound to the new objects and refreshed.
47838 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
47839 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
47841 reconfigure : function(dataSource, colModel){
47843 this.loadMask.destroy();
47844 this.loadMask = new Roo.LoadMask(this.container,
47845 Roo.apply({store:dataSource}, this.loadMask));
47847 this.view.bind(dataSource, colModel);
47848 this.dataSource = dataSource;
47849 this.colModel = colModel;
47850 this.view.refresh(true);
47854 onKeyDown : function(e){
47855 this.fireEvent("keydown", e);
47859 * Destroy this grid.
47860 * @param {Boolean} removeEl True to remove the element
47862 destroy : function(removeEl, keepListeners){
47864 this.loadMask.destroy();
47866 var c = this.container;
47867 c.removeAllListeners();
47868 this.view.destroy();
47869 this.colModel.purgeListeners();
47870 if(!keepListeners){
47871 this.purgeListeners();
47874 if(removeEl === true){
47880 processEvent : function(name, e){
47881 this.fireEvent(name, e);
47882 var t = e.getTarget();
47884 var header = v.findHeaderIndex(t);
47885 if(header !== false){
47886 this.fireEvent("header" + name, this, header, e);
47888 var row = v.findRowIndex(t);
47889 var cell = v.findCellIndex(t);
47891 this.fireEvent("row" + name, this, row, e);
47892 if(cell !== false){
47893 this.fireEvent("cell" + name, this, row, cell, e);
47900 onClick : function(e){
47901 this.processEvent("click", e);
47905 onContextMenu : function(e, t){
47906 this.processEvent("contextmenu", e);
47910 onDblClick : function(e){
47911 this.processEvent("dblclick", e);
47915 walkCells : function(row, col, step, fn, scope){
47916 var cm = this.colModel, clen = cm.getColumnCount();
47917 var ds = this.dataSource, rlen = ds.getCount(), first = true;
47929 if(fn.call(scope || this, row, col, cm) === true){
47947 if(fn.call(scope || this, row, col, cm) === true){
47959 getSelections : function(){
47960 return this.selModel.getSelections();
47964 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
47965 * but if manual update is required this method will initiate it.
47967 autoSize : function(){
47969 this.view.layout();
47970 if(this.view.adjustForScroll){
47971 this.view.adjustForScroll();
47977 * Returns the grid's underlying element.
47978 * @return {Element} The element
47980 getGridEl : function(){
47981 return this.container;
47984 // private for compatibility, overridden by editor grid
47985 stopEditing : function(){},
47988 * Returns the grid's SelectionModel.
47989 * @return {SelectionModel}
47991 getSelectionModel : function(){
47992 if(!this.selModel){
47993 this.selModel = new Roo.grid.RowSelectionModel();
47995 return this.selModel;
47999 * Returns the grid's DataSource.
48000 * @return {DataSource}
48002 getDataSource : function(){
48003 return this.dataSource;
48007 * Returns the grid's ColumnModel.
48008 * @return {ColumnModel}
48010 getColumnModel : function(){
48011 return this.colModel;
48015 * Returns the grid's GridView object.
48016 * @return {GridView}
48018 getView : function(){
48020 this.view = new Roo.grid.GridView(this.viewConfig);
48025 * Called to get grid's drag proxy text, by default returns this.ddText.
48028 getDragDropText : function(){
48029 var count = this.selModel.getCount();
48030 return String.format(this.ddText, count, count == 1 ? '' : 's');
48034 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
48035 * %0 is replaced with the number of selected rows.
48038 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
48040 * Ext JS Library 1.1.1
48041 * Copyright(c) 2006-2007, Ext JS, LLC.
48043 * Originally Released Under LGPL - original licence link has changed is not relivant.
48046 * <script type="text/javascript">
48049 Roo.grid.AbstractGridView = function(){
48053 "beforerowremoved" : true,
48054 "beforerowsinserted" : true,
48055 "beforerefresh" : true,
48056 "rowremoved" : true,
48057 "rowsinserted" : true,
48058 "rowupdated" : true,
48061 Roo.grid.AbstractGridView.superclass.constructor.call(this);
48064 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
48065 rowClass : "x-grid-row",
48066 cellClass : "x-grid-cell",
48067 tdClass : "x-grid-td",
48068 hdClass : "x-grid-hd",
48069 splitClass : "x-grid-hd-split",
48071 init: function(grid){
48073 var cid = this.grid.getGridEl().id;
48074 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
48075 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
48076 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
48077 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
48080 getColumnRenderers : function(){
48081 var renderers = [];
48082 var cm = this.grid.colModel;
48083 var colCount = cm.getColumnCount();
48084 for(var i = 0; i < colCount; i++){
48085 renderers[i] = cm.getRenderer(i);
48090 getColumnIds : function(){
48092 var cm = this.grid.colModel;
48093 var colCount = cm.getColumnCount();
48094 for(var i = 0; i < colCount; i++){
48095 ids[i] = cm.getColumnId(i);
48100 getDataIndexes : function(){
48101 if(!this.indexMap){
48102 this.indexMap = this.buildIndexMap();
48104 return this.indexMap.colToData;
48107 getColumnIndexByDataIndex : function(dataIndex){
48108 if(!this.indexMap){
48109 this.indexMap = this.buildIndexMap();
48111 return this.indexMap.dataToCol[dataIndex];
48115 * Set a css style for a column dynamically.
48116 * @param {Number} colIndex The index of the column
48117 * @param {String} name The css property name
48118 * @param {String} value The css value
48120 setCSSStyle : function(colIndex, name, value){
48121 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
48122 Roo.util.CSS.updateRule(selector, name, value);
48125 generateRules : function(cm){
48126 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
48127 Roo.util.CSS.removeStyleSheet(rulesId);
48128 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48129 var cid = cm.getColumnId(i);
48130 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
48131 this.tdSelector, cid, " {\n}\n",
48132 this.hdSelector, cid, " {\n}\n",
48133 this.splitSelector, cid, " {\n}\n");
48135 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
48139 * Ext JS Library 1.1.1
48140 * Copyright(c) 2006-2007, Ext JS, LLC.
48142 * Originally Released Under LGPL - original licence link has changed is not relivant.
48145 * <script type="text/javascript">
48149 // This is a support class used internally by the Grid components
48150 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
48152 this.view = grid.getView();
48153 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
48154 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
48156 this.setHandleElId(Roo.id(hd));
48157 this.setOuterHandleElId(Roo.id(hd2));
48159 this.scroll = false;
48161 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
48163 getDragData : function(e){
48164 var t = Roo.lib.Event.getTarget(e);
48165 var h = this.view.findHeaderCell(t);
48167 return {ddel: h.firstChild, header:h};
48172 onInitDrag : function(e){
48173 this.view.headersDisabled = true;
48174 var clone = this.dragData.ddel.cloneNode(true);
48175 clone.id = Roo.id();
48176 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
48177 this.proxy.update(clone);
48181 afterValidDrop : function(){
48183 setTimeout(function(){
48184 v.headersDisabled = false;
48188 afterInvalidDrop : function(){
48190 setTimeout(function(){
48191 v.headersDisabled = false;
48197 * Ext JS Library 1.1.1
48198 * Copyright(c) 2006-2007, Ext JS, LLC.
48200 * Originally Released Under LGPL - original licence link has changed is not relivant.
48203 * <script type="text/javascript">
48206 // This is a support class used internally by the Grid components
48207 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
48209 this.view = grid.getView();
48210 // split the proxies so they don't interfere with mouse events
48211 this.proxyTop = Roo.DomHelper.append(document.body, {
48212 cls:"col-move-top", html:" "
48214 this.proxyBottom = Roo.DomHelper.append(document.body, {
48215 cls:"col-move-bottom", html:" "
48217 this.proxyTop.hide = this.proxyBottom.hide = function(){
48218 this.setLeftTop(-100,-100);
48219 this.setStyle("visibility", "hidden");
48221 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
48222 // temporarily disabled
48223 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
48224 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
48226 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
48227 proxyOffsets : [-4, -9],
48228 fly: Roo.Element.fly,
48230 getTargetFromEvent : function(e){
48231 var t = Roo.lib.Event.getTarget(e);
48232 var cindex = this.view.findCellIndex(t);
48233 if(cindex !== false){
48234 return this.view.getHeaderCell(cindex);
48239 nextVisible : function(h){
48240 var v = this.view, cm = this.grid.colModel;
48243 if(!cm.isHidden(v.getCellIndex(h))){
48251 prevVisible : function(h){
48252 var v = this.view, cm = this.grid.colModel;
48255 if(!cm.isHidden(v.getCellIndex(h))){
48263 positionIndicator : function(h, n, e){
48264 var x = Roo.lib.Event.getPageX(e);
48265 var r = Roo.lib.Dom.getRegion(n.firstChild);
48266 var px, pt, py = r.top + this.proxyOffsets[1];
48267 if((r.right - x) <= (r.right-r.left)/2){
48268 px = r.right+this.view.borderWidth;
48274 var oldIndex = this.view.getCellIndex(h);
48275 var newIndex = this.view.getCellIndex(n);
48277 if(this.grid.colModel.isFixed(newIndex)){
48281 var locked = this.grid.colModel.isLocked(newIndex);
48286 if(oldIndex < newIndex){
48289 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
48292 px += this.proxyOffsets[0];
48293 this.proxyTop.setLeftTop(px, py);
48294 this.proxyTop.show();
48295 if(!this.bottomOffset){
48296 this.bottomOffset = this.view.mainHd.getHeight();
48298 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
48299 this.proxyBottom.show();
48303 onNodeEnter : function(n, dd, e, data){
48304 if(data.header != n){
48305 this.positionIndicator(data.header, n, e);
48309 onNodeOver : function(n, dd, e, data){
48310 var result = false;
48311 if(data.header != n){
48312 result = this.positionIndicator(data.header, n, e);
48315 this.proxyTop.hide();
48316 this.proxyBottom.hide();
48318 return result ? this.dropAllowed : this.dropNotAllowed;
48321 onNodeOut : function(n, dd, e, data){
48322 this.proxyTop.hide();
48323 this.proxyBottom.hide();
48326 onNodeDrop : function(n, dd, e, data){
48327 var h = data.header;
48329 var cm = this.grid.colModel;
48330 var x = Roo.lib.Event.getPageX(e);
48331 var r = Roo.lib.Dom.getRegion(n.firstChild);
48332 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
48333 var oldIndex = this.view.getCellIndex(h);
48334 var newIndex = this.view.getCellIndex(n);
48335 var locked = cm.isLocked(newIndex);
48339 if(oldIndex < newIndex){
48342 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
48345 cm.setLocked(oldIndex, locked, true);
48346 cm.moveColumn(oldIndex, newIndex);
48347 this.grid.fireEvent("columnmove", oldIndex, newIndex);
48355 * Ext JS Library 1.1.1
48356 * Copyright(c) 2006-2007, Ext JS, LLC.
48358 * Originally Released Under LGPL - original licence link has changed is not relivant.
48361 * <script type="text/javascript">
48365 * @class Roo.grid.GridView
48366 * @extends Roo.util.Observable
48369 * @param {Object} config
48371 Roo.grid.GridView = function(config){
48372 Roo.grid.GridView.superclass.constructor.call(this);
48375 Roo.apply(this, config);
48378 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
48381 * Override this function to apply custom css classes to rows during rendering
48382 * @param {Record} record The record
48383 * @param {Number} index
48384 * @method getRowClass
48386 rowClass : "x-grid-row",
48388 cellClass : "x-grid-col",
48390 tdClass : "x-grid-td",
48392 hdClass : "x-grid-hd",
48394 splitClass : "x-grid-split",
48396 sortClasses : ["sort-asc", "sort-desc"],
48398 enableMoveAnim : false,
48402 dh : Roo.DomHelper,
48404 fly : Roo.Element.fly,
48406 css : Roo.util.CSS,
48412 scrollIncrement : 22,
48414 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
48416 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
48418 bind : function(ds, cm){
48420 this.ds.un("load", this.onLoad, this);
48421 this.ds.un("datachanged", this.onDataChange, this);
48422 this.ds.un("add", this.onAdd, this);
48423 this.ds.un("remove", this.onRemove, this);
48424 this.ds.un("update", this.onUpdate, this);
48425 this.ds.un("clear", this.onClear, this);
48428 ds.on("load", this.onLoad, this);
48429 ds.on("datachanged", this.onDataChange, this);
48430 ds.on("add", this.onAdd, this);
48431 ds.on("remove", this.onRemove, this);
48432 ds.on("update", this.onUpdate, this);
48433 ds.on("clear", this.onClear, this);
48438 this.cm.un("widthchange", this.onColWidthChange, this);
48439 this.cm.un("headerchange", this.onHeaderChange, this);
48440 this.cm.un("hiddenchange", this.onHiddenChange, this);
48441 this.cm.un("columnmoved", this.onColumnMove, this);
48442 this.cm.un("columnlockchange", this.onColumnLock, this);
48445 this.generateRules(cm);
48446 cm.on("widthchange", this.onColWidthChange, this);
48447 cm.on("headerchange", this.onHeaderChange, this);
48448 cm.on("hiddenchange", this.onHiddenChange, this);
48449 cm.on("columnmoved", this.onColumnMove, this);
48450 cm.on("columnlockchange", this.onColumnLock, this);
48455 init: function(grid){
48456 Roo.grid.GridView.superclass.init.call(this, grid);
48458 this.bind(grid.dataSource, grid.colModel);
48460 grid.on("headerclick", this.handleHeaderClick, this);
48462 if(grid.trackMouseOver){
48463 grid.on("mouseover", this.onRowOver, this);
48464 grid.on("mouseout", this.onRowOut, this);
48466 grid.cancelTextSelection = function(){};
48467 this.gridId = grid.id;
48469 var tpls = this.templates || {};
48472 tpls.master = new Roo.Template(
48473 '<div class="x-grid" hidefocus="true">',
48474 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
48475 '<div class="x-grid-topbar"></div>',
48476 '<div class="x-grid-scroller"><div></div></div>',
48477 '<div class="x-grid-locked">',
48478 '<div class="x-grid-header">{lockedHeader}</div>',
48479 '<div class="x-grid-body">{lockedBody}</div>',
48481 '<div class="x-grid-viewport">',
48482 '<div class="x-grid-header">{header}</div>',
48483 '<div class="x-grid-body">{body}</div>',
48485 '<div class="x-grid-bottombar"></div>',
48487 '<div class="x-grid-resize-proxy"> </div>',
48490 tpls.master.disableformats = true;
48494 tpls.header = new Roo.Template(
48495 '<table border="0" cellspacing="0" cellpadding="0">',
48496 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
48499 tpls.header.disableformats = true;
48501 tpls.header.compile();
48504 tpls.hcell = new Roo.Template(
48505 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
48506 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
48509 tpls.hcell.disableFormats = true;
48511 tpls.hcell.compile();
48514 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
48515 tpls.hsplit.disableFormats = true;
48517 tpls.hsplit.compile();
48520 tpls.body = new Roo.Template(
48521 '<table border="0" cellspacing="0" cellpadding="0">',
48522 "<tbody>{rows}</tbody>",
48525 tpls.body.disableFormats = true;
48527 tpls.body.compile();
48530 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
48531 tpls.row.disableFormats = true;
48533 tpls.row.compile();
48536 tpls.cell = new Roo.Template(
48537 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
48538 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
48541 tpls.cell.disableFormats = true;
48543 tpls.cell.compile();
48545 this.templates = tpls;
48548 // remap these for backwards compat
48549 onColWidthChange : function(){
48550 this.updateColumns.apply(this, arguments);
48552 onHeaderChange : function(){
48553 this.updateHeaders.apply(this, arguments);
48555 onHiddenChange : function(){
48556 this.handleHiddenChange.apply(this, arguments);
48558 onColumnMove : function(){
48559 this.handleColumnMove.apply(this, arguments);
48561 onColumnLock : function(){
48562 this.handleLockChange.apply(this, arguments);
48565 onDataChange : function(){
48567 this.updateHeaderSortState();
48570 onClear : function(){
48574 onUpdate : function(ds, record){
48575 this.refreshRow(record);
48578 refreshRow : function(record){
48579 var ds = this.ds, index;
48580 if(typeof record == 'number'){
48582 record = ds.getAt(index);
48584 index = ds.indexOf(record);
48586 this.insertRows(ds, index, index, true);
48587 this.onRemove(ds, record, index+1, true);
48588 this.syncRowHeights(index, index);
48590 this.fireEvent("rowupdated", this, index, record);
48593 onAdd : function(ds, records, index){
48594 this.insertRows(ds, index, index + (records.length-1));
48597 onRemove : function(ds, record, index, isUpdate){
48598 if(isUpdate !== true){
48599 this.fireEvent("beforerowremoved", this, index, record);
48601 var bt = this.getBodyTable(), lt = this.getLockedTable();
48602 if(bt.rows[index]){
48603 bt.firstChild.removeChild(bt.rows[index]);
48605 if(lt.rows[index]){
48606 lt.firstChild.removeChild(lt.rows[index]);
48608 if(isUpdate !== true){
48609 this.stripeRows(index);
48610 this.syncRowHeights(index, index);
48612 this.fireEvent("rowremoved", this, index, record);
48616 onLoad : function(){
48617 this.scrollToTop();
48621 * Scrolls the grid to the top
48623 scrollToTop : function(){
48625 this.scroller.dom.scrollTop = 0;
48631 * Gets a panel in the header of the grid that can be used for toolbars etc.
48632 * After modifying the contents of this panel a call to grid.autoSize() may be
48633 * required to register any changes in size.
48634 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
48635 * @return Roo.Element
48637 getHeaderPanel : function(doShow){
48639 this.headerPanel.show();
48641 return this.headerPanel;
48645 * Gets a panel in the footer of the grid that can be used for toolbars etc.
48646 * After modifying the contents of this panel a call to grid.autoSize() may be
48647 * required to register any changes in size.
48648 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
48649 * @return Roo.Element
48651 getFooterPanel : function(doShow){
48653 this.footerPanel.show();
48655 return this.footerPanel;
48658 initElements : function(){
48659 var E = Roo.Element;
48660 var el = this.grid.getGridEl().dom.firstChild;
48661 var cs = el.childNodes;
48663 this.el = new E(el);
48665 this.focusEl = new E(el.firstChild);
48666 this.focusEl.swallowEvent("click", true);
48668 this.headerPanel = new E(cs[1]);
48669 this.headerPanel.enableDisplayMode("block");
48671 this.scroller = new E(cs[2]);
48672 this.scrollSizer = new E(this.scroller.dom.firstChild);
48674 this.lockedWrap = new E(cs[3]);
48675 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
48676 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
48678 this.mainWrap = new E(cs[4]);
48679 this.mainHd = new E(this.mainWrap.dom.firstChild);
48680 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
48682 this.footerPanel = new E(cs[5]);
48683 this.footerPanel.enableDisplayMode("block");
48685 this.resizeProxy = new E(cs[6]);
48687 this.headerSelector = String.format(
48688 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
48689 this.lockedHd.id, this.mainHd.id
48692 this.splitterSelector = String.format(
48693 '#{0} div.x-grid-split, #{1} div.x-grid-split',
48694 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
48697 idToCssName : function(s)
48699 return s.replace(/[^a-z0-9]+/ig, '-');
48702 getHeaderCell : function(index){
48703 return Roo.DomQuery.select(this.headerSelector)[index];
48706 getHeaderCellMeasure : function(index){
48707 return this.getHeaderCell(index).firstChild;
48710 getHeaderCellText : function(index){
48711 return this.getHeaderCell(index).firstChild.firstChild;
48714 getLockedTable : function(){
48715 return this.lockedBody.dom.firstChild;
48718 getBodyTable : function(){
48719 return this.mainBody.dom.firstChild;
48722 getLockedRow : function(index){
48723 return this.getLockedTable().rows[index];
48726 getRow : function(index){
48727 return this.getBodyTable().rows[index];
48730 getRowComposite : function(index){
48732 this.rowEl = new Roo.CompositeElementLite();
48734 var els = [], lrow, mrow;
48735 if(lrow = this.getLockedRow(index)){
48738 if(mrow = this.getRow(index)){
48741 this.rowEl.elements = els;
48745 * Gets the 'td' of the cell
48747 * @param {Integer} rowIndex row to select
48748 * @param {Integer} colIndex column to select
48752 getCell : function(rowIndex, colIndex){
48753 var locked = this.cm.getLockedCount();
48755 if(colIndex < locked){
48756 source = this.lockedBody.dom.firstChild;
48758 source = this.mainBody.dom.firstChild;
48759 colIndex -= locked;
48761 return source.rows[rowIndex].childNodes[colIndex];
48764 getCellText : function(rowIndex, colIndex){
48765 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
48768 getCellBox : function(cell){
48769 var b = this.fly(cell).getBox();
48770 if(Roo.isOpera){ // opera fails to report the Y
48771 b.y = cell.offsetTop + this.mainBody.getY();
48776 getCellIndex : function(cell){
48777 var id = String(cell.className).match(this.cellRE);
48779 return parseInt(id[1], 10);
48784 findHeaderIndex : function(n){
48785 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
48786 return r ? this.getCellIndex(r) : false;
48789 findHeaderCell : function(n){
48790 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
48791 return r ? r : false;
48794 findRowIndex : function(n){
48798 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
48799 return r ? r.rowIndex : false;
48802 findCellIndex : function(node){
48803 var stop = this.el.dom;
48804 while(node && node != stop){
48805 if(this.findRE.test(node.className)){
48806 return this.getCellIndex(node);
48808 node = node.parentNode;
48813 getColumnId : function(index){
48814 return this.cm.getColumnId(index);
48817 getSplitters : function()
48819 if(this.splitterSelector){
48820 return Roo.DomQuery.select(this.splitterSelector);
48826 getSplitter : function(index){
48827 return this.getSplitters()[index];
48830 onRowOver : function(e, t){
48832 if((row = this.findRowIndex(t)) !== false){
48833 this.getRowComposite(row).addClass("x-grid-row-over");
48837 onRowOut : function(e, t){
48839 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
48840 this.getRowComposite(row).removeClass("x-grid-row-over");
48844 renderHeaders : function(){
48846 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
48847 var cb = [], lb = [], sb = [], lsb = [], p = {};
48848 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48849 p.cellId = "x-grid-hd-0-" + i;
48850 p.splitId = "x-grid-csplit-0-" + i;
48851 p.id = cm.getColumnId(i);
48852 p.title = cm.getColumnTooltip(i) || "";
48853 p.value = cm.getColumnHeader(i) || "";
48854 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
48855 if(!cm.isLocked(i)){
48856 cb[cb.length] = ct.apply(p);
48857 sb[sb.length] = st.apply(p);
48859 lb[lb.length] = ct.apply(p);
48860 lsb[lsb.length] = st.apply(p);
48863 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
48864 ht.apply({cells: cb.join(""), splits:sb.join("")})];
48867 updateHeaders : function(){
48868 var html = this.renderHeaders();
48869 this.lockedHd.update(html[0]);
48870 this.mainHd.update(html[1]);
48874 * Focuses the specified row.
48875 * @param {Number} row The row index
48877 focusRow : function(row)
48879 //Roo.log('GridView.focusRow');
48880 var x = this.scroller.dom.scrollLeft;
48881 this.focusCell(row, 0, false);
48882 this.scroller.dom.scrollLeft = x;
48886 * Focuses the specified cell.
48887 * @param {Number} row The row index
48888 * @param {Number} col The column index
48889 * @param {Boolean} hscroll false to disable horizontal scrolling
48891 focusCell : function(row, col, hscroll)
48893 //Roo.log('GridView.focusCell');
48894 var el = this.ensureVisible(row, col, hscroll);
48895 this.focusEl.alignTo(el, "tl-tl");
48897 this.focusEl.focus();
48899 this.focusEl.focus.defer(1, this.focusEl);
48904 * Scrolls the specified cell into view
48905 * @param {Number} row The row index
48906 * @param {Number} col The column index
48907 * @param {Boolean} hscroll false to disable horizontal scrolling
48909 ensureVisible : function(row, col, hscroll)
48911 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
48912 //return null; //disable for testing.
48913 if(typeof row != "number"){
48914 row = row.rowIndex;
48916 if(row < 0 && row >= this.ds.getCount()){
48919 col = (col !== undefined ? col : 0);
48920 var cm = this.grid.colModel;
48921 while(cm.isHidden(col)){
48925 var el = this.getCell(row, col);
48929 var c = this.scroller.dom;
48931 var ctop = parseInt(el.offsetTop, 10);
48932 var cleft = parseInt(el.offsetLeft, 10);
48933 var cbot = ctop + el.offsetHeight;
48934 var cright = cleft + el.offsetWidth;
48936 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
48937 var stop = parseInt(c.scrollTop, 10);
48938 var sleft = parseInt(c.scrollLeft, 10);
48939 var sbot = stop + ch;
48940 var sright = sleft + c.clientWidth;
48942 Roo.log('GridView.ensureVisible:' +
48944 ' c.clientHeight:' + c.clientHeight +
48945 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
48953 c.scrollTop = ctop;
48954 //Roo.log("set scrolltop to ctop DISABLE?");
48955 }else if(cbot > sbot){
48956 //Roo.log("set scrolltop to cbot-ch");
48957 c.scrollTop = cbot-ch;
48960 if(hscroll !== false){
48962 c.scrollLeft = cleft;
48963 }else if(cright > sright){
48964 c.scrollLeft = cright-c.clientWidth;
48971 updateColumns : function(){
48972 this.grid.stopEditing();
48973 var cm = this.grid.colModel, colIds = this.getColumnIds();
48974 //var totalWidth = cm.getTotalWidth();
48976 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48977 //if(cm.isHidden(i)) continue;
48978 var w = cm.getColumnWidth(i);
48979 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48980 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
48982 this.updateSplitters();
48985 generateRules : function(cm){
48986 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
48987 Roo.util.CSS.removeStyleSheet(rulesId);
48988 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48989 var cid = cm.getColumnId(i);
48991 if(cm.config[i].align){
48992 align = 'text-align:'+cm.config[i].align+';';
48995 if(cm.isHidden(i)){
48996 hidden = 'display:none;';
48998 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
49000 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
49001 this.hdSelector, cid, " {\n", align, width, "}\n",
49002 this.tdSelector, cid, " {\n",hidden,"\n}\n",
49003 this.splitSelector, cid, " {\n", hidden , "\n}\n");
49005 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
49008 updateSplitters : function(){
49009 var cm = this.cm, s = this.getSplitters();
49010 if(s){ // splitters not created yet
49011 var pos = 0, locked = true;
49012 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
49013 if(cm.isHidden(i)) continue;
49014 var w = cm.getColumnWidth(i); // make sure it's a number
49015 if(!cm.isLocked(i) && locked){
49020 s[i].style.left = (pos-this.splitOffset) + "px";
49025 handleHiddenChange : function(colModel, colIndex, hidden){
49027 this.hideColumn(colIndex);
49029 this.unhideColumn(colIndex);
49033 hideColumn : function(colIndex){
49034 var cid = this.getColumnId(colIndex);
49035 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
49036 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
49038 this.updateHeaders();
49040 this.updateSplitters();
49044 unhideColumn : function(colIndex){
49045 var cid = this.getColumnId(colIndex);
49046 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
49047 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
49050 this.updateHeaders();
49052 this.updateSplitters();
49056 insertRows : function(dm, firstRow, lastRow, isUpdate){
49057 if(firstRow == 0 && lastRow == dm.getCount()-1){
49061 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
49063 var s = this.getScrollState();
49064 var markup = this.renderRows(firstRow, lastRow);
49065 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
49066 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
49067 this.restoreScroll(s);
49069 this.fireEvent("rowsinserted", this, firstRow, lastRow);
49070 this.syncRowHeights(firstRow, lastRow);
49071 this.stripeRows(firstRow);
49077 bufferRows : function(markup, target, index){
49078 var before = null, trows = target.rows, tbody = target.tBodies[0];
49079 if(index < trows.length){
49080 before = trows[index];
49082 var b = document.createElement("div");
49083 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
49084 var rows = b.firstChild.rows;
49085 for(var i = 0, len = rows.length; i < len; i++){
49087 tbody.insertBefore(rows[0], before);
49089 tbody.appendChild(rows[0]);
49096 deleteRows : function(dm, firstRow, lastRow){
49097 if(dm.getRowCount()<1){
49098 this.fireEvent("beforerefresh", this);
49099 this.mainBody.update("");
49100 this.lockedBody.update("");
49101 this.fireEvent("refresh", this);
49103 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
49104 var bt = this.getBodyTable();
49105 var tbody = bt.firstChild;
49106 var rows = bt.rows;
49107 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
49108 tbody.removeChild(rows[firstRow]);
49110 this.stripeRows(firstRow);
49111 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
49115 updateRows : function(dataSource, firstRow, lastRow){
49116 var s = this.getScrollState();
49118 this.restoreScroll(s);
49121 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
49125 this.updateHeaderSortState();
49128 getScrollState : function(){
49130 var sb = this.scroller.dom;
49131 return {left: sb.scrollLeft, top: sb.scrollTop};
49134 stripeRows : function(startRow){
49135 if(!this.grid.stripeRows || this.ds.getCount() < 1){
49138 startRow = startRow || 0;
49139 var rows = this.getBodyTable().rows;
49140 var lrows = this.getLockedTable().rows;
49141 var cls = ' x-grid-row-alt ';
49142 for(var i = startRow, len = rows.length; i < len; i++){
49143 var row = rows[i], lrow = lrows[i];
49144 var isAlt = ((i+1) % 2 == 0);
49145 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
49146 if(isAlt == hasAlt){
49150 row.className += " x-grid-row-alt";
49152 row.className = row.className.replace("x-grid-row-alt", "");
49155 lrow.className = row.className;
49160 restoreScroll : function(state){
49161 //Roo.log('GridView.restoreScroll');
49162 var sb = this.scroller.dom;
49163 sb.scrollLeft = state.left;
49164 sb.scrollTop = state.top;
49168 syncScroll : function(){
49169 //Roo.log('GridView.syncScroll');
49170 var sb = this.scroller.dom;
49171 var sh = this.mainHd.dom;
49172 var bs = this.mainBody.dom;
49173 var lv = this.lockedBody.dom;
49174 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
49175 lv.scrollTop = bs.scrollTop = sb.scrollTop;
49178 handleScroll : function(e){
49180 var sb = this.scroller.dom;
49181 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
49185 handleWheel : function(e){
49186 var d = e.getWheelDelta();
49187 this.scroller.dom.scrollTop -= d*22;
49188 // set this here to prevent jumpy scrolling on large tables
49189 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
49193 renderRows : function(startRow, endRow){
49194 // pull in all the crap needed to render rows
49195 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
49196 var colCount = cm.getColumnCount();
49198 if(ds.getCount() < 1){
49202 // build a map for all the columns
49204 for(var i = 0; i < colCount; i++){
49205 var name = cm.getDataIndex(i);
49207 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
49208 renderer : cm.getRenderer(i),
49209 id : cm.getColumnId(i),
49210 locked : cm.isLocked(i)
49214 startRow = startRow || 0;
49215 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
49217 // records to render
49218 var rs = ds.getRange(startRow, endRow);
49220 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
49223 // As much as I hate to duplicate code, this was branched because FireFox really hates
49224 // [].join("") on strings. The performance difference was substantial enough to
49225 // branch this function
49226 doRender : Roo.isGecko ?
49227 function(cs, rs, ds, startRow, colCount, stripe){
49228 var ts = this.templates, ct = ts.cell, rt = ts.row;
49230 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
49232 var hasListener = this.grid.hasListener('rowclass');
49234 for(var j = 0, len = rs.length; j < len; j++){
49235 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
49236 for(var i = 0; i < colCount; i++){
49238 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
49240 p.css = p.attr = "";
49241 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
49242 if(p.value == undefined || p.value === "") p.value = " ";
49243 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
49244 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
49246 var markup = ct.apply(p);
49254 if(stripe && ((rowIndex+1) % 2 == 0)){
49255 alt.push("x-grid-row-alt")
49258 alt.push( " x-grid-dirty-row");
49261 if(this.getRowClass){
49262 alt.push(this.getRowClass(r, rowIndex));
49268 rowIndex : rowIndex,
49271 this.grid.fireEvent('rowclass', this, rowcfg);
49272 alt.push(rowcfg.rowClass);
49274 rp.alt = alt.join(" ");
49275 lbuf+= rt.apply(rp);
49277 buf+= rt.apply(rp);
49279 return [lbuf, buf];
49281 function(cs, rs, ds, startRow, colCount, stripe){
49282 var ts = this.templates, ct = ts.cell, rt = ts.row;
49284 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
49285 var hasListener = this.grid.hasListener('rowclass');
49287 for(var j = 0, len = rs.length; j < len; j++){
49288 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
49289 for(var i = 0; i < colCount; i++){
49291 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
49293 p.css = p.attr = "";
49294 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
49295 if(p.value == undefined || p.value === "") p.value = " ";
49296 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
49297 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
49299 var markup = ct.apply(p);
49301 cb[cb.length] = markup;
49303 lcb[lcb.length] = markup;
49307 if(stripe && ((rowIndex+1) % 2 == 0)){
49308 alt.push( "x-grid-row-alt");
49311 alt.push(" x-grid-dirty-row");
49314 if(this.getRowClass){
49315 alt.push( this.getRowClass(r, rowIndex));
49321 rowIndex : rowIndex,
49324 this.grid.fireEvent('rowclass', this, rowcfg);
49325 alt.push(rowcfg.rowClass);
49327 rp.alt = alt.join(" ");
49328 rp.cells = lcb.join("");
49329 lbuf[lbuf.length] = rt.apply(rp);
49330 rp.cells = cb.join("");
49331 buf[buf.length] = rt.apply(rp);
49333 return [lbuf.join(""), buf.join("")];
49336 renderBody : function(){
49337 var markup = this.renderRows();
49338 var bt = this.templates.body;
49339 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
49343 * Refreshes the grid
49344 * @param {Boolean} headersToo
49346 refresh : function(headersToo){
49347 this.fireEvent("beforerefresh", this);
49348 this.grid.stopEditing();
49349 var result = this.renderBody();
49350 this.lockedBody.update(result[0]);
49351 this.mainBody.update(result[1]);
49352 if(headersToo === true){
49353 this.updateHeaders();
49354 this.updateColumns();
49355 this.updateSplitters();
49356 this.updateHeaderSortState();
49358 this.syncRowHeights();
49360 this.fireEvent("refresh", this);
49363 handleColumnMove : function(cm, oldIndex, newIndex){
49364 this.indexMap = null;
49365 var s = this.getScrollState();
49366 this.refresh(true);
49367 this.restoreScroll(s);
49368 this.afterMove(newIndex);
49371 afterMove : function(colIndex){
49372 if(this.enableMoveAnim && Roo.enableFx){
49373 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
49375 // if multisort - fix sortOrder, and reload..
49376 if (this.grid.dataSource.multiSort) {
49377 // the we can call sort again..
49378 var dm = this.grid.dataSource;
49379 var cm = this.grid.colModel;
49381 for(var i = 0; i < cm.config.length; i++ ) {
49383 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
49384 continue; // dont' bother, it's not in sort list or being set.
49387 so.push(cm.config[i].dataIndex);
49390 dm.load(dm.lastOptions);
49397 updateCell : function(dm, rowIndex, dataIndex){
49398 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
49399 if(typeof colIndex == "undefined"){ // not present in grid
49402 var cm = this.grid.colModel;
49403 var cell = this.getCell(rowIndex, colIndex);
49404 var cellText = this.getCellText(rowIndex, colIndex);
49407 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
49408 id : cm.getColumnId(colIndex),
49409 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
49411 var renderer = cm.getRenderer(colIndex);
49412 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
49413 if(typeof val == "undefined" || val === "") val = " ";
49414 cellText.innerHTML = val;
49415 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
49416 this.syncRowHeights(rowIndex, rowIndex);
49419 calcColumnWidth : function(colIndex, maxRowsToMeasure){
49421 if(this.grid.autoSizeHeaders){
49422 var h = this.getHeaderCellMeasure(colIndex);
49423 maxWidth = Math.max(maxWidth, h.scrollWidth);
49426 if(this.cm.isLocked(colIndex)){
49427 tb = this.getLockedTable();
49430 tb = this.getBodyTable();
49431 index = colIndex - this.cm.getLockedCount();
49434 var rows = tb.rows;
49435 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
49436 for(var i = 0; i < stopIndex; i++){
49437 var cell = rows[i].childNodes[index].firstChild;
49438 maxWidth = Math.max(maxWidth, cell.scrollWidth);
49441 return maxWidth + /*margin for error in IE*/ 5;
49444 * Autofit a column to its content.
49445 * @param {Number} colIndex
49446 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
49448 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
49449 if(this.cm.isHidden(colIndex)){
49450 return; // can't calc a hidden column
49453 var cid = this.cm.getColumnId(colIndex);
49454 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
49455 if(this.grid.autoSizeHeaders){
49456 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
49459 var newWidth = this.calcColumnWidth(colIndex);
49460 this.cm.setColumnWidth(colIndex,
49461 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
49462 if(!suppressEvent){
49463 this.grid.fireEvent("columnresize", colIndex, newWidth);
49468 * Autofits all columns to their content and then expands to fit any extra space in the grid
49470 autoSizeColumns : function(){
49471 var cm = this.grid.colModel;
49472 var colCount = cm.getColumnCount();
49473 for(var i = 0; i < colCount; i++){
49474 this.autoSizeColumn(i, true, true);
49476 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
49479 this.updateColumns();
49485 * Autofits all columns to the grid's width proportionate with their current size
49486 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
49488 fitColumns : function(reserveScrollSpace){
49489 var cm = this.grid.colModel;
49490 var colCount = cm.getColumnCount();
49494 for (i = 0; i < colCount; i++){
49495 if(!cm.isHidden(i) && !cm.isFixed(i)){
49496 w = cm.getColumnWidth(i);
49502 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
49503 if(reserveScrollSpace){
49506 var frac = (avail - cm.getTotalWidth())/width;
49507 while (cols.length){
49510 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
49512 this.updateColumns();
49516 onRowSelect : function(rowIndex){
49517 var row = this.getRowComposite(rowIndex);
49518 row.addClass("x-grid-row-selected");
49521 onRowDeselect : function(rowIndex){
49522 var row = this.getRowComposite(rowIndex);
49523 row.removeClass("x-grid-row-selected");
49526 onCellSelect : function(row, col){
49527 var cell = this.getCell(row, col);
49529 Roo.fly(cell).addClass("x-grid-cell-selected");
49533 onCellDeselect : function(row, col){
49534 var cell = this.getCell(row, col);
49536 Roo.fly(cell).removeClass("x-grid-cell-selected");
49540 updateHeaderSortState : function(){
49542 // sort state can be single { field: xxx, direction : yyy}
49543 // or { xxx=>ASC , yyy : DESC ..... }
49546 if (!this.ds.multiSort) {
49547 var state = this.ds.getSortState();
49551 mstate[state.field] = state.direction;
49552 // FIXME... - this is not used here.. but might be elsewhere..
49553 this.sortState = state;
49556 mstate = this.ds.sortToggle;
49558 //remove existing sort classes..
49560 var sc = this.sortClasses;
49561 var hds = this.el.select(this.headerSelector).removeClass(sc);
49563 for(var f in mstate) {
49565 var sortColumn = this.cm.findColumnIndex(f);
49567 if(sortColumn != -1){
49568 var sortDir = mstate[f];
49569 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
49578 handleHeaderClick : function(g, index){
49579 if(this.headersDisabled){
49582 var dm = g.dataSource, cm = g.colModel;
49583 if(!cm.isSortable(index)){
49588 if (dm.multiSort) {
49589 // update the sortOrder
49591 for(var i = 0; i < cm.config.length; i++ ) {
49593 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
49594 continue; // dont' bother, it's not in sort list or being set.
49597 so.push(cm.config[i].dataIndex);
49603 dm.sort(cm.getDataIndex(index));
49607 destroy : function(){
49609 this.colMenu.removeAll();
49610 Roo.menu.MenuMgr.unregister(this.colMenu);
49611 this.colMenu.getEl().remove();
49612 delete this.colMenu;
49615 this.hmenu.removeAll();
49616 Roo.menu.MenuMgr.unregister(this.hmenu);
49617 this.hmenu.getEl().remove();
49620 if(this.grid.enableColumnMove){
49621 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
49623 for(var dd in dds){
49624 if(!dds[dd].config.isTarget && dds[dd].dragElId){
49625 var elid = dds[dd].dragElId;
49627 Roo.get(elid).remove();
49628 } else if(dds[dd].config.isTarget){
49629 dds[dd].proxyTop.remove();
49630 dds[dd].proxyBottom.remove();
49633 if(Roo.dd.DDM.locationCache[dd]){
49634 delete Roo.dd.DDM.locationCache[dd];
49637 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
49640 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
49641 this.bind(null, null);
49642 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
49645 handleLockChange : function(){
49646 this.refresh(true);
49649 onDenyColumnLock : function(){
49653 onDenyColumnHide : function(){
49657 handleHdMenuClick : function(item){
49658 var index = this.hdCtxIndex;
49659 var cm = this.cm, ds = this.ds;
49662 ds.sort(cm.getDataIndex(index), "ASC");
49665 ds.sort(cm.getDataIndex(index), "DESC");
49668 var lc = cm.getLockedCount();
49669 if(cm.getColumnCount(true) <= lc+1){
49670 this.onDenyColumnLock();
49674 cm.setLocked(index, true, true);
49675 cm.moveColumn(index, lc);
49676 this.grid.fireEvent("columnmove", index, lc);
49678 cm.setLocked(index, true);
49682 var lc = cm.getLockedCount();
49683 if((lc-1) != index){
49684 cm.setLocked(index, false, true);
49685 cm.moveColumn(index, lc-1);
49686 this.grid.fireEvent("columnmove", index, lc-1);
49688 cm.setLocked(index, false);
49692 index = cm.getIndexById(item.id.substr(4));
49694 if(item.checked && cm.getColumnCount(true) <= 1){
49695 this.onDenyColumnHide();
49698 cm.setHidden(index, item.checked);
49704 beforeColMenuShow : function(){
49705 var cm = this.cm, colCount = cm.getColumnCount();
49706 this.colMenu.removeAll();
49707 for(var i = 0; i < colCount; i++){
49708 this.colMenu.add(new Roo.menu.CheckItem({
49709 id: "col-"+cm.getColumnId(i),
49710 text: cm.getColumnHeader(i),
49711 checked: !cm.isHidden(i),
49717 handleHdCtx : function(g, index, e){
49719 var hd = this.getHeaderCell(index);
49720 this.hdCtxIndex = index;
49721 var ms = this.hmenu.items, cm = this.cm;
49722 ms.get("asc").setDisabled(!cm.isSortable(index));
49723 ms.get("desc").setDisabled(!cm.isSortable(index));
49724 if(this.grid.enableColLock !== false){
49725 ms.get("lock").setDisabled(cm.isLocked(index));
49726 ms.get("unlock").setDisabled(!cm.isLocked(index));
49728 this.hmenu.show(hd, "tl-bl");
49731 handleHdOver : function(e){
49732 var hd = this.findHeaderCell(e.getTarget());
49733 if(hd && !this.headersDisabled){
49734 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
49735 this.fly(hd).addClass("x-grid-hd-over");
49740 handleHdOut : function(e){
49741 var hd = this.findHeaderCell(e.getTarget());
49743 this.fly(hd).removeClass("x-grid-hd-over");
49747 handleSplitDblClick : function(e, t){
49748 var i = this.getCellIndex(t);
49749 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
49750 this.autoSizeColumn(i, true);
49755 render : function(){
49758 var colCount = cm.getColumnCount();
49760 if(this.grid.monitorWindowResize === true){
49761 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
49763 var header = this.renderHeaders();
49764 var body = this.templates.body.apply({rows:""});
49765 var html = this.templates.master.apply({
49768 lockedHeader: header[0],
49772 //this.updateColumns();
49774 this.grid.getGridEl().dom.innerHTML = html;
49776 this.initElements();
49778 // a kludge to fix the random scolling effect in webkit
49779 this.el.on("scroll", function() {
49780 this.el.dom.scrollTop=0; // hopefully not recursive..
49783 this.scroller.on("scroll", this.handleScroll, this);
49784 this.lockedBody.on("mousewheel", this.handleWheel, this);
49785 this.mainBody.on("mousewheel", this.handleWheel, this);
49787 this.mainHd.on("mouseover", this.handleHdOver, this);
49788 this.mainHd.on("mouseout", this.handleHdOut, this);
49789 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
49790 {delegate: "."+this.splitClass});
49792 this.lockedHd.on("mouseover", this.handleHdOver, this);
49793 this.lockedHd.on("mouseout", this.handleHdOut, this);
49794 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
49795 {delegate: "."+this.splitClass});
49797 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
49798 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
49801 this.updateSplitters();
49803 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
49804 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
49805 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
49808 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
49809 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
49811 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
49812 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
49814 if(this.grid.enableColLock !== false){
49815 this.hmenu.add('-',
49816 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
49817 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
49820 if(this.grid.enableColumnHide !== false){
49822 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
49823 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
49824 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
49826 this.hmenu.add('-',
49827 {id:"columns", text: this.columnsText, menu: this.colMenu}
49830 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
49832 this.grid.on("headercontextmenu", this.handleHdCtx, this);
49835 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
49836 this.dd = new Roo.grid.GridDragZone(this.grid, {
49837 ddGroup : this.grid.ddGroup || 'GridDD'
49842 for(var i = 0; i < colCount; i++){
49843 if(cm.isHidden(i)){
49844 this.hideColumn(i);
49846 if(cm.config[i].align){
49847 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
49848 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
49852 this.updateHeaderSortState();
49854 this.beforeInitialResize();
49857 // two part rendering gives faster view to the user
49858 this.renderPhase2.defer(1, this);
49861 renderPhase2 : function(){
49862 // render the rows now
49864 if(this.grid.autoSizeColumns){
49865 this.autoSizeColumns();
49869 beforeInitialResize : function(){
49873 onColumnSplitterMoved : function(i, w){
49874 this.userResized = true;
49875 var cm = this.grid.colModel;
49876 cm.setColumnWidth(i, w, true);
49877 var cid = cm.getColumnId(i);
49878 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
49879 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
49880 this.updateSplitters();
49882 this.grid.fireEvent("columnresize", i, w);
49885 syncRowHeights : function(startIndex, endIndex){
49886 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
49887 startIndex = startIndex || 0;
49888 var mrows = this.getBodyTable().rows;
49889 var lrows = this.getLockedTable().rows;
49890 var len = mrows.length-1;
49891 endIndex = Math.min(endIndex || len, len);
49892 for(var i = startIndex; i <= endIndex; i++){
49893 var m = mrows[i], l = lrows[i];
49894 var h = Math.max(m.offsetHeight, l.offsetHeight);
49895 m.style.height = l.style.height = h + "px";
49900 layout : function(initialRender, is2ndPass){
49902 var auto = g.autoHeight;
49903 var scrollOffset = 16;
49904 var c = g.getGridEl(), cm = this.cm,
49905 expandCol = g.autoExpandColumn,
49907 //c.beginMeasure();
49909 if(!c.dom.offsetWidth){ // display:none?
49911 this.lockedWrap.show();
49912 this.mainWrap.show();
49917 var hasLock = this.cm.isLocked(0);
49919 var tbh = this.headerPanel.getHeight();
49920 var bbh = this.footerPanel.getHeight();
49923 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
49924 var newHeight = ch + c.getBorderWidth("tb");
49926 newHeight = Math.min(g.maxHeight, newHeight);
49928 c.setHeight(newHeight);
49932 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
49935 var s = this.scroller;
49937 var csize = c.getSize(true);
49939 this.el.setSize(csize.width, csize.height);
49941 this.headerPanel.setWidth(csize.width);
49942 this.footerPanel.setWidth(csize.width);
49944 var hdHeight = this.mainHd.getHeight();
49945 var vw = csize.width;
49946 var vh = csize.height - (tbh + bbh);
49950 var bt = this.getBodyTable();
49951 var ltWidth = hasLock ?
49952 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
49954 var scrollHeight = bt.offsetHeight;
49955 var scrollWidth = ltWidth + bt.offsetWidth;
49956 var vscroll = false, hscroll = false;
49958 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
49960 var lw = this.lockedWrap, mw = this.mainWrap;
49961 var lb = this.lockedBody, mb = this.mainBody;
49963 setTimeout(function(){
49964 var t = s.dom.offsetTop;
49965 var w = s.dom.clientWidth,
49966 h = s.dom.clientHeight;
49969 lw.setSize(ltWidth, h);
49971 mw.setLeftTop(ltWidth, t);
49972 mw.setSize(w-ltWidth, h);
49974 lb.setHeight(h-hdHeight);
49975 mb.setHeight(h-hdHeight);
49977 if(is2ndPass !== true && !gv.userResized && expandCol){
49978 // high speed resize without full column calculation
49980 var ci = cm.getIndexById(expandCol);
49982 ci = cm.findColumnIndex(expandCol);
49984 ci = Math.max(0, ci); // make sure it's got at least the first col.
49985 var expandId = cm.getColumnId(ci);
49986 var tw = cm.getTotalWidth(false);
49987 var currentWidth = cm.getColumnWidth(ci);
49988 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
49989 if(currentWidth != cw){
49990 cm.setColumnWidth(ci, cw, true);
49991 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
49992 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
49993 gv.updateSplitters();
49994 gv.layout(false, true);
50006 onWindowResize : function(){
50007 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
50013 appendFooter : function(parentEl){
50017 sortAscText : "Sort Ascending",
50018 sortDescText : "Sort Descending",
50019 lockText : "Lock Column",
50020 unlockText : "Unlock Column",
50021 columnsText : "Columns"
50025 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
50026 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
50027 this.proxy.el.addClass('x-grid3-col-dd');
50030 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
50031 handleMouseDown : function(e){
50035 callHandleMouseDown : function(e){
50036 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
50041 * Ext JS Library 1.1.1
50042 * Copyright(c) 2006-2007, Ext JS, LLC.
50044 * Originally Released Under LGPL - original licence link has changed is not relivant.
50047 * <script type="text/javascript">
50051 // This is a support class used internally by the Grid components
50052 Roo.grid.SplitDragZone = function(grid, hd, hd2){
50054 this.view = grid.getView();
50055 this.proxy = this.view.resizeProxy;
50056 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
50057 "gridSplitters" + this.grid.getGridEl().id, {
50058 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
50060 this.setHandleElId(Roo.id(hd));
50061 this.setOuterHandleElId(Roo.id(hd2));
50062 this.scroll = false;
50064 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
50065 fly: Roo.Element.fly,
50067 b4StartDrag : function(x, y){
50068 this.view.headersDisabled = true;
50069 this.proxy.setHeight(this.view.mainWrap.getHeight());
50070 var w = this.cm.getColumnWidth(this.cellIndex);
50071 var minw = Math.max(w-this.grid.minColumnWidth, 0);
50072 this.resetConstraints();
50073 this.setXConstraint(minw, 1000);
50074 this.setYConstraint(0, 0);
50075 this.minX = x - minw;
50076 this.maxX = x + 1000;
50078 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
50082 handleMouseDown : function(e){
50083 ev = Roo.EventObject.setEvent(e);
50084 var t = this.fly(ev.getTarget());
50085 if(t.hasClass("x-grid-split")){
50086 this.cellIndex = this.view.getCellIndex(t.dom);
50087 this.split = t.dom;
50088 this.cm = this.grid.colModel;
50089 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
50090 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
50095 endDrag : function(e){
50096 this.view.headersDisabled = false;
50097 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
50098 var diff = endX - this.startPos;
50099 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
50102 autoOffset : function(){
50103 this.setDelta(0,0);
50107 * Ext JS Library 1.1.1
50108 * Copyright(c) 2006-2007, Ext JS, LLC.
50110 * Originally Released Under LGPL - original licence link has changed is not relivant.
50113 * <script type="text/javascript">
50117 // This is a support class used internally by the Grid components
50118 Roo.grid.GridDragZone = function(grid, config){
50119 this.view = grid.getView();
50120 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
50121 if(this.view.lockedBody){
50122 this.setHandleElId(Roo.id(this.view.mainBody.dom));
50123 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
50125 this.scroll = false;
50127 this.ddel = document.createElement('div');
50128 this.ddel.className = 'x-grid-dd-wrap';
50131 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
50132 ddGroup : "GridDD",
50134 getDragData : function(e){
50135 var t = Roo.lib.Event.getTarget(e);
50136 var rowIndex = this.view.findRowIndex(t);
50137 if(rowIndex !== false){
50138 var sm = this.grid.selModel;
50139 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
50140 // sm.mouseDown(e, t);
50142 if (e.hasModifier()){
50143 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
50145 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
50150 onInitDrag : function(e){
50151 var data = this.dragData;
50152 this.ddel.innerHTML = this.grid.getDragDropText();
50153 this.proxy.update(this.ddel);
50154 // fire start drag?
50157 afterRepair : function(){
50158 this.dragging = false;
50161 getRepairXY : function(e, data){
50165 onEndDrag : function(data, e){
50169 onValidDrop : function(dd, e, id){
50174 beforeInvalidDrop : function(e, id){
50179 * Ext JS Library 1.1.1
50180 * Copyright(c) 2006-2007, Ext JS, LLC.
50182 * Originally Released Under LGPL - original licence link has changed is not relivant.
50185 * <script type="text/javascript">
50190 * @class Roo.grid.ColumnModel
50191 * @extends Roo.util.Observable
50192 * This is the default implementation of a ColumnModel used by the Grid. It defines
50193 * the columns in the grid.
50196 var colModel = new Roo.grid.ColumnModel([
50197 {header: "Ticker", width: 60, sortable: true, locked: true},
50198 {header: "Company Name", width: 150, sortable: true},
50199 {header: "Market Cap.", width: 100, sortable: true},
50200 {header: "$ Sales", width: 100, sortable: true, renderer: money},
50201 {header: "Employees", width: 100, sortable: true, resizable: false}
50206 * The config options listed for this class are options which may appear in each
50207 * individual column definition.
50208 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
50210 * @param {Object} config An Array of column config objects. See this class's
50211 * config objects for details.
50213 Roo.grid.ColumnModel = function(config){
50215 * The config passed into the constructor
50217 this.config = config;
50220 // if no id, create one
50221 // if the column does not have a dataIndex mapping,
50222 // map it to the order it is in the config
50223 for(var i = 0, len = config.length; i < len; i++){
50225 if(typeof c.dataIndex == "undefined"){
50228 if(typeof c.renderer == "string"){
50229 c.renderer = Roo.util.Format[c.renderer];
50231 if(typeof c.id == "undefined"){
50234 if(c.editor && c.editor.xtype){
50235 c.editor = Roo.factory(c.editor, Roo.grid);
50237 if(c.editor && c.editor.isFormField){
50238 c.editor = new Roo.grid.GridEditor(c.editor);
50240 this.lookup[c.id] = c;
50244 * The width of columns which have no width specified (defaults to 100)
50247 this.defaultWidth = 100;
50250 * Default sortable of columns which have no sortable specified (defaults to false)
50253 this.defaultSortable = false;
50257 * @event widthchange
50258 * Fires when the width of a column changes.
50259 * @param {ColumnModel} this
50260 * @param {Number} columnIndex The column index
50261 * @param {Number} newWidth The new width
50263 "widthchange": true,
50265 * @event headerchange
50266 * Fires when the text of a header changes.
50267 * @param {ColumnModel} this
50268 * @param {Number} columnIndex The column index
50269 * @param {Number} newText The new header text
50271 "headerchange": true,
50273 * @event hiddenchange
50274 * Fires when a column is hidden or "unhidden".
50275 * @param {ColumnModel} this
50276 * @param {Number} columnIndex The column index
50277 * @param {Boolean} hidden true if hidden, false otherwise
50279 "hiddenchange": true,
50281 * @event columnmoved
50282 * Fires when a column is moved.
50283 * @param {ColumnModel} this
50284 * @param {Number} oldIndex
50285 * @param {Number} newIndex
50287 "columnmoved" : true,
50289 * @event columlockchange
50290 * Fires when a column's locked state is changed
50291 * @param {ColumnModel} this
50292 * @param {Number} colIndex
50293 * @param {Boolean} locked true if locked
50295 "columnlockchange" : true
50297 Roo.grid.ColumnModel.superclass.constructor.call(this);
50299 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
50301 * @cfg {String} header The header text to display in the Grid view.
50304 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
50305 * {@link Roo.data.Record} definition from which to draw the column's value. If not
50306 * specified, the column's index is used as an index into the Record's data Array.
50309 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
50310 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
50313 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
50314 * Defaults to the value of the {@link #defaultSortable} property.
50315 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
50318 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
50321 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
50324 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
50327 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
50330 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
50331 * given the cell's data value. See {@link #setRenderer}. If not specified, the
50332 * default renderer uses the raw data value.
50335 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
50338 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
50342 * Returns the id of the column at the specified index.
50343 * @param {Number} index The column index
50344 * @return {String} the id
50346 getColumnId : function(index){
50347 return this.config[index].id;
50351 * Returns the column for a specified id.
50352 * @param {String} id The column id
50353 * @return {Object} the column
50355 getColumnById : function(id){
50356 return this.lookup[id];
50361 * Returns the column for a specified dataIndex.
50362 * @param {String} dataIndex The column dataIndex
50363 * @return {Object|Boolean} the column or false if not found
50365 getColumnByDataIndex: function(dataIndex){
50366 var index = this.findColumnIndex(dataIndex);
50367 return index > -1 ? this.config[index] : false;
50371 * Returns the index for a specified column id.
50372 * @param {String} id The column id
50373 * @return {Number} the index, or -1 if not found
50375 getIndexById : function(id){
50376 for(var i = 0, len = this.config.length; i < len; i++){
50377 if(this.config[i].id == id){
50385 * Returns the index for a specified column dataIndex.
50386 * @param {String} dataIndex The column dataIndex
50387 * @return {Number} the index, or -1 if not found
50390 findColumnIndex : function(dataIndex){
50391 for(var i = 0, len = this.config.length; i < len; i++){
50392 if(this.config[i].dataIndex == dataIndex){
50400 moveColumn : function(oldIndex, newIndex){
50401 var c = this.config[oldIndex];
50402 this.config.splice(oldIndex, 1);
50403 this.config.splice(newIndex, 0, c);
50404 this.dataMap = null;
50405 this.fireEvent("columnmoved", this, oldIndex, newIndex);
50408 isLocked : function(colIndex){
50409 return this.config[colIndex].locked === true;
50412 setLocked : function(colIndex, value, suppressEvent){
50413 if(this.isLocked(colIndex) == value){
50416 this.config[colIndex].locked = value;
50417 if(!suppressEvent){
50418 this.fireEvent("columnlockchange", this, colIndex, value);
50422 getTotalLockedWidth : function(){
50423 var totalWidth = 0;
50424 for(var i = 0; i < this.config.length; i++){
50425 if(this.isLocked(i) && !this.isHidden(i)){
50426 this.totalWidth += this.getColumnWidth(i);
50432 getLockedCount : function(){
50433 for(var i = 0, len = this.config.length; i < len; i++){
50434 if(!this.isLocked(i)){
50441 * Returns the number of columns.
50444 getColumnCount : function(visibleOnly){
50445 if(visibleOnly === true){
50447 for(var i = 0, len = this.config.length; i < len; i++){
50448 if(!this.isHidden(i)){
50454 return this.config.length;
50458 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
50459 * @param {Function} fn
50460 * @param {Object} scope (optional)
50461 * @return {Array} result
50463 getColumnsBy : function(fn, scope){
50465 for(var i = 0, len = this.config.length; i < len; i++){
50466 var c = this.config[i];
50467 if(fn.call(scope||this, c, i) === true){
50475 * Returns true if the specified column is sortable.
50476 * @param {Number} col The column index
50477 * @return {Boolean}
50479 isSortable : function(col){
50480 if(typeof this.config[col].sortable == "undefined"){
50481 return this.defaultSortable;
50483 return this.config[col].sortable;
50487 * Returns the rendering (formatting) function defined for the column.
50488 * @param {Number} col The column index.
50489 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
50491 getRenderer : function(col){
50492 if(!this.config[col].renderer){
50493 return Roo.grid.ColumnModel.defaultRenderer;
50495 return this.config[col].renderer;
50499 * Sets the rendering (formatting) function for a column.
50500 * @param {Number} col The column index
50501 * @param {Function} fn The function to use to process the cell's raw data
50502 * to return HTML markup for the grid view. The render function is called with
50503 * the following parameters:<ul>
50504 * <li>Data value.</li>
50505 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
50506 * <li>css A CSS style string to apply to the table cell.</li>
50507 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
50508 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
50509 * <li>Row index</li>
50510 * <li>Column index</li>
50511 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
50513 setRenderer : function(col, fn){
50514 this.config[col].renderer = fn;
50518 * Returns the width for the specified column.
50519 * @param {Number} col The column index
50522 getColumnWidth : function(col){
50523 return this.config[col].width * 1 || this.defaultWidth;
50527 * Sets the width for a column.
50528 * @param {Number} col The column index
50529 * @param {Number} width The new width
50531 setColumnWidth : function(col, width, suppressEvent){
50532 this.config[col].width = width;
50533 this.totalWidth = null;
50534 if(!suppressEvent){
50535 this.fireEvent("widthchange", this, col, width);
50540 * Returns the total width of all columns.
50541 * @param {Boolean} includeHidden True to include hidden column widths
50544 getTotalWidth : function(includeHidden){
50545 if(!this.totalWidth){
50546 this.totalWidth = 0;
50547 for(var i = 0, len = this.config.length; i < len; i++){
50548 if(includeHidden || !this.isHidden(i)){
50549 this.totalWidth += this.getColumnWidth(i);
50553 return this.totalWidth;
50557 * Returns the header for the specified column.
50558 * @param {Number} col The column index
50561 getColumnHeader : function(col){
50562 return this.config[col].header;
50566 * Sets the header for a column.
50567 * @param {Number} col The column index
50568 * @param {String} header The new header
50570 setColumnHeader : function(col, header){
50571 this.config[col].header = header;
50572 this.fireEvent("headerchange", this, col, header);
50576 * Returns the tooltip for the specified column.
50577 * @param {Number} col The column index
50580 getColumnTooltip : function(col){
50581 return this.config[col].tooltip;
50584 * Sets the tooltip for a column.
50585 * @param {Number} col The column index
50586 * @param {String} tooltip The new tooltip
50588 setColumnTooltip : function(col, tooltip){
50589 this.config[col].tooltip = tooltip;
50593 * Returns the dataIndex for the specified column.
50594 * @param {Number} col The column index
50597 getDataIndex : function(col){
50598 return this.config[col].dataIndex;
50602 * Sets the dataIndex for a column.
50603 * @param {Number} col The column index
50604 * @param {Number} dataIndex The new dataIndex
50606 setDataIndex : function(col, dataIndex){
50607 this.config[col].dataIndex = dataIndex;
50613 * Returns true if the cell is editable.
50614 * @param {Number} colIndex The column index
50615 * @param {Number} rowIndex The row index
50616 * @return {Boolean}
50618 isCellEditable : function(colIndex, rowIndex){
50619 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
50623 * Returns the editor defined for the cell/column.
50624 * return false or null to disable editing.
50625 * @param {Number} colIndex The column index
50626 * @param {Number} rowIndex The row index
50629 getCellEditor : function(colIndex, rowIndex){
50630 return this.config[colIndex].editor;
50634 * Sets if a column is editable.
50635 * @param {Number} col The column index
50636 * @param {Boolean} editable True if the column is editable
50638 setEditable : function(col, editable){
50639 this.config[col].editable = editable;
50644 * Returns true if the column is hidden.
50645 * @param {Number} colIndex The column index
50646 * @return {Boolean}
50648 isHidden : function(colIndex){
50649 return this.config[colIndex].hidden;
50654 * Returns true if the column width cannot be changed
50656 isFixed : function(colIndex){
50657 return this.config[colIndex].fixed;
50661 * Returns true if the column can be resized
50662 * @return {Boolean}
50664 isResizable : function(colIndex){
50665 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
50668 * Sets if a column is hidden.
50669 * @param {Number} colIndex The column index
50670 * @param {Boolean} hidden True if the column is hidden
50672 setHidden : function(colIndex, hidden){
50673 this.config[colIndex].hidden = hidden;
50674 this.totalWidth = null;
50675 this.fireEvent("hiddenchange", this, colIndex, hidden);
50679 * Sets the editor for a column.
50680 * @param {Number} col The column index
50681 * @param {Object} editor The editor object
50683 setEditor : function(col, editor){
50684 this.config[col].editor = editor;
50688 Roo.grid.ColumnModel.defaultRenderer = function(value){
50689 if(typeof value == "string" && value.length < 1){
50695 // Alias for backwards compatibility
50696 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
50699 * Ext JS Library 1.1.1
50700 * Copyright(c) 2006-2007, Ext JS, LLC.
50702 * Originally Released Under LGPL - original licence link has changed is not relivant.
50705 * <script type="text/javascript">
50709 * @class Roo.grid.AbstractSelectionModel
50710 * @extends Roo.util.Observable
50711 * Abstract base class for grid SelectionModels. It provides the interface that should be
50712 * implemented by descendant classes. This class should not be directly instantiated.
50715 Roo.grid.AbstractSelectionModel = function(){
50716 this.locked = false;
50717 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
50720 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
50721 /** @ignore Called by the grid automatically. Do not call directly. */
50722 init : function(grid){
50728 * Locks the selections.
50731 this.locked = true;
50735 * Unlocks the selections.
50737 unlock : function(){
50738 this.locked = false;
50742 * Returns true if the selections are locked.
50743 * @return {Boolean}
50745 isLocked : function(){
50746 return this.locked;
50750 * Ext JS Library 1.1.1
50751 * Copyright(c) 2006-2007, Ext JS, LLC.
50753 * Originally Released Under LGPL - original licence link has changed is not relivant.
50756 * <script type="text/javascript">
50759 * @extends Roo.grid.AbstractSelectionModel
50760 * @class Roo.grid.RowSelectionModel
50761 * The default SelectionModel used by {@link Roo.grid.Grid}.
50762 * It supports multiple selections and keyboard selection/navigation.
50764 * @param {Object} config
50766 Roo.grid.RowSelectionModel = function(config){
50767 Roo.apply(this, config);
50768 this.selections = new Roo.util.MixedCollection(false, function(o){
50773 this.lastActive = false;
50777 * @event selectionchange
50778 * Fires when the selection changes
50779 * @param {SelectionModel} this
50781 "selectionchange" : true,
50783 * @event afterselectionchange
50784 * Fires after the selection changes (eg. by key press or clicking)
50785 * @param {SelectionModel} this
50787 "afterselectionchange" : true,
50789 * @event beforerowselect
50790 * Fires when a row is selected being selected, return false to cancel.
50791 * @param {SelectionModel} this
50792 * @param {Number} rowIndex The selected index
50793 * @param {Boolean} keepExisting False if other selections will be cleared
50795 "beforerowselect" : true,
50798 * Fires when a row is selected.
50799 * @param {SelectionModel} this
50800 * @param {Number} rowIndex The selected index
50801 * @param {Roo.data.Record} r The record
50803 "rowselect" : true,
50805 * @event rowdeselect
50806 * Fires when a row is deselected.
50807 * @param {SelectionModel} this
50808 * @param {Number} rowIndex The selected index
50810 "rowdeselect" : true
50812 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
50813 this.locked = false;
50816 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
50818 * @cfg {Boolean} singleSelect
50819 * True to allow selection of only one row at a time (defaults to false)
50821 singleSelect : false,
50824 initEvents : function(){
50826 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
50827 this.grid.on("mousedown", this.handleMouseDown, this);
50828 }else{ // allow click to work like normal
50829 this.grid.on("rowclick", this.handleDragableRowClick, this);
50832 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
50833 "up" : function(e){
50835 this.selectPrevious(e.shiftKey);
50836 }else if(this.last !== false && this.lastActive !== false){
50837 var last = this.last;
50838 this.selectRange(this.last, this.lastActive-1);
50839 this.grid.getView().focusRow(this.lastActive);
50840 if(last !== false){
50844 this.selectFirstRow();
50846 this.fireEvent("afterselectionchange", this);
50848 "down" : function(e){
50850 this.selectNext(e.shiftKey);
50851 }else if(this.last !== false && this.lastActive !== false){
50852 var last = this.last;
50853 this.selectRange(this.last, this.lastActive+1);
50854 this.grid.getView().focusRow(this.lastActive);
50855 if(last !== false){
50859 this.selectFirstRow();
50861 this.fireEvent("afterselectionchange", this);
50866 var view = this.grid.view;
50867 view.on("refresh", this.onRefresh, this);
50868 view.on("rowupdated", this.onRowUpdated, this);
50869 view.on("rowremoved", this.onRemove, this);
50873 onRefresh : function(){
50874 var ds = this.grid.dataSource, i, v = this.grid.view;
50875 var s = this.selections;
50876 s.each(function(r){
50877 if((i = ds.indexOfId(r.id)) != -1){
50886 onRemove : function(v, index, r){
50887 this.selections.remove(r);
50891 onRowUpdated : function(v, index, r){
50892 if(this.isSelected(r)){
50893 v.onRowSelect(index);
50899 * @param {Array} records The records to select
50900 * @param {Boolean} keepExisting (optional) True to keep existing selections
50902 selectRecords : function(records, keepExisting){
50904 this.clearSelections();
50906 var ds = this.grid.dataSource;
50907 for(var i = 0, len = records.length; i < len; i++){
50908 this.selectRow(ds.indexOf(records[i]), true);
50913 * Gets the number of selected rows.
50916 getCount : function(){
50917 return this.selections.length;
50921 * Selects the first row in the grid.
50923 selectFirstRow : function(){
50928 * Select the last row.
50929 * @param {Boolean} keepExisting (optional) True to keep existing selections
50931 selectLastRow : function(keepExisting){
50932 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
50936 * Selects the row immediately following the last selected row.
50937 * @param {Boolean} keepExisting (optional) True to keep existing selections
50939 selectNext : function(keepExisting){
50940 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
50941 this.selectRow(this.last+1, keepExisting);
50942 this.grid.getView().focusRow(this.last);
50947 * Selects the row that precedes the last selected row.
50948 * @param {Boolean} keepExisting (optional) True to keep existing selections
50950 selectPrevious : function(keepExisting){
50952 this.selectRow(this.last-1, keepExisting);
50953 this.grid.getView().focusRow(this.last);
50958 * Returns the selected records
50959 * @return {Array} Array of selected records
50961 getSelections : function(){
50962 return [].concat(this.selections.items);
50966 * Returns the first selected record.
50969 getSelected : function(){
50970 return this.selections.itemAt(0);
50975 * Clears all selections.
50977 clearSelections : function(fast){
50978 if(this.locked) return;
50980 var ds = this.grid.dataSource;
50981 var s = this.selections;
50982 s.each(function(r){
50983 this.deselectRow(ds.indexOfId(r.id));
50987 this.selections.clear();
50994 * Selects all rows.
50996 selectAll : function(){
50997 if(this.locked) return;
50998 this.selections.clear();
50999 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
51000 this.selectRow(i, true);
51005 * Returns True if there is a selection.
51006 * @return {Boolean}
51008 hasSelection : function(){
51009 return this.selections.length > 0;
51013 * Returns True if the specified row is selected.
51014 * @param {Number/Record} record The record or index of the record to check
51015 * @return {Boolean}
51017 isSelected : function(index){
51018 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
51019 return (r && this.selections.key(r.id) ? true : false);
51023 * Returns True if the specified record id is selected.
51024 * @param {String} id The id of record to check
51025 * @return {Boolean}
51027 isIdSelected : function(id){
51028 return (this.selections.key(id) ? true : false);
51032 handleMouseDown : function(e, t){
51033 var view = this.grid.getView(), rowIndex;
51034 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
51037 if(e.shiftKey && this.last !== false){
51038 var last = this.last;
51039 this.selectRange(last, rowIndex, e.ctrlKey);
51040 this.last = last; // reset the last
51041 view.focusRow(rowIndex);
51043 var isSelected = this.isSelected(rowIndex);
51044 if(e.button !== 0 && isSelected){
51045 view.focusRow(rowIndex);
51046 }else if(e.ctrlKey && isSelected){
51047 this.deselectRow(rowIndex);
51048 }else if(!isSelected){
51049 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
51050 view.focusRow(rowIndex);
51053 this.fireEvent("afterselectionchange", this);
51056 handleDragableRowClick : function(grid, rowIndex, e)
51058 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
51059 this.selectRow(rowIndex, false);
51060 grid.view.focusRow(rowIndex);
51061 this.fireEvent("afterselectionchange", this);
51066 * Selects multiple rows.
51067 * @param {Array} rows Array of the indexes of the row to select
51068 * @param {Boolean} keepExisting (optional) True to keep existing selections
51070 selectRows : function(rows, keepExisting){
51072 this.clearSelections();
51074 for(var i = 0, len = rows.length; i < len; i++){
51075 this.selectRow(rows[i], true);
51080 * Selects a range of rows. All rows in between startRow and endRow are also selected.
51081 * @param {Number} startRow The index of the first row in the range
51082 * @param {Number} endRow The index of the last row in the range
51083 * @param {Boolean} keepExisting (optional) True to retain existing selections
51085 selectRange : function(startRow, endRow, keepExisting){
51086 if(this.locked) return;
51088 this.clearSelections();
51090 if(startRow <= endRow){
51091 for(var i = startRow; i <= endRow; i++){
51092 this.selectRow(i, true);
51095 for(var i = startRow; i >= endRow; i--){
51096 this.selectRow(i, true);
51102 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
51103 * @param {Number} startRow The index of the first row in the range
51104 * @param {Number} endRow The index of the last row in the range
51106 deselectRange : function(startRow, endRow, preventViewNotify){
51107 if(this.locked) return;
51108 for(var i = startRow; i <= endRow; i++){
51109 this.deselectRow(i, preventViewNotify);
51115 * @param {Number} row The index of the row to select
51116 * @param {Boolean} keepExisting (optional) True to keep existing selections
51118 selectRow : function(index, keepExisting, preventViewNotify){
51119 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
51120 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
51121 if(!keepExisting || this.singleSelect){
51122 this.clearSelections();
51124 var r = this.grid.dataSource.getAt(index);
51125 this.selections.add(r);
51126 this.last = this.lastActive = index;
51127 if(!preventViewNotify){
51128 this.grid.getView().onRowSelect(index);
51130 this.fireEvent("rowselect", this, index, r);
51131 this.fireEvent("selectionchange", this);
51137 * @param {Number} row The index of the row to deselect
51139 deselectRow : function(index, preventViewNotify){
51140 if(this.locked) return;
51141 if(this.last == index){
51144 if(this.lastActive == index){
51145 this.lastActive = false;
51147 var r = this.grid.dataSource.getAt(index);
51148 this.selections.remove(r);
51149 if(!preventViewNotify){
51150 this.grid.getView().onRowDeselect(index);
51152 this.fireEvent("rowdeselect", this, index);
51153 this.fireEvent("selectionchange", this);
51157 restoreLast : function(){
51159 this.last = this._last;
51164 acceptsNav : function(row, col, cm){
51165 return !cm.isHidden(col) && cm.isCellEditable(col, row);
51169 onEditorKey : function(field, e){
51170 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
51175 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
51177 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
51179 }else if(k == e.ENTER && !e.ctrlKey){
51183 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
51185 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
51187 }else if(k == e.ESC){
51191 g.startEditing(newCell[0], newCell[1]);
51196 * Ext JS Library 1.1.1
51197 * Copyright(c) 2006-2007, Ext JS, LLC.
51199 * Originally Released Under LGPL - original licence link has changed is not relivant.
51202 * <script type="text/javascript">
51205 * @class Roo.grid.CellSelectionModel
51206 * @extends Roo.grid.AbstractSelectionModel
51207 * This class provides the basic implementation for cell selection in a grid.
51209 * @param {Object} config The object containing the configuration of this model.
51210 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
51212 Roo.grid.CellSelectionModel = function(config){
51213 Roo.apply(this, config);
51215 this.selection = null;
51219 * @event beforerowselect
51220 * Fires before a cell is selected.
51221 * @param {SelectionModel} this
51222 * @param {Number} rowIndex The selected row index
51223 * @param {Number} colIndex The selected cell index
51225 "beforecellselect" : true,
51227 * @event cellselect
51228 * Fires when a cell is selected.
51229 * @param {SelectionModel} this
51230 * @param {Number} rowIndex The selected row index
51231 * @param {Number} colIndex The selected cell index
51233 "cellselect" : true,
51235 * @event selectionchange
51236 * Fires when the active selection changes.
51237 * @param {SelectionModel} this
51238 * @param {Object} selection null for no selection or an object (o) with two properties
51240 <li>o.record: the record object for the row the selection is in</li>
51241 <li>o.cell: An array of [rowIndex, columnIndex]</li>
51244 "selectionchange" : true,
51247 * Fires when the tab (or enter) was pressed on the last editable cell
51248 * You can use this to trigger add new row.
51249 * @param {SelectionModel} this
51253 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
51256 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
51258 enter_is_tab: false,
51261 initEvents : function(){
51262 this.grid.on("mousedown", this.handleMouseDown, this);
51263 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
51264 var view = this.grid.view;
51265 view.on("refresh", this.onViewChange, this);
51266 view.on("rowupdated", this.onRowUpdated, this);
51267 view.on("beforerowremoved", this.clearSelections, this);
51268 view.on("beforerowsinserted", this.clearSelections, this);
51269 if(this.grid.isEditor){
51270 this.grid.on("beforeedit", this.beforeEdit, this);
51275 beforeEdit : function(e){
51276 this.select(e.row, e.column, false, true, e.record);
51280 onRowUpdated : function(v, index, r){
51281 if(this.selection && this.selection.record == r){
51282 v.onCellSelect(index, this.selection.cell[1]);
51287 onViewChange : function(){
51288 this.clearSelections(true);
51292 * Returns the currently selected cell,.
51293 * @return {Array} The selected cell (row, column) or null if none selected.
51295 getSelectedCell : function(){
51296 return this.selection ? this.selection.cell : null;
51300 * Clears all selections.
51301 * @param {Boolean} true to prevent the gridview from being notified about the change.
51303 clearSelections : function(preventNotify){
51304 var s = this.selection;
51306 if(preventNotify !== true){
51307 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
51309 this.selection = null;
51310 this.fireEvent("selectionchange", this, null);
51315 * Returns true if there is a selection.
51316 * @return {Boolean}
51318 hasSelection : function(){
51319 return this.selection ? true : false;
51323 handleMouseDown : function(e, t){
51324 var v = this.grid.getView();
51325 if(this.isLocked()){
51328 var row = v.findRowIndex(t);
51329 var cell = v.findCellIndex(t);
51330 if(row !== false && cell !== false){
51331 this.select(row, cell);
51337 * @param {Number} rowIndex
51338 * @param {Number} collIndex
51340 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
51341 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
51342 this.clearSelections();
51343 r = r || this.grid.dataSource.getAt(rowIndex);
51346 cell : [rowIndex, colIndex]
51348 if(!preventViewNotify){
51349 var v = this.grid.getView();
51350 v.onCellSelect(rowIndex, colIndex);
51351 if(preventFocus !== true){
51352 v.focusCell(rowIndex, colIndex);
51355 this.fireEvent("cellselect", this, rowIndex, colIndex);
51356 this.fireEvent("selectionchange", this, this.selection);
51361 isSelectable : function(rowIndex, colIndex, cm){
51362 return !cm.isHidden(colIndex);
51366 handleKeyDown : function(e){
51367 //Roo.log('Cell Sel Model handleKeyDown');
51368 if(!e.isNavKeyPress()){
51371 var g = this.grid, s = this.selection;
51374 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
51376 this.select(cell[0], cell[1]);
51381 var walk = function(row, col, step){
51382 return g.walkCells(row, col, step, sm.isSelectable, sm);
51384 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
51391 // handled by onEditorKey
51392 if (g.isEditor && g.editing) {
51396 newCell = walk(r, c-1, -1);
51398 newCell = walk(r, c+1, 1);
51403 newCell = walk(r+1, c, 1);
51407 newCell = walk(r-1, c, -1);
51411 newCell = walk(r, c+1, 1);
51415 newCell = walk(r, c-1, -1);
51420 if(g.isEditor && !g.editing){
51421 g.startEditing(r, c);
51430 this.select(newCell[0], newCell[1]);
51436 acceptsNav : function(row, col, cm){
51437 return !cm.isHidden(col) && cm.isCellEditable(col, row);
51441 * @param {Number} field (not used) - as it's normally used as a listener
51442 * @param {Number} e - event - fake it by using
51444 * var e = Roo.EventObjectImpl.prototype;
51445 * e.keyCode = e.TAB
51449 onEditorKey : function(field, e){
51451 var k = e.getKey(),
51454 ed = g.activeEditor,
51456 ///Roo.log('onEditorKey' + k);
51459 if (this.enter_is_tab && k == e.ENTER) {
51465 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
51467 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
51473 }else if(k == e.ENTER && !e.ctrlKey){
51476 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
51477 }else if(k == e.ESC){
51483 //Roo.log('next cell after edit');
51484 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
51485 } else if (forward) {
51486 // tabbed past last
51487 this.fireEvent.defer(100, this, ['tabend',this]);
51492 * Ext JS Library 1.1.1
51493 * Copyright(c) 2006-2007, Ext JS, LLC.
51495 * Originally Released Under LGPL - original licence link has changed is not relivant.
51498 * <script type="text/javascript">
51502 * @class Roo.grid.EditorGrid
51503 * @extends Roo.grid.Grid
51504 * Class for creating and editable grid.
51505 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51506 * The container MUST have some type of size defined for the grid to fill. The container will be
51507 * automatically set to position relative if it isn't already.
51508 * @param {Object} dataSource The data model to bind to
51509 * @param {Object} colModel The column model with info about this grid's columns
51511 Roo.grid.EditorGrid = function(container, config){
51512 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
51513 this.getGridEl().addClass("xedit-grid");
51515 if(!this.selModel){
51516 this.selModel = new Roo.grid.CellSelectionModel();
51519 this.activeEditor = null;
51523 * @event beforeedit
51524 * Fires before cell editing is triggered. The edit event object has the following properties <br />
51525 * <ul style="padding:5px;padding-left:16px;">
51526 * <li>grid - This grid</li>
51527 * <li>record - The record being edited</li>
51528 * <li>field - The field name being edited</li>
51529 * <li>value - The value for the field being edited.</li>
51530 * <li>row - The grid row index</li>
51531 * <li>column - The grid column index</li>
51532 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
51534 * @param {Object} e An edit event (see above for description)
51536 "beforeedit" : true,
51539 * Fires after a cell is edited. <br />
51540 * <ul style="padding:5px;padding-left:16px;">
51541 * <li>grid - This grid</li>
51542 * <li>record - The record being edited</li>
51543 * <li>field - The field name being edited</li>
51544 * <li>value - The value being set</li>
51545 * <li>originalValue - The original value for the field, before the edit.</li>
51546 * <li>row - The grid row index</li>
51547 * <li>column - The grid column index</li>
51549 * @param {Object} e An edit event (see above for description)
51551 "afteredit" : true,
51553 * @event validateedit
51554 * Fires after a cell is edited, but before the value is set in the record.
51555 * You can use this to modify the value being set in the field, Return false
51556 * to cancel the change. The edit event object has the following properties <br />
51557 * <ul style="padding:5px;padding-left:16px;">
51558 * <li>editor - This editor</li>
51559 * <li>grid - This grid</li>
51560 * <li>record - The record being edited</li>
51561 * <li>field - The field name being edited</li>
51562 * <li>value - The value being set</li>
51563 * <li>originalValue - The original value for the field, before the edit.</li>
51564 * <li>row - The grid row index</li>
51565 * <li>column - The grid column index</li>
51566 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
51568 * @param {Object} e An edit event (see above for description)
51570 "validateedit" : true
51572 this.on("bodyscroll", this.stopEditing, this);
51573 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
51576 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
51578 * @cfg {Number} clicksToEdit
51579 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
51586 trackMouseOver: false, // causes very odd FF errors
51588 onCellDblClick : function(g, row, col){
51589 this.startEditing(row, col);
51592 onEditComplete : function(ed, value, startValue){
51593 this.editing = false;
51594 this.activeEditor = null;
51595 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
51597 var field = this.colModel.getDataIndex(ed.col);
51602 originalValue: startValue,
51609 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
51612 if(String(value) !== String(startValue)){
51614 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
51615 r.set(field, e.value);
51616 // if we are dealing with a combo box..
51617 // then we also set the 'name' colum to be the displayField
51618 if (ed.field.displayField && ed.field.name) {
51619 r.set(ed.field.name, ed.field.el.dom.value);
51622 delete e.cancel; //?? why!!!
51623 this.fireEvent("afteredit", e);
51626 this.fireEvent("afteredit", e); // always fire it!
51628 this.view.focusCell(ed.row, ed.col);
51632 * Starts editing the specified for the specified row/column
51633 * @param {Number} rowIndex
51634 * @param {Number} colIndex
51636 startEditing : function(row, col){
51637 this.stopEditing();
51638 if(this.colModel.isCellEditable(col, row)){
51639 this.view.ensureVisible(row, col, true);
51641 var r = this.dataSource.getAt(row);
51642 var field = this.colModel.getDataIndex(col);
51643 var cell = Roo.get(this.view.getCell(row,col));
51648 value: r.data[field],
51653 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
51654 this.editing = true;
51655 var ed = this.colModel.getCellEditor(col, row);
51661 ed.render(ed.parentEl || document.body);
51667 (function(){ // complex but required for focus issues in safari, ie and opera
51671 ed.on("complete", this.onEditComplete, this, {single: true});
51672 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
51673 this.activeEditor = ed;
51674 var v = r.data[field];
51675 ed.startEdit(this.view.getCell(row, col), v);
51676 // combo's with 'displayField and name set
51677 if (ed.field.displayField && ed.field.name) {
51678 ed.field.el.dom.value = r.data[ed.field.name];
51682 }).defer(50, this);
51688 * Stops any active editing
51690 stopEditing : function(){
51691 if(this.activeEditor){
51692 this.activeEditor.completeEdit();
51694 this.activeEditor = null;
51698 * Ext JS Library 1.1.1
51699 * Copyright(c) 2006-2007, Ext JS, LLC.
51701 * Originally Released Under LGPL - original licence link has changed is not relivant.
51704 * <script type="text/javascript">
51707 // private - not really -- you end up using it !
51708 // This is a support class used internally by the Grid components
51711 * @class Roo.grid.GridEditor
51712 * @extends Roo.Editor
51713 * Class for creating and editable grid elements.
51714 * @param {Object} config any settings (must include field)
51716 Roo.grid.GridEditor = function(field, config){
51717 if (!config && field.field) {
51719 field = Roo.factory(config.field, Roo.form);
51721 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
51722 field.monitorTab = false;
51725 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
51728 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
51731 alignment: "tl-tl",
51734 cls: "x-small-editor x-grid-editor",
51739 * Ext JS Library 1.1.1
51740 * Copyright(c) 2006-2007, Ext JS, LLC.
51742 * Originally Released Under LGPL - original licence link has changed is not relivant.
51745 * <script type="text/javascript">
51750 Roo.grid.PropertyRecord = Roo.data.Record.create([
51751 {name:'name',type:'string'}, 'value'
51755 Roo.grid.PropertyStore = function(grid, source){
51757 this.store = new Roo.data.Store({
51758 recordType : Roo.grid.PropertyRecord
51760 this.store.on('update', this.onUpdate, this);
51762 this.setSource(source);
51764 Roo.grid.PropertyStore.superclass.constructor.call(this);
51769 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
51770 setSource : function(o){
51772 this.store.removeAll();
51775 if(this.isEditableValue(o[k])){
51776 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
51779 this.store.loadRecords({records: data}, {}, true);
51782 onUpdate : function(ds, record, type){
51783 if(type == Roo.data.Record.EDIT){
51784 var v = record.data['value'];
51785 var oldValue = record.modified['value'];
51786 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
51787 this.source[record.id] = v;
51789 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
51796 getProperty : function(row){
51797 return this.store.getAt(row);
51800 isEditableValue: function(val){
51801 if(val && val instanceof Date){
51803 }else if(typeof val == 'object' || typeof val == 'function'){
51809 setValue : function(prop, value){
51810 this.source[prop] = value;
51811 this.store.getById(prop).set('value', value);
51814 getSource : function(){
51815 return this.source;
51819 Roo.grid.PropertyColumnModel = function(grid, store){
51822 g.PropertyColumnModel.superclass.constructor.call(this, [
51823 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
51824 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
51826 this.store = store;
51827 this.bselect = Roo.DomHelper.append(document.body, {
51828 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
51829 {tag: 'option', value: 'true', html: 'true'},
51830 {tag: 'option', value: 'false', html: 'false'}
51833 Roo.id(this.bselect);
51836 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
51837 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
51838 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
51839 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
51840 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
51842 this.renderCellDelegate = this.renderCell.createDelegate(this);
51843 this.renderPropDelegate = this.renderProp.createDelegate(this);
51846 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
51850 valueText : 'Value',
51852 dateFormat : 'm/j/Y',
51855 renderDate : function(dateVal){
51856 return dateVal.dateFormat(this.dateFormat);
51859 renderBool : function(bVal){
51860 return bVal ? 'true' : 'false';
51863 isCellEditable : function(colIndex, rowIndex){
51864 return colIndex == 1;
51867 getRenderer : function(col){
51869 this.renderCellDelegate : this.renderPropDelegate;
51872 renderProp : function(v){
51873 return this.getPropertyName(v);
51876 renderCell : function(val){
51878 if(val instanceof Date){
51879 rv = this.renderDate(val);
51880 }else if(typeof val == 'boolean'){
51881 rv = this.renderBool(val);
51883 return Roo.util.Format.htmlEncode(rv);
51886 getPropertyName : function(name){
51887 var pn = this.grid.propertyNames;
51888 return pn && pn[name] ? pn[name] : name;
51891 getCellEditor : function(colIndex, rowIndex){
51892 var p = this.store.getProperty(rowIndex);
51893 var n = p.data['name'], val = p.data['value'];
51895 if(typeof(this.grid.customEditors[n]) == 'string'){
51896 return this.editors[this.grid.customEditors[n]];
51898 if(typeof(this.grid.customEditors[n]) != 'undefined'){
51899 return this.grid.customEditors[n];
51901 if(val instanceof Date){
51902 return this.editors['date'];
51903 }else if(typeof val == 'number'){
51904 return this.editors['number'];
51905 }else if(typeof val == 'boolean'){
51906 return this.editors['boolean'];
51908 return this.editors['string'];
51914 * @class Roo.grid.PropertyGrid
51915 * @extends Roo.grid.EditorGrid
51916 * This class represents the interface of a component based property grid control.
51917 * <br><br>Usage:<pre><code>
51918 var grid = new Roo.grid.PropertyGrid("my-container-id", {
51926 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51927 * The container MUST have some type of size defined for the grid to fill. The container will be
51928 * automatically set to position relative if it isn't already.
51929 * @param {Object} config A config object that sets properties on this grid.
51931 Roo.grid.PropertyGrid = function(container, config){
51932 config = config || {};
51933 var store = new Roo.grid.PropertyStore(this);
51934 this.store = store;
51935 var cm = new Roo.grid.PropertyColumnModel(this, store);
51936 store.store.sort('name', 'ASC');
51937 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
51940 enableColLock:false,
51941 enableColumnMove:false,
51943 trackMouseOver: false,
51946 this.getGridEl().addClass('x-props-grid');
51947 this.lastEditRow = null;
51948 this.on('columnresize', this.onColumnResize, this);
51951 * @event beforepropertychange
51952 * Fires before a property changes (return false to stop?)
51953 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
51954 * @param {String} id Record Id
51955 * @param {String} newval New Value
51956 * @param {String} oldval Old Value
51958 "beforepropertychange": true,
51960 * @event propertychange
51961 * Fires after a property changes
51962 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
51963 * @param {String} id Record Id
51964 * @param {String} newval New Value
51965 * @param {String} oldval Old Value
51967 "propertychange": true
51969 this.customEditors = this.customEditors || {};
51971 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
51974 * @cfg {Object} customEditors map of colnames=> custom editors.
51975 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
51976 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
51977 * false disables editing of the field.
51981 * @cfg {Object} propertyNames map of property Names to their displayed value
51984 render : function(){
51985 Roo.grid.PropertyGrid.superclass.render.call(this);
51986 this.autoSize.defer(100, this);
51989 autoSize : function(){
51990 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
51992 this.view.fitColumns();
51996 onColumnResize : function(){
51997 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
52001 * Sets the data for the Grid
52002 * accepts a Key => Value object of all the elements avaiable.
52003 * @param {Object} data to appear in grid.
52005 setSource : function(source){
52006 this.store.setSource(source);
52010 * Gets all the data from the grid.
52011 * @return {Object} data data stored in grid
52013 getSource : function(){
52014 return this.store.getSource();
52018 * Ext JS Library 1.1.1
52019 * Copyright(c) 2006-2007, Ext JS, LLC.
52021 * Originally Released Under LGPL - original licence link has changed is not relivant.
52024 * <script type="text/javascript">
52028 * @class Roo.LoadMask
52029 * A simple utility class for generically masking elements while loading data. If the element being masked has
52030 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
52031 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
52032 * element's UpdateManager load indicator and will be destroyed after the initial load.
52034 * Create a new LoadMask
52035 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
52036 * @param {Object} config The config object
52038 Roo.LoadMask = function(el, config){
52039 this.el = Roo.get(el);
52040 Roo.apply(this, config);
52042 this.store.on('beforeload', this.onBeforeLoad, this);
52043 this.store.on('load', this.onLoad, this);
52044 this.store.on('loadexception', this.onLoadException, this);
52045 this.removeMask = false;
52047 var um = this.el.getUpdateManager();
52048 um.showLoadIndicator = false; // disable the default indicator
52049 um.on('beforeupdate', this.onBeforeLoad, this);
52050 um.on('update', this.onLoad, this);
52051 um.on('failure', this.onLoad, this);
52052 this.removeMask = true;
52056 Roo.LoadMask.prototype = {
52058 * @cfg {Boolean} removeMask
52059 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
52060 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
52063 * @cfg {String} msg
52064 * The text to display in a centered loading message box (defaults to 'Loading...')
52066 msg : 'Loading...',
52068 * @cfg {String} msgCls
52069 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
52071 msgCls : 'x-mask-loading',
52074 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
52080 * Disables the mask to prevent it from being displayed
52082 disable : function(){
52083 this.disabled = true;
52087 * Enables the mask so that it can be displayed
52089 enable : function(){
52090 this.disabled = false;
52093 onLoadException : function()
52095 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
52096 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
52098 this.el.unmask(this.removeMask);
52101 onLoad : function()
52103 this.el.unmask(this.removeMask);
52107 onBeforeLoad : function(){
52108 if(!this.disabled){
52109 this.el.mask(this.msg, this.msgCls);
52114 destroy : function(){
52116 this.store.un('beforeload', this.onBeforeLoad, this);
52117 this.store.un('load', this.onLoad, this);
52118 this.store.un('loadexception', this.onLoadException, this);
52120 var um = this.el.getUpdateManager();
52121 um.un('beforeupdate', this.onBeforeLoad, this);
52122 um.un('update', this.onLoad, this);
52123 um.un('failure', this.onLoad, this);
52128 * Ext JS Library 1.1.1
52129 * Copyright(c) 2006-2007, Ext JS, LLC.
52131 * Originally Released Under LGPL - original licence link has changed is not relivant.
52134 * <script type="text/javascript">
52136 Roo.XTemplate = function(){
52137 Roo.XTemplate.superclass.constructor.apply(this, arguments);
52140 s = ['<tpl>', s, '</tpl>'].join('');
52142 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
52144 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
52145 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
52146 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
52150 while(m = s.match(re)){
52151 var m2 = m[0].match(nameRe);
52152 var m3 = m[0].match(ifRe);
52153 var m4 = m[0].match(execRe);
52154 var exp = null, fn = null, exec = null;
52155 var name = m2 && m2[1] ? m2[1] : '';
52157 exp = m3 && m3[1] ? m3[1] : null;
52159 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
52163 exp = m4 && m4[1] ? m4[1] : null;
52165 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
52170 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
52171 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
52172 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
52182 s = s.replace(m[0], '{xtpl'+ id + '}');
52185 for(var i = tpls.length-1; i >= 0; --i){
52186 this.compileTpl(tpls[i]);
52188 this.master = tpls[tpls.length-1];
52191 Roo.extend(Roo.XTemplate, Roo.Template, {
52193 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
52195 applySubTemplate : function(id, values, parent){
52196 var t = this.tpls[id];
52197 if(t.test && !t.test.call(this, values, parent)){
52200 if(t.exec && t.exec.call(this, values, parent)){
52203 var vs = t.target ? t.target.call(this, values, parent) : values;
52204 parent = t.target ? values : parent;
52205 if(t.target && vs instanceof Array){
52207 for(var i = 0, len = vs.length; i < len; i++){
52208 buf[buf.length] = t.compiled.call(this, vs[i], parent);
52210 return buf.join('');
52212 return t.compiled.call(this, vs, parent);
52215 compileTpl : function(tpl){
52216 var fm = Roo.util.Format;
52217 var useF = this.disableFormats !== true;
52218 var sep = Roo.isGecko ? "+" : ",";
52219 var fn = function(m, name, format, args){
52220 if(name.substr(0, 4) == 'xtpl'){
52221 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
52224 if(name.indexOf('.') != -1){
52227 v = "values['" + name + "']";
52229 if(format && useF){
52230 args = args ? ',' + args : "";
52231 if(format.substr(0, 5) != "this."){
52232 format = "fm." + format + '(';
52234 format = 'this.call("'+ format.substr(5) + '", ';
52238 args= ''; format = "("+v+" === undefined ? '' : ";
52240 return "'"+ sep + format + v + args + ")"+sep+"'";
52243 // branched to use + in gecko and [].join() in others
52245 body = "tpl.compiled = function(values, parent){ return '" +
52246 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
52249 body = ["tpl.compiled = function(values, parent){ return ['"];
52250 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
52251 body.push("'].join('');};");
52252 body = body.join('');
52254 /** eval:var:zzzzzzz */
52259 applyTemplate : function(values){
52260 return this.master.compiled.call(this, values, {});
52264 apply : function(){
52265 return this.applyTemplate.apply(this, arguments);
52268 compile : function(){return this;}
52271 Roo.XTemplate.from = function(el){
52272 el = Roo.getDom(el);
52273 return new Roo.XTemplate(el.value || el.innerHTML);
52275 * Original code for Roojs - LGPL
52276 * <script type="text/javascript">
52280 * @class Roo.XComponent
52281 * A delayed Element creator...
52282 * Or a way to group chunks of interface together.
52284 * Mypart.xyx = new Roo.XComponent({
52286 parent : 'Mypart.xyz', // empty == document.element.!!
52290 disabled : function() {}
52292 tree : function() { // return an tree of xtype declared components
52296 xtype : 'NestedLayoutPanel',
52303 * It can be used to build a big heiracy, with parent etc.
52304 * or you can just use this to render a single compoent to a dom element
52305 * MYPART.render(Roo.Element | String(id) | dom_element )
52307 * @extends Roo.util.Observable
52309 * @param cfg {Object} configuration of component
52312 Roo.XComponent = function(cfg) {
52313 Roo.apply(this, cfg);
52317 * Fires when this the componnt is built
52318 * @param {Roo.XComponent} c the component
52322 * @event buildcomplete
52323 * Fires on the top level element when all elements have been built
52324 * @param {Roo.XComponent} c the top level component.
52326 'buildcomplete' : true
52329 this.region = this.region || 'center'; // default..
52330 Roo.XComponent.register(this);
52331 this.modules = false;
52332 this.el = false; // where the layout goes..
52336 Roo.extend(Roo.XComponent, Roo.util.Observable, {
52339 * The created element (with Roo.factory())
52340 * @type {Roo.Layout}
52346 * for BC - use el in new code
52347 * @type {Roo.Layout}
52353 * for BC - use el in new code
52354 * @type {Roo.Layout}
52359 * @cfg {Function|boolean} disabled
52360 * If this module is disabled by some rule, return true from the funtion
52365 * @cfg {String} parent
52366 * Name of parent element which it get xtype added to..
52371 * @cfg {String} order
52372 * Used to set the order in which elements are created (usefull for multiple tabs)
52377 * @cfg {String} name
52378 * String to display while loading.
52382 * @cfg {String} region
52383 * Region to render component to (defaults to center)
52388 * @cfg {Array} items
52389 * A single item array - the first element is the root of the tree..
52390 * It's done this way to stay compatible with the Xtype system...
52397 * render element to dom or tree
52398 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
52401 render : function(el)
52405 var hp = this.parent ? 1 : 0;
52407 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
52408 // if parent is a '#.....' string, then let's use that..
52409 var ename = this.parent.substr(1)
52410 this.parent = false;
52411 el = Roo.get(ename);
52413 Roo.log("Warning - element can not be found :#" + ename );
52419 if (!this.parent) {
52421 el = el ? Roo.get(el) : false;
52423 // it's a top level one..
52425 el : new Roo.BorderLayout(el || document.body, {
52431 tabPosition: 'top',
52432 //resizeTabs: true,
52433 alwaysShowTabs: el && hp? false : true,
52434 hideTabs: el || !hp ? true : false,
52443 var tree = this.tree();
52444 tree.region = tree.region || this.region;
52445 this.el = this.parent.el.addxtype(tree);
52446 this.fireEvent('built', this);
52448 this.panel = this.el;
52449 this.layout = this.panel.layout;
52455 Roo.apply(Roo.XComponent, {
52458 * @property buildCompleted
52459 * True when the builder has completed building the interface.
52462 buildCompleted : false,
52465 * @property topModule
52466 * the upper most module - uses document.element as it's constructor.
52473 * @property modules
52474 * array of modules to be created by registration system.
52475 * @type {Array} of Roo.XComponent
52480 * @property elmodules
52481 * array of modules to be created by which use #ID
52482 * @type {Array} of Roo.XComponent
52489 * Register components to be built later.
52491 * This solves the following issues
52492 * - Building is not done on page load, but after an authentication process has occured.
52493 * - Interface elements are registered on page load
52494 * - Parent Interface elements may not be loaded before child, so this handles that..
52501 module : 'Pman.Tab.projectMgr',
52503 parent : 'Pman.layout',
52504 disabled : false, // or use a function..
52507 * * @param {Object} details about module
52509 register : function(obj) {
52510 this.modules.push(obj);
52514 * convert a string to an object..
52515 * eg. 'AAA.BBB' -> finds AAA.BBB
52519 toObject : function(str)
52521 if (!str || typeof(str) == 'object') {
52524 if (str.substring(0,1) == '#') {
52528 var ar = str.split('.');
52533 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
52535 throw "Module not found : " + str;
52539 throw "Module not found : " + str;
52541 Roo.each(ar, function(e) {
52542 if (typeof(o[e]) == 'undefined') {
52543 throw "Module not found : " + str;
52554 * move modules into their correct place in the tree..
52557 preBuild : function ()
52560 Roo.each(this.modules , function (obj)
52562 var opar = obj.parent;
52564 obj.parent = this.toObject(opar);
52566 Roo.log(e.toString());
52571 this.topModule = obj;
52574 if (typeof(obj.parent) == 'string') {
52575 this.elmodules.push(obj);
52578 if (obj.parent.constructor != Roo.XComponent) {
52579 Roo.log("Object Parent is not instance of XComponent:" + obj.name)
52581 if (!obj.parent.modules) {
52582 obj.parent.modules = new Roo.util.MixedCollection(false,
52583 function(o) { return o.order + '' }
52587 obj.parent.modules.add(obj);
52592 * make a list of modules to build.
52593 * @return {Array} list of modules.
52596 buildOrder : function()
52599 var cmp = function(a,b) {
52600 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
52602 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
52603 throw "No top level modules to build";
52606 // make a flat list in order of modules to build.
52607 var mods = this.topModule ? [ this.topModule ] : [];
52608 Roo.each(this.elmodules,function(e) { mods.push(e) });
52611 // add modules to their parents..
52612 var addMod = function(m) {
52613 // Roo.debug && Roo.log(m.modKey);
52617 m.modules.keySort('ASC', cmp );
52618 m.modules.each(addMod);
52620 // not sure if this is used any more..
52622 m.finalize.name = m.name + " (clean up) ";
52623 mods.push(m.finalize);
52627 if (this.topModule) {
52628 this.topModule.modules.keySort('ASC', cmp );
52629 this.topModule.modules.each(addMod);
52635 * Build the registered modules.
52636 * @param {Object} parent element.
52637 * @param {Function} optional method to call after module has been added.
52645 var mods = this.buildOrder();
52647 //this.allmods = mods;
52648 //Roo.debug && Roo.log(mods);
52650 if (!mods.length) { // should not happen
52651 throw "NO modules!!!";
52656 // flash it up as modal - so we store the mask!?
52657 Roo.MessageBox.show({ title: 'loading' });
52658 Roo.MessageBox.show({
52659 title: "Please wait...",
52660 msg: "Building Interface...",
52667 var total = mods.length;
52670 var progressRun = function() {
52671 if (!mods.length) {
52672 Roo.debug && Roo.log('hide?');
52673 Roo.MessageBox.hide();
52674 if (_this.topModule) {
52675 _this.topModule.fireEvent('buildcomplete', _this.topModule);
52681 var m = mods.shift();
52684 Roo.debug && Roo.log(m);
52685 // not sure if this is supported any more.. - modules that are are just function
52686 if (typeof(m) == 'function') {
52688 return progressRun.defer(10, _this);
52693 Roo.MessageBox.updateProgress(
52694 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
52696 (m.name ? (' - ' + m.name) : '')
52700 // is the module disabled?
52701 var disabled = (typeof(m.disabled) == 'function') ?
52702 m.disabled.call(m.module.disabled) : m.disabled;
52706 return progressRun(); // we do not update the display!
52712 // it's 10 on top level, and 1 on others??? why...
52713 return progressRun.defer(10, _this);
52716 progressRun.defer(1, _this);
52727 //<script type="text/javascript">
52732 * @extends Roo.LayoutDialog
52733 * A generic Login Dialog..... - only one needed in theory!?!?
52735 * Fires XComponent builder on success...
52738 * username,password, lang = for login actions.
52739 * check = 1 for periodic checking that sesion is valid.
52740 * passwordRequest = email request password
52741 * logout = 1 = to logout
52743 * Affects: (this id="????" elements)
52744 * loading (removed) (used to indicate application is loading)
52745 * loading-mask (hides) (used to hide application when it's building loading)
52751 * Myapp.login = Roo.Login({
52767 Roo.Login = function(cfg)
52773 Roo.apply(this,cfg);
52775 Roo.onReady(function() {
52781 Roo.Login.superclass.constructor.call(this, this);
52782 //this.addxtype(this.items[0]);
52788 Roo.extend(Roo.Login, Roo.LayoutDialog, {
52791 * @cfg {String} method
52792 * Method used to query for login details.
52797 * @cfg {String} url
52798 * URL to query login data. - eg. baseURL + '/Login.php'
52804 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
52809 * @property checkFails
52810 * Number of times we have attempted to get authentication check, and failed.
52815 * @property intervalID
52816 * The window interval that does the constant login checking.
52822 onLoad : function() // called on page load...
52826 if (Roo.get('loading')) { // clear any loading indicator..
52827 Roo.get('loading').remove();
52830 //this.switchLang('en'); // set the language to english..
52833 success: function(response, opts) { // check successfull...
52835 var res = this.processResponse(response);
52836 this.checkFails =0;
52837 if (!res.success) { // error!
52838 this.checkFails = 5;
52839 //console.log('call failure');
52840 return this.failure(response,opts);
52843 if (!res.data.id) { // id=0 == login failure.
52844 return this.show();
52848 //console.log(success);
52849 this.fillAuth(res.data);
52850 this.checkFails =0;
52851 Roo.XComponent.build();
52853 failure : this.show
52859 check: function(cfg) // called every so often to refresh cookie etc..
52861 if (cfg.again) { // could be undefined..
52864 this.checkFails = 0;
52867 if (this.sending) {
52868 if ( this.checkFails > 4) {
52869 Roo.MessageBox.alert("Error",
52870 "Error getting authentication status. - try reloading, or wait a while", function() {
52871 _this.sending = false;
52876 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
52879 this.sending = true;
52886 method: this.method,
52887 success: cfg.success || this.success,
52888 failure : cfg.failure || this.failure,
52898 window.onbeforeunload = function() { }; // false does not work for IE..
52908 failure : function() {
52909 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
52910 document.location = document.location.toString() + '?ts=' + Math.random();
52914 success : function() {
52915 _this.user = false;
52916 this.checkFails =0;
52918 document.location = document.location.toString() + '?ts=' + Math.random();
52925 processResponse : function (response)
52929 res = Roo.decode(response.responseText);
52931 if (typeof(res) != 'object') {
52932 res = { success : false, errorMsg : res, errors : true };
52934 if (typeof(res.success) == 'undefined') {
52935 res.success = false;
52939 res = { success : false, errorMsg : response.responseText, errors : true };
52944 success : function(response, opts) // check successfull...
52946 this.sending = false;
52947 var res = this.processResponse(response);
52948 if (!res.success) {
52949 return this.failure(response, opts);
52951 if (!res.data || !res.data.id) {
52952 return this.failure(response,opts);
52954 //console.log(res);
52955 this.fillAuth(res.data);
52957 this.checkFails =0;
52962 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
52964 this.authUser = -1;
52965 this.sending = false;
52966 var res = this.processResponse(response);
52967 //console.log(res);
52968 if ( this.checkFails > 2) {
52970 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
52971 "Error getting authentication status. - try reloading");
52974 opts.callCfg.again = true;
52975 this.check.defer(1000, this, [ opts.callCfg ]);
52981 fillAuth: function(au) {
52982 this.startAuthCheck();
52983 this.authUserId = au.id;
52984 this.authUser = au;
52985 this.lastChecked = new Date();
52986 this.fireEvent('refreshed', au);
52987 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
52988 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
52989 au.lang = au.lang || 'en';
52990 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
52991 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
52992 this.switchLang(au.lang );
52995 // open system... - -on setyp..
52996 if (this.authUserId < 0) {
52997 Roo.MessageBox.alert("Warning",
52998 "This is an open system - please set up a admin user with a password.");
53001 //Pman.onload(); // which should do nothing if it's a re-auth result...
53006 startAuthCheck : function() // starter for timeout checking..
53008 if (this.intervalID) { // timer already in place...
53012 this.intervalID = window.setInterval(function() {
53013 _this.check(false);
53014 }, 120000); // every 120 secs = 2mins..
53020 switchLang : function (lang)
53022 _T = typeof(_T) == 'undefined' ? false : _T;
53023 if (!_T || !lang.length) {
53027 if (!_T && lang != 'en') {
53028 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
53032 if (typeof(_T.en) == 'undefined') {
53034 Roo.apply(_T.en, _T);
53037 if (typeof(_T[lang]) == 'undefined') {
53038 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
53043 Roo.apply(_T, _T[lang]);
53044 // just need to set the text values for everything...
53046 /* this will not work ...
53050 function formLabel(name, val) {
53051 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
53054 formLabel('password', "Password"+':');
53055 formLabel('username', "Email Address"+':');
53056 formLabel('lang', "Language"+':');
53057 this.dialog.setTitle("Login");
53058 this.dialog.buttons[0].setText("Forgot Password");
53059 this.dialog.buttons[1].setText("Login");
53078 collapsible: false,
53080 center: { // needed??
53083 // tabPosition: 'top',
53086 alwaysShowTabs: false
53090 show : function(dlg)
53092 //console.log(this);
53093 this.form = this.layout.getRegion('center').activePanel.form;
53094 this.form.dialog = dlg;
53095 this.buttons[0].form = this.form;
53096 this.buttons[0].dialog = dlg;
53097 this.buttons[1].form = this.form;
53098 this.buttons[1].dialog = dlg;
53100 //this.resizeToLogo.defer(1000,this);
53101 // this is all related to resizing for logos..
53102 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
53104 // this.resizeToLogo.defer(1000,this);
53107 //var w = Ext.lib.Dom.getViewWidth() - 100;
53108 //var h = Ext.lib.Dom.getViewHeight() - 100;
53109 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
53111 if (this.disabled) {
53116 if (this.user.id < 0) { // used for inital setup situations.
53120 if (this.intervalID) {
53121 // remove the timer
53122 window.clearInterval(this.intervalID);
53123 this.intervalID = false;
53127 if (Roo.get('loading')) {
53128 Roo.get('loading').remove();
53130 if (Roo.get('loading-mask')) {
53131 Roo.get('loading-mask').hide();
53134 //incomming._node = tnode;
53136 //this.dialog.modal = !modal;
53137 //this.dialog.show();
53141 this.form.setValues({
53142 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
53143 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
53146 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
53147 if (this.form.findField('username').getValue().length > 0 ){
53148 this.form.findField('password').focus();
53150 this.form.findField('username').focus();
53158 xtype : 'ContentPanel',
53170 style : 'margin: 10px;',
53173 actionfailed : function(f, act) {
53174 // form can return { errors: .... }
53176 //act.result.errors // invalid form element list...
53177 //act.result.errorMsg// invalid form element list...
53179 this.dialog.el.unmask();
53180 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
53181 "Login failed - communication error - try again.");
53184 actioncomplete: function(re, act) {
53186 Roo.state.Manager.set(
53187 this.dialog.realm + '.username',
53188 this.findField('username').getValue()
53190 Roo.state.Manager.set(
53191 this.dialog.realm + '.lang',
53192 this.findField('lang').getValue()
53195 this.dialog.fillAuth(act.result.data);
53197 this.dialog.hide();
53199 if (Roo.get('loading-mask')) {
53200 Roo.get('loading-mask').show();
53202 Roo.XComponent.build();
53210 xtype : 'TextField',
53212 fieldLabel: "Email Address",
53215 autoCreate : {tag: "input", type: "text", size: "20"}
53218 xtype : 'TextField',
53220 fieldLabel: "Password",
53221 inputType: 'password',
53224 autoCreate : {tag: "input", type: "text", size: "20"},
53226 specialkey : function(e,ev) {
53227 if (ev.keyCode == 13) {
53228 this.form.dialog.el.mask("Logging in");
53229 this.form.doAction('submit', {
53230 url: this.form.dialog.url,
53231 method: this.form.dialog.method
53238 xtype : 'ComboBox',
53240 fieldLabel: "Language",
53243 xtype : 'SimpleStore',
53244 fields: ['lang', 'ldisp'],
53246 [ 'en', 'English' ],
53247 [ 'zh_HK' , '\u7E41\u4E2D' ],
53248 [ 'zh_CN', '\u7C21\u4E2D' ]
53252 valueField : 'lang',
53253 hiddenName: 'lang',
53255 displayField:'ldisp',
53259 triggerAction: 'all',
53260 emptyText:'Select a Language...',
53261 selectOnFocus:true,
53263 select : function(cb, rec, ix) {
53264 this.form.switchLang(rec.data.lang);
53280 text : "Forgot Password",
53282 click : function() {
53283 //console.log(this);
53284 var n = this.form.findField('username').getValue();
53286 Roo.MessageBox.alert("Error", "Fill in your email address");
53290 url: this.dialog.url,
53294 method: this.dialog.method,
53295 success: function(response, opts) { // check successfull...
53297 var res = this.dialog.processResponse(response);
53298 if (!res.success) { // error!
53299 Roo.MessageBox.alert("Error" ,
53300 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
53303 Roo.MessageBox.alert("Notice" ,
53304 "Please check you email for the Password Reset message");
53306 failure : function() {
53307 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
53320 click : function () {
53322 this.dialog.el.mask("Logging in");
53323 this.form.doAction('submit', {
53324 url: this.dialog.url,
53325 method: this.dialog.method